commit ba34626bc13877c93836c8ee873acf1be8429ead from: Stefan Sperling via: Thomas Adam date: Mon Sep 27 18:32:16 2021 UTC implement 'got merge -n' which interrupts before creating a merge commit commit - 768705e331a0ff020ecc806142aecdecdbfb2e89 commit + ba34626bc13877c93836c8ee873acf1be8429ead blob - c408a296cf7c404394c1001c724ca9a0355c7e6a blob + 87a57e122c712ef21868c139097562f10ce37ee6 --- got/got.1 +++ 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 argument .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 blob - ad95c4f4600316e0434df71d4de1a2c764eaa8ff blob + 7e1da95f5c59517cd657b81619f6f8e89e5c425e --- got/got.c +++ 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,10 +10784,15 @@ 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; if (upa.conflicts > 0 && upa.missing == 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before merging " blob - 1d534c5958a2e7da9413b01d8fcff42599c6f25b blob + 38220a83f2af8fc1c889f9271a2cd263cbed1dad --- regress/cmdline/merge.sh +++ regress/cmdline/merge.sh @@ -1235,7 +1235,153 @@ EOF fi 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