commit - efa2b6f7f70fe602a9b33db56006e6783b2ee7d9
commit + a367ff0fbac77bc991350a4463ee56e3cb0d9e7e
blob - b4af86251f09f27f3c1a0a121b7a66d9b07da341
blob + 3bdf53187da1ea5a8532d5825fa083375dda1c7f
--- got/got.c
+++ got/got.c
free(yca_id);
return NULL;
}
+
+static const struct got_error *
+check_same_branch(struct got_object_id *commit_id,
+ struct got_reference *head_ref, struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ struct got_commit_graph *graph = NULL;
+ struct got_object_id *head_commit_id = NULL;
+ int is_same_branch = 0;
+
+ err = got_ref_resolve(&head_commit_id, repo, head_ref);
+ if (err)
+ goto done;
+
+ 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;
+ err = got_commit_graph_iter_next(&id, graph);
+ if (err) {
+ if (err->code == GOT_ERR_ITER_COMPLETED) {
+ err = NULL;
+ break;
+ }
+ else if (err->code != GOT_ERR_ITER_NEED_MORE)
+ break;
+ err = got_commit_graph_fetch_commits(graph, 1,
+ repo);
+ if (err)
+ break;
+ }
+ if (id) {
+ if (got_object_id_cmp(id, commit_id) == 0) {
+ is_same_branch = 1;
+ break;
+ }
+ }
+ }
+done:
+ if (graph)
+ got_commit_graph_close(graph);
+ free(head_commit_id);
+ if (!err && !is_same_branch)
+ err = got_error(GOT_ERR_ANCESTRY);
+ return err;
+}
static const struct got_error *
cmd_checkout(int argc, char *argv[])
if (error)
goto done;
error = check_linear_ancestry(commit_id, head_commit_id, repo);
+ free(head_commit_id);
if (error != NULL)
goto done;
+ error = check_same_branch(commit_id, head_ref, repo);
+ if (error)
+ goto done;
error = got_worktree_set_head_ref(worktree, head_ref);
if (error)
goto done;
} else {
error = check_linear_ancestry(commit_id,
got_worktree_get_base_commit_id(worktree), repo);
- if (error != NULL)
+ if (error != NULL) {
+ if (error->code == GOT_ERR_ANCESTRY)
+ error = got_error(GOT_ERR_BRANCH_MOVED);
goto done;
+ }
+ error = check_same_branch(commit_id, head_ref, repo);
+ if (error)
+ goto done;
}
if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
blob - ac0dd60795055f7852165994cc7a04140e98ade4
blob + a5adad9c7b78c20784ce7bf60421c298f36574e6
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_COMMIT_MSG_EMPTY 74
#define GOT_ERR_DIR_NOT_EMPTY 75
#define GOT_ERR_COMMIT_NO_CHANGES 76
+#define GOT_ERR_BRANCH_MOVED 77
static const struct got_error {
int code;
{ GOT_ERR_FILEIDX_CSUM, "bad file index checksum" },
{ GOT_ERR_PATH_PREFIX, "worktree already contains items from a "
"different path prefix" },
- { GOT_ERR_ANCESTRY, "new branch or rebase required" },
+ { GOT_ERR_ANCESTRY, "target commit is on a different branch" },
{ 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" },
"changes can be committed" },
{ GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty" },
{ GOT_ERR_COMMIT_NO_CHANGES, "no changes to commit" },
+ { GOT_ERR_BRANCH_MOVED, "work tree's branch reference has moved; "
+ "new branch or rebase required" },
};
/*
blob - 6d4a991bc7cf8d3edfaf88297fdbf43787ce5f9f
blob + afaf069181d0253e696db8ca47abee92de936fd0
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
(cd $testroot/repo2 && git fetch -q --all)
echo -n > $testroot/stdout.expected
- echo "got: new branch or rebase required" >> $testroot/stderr.expected
+ echo -n "got: work tree's branch reference has moved; " \
+ > $testroot/stderr.expected
+ echo "new branch or rebase required" >> $testroot/stderr.expected
(cd $testroot/wt && got update > $testroot/stdout 2> $testroot/stderr)
ret="$?"
if [ "$ret" != "0" ]; then
diff -u $testroot/head-ref.expected $testroot/wt/.got/head-ref
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
+function test_update_to_commit_on_wrong_branch {
+ local testroot=`test_init update_to_commit_on_wrong_branch`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ echo "modified alpha on new branch" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "modified alpha on new branch"
+
+ echo -n "" > $testroot/stdout.expected
+ echo "got: target commit is on a different branch" \
+ > $testroot/stderr.expected
+
+ local head_rev=`git_show_head $testroot/repo`
+ (cd $testroot/wt && got update -c $head_rev > $testroot/stdout \
+ 2> $testroot/stderr)
+
+ 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
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
test_done "$testroot" "$ret"
}
run_test test_update_partial_dir
run_test test_update_moved_branch_ref
run_test test_update_to_another_branch
+run_test test_update_to_commit_on_wrong_branch