implement 'got merge -n' which interrupts before creating a merge commit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
diff --git a/got/got.1 b/got/got.1
index c408a29..87a57e1 100644
--- a/got/got.1
+++ b/got/got.1
@@ -2132,7 +2132,7 @@ or reverted with
.It Cm ig
Short alias for
.Cm integrate .
-.It Cm merge Oo Fl a Oc Oo Fl c Oc Op Ar branch
+.It Cm merge Oo Fl a Oc Oo Fl c Oc Oo Fl n Oc Op Ar branch
Create a merge commit based on the current branch of the work tree and
the specified
.Ar branch .
@@ -2246,6 +2246,14 @@ If this option is used, no other command-line arguments are allowed.
.It Fl c
Continue an interrupted merge operation.
If this option is used, no other command-line arguments are allowed.
+.It Fl n
+Merge changes into the work tree as usual but do not create a merge
+commit immediately.
+The merge result can be adjusted as desired before a merge commit is
+created with
+.Cm got merge -c .
+Alternatively, the merge may be aborted with
+.Cm got merge -a .
.El
.It Cm mg
Short alias for
diff --git a/got/got.c b/got/got.c
index 461ac8d..2ffb450 100644
--- a/got/got.c
+++ b/got/got.c
@@ -10590,7 +10590,7 @@ done:
__dead static void
usage_merge(void)
{
- fprintf(stderr, "usage: %s merge [-a] [-c] [branch]\n",
+ fprintf(stderr, "usage: %s merge [-a] [-c] [-n] [branch]\n",
getprogname());
exit(1);
}
@@ -10607,13 +10607,14 @@ cmd_merge(int argc, char *argv[])
struct got_object_id *branch_tip = NULL, *yca_id = NULL;
struct got_object_id *wt_branch_tip = NULL;
int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0;
+ int interrupt_merge = 0;
struct got_update_progress_arg upa;
struct got_object_id *merge_commit_id = NULL;
char *branch_name = NULL;
memset(&upa, 0, sizeof(upa));
- while ((ch = getopt(argc, argv, "ac")) != -1) {
+ while ((ch = getopt(argc, argv, "acn")) != -1) {
switch (ch) {
case 'a':
abort_merge = 1;
@@ -10621,6 +10622,9 @@ cmd_merge(int argc, char *argv[])
case 'c':
continue_merge = 1;
break;
+ case 'n':
+ interrupt_merge = 1;
+ break;
default:
usage_rebase();
/* NOTREACHED */
@@ -10780,7 +10784,12 @@ cmd_merge(int argc, char *argv[])
}
}
- if (upa.conflicts > 0 || upa.missing > 0) {
+ if (interrupt_merge) {
+ error = got_worktree_merge_postpone(worktree, fileindex);
+ if (error)
+ goto done;
+ printf("Merge of %s interrupted on request\n", branch_name);
+ } else if (upa.conflicts > 0 || upa.missing > 0) {
error = got_worktree_merge_postpone(worktree, fileindex);
if (error)
goto done;
diff --git a/regress/cmdline/merge.sh b/regress/cmdline/merge.sh
index 1d534c5..38220a8 100755
--- a/regress/cmdline/merge.sh
+++ b/regress/cmdline/merge.sh
@@ -1236,6 +1236,152 @@ EOF
test_done "$testroot" "$ret"
}
+test_merge_interrupt() {
+ local testroot=`test_init merge_interrupt`
+ local commit0=`git_show_head $testroot/repo`
+ local commit0_author_time=`git_show_author_time $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ echo "modified alpha on branch" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "committing to alpha on newbranch"
+ local branch_commit0=`git_show_branch_head $testroot/repo newbranch`
+
+ got checkout -b master $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got checkout failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # create a non-conflicting commit
+ (cd $testroot/repo && git checkout -q master)
+ echo "modified beta on master" > $testroot/repo/beta
+ git_commit $testroot/repo -m "committing to beta on master"
+ local master_commit=`git_show_head $testroot/repo`
+
+ # need an up-to-date work tree for 'got merge'
+ (cd $testroot/wt && got update > /dev/null)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got update failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got merge -n newbranch \
+ > $testroot/stdout 2> $testroot/stderr)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got merge failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo "G alpha" > $testroot/stdout.expected
+ echo "Merge of refs/heads/newbranch interrupted on request" \
+ >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got status > $testroot/stdout)
+
+ echo "M alpha" > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha on branch" > $testroot/content.expected
+ cat $testroot/wt/alpha > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # adjust merge result
+ echo "adjusted merge result" > $testroot/wt/alpha
+
+ # continue the merge
+ (cd $testroot/wt && got merge -c > $testroot/stdout)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got merge failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ local merge_commit=`git_show_head $testroot/repo`
+
+ echo -n "Merged refs/heads/newbranch into refs/heads/master: " \
+ > $testroot/stdout.expected
+ echo $merge_commit >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got status > $testroot/stdout)
+
+ echo -n > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got log -l3 | grep ^commit > $testroot/stdout)
+ echo "commit $merge_commit (master)" > $testroot/stdout.expected
+ echo "commit $master_commit" >> $testroot/stdout.expected
+ echo "commit $commit0" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got update > $testroot/stdout)
+
+ echo 'Already up-to-date' > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # We should have created a merge commit with two parents.
+ (cd $testroot/wt && got log -l1 | grep ^parent > $testroot/stdout)
+ echo "parent 1: $master_commit" > $testroot/stdout.expected
+ echo "parent 2: $branch_commit0" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
test_parseargs "$@"
run_test test_merge_basic
run_test test_merge_continue
@@ -1245,3 +1391,4 @@ run_test test_merge_path_prefix
run_test test_merge_missing_file
run_test test_merge_no_op
run_test test_merge_imported_branch
+run_test test_merge_interrupt