commit 3aef623b225b81a61fd3786dc79d091f47b68225 from: Stefan Sperling date: Tue Oct 15 11:38:28 2019 UTC catch and reject integration into the freshly rebased branch commit - 2822a3526b8c61302ec86e0871e724c07a4b078d commit + 3aef623b225b81a61fd3786dc79d091f47b68225 blob - c2246a9a4a1eb2d49378c3096a50bcbf472739e2 blob + 5423c33764d81bfc3fd2c71dc7f9ca32f22bad4a --- got/got.c +++ got/got.c @@ -775,7 +775,8 @@ check_cancelled(void *arg) static const struct got_error * check_linear_ancestry(struct got_object_id *commit_id, - struct got_object_id *base_commit_id, struct got_repository *repo) + struct got_object_id *base_commit_id, int allow_forwards_in_time_only, + struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *yca_id; @@ -806,7 +807,10 @@ check_linear_ancestry(struct got_object_id *commit_id, * Update forwards in time: A (base/yca) - B - C - D (commit) * Update backwards in time: D (base) - C - B - A (commit/yca) */ - if (got_object_id_cmp(commit_id, yca_id) != 0 && + if (allow_forwards_in_time_only) { + if (got_object_id_cmp(base_commit_id, yca_id) != 0) + return got_error(GOT_ERR_ANCESTRY); + } else if (got_object_id_cmp(commit_id, yca_id) != 0 && got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); @@ -1063,7 +1067,7 @@ cmd_checkout(int argc, char *argv[]) if (error) goto done; error = check_linear_ancestry(commit_id, - got_worktree_get_base_commit_id(worktree), repo); + got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { free(commit_id); goto done; @@ -1143,7 +1147,7 @@ switch_head_ref(struct got_reference *head_ref, } err = check_linear_ancestry(commit_id, - got_worktree_get_base_commit_id(worktree), repo); + got_worktree_get_base_commit_id(worktree), 0, repo); if (err) { if (err->code != GOT_ERR_ANCESTRY) return err; @@ -1317,7 +1321,8 @@ cmd_update(int argc, char *argv[]) error = got_ref_resolve(&head_commit_id, repo, head_ref); if (error) goto done; - error = check_linear_ancestry(commit_id, head_commit_id, repo); + error = check_linear_ancestry(commit_id, head_commit_id, 0, + repo); free(head_commit_id); if (error != NULL) goto done; @@ -1329,7 +1334,7 @@ cmd_update(int argc, char *argv[]) goto done; } else { error = check_linear_ancestry(commit_id, - got_worktree_get_base_commit_id(worktree), repo); + got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) error = got_error(GOT_ERR_BRANCH_MOVED); @@ -6564,7 +6569,7 @@ cmd_integrate(int argc, char *argv[]) goto done; } - error = check_linear_ancestry(commit_id, base_commit_id, repo); + error = check_linear_ancestry(commit_id, base_commit_id, 1, repo); if (error) { if (error->code == GOT_ERR_ANCESTRY) error = got_error(GOT_ERR_REBASE_REQUIRED); blob - 86d2fa9ed1614f01bad8d546d2b87b57266c3147 blob + 35a98a41a609ebbd3f4945600522a843e17529f2 --- regress/cmdline/integrate.sh +++ regress/cmdline/integrate.sh @@ -290,8 +290,85 @@ function test_integrate_path_prefix { fi test_done "$testroot" "$ret" } + +function test_integrate_backwards_in_time { + local testroot=`test_init integrate_backwards_in_time` + + (cd $testroot/repo && git checkout -q -b newbranch) + echo "modified delta on branch" > $testroot/repo/gamma/delta + git_commit $testroot/repo -m "committing to delta on newbranch" + + echo "modified alpha on branch" > $testroot/repo/alpha + (cd $testroot/repo && git rm -q beta) + echo "new file on branch" > $testroot/repo/epsilon/new + (cd $testroot/repo && git add epsilon/new) + git_commit $testroot/repo -m "committing more changes on newbranch" + + local orig_commit1=`git_show_parent_commit $testroot/repo` + local orig_commit2=`git_show_head $testroot/repo` + + (cd $testroot/repo && git checkout -q master) + echo "modified zeta on master" > $testroot/repo/epsilon/zeta + git_commit $testroot/repo -m "committing to zeta on master" + local master_commit=`git_show_head $testroot/repo` + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + (cd $testroot/wt && got rebase newbranch > /dev/null) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got rebase failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/repo && git checkout -q newbranch) + local new_commit1=`git_show_parent_commit $testroot/repo` + local new_commit2=`git_show_head $testroot/repo` + + # attempt to integrate master into newbranch (wrong way around) + (cd $testroot/wt && got update -b newbranch > /dev/null) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got update failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got integrate master \ + > $testroot/stdout 2> $testroot/stderr) + ret="$?" + if [ "$ret" == "0" ]; then + echo "got integrate succeeded unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + 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 + + echo "got: specified branch must be rebased first" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + fi + test_done "$testroot" "$ret" +} + run_test test_integrate_basic run_test test_integrate_requires_rebase_first run_test test_integrate_path_prefix +run_test test_integrate_backwards_in_time