Would a struct string_list make sense here? (See
Documentation/technical/api-string-list.txt.)
[...]
> };
>
> static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
> {
> struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
> + int i;
> + for(i = 0; i < data->skipnum; i++) {
(style nit) missing space after 'for'.
> + if (!strcmp(entry->name, data->skip[i])) {
> + return 0;
> + }
Style: git tends to avoid braces around a single-line if/for/etc body.
[...]
> @@ -817,15 +825,21 @@ static int name_conflict_fn(struct ref_entry *entry,
> void *cb_data)
> * conflicting with the name of an existing reference in dir. If
> * oldrefname is non-NULL, ignore potential conflicts with oldrefname
> * (e.g., because oldrefname is scheduled for deletion in the same
> - * operation).
> + * operation). skip contains a list of refs we want to skip checking for
> + * conflicts with. Refs may be skipped due to us knowing that it will
> + * be deleted later during a transaction that deletes one reference and then
> + * creates a new conflicting reference. For example a rename from m to m/m.
This example of "Refs may be skipped due to" seems overly complicated.
Isn't the idea just that skip contains a list of refs scheduled for
deletion in this transaction, since they shouldn't be treated as
conflicts at all (for example when renamining m to m/m)?
I wonder if there's some way to make use of the result of the naive
refname_available check to decide what to do when creating a ref.
E.g.: if a refname would be available except there's a ref being
deleted in the way, we could do one of the following:
a. delete all relevant loose refs and perform the transaction in
packed-refs, or
b. order operations to avoid the D/F conflict, even with loose refs
(the hardest case is if the ref being deleted uses a directory
and we want to create a file with the same name. But that's
still doable if we're willing to rmdir when needed as part of
the loop to commit changes)
The packed-refs trick (a) seems much simpler, but either should work.
This could be done e.g. by checking is_refname_available with an empty
list first before doing the real thing with a list of exclusions.
[...]
> @@ -2592,6 +2609,9 @@ int rename_ref(const char *oldrefname, const char
> *newrefname, const char *logms
> int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
> const char *symref = NULL;
>
> + if (!strcmp(oldrefname, newrefname))
> + return 0;
What is the intended result if I try to rename a nonexistent ref or an
existent symref to its own name?
Sorry to be so fussy about this part. It's not that I think that this
change is trying to do something bad --- in fact, it's more the
opposite, that I'm excited to see git learning to have a better
understanding and handling of refname D/F conflicts.
That would allow:
* "git fetch --prune" working as a single transaction even if
the repository being fetched from removed a refs/heads/topic
branch and created refs/heads/topic/1 and refs/heads/topic/2
* "git fast-import" and "git fetch --mirror" learning the same trick
* fewer code paths having to be touched to be able to (optionally)
let git actually tolerate D/F conflicts, for people who want to
have 'topic', 'topic/1', and 'topic/2' branches at the same time.
This could be turned on by default for remote-tracking refs. It
would be especially nice for people on Windows and Mac OS where
there can be D/F conflicts that people on Linux didn't notice due
to case-sensitivity.
Longer term, through a configuration that starts turned off by
default and has the default flipped as more people have upgraded
git, this could make D/F conflicts in refnames stop being an error
altogether.
So it's kind of exciting to see, even though it's fussy to get it
right.
Thanks,
Jonathan
--
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