catch and reject integration into the freshly rebased branch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
diff --git a/got/got.c b/got/got.c
index c2246a9..5423c33 100644
--- a/got/got.c
+++ b/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);
diff --git a/regress/cmdline/integrate.sh b/regress/cmdline/integrate.sh
index 86d2fa9..35a98a4 100644
--- a/regress/cmdline/integrate.sh
+++ b/regress/cmdline/integrate.sh
@@ -291,7 +291,84 @@ function test_integrate_path_prefix {
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