refs: break out ref conflict checks
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index 1620a53c484efb4e9aa669e8569720d4c2d2ea8d..ad883ec4d9dc6b7ae318f90afa6600fa80952963 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1029,3 +1029,47 @@ int ref_is_hidden(const char *refname)
        }
        return 0;
 }
+
+const char *find_descendant_ref(const char *dirname,
+                               const struct string_list *extras,
+                               const struct string_list *skip)
+{
+       int pos;
+
+       if (!extras)
+               return NULL;
+
+       /*
+        * Look at the place where dirname would be inserted into
+        * extras. If there is an entry at that position that starts
+        * with dirname (remember, dirname includes the trailing
+        * slash) and is not in skip, then we have a conflict.
+        */
+       for (pos = string_list_find_insert_index(extras, dirname, 0);
+            pos < extras->nr; pos++) {
+               const char *extra_refname = extras->items[pos].string;
+
+               if (!starts_with(extra_refname, dirname))
+                       break;
+
+               if (!skip || !string_list_has_string(skip, extra_refname))
+                       return extra_refname;
+       }
+       return NULL;
+}
+
+int rename_ref_available(const char *oldname, const char *newname)
+{
+       struct string_list skip = STRING_LIST_INIT_NODUP;
+       struct strbuf err = STRBUF_INIT;
+       int ret;
+
+       string_list_insert(&skip, oldname);
+       ret = !verify_refname_available(newname, NULL, &skip, &err);
+       if (!ret)
+               error("%s", err.buf);
+
+       string_list_clear(&skip, 0);
+       strbuf_release(&err);
+       return ret;
+}