"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
add got merge -n option
To:
gameoftrees@openbsd.org
Date:
Sun, 26 Sep 2021 16:22:58 +0200

Download raw body.

Thread
  • Stefan Sperling:

    add got merge -n option

Implement 'got merge -n' which always interrupts a merge before creating
the merge commit. I believe this will useful if the changes being merged
are non-trivial. For example, vendor branch merges may need to
reconcile local changes with a potentially large amount of changes
coming from an upstream project. Even when there are no merge conflicts
or missing files, additional testing and verification may be required.

This patch applies on top of my vendor-merge patch which I sent yesterday.

ok?
 
diff 400d752d446c28769c6aa522c3b8e8d699582ec6 ab784d002f85b2e06a56939ea5dfce2e61972532
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 - 39c5172e4d8e1b72ff03f0dbd81fc4ae8935b1b9
blob + 306de47eabea9518ce4c7e1562e583e3cb83ab49
--- 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
@@ -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