We need a place to stick refs for bisects in progress that is not
shared between worktrees.  So we use the refs/worktree/ hierarchy.

The is_per_worktree_ref function and associated docs learn that
refs/worktree/ is per-worktree, as does the git_path code in path.c

The ref-packing functions learn that refs beginning with
refs/worktree/ should not be packed (since packed-refs is common
rather than per-worktree).

Signed-off-by: David Turner <dtur...@twopensource.com>
---

This implements the very simple solution of making refs/worktree/
per-worktree, as we discussed on the PATCH/RFC first version of this
patch.

Note that git for-each-ref may have inconsistent behavior (I think; I
haven't confirmed this), sometimes showing refs/worktree/* and sometimes
not.  In the long run, we should fix this, but right now, I don't know
that it matters, since the only refs affected are these bisect refs.

---
 Documentation/glossary-content.txt |  5 +++--
 path.c                             | 15 ++++++++++++---
 refs.c                             |  7 ++++++-
 t/t1400-update-ref.sh              | 16 ++++++++++++++++
 t/t3210-pack-refs.sh               |  7 +++++++
 5 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/Documentation/glossary-content.txt 
b/Documentation/glossary-content.txt
index 8c6478b..5c707e6 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -413,8 +413,9 @@ exclude;;
 
 [[def_per_worktree_ref]]per-worktree ref::
        Refs that are per-<<def_working_tree,worktree>>, rather than
-       global.  This is presently only <<def_HEAD,HEAD>>, but might
-       later include other unusual refs.
+       global.  This is presently only <<def_HEAD,HEAD>> and any refs
+       that start with `refs/worktree/`, but might later include other
+       unusual refs.
 
 [[def_pseudoref]]pseudoref::
        Pseudorefs are a class of files under `$GIT_DIR` which behave
diff --git a/path.c b/path.c
index 10f4cbf..da0f767 100644
--- a/path.c
+++ b/path.c
@@ -92,8 +92,9 @@ static void replace_dir(struct strbuf *buf, int len, const 
char *newdir)
 }
 
 static const char *common_list[] = {
+       "/refs", /* special case, since refs/worktree/ is per-worktree */
        "/branches", "/hooks", "/info", "!/logs", "/lost-found",
-       "/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
+       "/objects", "/remotes", "/worktrees", "/rr-cache", "/svn",
        "config", "!gc.pid", "packed-refs", "shallow",
        NULL
 };
@@ -116,8 +117,16 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
                        is_dir = 1;
                }
                if (is_dir && dir_prefix(base, path)) {
-                       replace_dir(buf, git_dir_len, get_git_common_dir());
-                       return;
+                       /*
+                        * The first entry in common_list is refs, and
+                        * refs/worktree is *not* common.
+                        */
+
+                       if (p != common_list ||
+                           !dir_prefix(base, "refs/worktree")) {
+                               replace_dir(buf, git_dir_len, 
get_git_common_dir());
+                               return;
+                       }
                }
                if (!is_dir && !strcmp(base, path)) {
                        replace_dir(buf, git_dir_len, get_git_common_dir());
diff --git a/refs.c b/refs.c
index e6fc3fe..d43bfe1 100644
--- a/refs.c
+++ b/refs.c
@@ -2656,6 +2656,10 @@ static int pack_if_possible_fn(struct ref_entry *entry, 
void *cb_data)
        struct ref_entry *packed_entry;
        int is_tag_ref = starts_with(entry->name, "refs/tags/");
 
+       /* Do not pack per-worktree refs: */
+       if (starts_with(entry->name, "refs/worktree/"))
+               return 0;
+
        /* ALWAYS pack tags */
        if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
                return 0;
@@ -2850,7 +2854,8 @@ static int delete_ref_loose(struct ref_lock *lock, int 
flag, struct strbuf *err)
 
 static int is_per_worktree_ref(const char *refname)
 {
-       return !strcmp(refname, "HEAD");
+       return !strcmp(refname, "HEAD") ||
+               starts_with(refname, "refs/worktree/");
 }
 
 static int is_pseudoref_syntax(const char *refname)
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 9d21c19..c9fd1ca 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -1131,4 +1131,20 @@ test_expect_success ULIMIT_FILE_DESCRIPTORS 'large 
transaction deleting branches
 )
 '
 
+test_expect_success 'handle per-worktree refs in refs/worktree' '
+       git commit --allow-empty -m "initial commit" &&
+       git worktree add -b branch worktree &&
+       (
+               cd worktree &&
+               git commit --allow-empty -m "test commit"  &&
+               git update-ref refs/worktree/something HEAD &&
+               git rev-parse refs/worktree/something > ../worktree-head
+       ) &&
+       ! test -e .git/refs/worktree &&
+       test_must_fail git rev-parse refs/worktree/something &&
+       git update-ref refs/worktree/something HEAD &&
+       git rev-parse refs/worktree/something > main-head &&
+       ! test_cmp main-head worktree-head
+'
+
 test_done
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 8aae98d..c54cd29 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -160,6 +160,13 @@ test_expect_success 'pack ref directly below refs/' '
        test_path_is_missing .git/refs/top
 '
 
+test_expect_success 'do not pack ref in refs/worktree' '
+       git update-ref refs/worktree/local HEAD &&
+       git pack-refs --all --prune &&
+       ! grep refs/worktree/local .git/packed-refs >/dev/null &&
+       test_path_is_file .git/refs/worktree/local
+'
+
 test_expect_success 'disable reflogs' '
        git config core.logallrefupdates false &&
        rm -rf .git/logs
-- 
2.0.4.315.gad8727a-twtrsrc

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to