commit - a9833bc916b1790a1f3ff4981a1ebe2dd026c9ae
commit + d5bea53959deb7a1dd486dce9bca4f295c12589b
blob - 9f023e7c97fd57dec07e2583bf5cc55a3e12417b
blob + 33f2e988a9bca9de9b8ab6bc7986acae6cb956fe
--- got/got.c
+++ got/got.c
}
static const struct got_error *
-check_ancestry(struct got_worktree *worktree, struct got_object_id *commit_id,
- struct got_repository *repo)
+check_linear_ancestry(struct got_worktree *worktree,
+ struct got_object_id *commit_id, struct got_repository *repo)
{
- const struct got_error *err;
- struct got_reference *head_ref = NULL;
- struct got_object_id *head_commit_id = NULL;
- struct got_commit_graph *graph = NULL;
+ const struct got_error *err = NULL;
+ struct got_object_id *yca_id, *base_commit_id;
- err = got_ref_open(&head_ref, repo,
- got_worktree_get_head_ref_name(worktree), 0);
+ base_commit_id = got_worktree_get_base_commit_id(worktree);
+ err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
+ commit_id, base_commit_id, repo);
if (err)
return err;
- /* TODO: Check the reflog. The head ref may have been rebased. */
- err = got_ref_resolve(&head_commit_id, repo, head_ref);
- if (err)
- goto done;
+ if (yca_id == NULL)
+ return got_error(GOT_ERR_ANCESTRY);
- err = got_commit_graph_open(&graph, head_commit_id, "/", 1, repo);
- if (err)
- goto done;
-
- err = got_commit_graph_iter_start(graph, head_commit_id, repo);
- if (err)
- goto done;
- for (;;) {
- struct got_object_id *id;
-
- if (sigint_received || sigpipe_received)
- break;
+ /*
+ * Require a straight line of history between the target commit
+ * and the work tree's base commit.
+ *
+ * Non-linear situation such as the this require a rebase:
+ *
+ * (commit) D F (base_commit)
+ * \ /
+ * C E
+ * \ /
+ * B (yca)
+ * |
+ * A
+ *
+ * 'got update' only handles linear cases:
+ * Update forwards in time: A (base/yca) - B - C - D (commit)
+ * Update backwards in time: D (base) - C - D - A (commit/yca)
+ */
+ 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);
- err = got_commit_graph_iter_next(&id, graph);
- if (err) {
- if (err->code == GOT_ERR_ITER_COMPLETED) {
- err = got_error(GOT_ERR_ANCESTRY);
- break;
- }
- if (err->code != GOT_ERR_ITER_NEED_MORE)
- break;
- err = got_commit_graph_fetch_commits(graph, 1, repo);
- if (err)
- break;
- else
- continue;
- }
- if (id == NULL)
- break;
- if (got_object_id_cmp(id, commit_id) == 0)
- break;
- }
-done:
- if (head_ref)
- got_ref_close(head_ref);
- if (graph)
- got_commit_graph_close(graph);
- return err;
+ free(yca_id);
+ return NULL;
}
commit_id_str);
if (error != NULL)
goto done;
- error = check_ancestry(worktree, commit_id, repo);
+ error = check_linear_ancestry(worktree, commit_id, repo);
if (error != NULL) {
free(commit_id);
goto done;
goto done;
}
- error = check_ancestry(worktree, commit_id, repo);
+ error = check_linear_ancestry(worktree, commit_id, repo);
if (error != NULL)
goto done;
blob - 2d5f5bdc1070d54afafaa832ad1ba9e483d82233
blob + 8c60816b6a8c0f225778df8ccd601ec24c75905d
--- include/got_error.h
+++ include/got_error.h
{ GOT_ERR_FILEIDX_CSUM, "bad file index checksum" },
{ GOT_ERR_PATH_PREFIX, "worktree already contains items from a "
"different path prefix" },
- { GOT_ERR_ANCESTRY, "specified commit does not share ancestry with "
- "the current branch" },
+ { GOT_ERR_ANCESTRY, "new branch or rebase required" },
{ GOT_ERR_FILEIDX_BAD, "file index is corrupt" },
{ GOT_ERR_BAD_REF_DATA, "could not parse reference data" },
{ GOT_ERR_TREE_DUP_ENTRY,"duplicate entry in tree object" },
blob - 5f2aab89f919b879ec631497eacba660266869c4
blob + 00c8418960dd9b88696917d8441bb984e4f94d46
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
return 1
fi
test_done "$testroot" "$ret"
+
+}
+
+function test_update_moved_branch_ref {
+ local testroot=`test_init update_moved_branch_ref`
+
+ git clone -q --mirror $testroot/repo $testroot/repo2
+
+ echo "modified alpha with git" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "modified alpha with git"
+
+ got checkout $testroot/repo2 $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha with got" > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "modified alpha with got" > /dev/null)
+
+ # + xxxxxxx...yyyyyyy master -> master (forced update)
+ (cd $testroot/repo2 && git fetch -q --all)
+ echo -n > $testroot/stdout.expected
+ echo "got: new branch or rebase required" >> $testroot/stderr.expected
+
+ (cd $testroot/wt && got update > $testroot/stdout 2> $testroot/stderr)
+
+ cmp $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cmp $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_update_basic
run_test test_update_adds_file
run_test test_update_deletes_file
run_test test_update_partial_add
run_test test_update_partial_rm
run_test test_update_partial_dir
+run_test test_update_moved_branch_ref