branch: publish die_if_checked_out()
git-worktree currently conflates new branch creation, setting of HEAD in the new wortkree, and worktree population into a single sub-invocation of git-checkout. However, these operations will eventually be separated, and git-worktree itself will need to be able to detect if the branch is already checked out elsewhere, rather than relying upon git-branch to make this determination, so publish die_if_checked_out(). Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eric Sunshine committed
Jul 17, 2015 at 19:00 UTC
ed89f84b3c05d6359aba842e245910c996d91859
3 files changed
+74
-67
branch.c
+67
@@ -309,3 +309,70 @@ void remove_branch_state(void)
309
unlink(git_path("MERGE_MODE"));
310
unlink(git_path("SQUASH_MSG"));
311
}
312
+
313
+static void check_linked_checkout(const char *branch, const char *id)
314
+{
315
+ struct strbuf sb = STRBUF_INIT;
316
+ struct strbuf path = STRBUF_INIT;
317
+ struct strbuf gitdir = STRBUF_INIT;
318
+
319
+ /*
320
+ * $GIT_COMMON_DIR/HEAD is practically outside
321
+ * $GIT_DIR so resolve_ref_unsafe() won't work (it
322
+ * uses git_path). Parse the ref ourselves.
323
+ */
324
+ if (id)
325
+ strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
326
+ else
327
+ strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
328
+
329
+ if (!strbuf_readlink(&sb, path.buf, 0)) {
330
+ if (!starts_with(sb.buf, "refs/") ||
331
+ check_refname_format(sb.buf, 0))
332
+ goto done;
333
+ } else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
334
+ starts_with(sb.buf, "ref:")) {
335
+ strbuf_remove(&sb, 0, strlen("ref:"));
336
+ strbuf_trim(&sb);
337
+ } else
338
+ goto done;
339
+ if (strcmp(sb.buf, branch))
340
+ goto done;
341
+ if (id) {
342
+ strbuf_reset(&path);
343
+ strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
344
+ if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
345
+ goto done;
346
+ strbuf_rtrim(&gitdir);
347
+ } else
348
+ strbuf_addstr(&gitdir, get_git_common_dir());
349
+ skip_prefix(branch, "refs/heads/", &branch);
350
+ strbuf_strip_suffix(&gitdir, ".git");
351
+ die(_("'%s' is already checked out at '%s'"), branch, gitdir.buf);
352
+done:
353
+ strbuf_release(&path);
354
+ strbuf_release(&sb);
355
+ strbuf_release(&gitdir);
356
+}
357
+
358
+void die_if_checked_out(const char *branch)
359
+{
360
+ struct strbuf path = STRBUF_INIT;
361
+ DIR *dir;
362
+ struct dirent *d;
363
+
364
+ check_linked_checkout(branch, NULL);
365
+
366
+ strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
367
+ dir = opendir(path.buf);
368
+ strbuf_release(&path);
369
+ if (!dir)
370
+ return;
371
+
372
+ while ((d = readdir(dir)) != NULL) {
373
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
374
+ continue;
375
+ check_linked_checkout(branch, d->d_name);
376
+ }
377
+ closedir(dir);
378
+}
branch.h
+7
@@ -52,4 +52,11 @@ extern void install_branch_config(int flag, const char *local, const char *origi
52
*/
53
extern int read_branch_desc(struct strbuf *, const char *branch_name);
54
55
+/*
56
+ * Check if a branch is checked out in the main worktree or any linked
57
+ * worktree and die (with a message describing its checkout location) if
58
+ * it is.
59
+ */
60
+extern void die_if_checked_out(const char *branch);
61
+
62
#endif
builtin/checkout.c
-67
@@ -873,73 +873,6 @@ static const char *unique_tracking_name(const char *name, unsigned char *sha1)
873
return NULL;
874
}
875
876
-static void check_linked_checkout(const char *branch, const char *id)
877
-{
878
- struct strbuf sb = STRBUF_INIT;
879
- struct strbuf path = STRBUF_INIT;
880
- struct strbuf gitdir = STRBUF_INIT;
881
-
882
- /*
883
- * $GIT_COMMON_DIR/HEAD is practically outside
884
- * $GIT_DIR so resolve_ref_unsafe() won't work (it
885
- * uses git_path). Parse the ref ourselves.
886
- */
887
- if (id)
888
- strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
889
- else
890
- strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
891
-
892
- if (!strbuf_readlink(&sb, path.buf, 0)) {
893
- if (!starts_with(sb.buf, "refs/") ||
894
- check_refname_format(sb.buf, 0))
895
- goto done;
896
- } else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
897
- starts_with(sb.buf, "ref:")) {
898
- strbuf_remove(&sb, 0, strlen("ref:"));
899
- strbuf_trim(&sb);
900
- } else
901
- goto done;
902
- if (strcmp(sb.buf, branch))
903
- goto done;
904
- if (id) {
905
- strbuf_reset(&path);
906
- strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
907
- if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
908
- goto done;
909
- strbuf_rtrim(&gitdir);
910
- } else
911
- strbuf_addstr(&gitdir, get_git_common_dir());
912
- skip_prefix(branch, "refs/heads/", &branch);
913
- strbuf_strip_suffix(&gitdir, ".git");
914
- die(_("'%s' is already checked out at '%s'"), branch, gitdir.buf);
915
-done:
916
- strbuf_release(&path);
917
- strbuf_release(&sb);
918
- strbuf_release(&gitdir);
919
-}
920
-
921
-static void die_if_checked_out(const char *branch)
922
-{
923
- struct strbuf path = STRBUF_INIT;
924
- DIR *dir;
925
- struct dirent *d;
926
-
927
- check_linked_checkout(branch, NULL);
928
-
929
- strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
930
- dir = opendir(path.buf);
931
- strbuf_release(&path);
932
- if (!dir)
933
- return;
934
-
935
- while ((d = readdir(dir)) != NULL) {
936
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
937
- continue;
938
- check_linked_checkout(branch, d->d_name);
939
- }
940
- closedir(dir);
941
-}
942
-
876
static int parse_branchname_arg(int argc, const char **argv,
877
int dwim_new_local_branch_ok,
878
struct branch_info *new,