ensure that 'got update' stays on the current 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
diff --git a/got/got.c b/got/got.c
index 9e9dfd9..74a744a 100644
--- a/got/got.c
+++ b/got/got.c
@@ -329,6 +329,63 @@ update_progress(void *arg, unsigned char status, const char *path)
}
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) {
diff --git a/include/got_commit_graph.h b/include/got_commit_graph.h
index 0654096..19df892 100644
--- a/include/got_commit_graph.h
+++ b/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 *);
diff --git a/include/got_error.h b/include/got_error.h
index 7720ed2..34bd324 100644
--- a/include/got_error.h
+++ b/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" },
};
/*
diff --git a/include/got_worktree.h b/include/got_worktree.h
index 43411d6..1424a42 100644
--- a/include/got_worktree.h
+++ b/include/got_worktree.h
@@ -64,6 +64,12 @@ const struct got_error *got_worktree_match_path_prefix(int *,
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 *);
diff --git a/lib/worktree.c b/lib/worktree.c
index 67ce5a4..94e0615 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -441,6 +441,12 @@ 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 *
got_worktree_get_base_commit_id(struct got_worktree *worktree)
{