commit 481cdc746b012203f39047cbc55f8b65ae40d046 from: James Cook date: Sat Jul 01 13:13:02 2023 UTC add -M option: tell got merge not to fast-forward ok stsp@ commit - 13d9dc7e2e880cfe93cf23a39c48427cda7ff636 commit + 481cdc746b012203f39047cbc55f8b65ae40d046 blob - 71c0950fc006ad8faab300bfdc70c29496c8493d blob + 234d94604d5296c784792c130bb88dd64b8393bb --- got/got.1 +++ got/got.1 @@ -2811,7 +2811,7 @@ or reverted with .Tg mg .It Xo .Cm merge -.Op Fl aCcn +.Op Fl aCcMn .Op Ar branch .Xc .Dl Pq alias: Cm mg @@ -2940,6 +2940,8 @@ option. .It Fl c Continue an interrupted merge operation. If this option is used, no other command-line arguments are allowed. +.It Fl M +Create a merge commit even if the branches have not diverged. .It Fl n Merge changes into the work tree as usual but do not create a merge commit immediately. blob - 5348f3e02299f72518fb1fae98ac8eb68f013b85 blob + f0f73cb11cc2c22294fb3716a2eba2a4a2ba8be9 --- got/got.c +++ got/got.c @@ -13144,7 +13144,7 @@ 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 allow_conflict = 0, interrupt_merge = 0; + int allow_conflict = 0, prefer_fast_forward = 1, interrupt_merge = 0; struct got_update_progress_arg upa; struct got_object_id *merge_commit_id = NULL; char *branch_name = NULL; @@ -13158,7 +13158,7 @@ cmd_merge(int argc, char *argv[]) err(1, "pledge"); #endif - while ((ch = getopt(argc, argv, "aCcn")) != -1) { + while ((ch = getopt(argc, argv, "aCcMn")) != -1) { switch (ch) { case 'a': abort_merge = 1; @@ -13167,6 +13167,9 @@ cmd_merge(int argc, char *argv[]) allow_conflict = 1; case 'c': continue_merge = 1; + break; + case 'M': + prefer_fast_forward = 0; break; case 'n': interrupt_merge = 1; @@ -13188,6 +13191,10 @@ cmd_merge(int argc, char *argv[]) } if (abort_merge && continue_merge) option_conflict('a', 'c'); + if (abort_merge && !prefer_fast_forward) + option_conflict('a', 'M'); + if (continue_merge && !prefer_fast_forward) + option_conflict('c', 'M'); if (abort_merge || continue_merge) { if (argc != 0) usage_merge(); @@ -13326,7 +13333,8 @@ cmd_merge(int argc, char *argv[]) error = got_worktree_merge_prepare(&fileindex, worktree, repo); if (error) goto done; - if (yca_id && got_object_id_cmp(wt_branch_tip, yca_id) == 0) { + if (prefer_fast_forward && yca_id && + got_object_id_cmp(wt_branch_tip, yca_id) == 0) { struct got_pathlist_head paths; if (interrupt_merge) { error = got_error_fmt(GOT_ERR_BAD_OPTION, blob - b1980ee2c0e36130e8066d6897401ba97642d4a4 blob + a7908e3851266c3fe538eb4321c3fab455fc0d8d --- regress/cmdline/merge.sh +++ regress/cmdline/merge.sh @@ -460,6 +460,124 @@ test_merge_forward() { echo "(master, newbranch)" >> $testroot/stdout.expected echo "commit $commit1" >> $testroot/stdout.expected echo "commit $commit0" >> $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + test_done "$testroot" "$ret" +} + +test_merge_forward_commit() { + local testroot=`test_init merge_forward_commit` + local commit0=`git_show_head $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 commit1=`git_show_head $testroot/repo` + + got checkout -b master $testroot/repo $testroot/wt > /dev/null + ret=$? + if [ $ret -ne 0 ]; then + echo "got checkout failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got merge -M newbranch > $testroot/stdout) + ret=$? + if [ $ret -ne 0 ]; then + echo "got merge failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + local merge_commit=`git_show_branch_head $testroot/repo master` + + echo "G alpha" >> $testroot/stdout.expected + 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 -ne 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: $commit0" > $testroot/stdout.expected + echo "parent 2: $commit1" >> $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + test_done "$testroot" "$ret" +} + +test_merge_forward_interrupt() { + # Test -M and -n options together. + local testroot=`test_init merge_forward_commit` + local commit0=`git_show_head $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 commit1=`git_show_head $testroot/repo` + + got checkout -b master $testroot/repo $testroot/wt > /dev/null + ret=$? + if [ $ret -ne 0 ]; then + echo "got checkout failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got merge -M -n newbranch > $testroot/stdout) + ret=$? + if [ $ret -ne 0 ]; then + echo "got merge failed unexpectedly" >&2 + test_done "$testroot" "$ret" + 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 -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + # Continue the merge. + (cd $testroot/wt && got merge -c > $testroot/stdout) + ret=$? + if [ $ret -ne 0 ]; then + echo "got merge failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + local merge_commit=`git_show_branch_head $testroot/repo master` + + echo "M alpha" > $testroot/stdout.expected + 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 -ne 0 ]; then @@ -467,6 +585,16 @@ test_merge_forward() { 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: $commit0" > $testroot/stdout.expected + echo "parent 2: $commit1" >> $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi test_done "$testroot" "$ret" } @@ -1867,6 +1995,8 @@ test_merge_fetched_branch_remote() { test_parseargs "$@" run_test test_merge_basic run_test test_merge_forward +run_test test_merge_forward_commit +run_test test_merge_forward_interrupt run_test test_merge_backward run_test test_merge_continue run_test test_merge_continue_new_commit