commit - 13d9dc7e2e880cfe93cf23a39c48427cda7ff636
commit + 481cdc746b012203f39047cbc55f8b65ae40d046
blob - 71c0950fc006ad8faab300bfdc70c29496c8493d
blob + 234d94604d5296c784792c130bb88dd64b8393bb
--- got/got.1
+++ got/got.1
.Tg mg
.It Xo
.Cm merge
-.Op Fl aCcn
+.Op Fl aCcMn
.Op Ar branch
.Xc
.Dl Pq alias: Cm mg
.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
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;
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;
allow_conflict = 1;
case 'c':
continue_merge = 1;
+ break;
+ case 'M':
+ prefer_fast_forward = 0;
break;
case 'n':
interrupt_merge = 1;
}
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();
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
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
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"
}
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