Commit Diff


commit - 35c965b2755aaf9dc232228d76d19cb2e8907d9a
commit + be7061eb8834a24d83d6376aa2586e1b3e2232ab
blob - 9e9dfd9ecd25f2570ce974d906a9f376a022448d
blob + 74a744a651a7a4f591fd5c53a0724ec69fbce4bd
--- got/got.c
+++ got/got.c
@@ -329,6 +329,63 @@ update_progress(void *arg, unsigned char status, const
 }
 
 static const struct got_error *
+check_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;
+
+	head_ref = got_worktree_get_head_ref(worktree);
+	if (head_ref == NULL)
+		return got_error_from_errno();
+
+	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;
+	while (1) {
+		struct got_object_id *id;
+
+		if (sigint_received || sigpipe_received)
+			break;
+
+		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;
+}
+
+static const struct got_error *
 cmd_update(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
@@ -396,7 +453,9 @@ cmd_update(int argc, char *argv[])
 			goto done;
 	}
 
-	/* TODO: Ensure that we are staying on the current branch. */
+	error = check_ancestry(worktree, commit_id, repo);
+	if (error != NULL)
+		goto done;
 
 	if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
 	    commit_id) != 0) {
blob - 065409662149bcf0dd01a8ce82c8989d096cefd7
blob + 19df8926d7f0feb219d5f654a077dac2f6110760
--- include/got_commit_graph.h
+++ include/got_commit_graph.h
@@ -28,3 +28,6 @@ const struct got_error *got_commit_graph_iter_start(
     struct got_commit_graph *, struct got_object_id *, struct got_repository *);
 const struct got_error *got_commit_graph_iter_next(struct got_object_id **,
     struct got_commit_graph *);
+const struct got_error *got_commit_graph_intersect(struct got_object_id **,
+    struct got_commit_graph *, struct got_commit_graph *,
+    struct got_repository *);
blob - 7720ed223a4d642bf1479c1aed2af411b2dadc87
blob + 34bd324b68b53131fb06adc2a13b17f6a601bc78
--- include/got_error.h
+++ include/got_error.h
@@ -68,6 +68,7 @@
 #define GOT_ERR_FILEIDX_VER	52
 #define GOT_ERR_FILEIDX_CSUM	53
 #define GOT_ERR_PATH_PREFIX	54
+#define GOT_ERR_ANCESTRY	55
 
 static const struct got_error {
 	int code;
@@ -125,6 +126,8 @@ static const struct got_error {
 	{ 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" },
 };
 
 /*
blob - 43411d61291f20f6d25f20ec303368bac36730c1
blob + 1424a427f623a992ad42ee5b418df6c7f7b3c687
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -64,6 +64,12 @@ const struct got_error *got_worktree_match_path_prefix
 char  *got_worktree_get_head_ref_name(struct got_worktree *);
 
 /*
+ * Get the work tree's HEAD reference.
+ * The caller must dispose of it with free(3).
+ */
+struct got_reference *got_worktree_get_head_ref(struct got_worktree *);
+
+/*
  * Get the current base commit ID of a worktree.
  */
 const struct got_object_id *got_worktree_get_base_commit_id(struct got_worktree *);
blob - 67ce5a4496764e165e3247162f316282aa5b2736
blob + 94e0615878acd046d8424d079eb4ad72548eee1d
--- lib/worktree.c
+++ lib/worktree.c
@@ -439,6 +439,12 @@ char *
 got_worktree_get_head_ref_name(struct got_worktree *worktree)
 {
 	return got_ref_to_str(worktree->head_ref);
+}
+
+struct got_reference *
+got_worktree_get_head_ref(struct got_worktree *worktree)
+{
+	return got_ref_dup(worktree->head_ref);
 }
 
 const struct got_object_id *