Commit Diff


commit - 35d2583f834a66f801dc229002d45e735882ba78
commit + e166551f658768ab6f4f75386d7da7d6c67b7ee3
blob - baff5126bef7368795495150bcfabcb49a70dcd8
blob + 2de21da09b554d15bc73174e05f9df16eaa3e746
--- lib/send.c
+++ lib/send.c
@@ -162,7 +162,7 @@ insert_ref(struct got_reflist_head *refs, const char *
 }
 
 static const struct got_error *
-check_linear_ancestry(const char *refname, struct got_object_id *my_id,
+check_common_ancestry(const char *refname, struct got_object_id *my_id,
     struct got_object_id *their_id, struct got_repository *repo,
     got_cancel_cb cancel_cb, void *cancel_arg)
 {
@@ -178,26 +178,12 @@ check_linear_ancestry(const char *refname, struct got_
 		    "bad object type on server for %s", refname);
 
 	err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
-	    my_id, their_id, 1, repo, cancel_cb, cancel_arg);
+	    my_id, their_id, 0, repo, cancel_cb, cancel_arg);
 	if (err)
 		return err;
 	if (yca_id == NULL)
 		return got_error_fmt(GOT_ERR_SEND_ANCESTRY, "%s", refname);
 
-	/*
-	 * Require a straight line of history between the two commits,
-	 * with their commit being older than my commit.
-	 *
-	 * Non-linear situations such as this require a rebase:
-	 *
-	 * (theirs) D       F (mine)
-	 *           \     /
-	 *            C   E
-	 *             \ /
-	 *              B (yca)
-	 *              |
-	 *              A
-	 */
 	if (got_object_id_cmp(their_id, yca_id) != 0)
 		err = got_error_fmt(GOT_ERR_SEND_ANCESTRY, "%s", refname);
 
@@ -581,7 +567,7 @@ got_send_pack(const char *remote_name, struct got_path
 				err = got_ref_resolve(&my_id, repo, my_ref);
 				if (err)
 					goto done;
-				err = check_linear_ancestry(refname, my_id,
+				err = check_common_ancestry(refname, my_id,
 				    their_id, repo, cancel_cb, cancel_arg);
 				free(my_id);
 				my_id = NULL;
blob - db8ed49392c78fe028db90d4d5c318b3d0fa8130
blob + 039969d0a73f3e098fb5b034b25b18a4223036f4
--- regress/cmdline/send.sh
+++ regress/cmdline/send.sh
@@ -320,6 +320,45 @@ EOF
 	git_fsck "$testroot" "$testroot/repo-clone"
 	ret=$?
 	test_done "$testroot" "$ret"
+}
+
+test_send_merge_commit() {
+	local testroot=`test_init send_merge_commit`
+	local testurl=ssh://127.0.0.1/$testroot
+
+	if ! got clone -q "$testurl/repo" "$testroot/repo-clone"; then
+		echo "got clone command failed unexpectedly" >&2
+		test_done "$testroot" 1
+		return 1
+	fi
+
+	echo 'upstream change' > $testroot/repo/alpha
+	git_commit $testroot/repo -m 'upstream change'
+
+	got checkout $testroot/repo-clone $testroot/wt-clone > /dev/null
+	echo 'downstream change' > $testroot/wt-clone/beta
+	(cd $testroot/wt-clone && got commit -m 'downstream change' > /dev/null)
+
+	got fetch -q -r $testroot/repo-clone
+	(cd $testroot/wt-clone && got update > /dev/null)
+	(cd $testroot/wt-clone && got merge origin/master > /dev/null)
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		echo "got merge command failed unexpectedly" >&2
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/repo && git config receive.denyCurrentBranch ignore)
+
+	got send -q -r $testroot/repo-clone
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	test_done "$testroot" 0
 }
 
 test_send_delete() {
@@ -1583,6 +1622,7 @@ test_parseargs "$@"
 run_test test_send_basic
 run_test test_send_rebase_required
 run_test test_send_rebase_required_overwrite
+run_test test_send_merge_commit
 run_test test_send_delete
 run_test test_send_clone_and_send
 run_test test_send_tags