Merge branch 'fp/subtree-todo-update'
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index b2a922945d2a5e6adc96da2ba96ba1be90c03cce..bab92d773d1e06a29805564e48b96d500a6f9b9b 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -304,6 +304,11 @@ struct ref_entry {
 };
 
 static void read_loose_refs(const char *dirname, struct ref_dir *dir);
+static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len);
+static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
+                                         const char *dirname, size_t len,
+                                         int incomplete);
+static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry);
 
 static struct ref_dir *get_ref_dir(struct ref_entry *entry)
 {
@@ -312,6 +317,24 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)
        dir = &entry->u.subdir;
        if (entry->flag & REF_INCOMPLETE) {
                read_loose_refs(entry->name, dir);
+
+               /*
+                * Manually add refs/bisect, which, being
+                * per-worktree, might not appear in the directory
+                * listing for refs/ in the main repo.
+                */
+               if (!strcmp(entry->name, "refs/")) {
+                       int pos = search_ref_dir(dir, "refs/bisect/", 12);
+                       if (pos < 0) {
+                               struct ref_entry *child_entry;
+                               child_entry = create_dir_entry(dir->ref_cache,
+                                                              "refs/bisect/",
+                                                              12, 1);
+                               add_entry_to_dir(dir, child_entry);
+                               read_loose_refs("refs/bisect",
+                                               &child_entry->u.subdir);
+                       }
+               }
                entry->flag &= ~REF_INCOMPLETE;
        }
        return dir;
@@ -2111,6 +2134,15 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
        return do_for_each_ref(&ref_cache, prefix, fn, strlen(prefix), 0, cb_data);
 }
 
+int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)
+{
+       unsigned int flag = 0;
+
+       if (broken)
+               flag = DO_FOR_EACH_INCLUDE_BROKEN;
+       return do_for_each_ref(&ref_cache, prefix, fn, 0, flag, cb_data);
+}
+
 int for_each_ref_in_submodule(const char *submodule, const char *prefix,
                each_ref_fn fn, void *cb_data)
 {
@@ -2651,6 +2683,8 @@ struct pack_refs_cb_data {
        struct ref_to_prune *ref_to_prune;
 };
 
+static int is_per_worktree_ref(const char *refname);
+
 /*
  * An each_ref_entry_fn that is run over loose references only.  If
  * the loose reference can be packed, add an entry in the packed ref
@@ -2664,6 +2698,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 (is_per_worktree_ref(entry->name))
+               return 0;
+
        /* ALWAYS pack tags */
        if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
                return 0;
@@ -2858,7 +2896,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/bisect/");
 }
 
 static int is_pseudoref_syntax(const char *refname)
@@ -4495,7 +4534,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
        return 0;
 }
 
-int ref_is_hidden(const char *refname)
+int ref_is_hidden(const char *refname, const char *refname_full)
 {
        int i;
 
@@ -4503,6 +4542,7 @@ int ref_is_hidden(const char *refname)
                return 0;
        for (i = hide_refs->nr - 1; i >= 0; i--) {
                const char *match = hide_refs->items[i].string;
+               const char *subject;
                int neg = 0;
                int len;
 
@@ -4511,10 +4551,18 @@ int ref_is_hidden(const char *refname)
                        match++;
                }
 
-               if (!starts_with(refname, match))
+               if (*match == '^') {
+                       subject = refname_full;
+                       match++;
+               } else {
+                       subject = refname;
+               }
+
+               /* refname can be NULL when namespaces are used. */
+               if (!subject || !starts_with(subject, match))
                        continue;
                len = strlen(match);
-               if (!refname[len] || refname[len] == '/')
+               if (!subject[len] || subject[len] == '/')
                        return !neg;
        }
        return 0;