Skip to content

Commit 5fe7d82

Browse files
rsahlberggitster
authored andcommitted
refs.c: pass a list of names to skip to is_refname_available
Change is_refname_available to take a list of strings to exclude when checking for conflicts instead of just one single name. We can already exclude a single name for the sake of renames. This generalizes that support. ref_transaction_commit already tracks a set of refs that are being deleted in an array. This array is then used to exclude refs from being written to the packed-refs file. At some stage we will want to change this array to a struct string_list and then we can pass it to is_refname_available via the call to lock_ref_sha1_basic. That will allow us to perform transactions that perform multiple renames as long as there are no conflicts within the starting or ending state. For example, that would allow a single transaction that contains two renames that are both individually conflicting: m -> n/n n -> m/m No functional change intended yet. Signed-off-by: Ronnie Sahlberg <[email protected]> Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5d94a1b commit 5fe7d82

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed

refs.c

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -787,13 +787,13 @@ static void prime_ref_dir(struct ref_dir *dir)
787787
}
788788
}
789789

790-
static int entry_matches(struct ref_entry *entry, const char *refname)
790+
static int entry_matches(struct ref_entry *entry, const struct string_list *list)
791791
{
792-
return refname && !strcmp(entry->name, refname);
792+
return list && string_list_has_string(list, entry->name);
793793
}
794794

795795
struct nonmatching_ref_data {
796-
const char *skip;
796+
const struct string_list *skip;
797797
struct ref_entry *found;
798798
};
799799

@@ -817,16 +817,19 @@ static void report_refname_conflict(struct ref_entry *entry,
817817
/*
818818
* Return true iff a reference named refname could be created without
819819
* conflicting with the name of an existing reference in dir. If
820-
* oldrefname is non-NULL, ignore potential conflicts with oldrefname
821-
* (e.g., because oldrefname is scheduled for deletion in the same
820+
* skip is non-NULL, ignore potential conflicts with refs in skip
821+
* (e.g., because they are scheduled for deletion in the same
822822
* operation).
823823
*
824824
* Two reference names conflict if one of them exactly matches the
825825
* leading components of the other; e.g., "foo/bar" conflicts with
826826
* both "foo" and with "foo/bar/baz" but not with "foo/bar" or
827827
* "foo/barbados".
828+
*
829+
* skip must be sorted.
828830
*/
829-
static int is_refname_available(const char *refname, const char *oldrefname,
831+
static int is_refname_available(const char *refname,
832+
const struct string_list *skip,
830833
struct ref_dir *dir)
831834
{
832835
const char *slash;
@@ -840,12 +843,12 @@ static int is_refname_available(const char *refname, const char *oldrefname,
840843
* looking for a conflict with a leaf entry.
841844
*
842845
* If we find one, we still must make sure it is
843-
* not "oldrefname".
846+
* not in "skip".
844847
*/
845848
pos = search_ref_dir(dir, refname, slash - refname);
846849
if (pos >= 0) {
847850
struct ref_entry *entry = dir->entries[pos];
848-
if (entry_matches(entry, oldrefname))
851+
if (entry_matches(entry, skip))
849852
return 1;
850853
report_refname_conflict(entry, refname);
851854
return 0;
@@ -878,13 +881,13 @@ static int is_refname_available(const char *refname, const char *oldrefname,
878881
/*
879882
* We found a directory named "refname". It is a
880883
* problem iff it contains any ref that is not
881-
* "oldrefname".
884+
* in "skip".
882885
*/
883886
struct ref_entry *entry = dir->entries[pos];
884887
struct ref_dir *dir = get_ref_dir(entry);
885888
struct nonmatching_ref_data data;
886889

887-
data.skip = oldrefname;
890+
data.skip = skip;
888891
sort_ref_dir(dir);
889892
if (!do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data))
890893
return 1;
@@ -2139,6 +2142,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
21392142
*/
21402143
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
21412144
const unsigned char *old_sha1,
2145+
const struct string_list *skip,
21422146
int flags, int *type_p)
21432147
{
21442148
char *ref_file;
@@ -2188,7 +2192,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
21882192
* name is a proper prefix of our refname.
21892193
*/
21902194
if (missing &&
2191-
!is_refname_available(refname, NULL, get_packed_refs(&ref_cache))) {
2195+
!is_refname_available(refname, skip, get_packed_refs(&ref_cache))) {
21922196
last_errno = ENOTDIR;
21932197
goto error_return;
21942198
}
@@ -2246,7 +2250,7 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
22462250
const unsigned char *old_sha1,
22472251
int flags, int *type_p)
22482252
{
2249-
return lock_ref_sha1_basic(refname, old_sha1, flags, type_p);
2253+
return lock_ref_sha1_basic(refname, old_sha1, NULL, flags, type_p);
22502254
}
22512255

22522256
/*
@@ -2690,6 +2694,18 @@ static int rename_tmp_log(const char *newrefname)
26902694
return 0;
26912695
}
26922696

2697+
static int rename_ref_available(const char *oldname, const char *newname)
2698+
{
2699+
struct string_list skip = STRING_LIST_INIT_NODUP;
2700+
int ret;
2701+
2702+
string_list_insert(&skip, oldname);
2703+
ret = is_refname_available(newname, &skip, get_packed_refs(&ref_cache))
2704+
&& is_refname_available(newname, &skip, get_loose_refs(&ref_cache));
2705+
string_list_clear(&skip, 0);
2706+
return ret;
2707+
}
2708+
26932709
int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
26942710
{
26952711
unsigned char sha1[20], orig_sha1[20];
@@ -2709,10 +2725,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
27092725
if (!symref)
27102726
return error("refname %s not found", oldrefname);
27112727

2712-
if (!is_refname_available(newrefname, oldrefname, get_packed_refs(&ref_cache)))
2713-
return 1;
2714-
2715-
if (!is_refname_available(newrefname, oldrefname, get_loose_refs(&ref_cache)))
2728+
if (!rename_ref_available(oldrefname, newrefname))
27162729
return 1;
27172730

27182731
if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
@@ -2742,7 +2755,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
27422755

27432756
logmoved = log;
27442757

2745-
lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL);
2758+
lock = lock_ref_sha1_basic(newrefname, NULL, NULL, 0, NULL);
27462759
if (!lock) {
27472760
error("unable to lock %s for update", newrefname);
27482761
goto rollback;
@@ -2757,7 +2770,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
27572770
return 0;
27582771

27592772
rollback:
2760-
lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL);
2773+
lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, 0, NULL);
27612774
if (!lock) {
27622775
error("unable to lock %s for rollback", oldrefname);
27632776
goto rollbacklog;
@@ -3636,6 +3649,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
36363649
(update->have_old ?
36373650
update->old_sha1 :
36383651
NULL),
3652+
NULL,
36393653
update->flags,
36403654
&update->type);
36413655
if (!update->lock) {

0 commit comments

Comments
 (0)