worktree: refactor find_linked_symref function

Refactoring will help transition this code to provide additional useful worktree functions. Signed-off-by: Michael Rappazzo <rappazzo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Rappazzo committed Oct 8, 2015 at 13:01 UTC 1ceb7f90674897a24a9f2a56abf7d26297761f18
1 file changed +69 -27
worktree.c
+69 -27
@@ -3,6 +3,64 @@
3 #include "strbuf.h"
4 #include "worktree.h"
5
6 +/*
7 + * read 'path_to_ref' into 'ref'. Also if is_detached is not NULL,
8 + * set is_detached to 1 (0) if the ref is detatched (is not detached).
9 + *
10 + * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so
11 + * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses
12 + * git_path). Parse the ref ourselves.
13 + *
14 + * return -1 if the ref is not a proper ref, 0 otherwise (success)
15 + */
16 +static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
17 +{
18 + if (is_detached)
19 + *is_detached = 0;
20 + if (!strbuf_readlink(ref, path_to_ref, 0)) {
21 + /* HEAD is symbolic link */
22 + if (!starts_with(ref->buf, "refs/") ||
23 + check_refname_format(ref->buf, 0))
24 + return -1;
25 + } else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
26 + /* textual symref or detached */
27 + if (!starts_with(ref->buf, "ref:")) {
28 + if (is_detached)
29 + *is_detached = 1;
30 + } else {
31 + strbuf_remove(ref, 0, strlen("ref:"));
32 + strbuf_trim(ref);
33 + if (check_refname_format(ref->buf, 0))
34 + return -1;
35 + }
36 + } else
37 + return -1;
38 + return 0;
39 +}
40 +
41 +static char *find_main_symref(const char *symref, const char *branch)
42 +{
43 + struct strbuf sb = STRBUF_INIT;
44 + struct strbuf path = STRBUF_INIT;
45 + struct strbuf gitdir = STRBUF_INIT;
46 + char *existing = NULL;
47 +
48 + strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
49 + if (parse_ref(path.buf, &sb, NULL) < 0)
50 + goto done;
51 + if (strcmp(sb.buf, branch))
52 + goto done;
53 + strbuf_addstr(&gitdir, get_git_common_dir());
54 + strbuf_strip_suffix(&gitdir, ".git");
55 + existing = strbuf_detach(&gitdir, NULL);
56 +done:
57 + strbuf_release(&path);
58 + strbuf_release(&sb);
59 + strbuf_release(&gitdir);
60 +
61 + return existing;
62 +}
63 +
64 static char *find_linked_symref(const char *symref, const char *branch,
65 const char *id)
66 {
@@ -11,36 +69,20 @@ static char *find_linked_symref(const char *symref, const char *branch,
69 struct strbuf gitdir = STRBUF_INIT;
70 char *existing = NULL;
71
14 - /*
15 - * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
16 - * $GIT_DIR so resolve_ref_unsafe() won't work (it uses
17 - * git_path). Parse the ref ourselves.
18 - */
19 - if (id)
20 - strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
21 - else
22 - strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
72 + if (!id)
73 + die("Missing linked worktree name");
74
24 - if (!strbuf_readlink(&sb, path.buf, 0)) {
25 - if (!starts_with(sb.buf, "refs/") ||
26 - check_refname_format(sb.buf, 0))
27 - goto done;
28 - } else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
29 - starts_with(sb.buf, "ref:")) {
30 - strbuf_remove(&sb, 0, strlen("ref:"));
31 - strbuf_trim(&sb);
32 - } else
75 + strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
76 +
77 + if (parse_ref(path.buf, &sb, NULL) < 0)
78 goto done;
79 if (strcmp(sb.buf, branch))
80 goto done;
36 - if (id) {
37 - strbuf_reset(&path);
38 - strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
39 - if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
40 - goto done;
41 - strbuf_rtrim(&gitdir);
42 - } else
43 - strbuf_addstr(&gitdir, get_git_common_dir());
81 + strbuf_reset(&path);
82 + strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
83 + if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
84 + goto done;
85 + strbuf_rtrim(&gitdir);
86 strbuf_strip_suffix(&gitdir, ".git");
87
88 existing = strbuf_detach(&gitdir, NULL);
@@ -59,7 +101,7 @@ char *find_shared_symref(const char *symref, const char *target)
101 struct dirent *d;
102 char *existing;
103
62 - if ((existing = find_linked_symref(symref, target, NULL)))
104 + if ((existing = find_main_symref(symref, target)))
105 return existing;
106
107 strbuf_addf(&path, "%s/worktrees", get_git_common_dir());