refs: break out ref conflict checks
Create new function find_descendant_ref, to hold one of the ref conflict checks used in verify_refname_available. Multiple backends will need this function, so move it to the common code. Also move rename_ref_available to the common code, because alternate backends might need it and it has no files-backend-specific code. Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net>
David Turner committed
Nov 10, 2015 at 12:42 UTC
0845122c39c415fa50904ee94c6b60e4e722466b
3 files changed
+67
-42
refs.c
+44
@@ -1029,3 +1029,47 @@ int ref_is_hidden(const char *refname)
1029
}
1030
return 0;
1031
}
1032
+
1033
+const char *find_descendant_ref(const char *dirname,
1034
+ const struct string_list *extras,
1035
+ const struct string_list *skip)
1036
+{
1037
+ int pos;
1038
+
1039
+ if (!extras)
1040
+ return NULL;
1041
+
1042
+ /*
1043
+ * Look at the place where dirname would be inserted into
1044
+ * extras. If there is an entry at that position that starts
1045
+ * with dirname (remember, dirname includes the trailing
1046
+ * slash) and is not in skip, then we have a conflict.
1047
+ */
1048
+ for (pos = string_list_find_insert_index(extras, dirname, 0);
1049
+ pos < extras->nr; pos++) {
1050
+ const char *extra_refname = extras->items[pos].string;
1051
+
1052
+ if (!starts_with(extra_refname, dirname))
1053
+ break;
1054
+
1055
+ if (!skip || !string_list_has_string(skip, extra_refname))
1056
+ return extra_refname;
1057
+ }
1058
+ return NULL;
1059
+}
1060
+
1061
+int rename_ref_available(const char *oldname, const char *newname)
1062
+{
1063
+ struct string_list skip = STRING_LIST_INIT_NODUP;
1064
+ struct strbuf err = STRBUF_INIT;
1065
+ int ret;
1066
+
1067
+ string_list_insert(&skip, oldname);
1068
+ ret = !verify_refname_available(newname, NULL, &skip, &err);
1069
+ if (!ret)
1070
+ error("%s", err.buf);
1071
+
1072
+ string_list_clear(&skip, 0);
1073
+ strbuf_release(&err);
1074
+ return ret;
1075
+}
refs/files-backend.c
+7
-42
@@ -728,6 +728,7 @@ static int verify_refname_available_dir(const char *refname,
728
struct strbuf *err)
729
{
730
const char *slash;
731
+ const char *extra_refname;
732
int pos;
733
struct strbuf dirname = STRBUF_INIT;
734
int ret = -1;
@@ -833,32 +834,12 @@ static int verify_refname_available_dir(const char *refname,
834
}
835
}
836
836
- if (extras) {
837
- /*
838
- * Check for entries in extras that start with
839
- * "$refname/". We do that by looking for the place
840
- * where "$refname/" would be inserted in extras. If
841
- * there is an entry at that position that starts with
842
- * "$refname/" and is not in skip, then we have a
843
- * conflict.
844
- */
845
- for (pos = string_list_find_insert_index(extras, dirname.buf, 0);
846
- pos < extras->nr; pos++) {
847
- const char *extra_refname = extras->items[pos].string;
848
-
849
- if (!starts_with(extra_refname, dirname.buf))
850
- break;
851
-
852
- if (!skip || !string_list_has_string(skip, extra_refname)) {
853
- strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
854
- refname, extra_refname);
855
- goto cleanup;
856
- }
857
- }
858
- }
859
-
860
- /* No conflicts were found */
861
- ret = 0;
837
+ extra_refname = find_descendant_ref(dirname.buf, extras, skip);
838
+ if (extra_refname)
839
+ strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
840
+ refname, extra_refname);
841
+ else
842
+ ret = 0;
843
844
cleanup:
845
strbuf_release(&dirname);
@@ -2473,22 +2454,6 @@ int verify_refname_available(const char *newname,
2454
return 0;
2455
}
2456
2476
-static int rename_ref_available(const char *oldname, const char *newname)
2477
-{
2478
- struct string_list skip = STRING_LIST_INIT_NODUP;
2479
- struct strbuf err = STRBUF_INIT;
2480
- int ret;
2481
-
2482
- string_list_insert(&skip, oldname);
2483
- ret = !verify_refname_available(newname, NULL, &skip, &err);
2484
- if (!ret)
2485
- error("%s", err.buf);
2486
-
2487
- string_list_clear(&skip, 0);
2488
- strbuf_release(&err);
2489
- return ret;
2490
-}
2491
-
2457
static int write_ref_to_lockfile(struct ref_lock *lock,
2458
const unsigned char *sha1, struct strbuf *err);
2459
static int commit_ref_update(struct ref_lock *lock,
refs/refs-internal.h
+16
@@ -181,4 +181,20 @@ int files_log_ref_write(const char *refname, const unsigned char *old_sha1,
181
const unsigned char *new_sha1, const char *msg,
182
int flags, struct strbuf *err);
183
184
+/*
185
+ * Check for entries in extras that are within the specified
186
+ * directory, where dirname is a reference directory name including
187
+ * the trailing slash (e.g., "refs/heads/foo/"). Ignore any
188
+ * conflicting references that are found in skip. If there is a
189
+ * conflicting reference, return its name.
190
+ *
191
+ * extras and skip must be sorted lists of reference names. Either one
192
+ * can be NULL, signifying the empty list.
193
+ */
194
+const char *find_descendant_ref(const char *dirname,
195
+ const struct string_list *extras,
196
+ const struct string_list *skip);
197
+
198
+int rename_ref_available(const char *oldname, const char *newname);
199
+
200
#endif /* REFS_REFS_INTERNAL_H */