Merge branch 'ps/remote-rename-fix'

"git remote rename origin upstream" failed to move origin/HEAD to
upstream/HEAD when origin/HEAD is unborn and performed other
renames extremely inefficiently, which has been corrected.

* ps/remote-rename-fix:
  builtin/remote: only iterate through refs that are to be renamed
  builtin/remote: rework how remote refs get renamed
  builtin/remote: determine whether refs need renaming early on
  builtin/remote: fix sign comparison warnings
  refs: simplify logic when migrating reflog entries
  refs: pass refname when invoking reflog entry callback
main
Junio C Hamano 2025-08-21 13:46:58 -07:00
commit 9a85fa8406
19 changed files with 372 additions and 200 deletions

View File

@ -503,13 +503,12 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
} }
} }


static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid, static int fsck_handle_reflog_ent(const char *refname,
struct object_id *ooid, struct object_id *noid,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED, timestamp_t timestamp, int tz UNUSED,
const char *message UNUSED, void *cb_data) const char *message UNUSED, void *cb_data UNUSED)
{ {
const char *refname = cb_data;

if (verbose) if (verbose)
fprintf_ln(stderr, _("Checking reflog %s->%s"), fprintf_ln(stderr, _("Checking reflog %s->%s"),
oid_to_hex(ooid), oid_to_hex(noid)); oid_to_hex(ooid), oid_to_hex(noid));
@ -526,7 +525,7 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
strbuf_worktree_ref(cb_data, &refname, logname); strbuf_worktree_ref(cb_data, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(the_repository), refs_for_each_reflog_ent(get_main_ref_store(the_repository),
refname.buf, fsck_handle_reflog_ent, refname.buf, fsck_handle_reflog_ent,
refname.buf); NULL);
strbuf_release(&refname); strbuf_release(&refname);
return 0; return 0;
} }

View File

@ -312,7 +312,8 @@ struct count_reflog_entries_data {
size_t limit; size_t limit;
}; };


static int count_reflog_entries(struct object_id *old_oid, struct object_id *new_oid, static int count_reflog_entries(const char *refname UNUSED,
struct object_id *old_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp, const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data) int tz, const char *msg, void *cb_data)
{ {

View File

@ -1,9 +1,11 @@
#define USE_THE_REPOSITORY_VARIABLE #define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS


#include "builtin.h" #include "builtin.h"
#include "advice.h"
#include "config.h" #include "config.h"
#include "date.h"
#include "gettext.h" #include "gettext.h"
#include "ident.h"
#include "parse-options.h" #include "parse-options.h"
#include "path.h" #include "path.h"
#include "transport.h" #include "transport.h"
@ -182,7 +184,6 @@ static int add(int argc, const char **argv, const char *prefix,
struct remote *remote; struct remote *remote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT; struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url; const char *name, *url;
int i;
int result = 0; int result = 0;


struct option options[] = { struct option options[] = {
@ -233,7 +234,7 @@ static int add(int argc, const char **argv, const char *prefix,
strbuf_addf(&buf, "remote.%s.fetch", name); strbuf_addf(&buf, "remote.%s.fetch", name);
if (track.nr == 0) if (track.nr == 0)
string_list_append(&track, "*"); string_list_append(&track, "*");
for (i = 0; i < track.nr; i++) { for (size_t i = 0; i < track.nr; i++) {
add_branch(buf.buf, track.items[i].string, add_branch(buf.buf, track.items[i].string,
name, mirror, &buf2); name, mirror, &buf2);
} }
@ -612,53 +613,169 @@ static int add_branch_for_removal(const char *refname,
struct rename_info { struct rename_info {
const char *old_name; const char *old_name;
const char *new_name; const char *new_name;
struct string_list *remote_branches; struct ref_transaction *transaction;
uint32_t symrefs_nr; struct progress *progress;
struct strbuf *err;
uint32_t progress_nr;
uint64_t index;
}; };


static int read_remote_branches(const char *refname, const char *referent UNUSED, static void compute_renamed_ref(struct rename_info *rename,
const struct object_id *oid UNUSED, const char *refname,
int flags UNUSED, void *cb_data) struct strbuf *out)
{
strbuf_reset(out);
strbuf_addstr(out, refname);
strbuf_splice(out, strlen("refs/remotes/"), strlen(rename->old_name),
rename->new_name, strlen(rename->new_name));
}

static int rename_one_reflog_entry(const char *old_refname,
struct object_id *old_oid,
struct object_id *new_oid,
const char *committer,
timestamp_t timestamp, int tz,
const char *msg, void *cb_data)
{ {
struct rename_info *rename = cb_data; struct rename_info *rename = cb_data;
struct strbuf buf = STRBUF_INIT; struct strbuf new_refname = STRBUF_INIT;
struct string_list_item *item; struct strbuf identity = STRBUF_INIT;
int flag; struct strbuf name = STRBUF_INIT;
const char *symref; struct strbuf mail = STRBUF_INIT;
struct ident_split ident;
const char *date;
int error;


strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name); compute_renamed_ref(rename, old_refname, &new_refname);
if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, refname);
symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
refname, RESOLVE_REF_READING,
NULL, &flag);
if (symref && (flag & REF_ISSYMREF)) {
item->util = xstrdup(symref);
rename->symrefs_nr++;
} else {
item->util = NULL;
}
}
strbuf_release(&buf);


if (split_ident_line(&ident, committer, strlen(committer)) < 0) {
error = -1;
goto out;
}

strbuf_add(&name, ident.name_begin, ident.name_end - ident.name_begin);
strbuf_add(&mail, ident.mail_begin, ident.mail_end - ident.mail_begin);

date = show_date(timestamp, tz, DATE_MODE(NORMAL));
strbuf_addstr(&identity, fmt_ident(name.buf, mail.buf,
WANT_BLANK_IDENT, date, 0));

error = ref_transaction_update_reflog(rename->transaction, new_refname.buf,
new_oid, old_oid, identity.buf, msg,
rename->index++, rename->err);

out:
strbuf_release(&new_refname);
strbuf_release(&identity);
strbuf_release(&name);
strbuf_release(&mail);
return error;
}

static int rename_one_reflog(const char *old_refname,
const struct object_id *old_oid,
struct rename_info *rename)
{
struct strbuf new_refname = STRBUF_INIT;
struct strbuf message = STRBUF_INIT;
int error;

if (!refs_reflog_exists(get_main_ref_store(the_repository), old_refname))
return 0; return 0;

error = refs_for_each_reflog_ent(get_main_ref_store(the_repository),
old_refname, rename_one_reflog_entry, rename);
if (error < 0)
goto out;

compute_renamed_ref(rename, old_refname, &new_refname);

/*
* Manually write the reflog entry for the now-renamed ref. We cannot
* rely on `rename_one_ref()` to do this for us as that would screw
* over order in which reflog entries are being written.
*
* Furthermore, we only append the entry in case the reference
* resolves. Missing references shouldn't have reflogs anyway.
*/
strbuf_addf(&message, "remote: renamed %s to %s", old_refname,
new_refname.buf);

error = ref_transaction_update_reflog(rename->transaction, new_refname.buf,
old_oid, old_oid, git_committer_info(0),
message.buf, rename->index++, rename->err);
if (error < 0)
return error;

out:
strbuf_release(&new_refname);
strbuf_release(&message);
return error;
}

static int rename_one_ref(const char *old_refname, const char *referent,
const struct object_id *oid,
int flags, void *cb_data)
{
struct strbuf new_referent = STRBUF_INIT;
struct strbuf new_refname = STRBUF_INIT;
struct rename_info *rename = cb_data;
int error;

compute_renamed_ref(rename, old_refname, &new_refname);

if (flags & REF_ISSYMREF) {
/*
* Stupidly enough `referent` is not pointing to the immediate
* target of a symref, but it's the recursively resolved value.
* So symrefs pointing to symrefs would be misresolved, and
* unborn symrefs don't have any value for the `referent` at all.
*/
referent = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
old_refname, RESOLVE_REF_NO_RECURSE,
NULL, NULL);
compute_renamed_ref(rename, referent, &new_referent);
oid = NULL;
}

error = ref_transaction_delete(rename->transaction, old_refname,
oid, referent, REF_NO_DEREF, NULL, rename->err);
if (error < 0)
goto out;

error = ref_transaction_update(rename->transaction, new_refname.buf, oid, null_oid(the_hash_algo),
(flags & REF_ISSYMREF) ? new_referent.buf : NULL, NULL,
REF_SKIP_CREATE_REFLOG | REF_NO_DEREF | REF_SKIP_OID_VERIFICATION,
NULL, rename->err);
if (error < 0)
goto out;

error = rename_one_reflog(old_refname, oid, rename);
if (error < 0)
goto out;

display_progress(rename->progress, ++rename->progress_nr);

out:
strbuf_release(&new_referent);
strbuf_release(&new_refname);
return error;
} }


static int migrate_file(struct remote *remote) static int migrate_file(struct remote *remote)
{ {
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
int i;


strbuf_addf(&buf, "remote.%s.url", remote->name); strbuf_addf(&buf, "remote.%s.url", remote->name);
for (i = 0; i < remote->url.nr; i++) for (size_t i = 0; i < remote->url.nr; i++)
repo_config_set_multivar(the_repository, buf.buf, remote->url.v[i], "^$", 0); repo_config_set_multivar(the_repository, buf.buf, remote->url.v[i], "^$", 0);
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name); strbuf_addf(&buf, "remote.%s.push", remote->name);
for (i = 0; i < remote->push.nr; i++) for (int i = 0; i < remote->push.nr; i++)
repo_config_set_multivar(the_repository, buf.buf, remote->push.items[i].raw, "^$", 0); repo_config_set_multivar(the_repository, buf.buf, remote->push.items[i].raw, "^$", 0);
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name); strbuf_addf(&buf, "remote.%s.fetch", remote->name);
for (i = 0; i < remote->fetch.nr; i++) for (int i = 0; i < remote->fetch.nr; i++)
repo_config_set_multivar(the_repository, buf.buf, remote->fetch.items[i].raw, "^$", 0); repo_config_set_multivar(the_repository, buf.buf, remote->fetch.items[i].raw, "^$", 0);
#ifndef WITH_BREAKING_CHANGES #ifndef WITH_BREAKING_CHANGES
if (remote->origin == REMOTE_REMOTES) if (remote->origin == REMOTE_REMOTES)
@ -730,6 +847,14 @@ static void handle_push_default(const char* old_name, const char* new_name)
strbuf_release(&push_default.origin); strbuf_release(&push_default.origin);
} }


static const char conflicting_remote_refs_advice[] = N_(
"The remote you are trying to rename has conflicting references in the\n"
"new target refspec. This is most likely caused by you trying to nest\n"
"a remote into itself, e.g. by renaming 'parent' into 'parent/child'\n"
"or by unnesting a remote, e.g. the other way round.\n"
"\n"
"If that is the case, you can address this by first renaming the\n"
"remote to a different name.\n");


static int mv(int argc, const char **argv, const char *prefix, static int mv(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED) struct repository *repo UNUSED)
@ -741,11 +866,11 @@ static int mv(int argc, const char **argv, const char *prefix,
}; };
struct remote *oldremote, *newremote; struct remote *oldremote, *newremote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT, struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT,
old_remote_context = STRBUF_INIT; old_remote_context = STRBUF_INIT, err = STRBUF_INIT;
struct string_list remote_branches = STRING_LIST_INIT_DUP; struct rename_info rename = {
struct rename_info rename; .err = &err,
int i, refs_renamed_nr = 0, refspec_updated = 0; };
struct progress *progress = NULL; int refspecs_need_update = 0;
int result = 0; int result = 0;


argc = parse_options(argc, argv, prefix, options, argc = parse_options(argc, argv, prefix, options,
@ -756,8 +881,6 @@ static int mv(int argc, const char **argv, const char *prefix,


rename.old_name = argv[0]; rename.old_name = argv[0];
rename.new_name = argv[1]; rename.new_name = argv[1];
rename.remote_branches = &remote_branches;
rename.symrefs_nr = 0;


oldremote = remote_get(rename.old_name); oldremote = remote_get(rename.old_name);
if (!remote_is_configured(oldremote, 1)) { if (!remote_is_configured(oldremote, 1)) {
@ -785,19 +908,50 @@ static int mv(int argc, const char **argv, const char *prefix,
goto out; goto out;
} }


strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);

for (int i = 0; i < oldremote->fetch.nr && !refspecs_need_update; i++)
refspecs_need_update = !!strstr(oldremote->fetch.items[i].raw,
old_remote_context.buf);

if (refspecs_need_update) {
rename.transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
0, &err);
if (!rename.transaction)
goto out;

if (show_progress)
rename.progress = start_delayed_progress(the_repository,
_("Renaming remote references"), 0);

strbuf_reset(&buf);
strbuf_addf(&buf, "refs/remotes/%s/", rename.old_name);

result = refs_for_each_rawref_in(get_main_ref_store(the_repository), buf.buf,
rename_one_ref, &rename);
if (result < 0)
die(_("queueing remote ref renames failed: %s"), rename.err->buf);

result = ref_transaction_prepare(rename.transaction, &err);
if (result < 0) {
error("renaming remote references failed: %s", err.buf);
if (result == REF_TRANSACTION_ERROR_NAME_CONFLICT)
advise(conflicting_remote_refs_advice);
die(NULL);
}
}

if (oldremote->fetch.nr) { if (oldremote->fetch.nr) {
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); for (int i = 0; i < oldremote->fetch.nr; i++) {
for (i = 0; i < oldremote->fetch.nr; i++) {
char *ptr; char *ptr;


strbuf_reset(&buf2); strbuf_reset(&buf2);
strbuf_addstr(&buf2, oldremote->fetch.items[i].raw); strbuf_addstr(&buf2, oldremote->fetch.items[i].raw);
ptr = strstr(buf2.buf, old_remote_context.buf); ptr = strstr(buf2.buf, old_remote_context.buf);
if (ptr) { if (ptr) {
refspec_updated = 1;
strbuf_splice(&buf2, strbuf_splice(&buf2,
ptr-buf2.buf + strlen(":refs/remotes/"), ptr-buf2.buf + strlen(":refs/remotes/"),
strlen(rename.old_name), rename.new_name, strlen(rename.old_name), rename.new_name,
@ -813,7 +967,7 @@ static int mv(int argc, const char **argv, const char *prefix,
} }


read_branches(); read_branches();
for (i = 0; i < branch_list.nr; i++) { for (size_t i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i; struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util; struct branch_info *info = item->util;
if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) { if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) {
@ -828,83 +982,23 @@ static int mv(int argc, const char **argv, const char *prefix,
} }
} }


if (!refspec_updated) if (refspecs_need_update) {
goto out; result = ref_transaction_commit(rename.transaction, &err);
if (result < 0)
die(_("renaming remote refs failed: %s"), rename.err->buf);


/* stop_progress(&rename.progress);
* First remove symrefs, then rename the rest, finally create
* the new symrefs.
*/
refs_for_each_ref(get_main_ref_store(the_repository),
read_remote_branches, &rename);
if (show_progress) {
/*
* Count symrefs twice, since "renaming" them is done by
* deleting and recreating them in two separate passes.
*/
progress = start_progress(the_repository,
_("Renaming remote references"),
rename.remote_branches->nr + rename.symrefs_nr);
}
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;
struct strbuf referent = STRBUF_INIT;

if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
&referent))
continue;
if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
die(_("deleting '%s' failed"), item->string);

strbuf_release(&referent);
display_progress(progress, ++refs_renamed_nr);
}
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;

if (item->util)
continue;
strbuf_reset(&buf);
strbuf_addstr(&buf, item->string);
strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
rename.new_name, strlen(rename.new_name));
strbuf_reset(&buf2);
strbuf_addf(&buf2, "remote: renamed %s to %s",
item->string, buf.buf);
if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
die(_("renaming '%s' failed"), item->string);
display_progress(progress, ++refs_renamed_nr);
}
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;

if (!item->util)
continue;
strbuf_reset(&buf);
strbuf_addstr(&buf, item->string);
strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
rename.new_name, strlen(rename.new_name));
strbuf_reset(&buf2);
strbuf_addstr(&buf2, item->util);
strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old_name),
rename.new_name, strlen(rename.new_name));
strbuf_reset(&buf3);
strbuf_addf(&buf3, "remote: renamed %s to %s",
item->string, buf.buf);
if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
die(_("creating '%s' failed"), buf.buf);
display_progress(progress, ++refs_renamed_nr);
}
stop_progress(&progress);


handle_push_default(rename.old_name, rename.new_name); handle_push_default(rename.old_name, rename.new_name);
}


out: out:
string_list_clear(&remote_branches, 1); ref_transaction_free(rename.transaction);
strbuf_release(&old_remote_context); strbuf_release(&old_remote_context);
strbuf_release(&buf); strbuf_release(&buf);
strbuf_release(&buf2); strbuf_release(&buf2);
strbuf_release(&buf3); strbuf_release(&buf3);
strbuf_release(&err);
return result; return result;
} }


@ -920,7 +1014,7 @@ static int rm(int argc, const char **argv, const char *prefix,
struct string_list branches = STRING_LIST_INIT_DUP; struct string_list branches = STRING_LIST_INIT_DUP;
struct string_list skipped = STRING_LIST_INIT_DUP; struct string_list skipped = STRING_LIST_INIT_DUP;
struct branches_for_remote cb_data; struct branches_for_remote cb_data;
int i, result; int result;


memset(&cb_data, 0, sizeof(cb_data)); memset(&cb_data, 0, sizeof(cb_data));
cb_data.branches = &branches; cb_data.branches = &branches;
@ -942,7 +1036,7 @@ static int rm(int argc, const char **argv, const char *prefix,
for_each_remote(add_known_remote, &known_remotes); for_each_remote(add_known_remote, &known_remotes);


read_branches(); read_branches();
for (i = 0; i < branch_list.nr; i++) { for (size_t i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i; struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util; struct branch_info *info = item->util;
if (info->remote_name && !strcmp(info->remote_name, remote->name)) { if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
@ -988,7 +1082,7 @@ static int rm(int argc, const char **argv, const char *prefix,
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n" "Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:", "to delete them, use:",
skipped.nr)); skipped.nr));
for (i = 0; i < skipped.nr; i++) for (size_t i = 0; i < skipped.nr; i++)
fprintf(stderr, " git branch -d %s\n", fprintf(stderr, " git branch -d %s\n",
skipped.items[i].string); skipped.items[i].string);
} }
@ -1166,7 +1260,6 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
struct branch_info *branch_info = item->util; struct branch_info *branch_info = item->util;
struct string_list *merge = &branch_info->merge; struct string_list *merge = &branch_info->merge;
int width = show_info->width + 4; int width = show_info->width + 4;
int i;


if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) { if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"), error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
@ -1192,7 +1285,7 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
} else { } else {
printf_ln(_("merges with remote %s"), merge->items[0].string); printf_ln(_("merges with remote %s"), merge->items[0].string);
} }
for (i = 1; i < merge->nr; i++) for (size_t i = 1; i < merge->nr; i++)
printf(_("%-*s and with remote %s\n"), width, "", printf(_("%-*s and with remote %s\n"), width, "",
merge->items[i].string); merge->items[i].string);


@ -1277,7 +1370,6 @@ static int get_one_entry(struct remote *remote, void *priv)
struct string_list *list = priv; struct string_list *list = priv;
struct strbuf remote_info_buf = STRBUF_INIT; struct strbuf remote_info_buf = STRBUF_INIT;
struct strvec *url; struct strvec *url;
int i;


if (remote->url.nr > 0) { if (remote->url.nr > 0) {
struct strbuf promisor_config = STRBUF_INIT; struct strbuf promisor_config = STRBUF_INIT;
@ -1294,8 +1386,7 @@ static int get_one_entry(struct remote *remote, void *priv)
} else } else
string_list_append(list, remote->name)->util = NULL; string_list_append(list, remote->name)->util = NULL;
url = push_url_of_remote(remote); url = push_url_of_remote(remote);
for (i = 0; i < url->nr; i++) for (size_t i = 0; i < url->nr; i++) {
{
strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]); strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]);
string_list_append(list, remote->name)->util = string_list_append(list, remote->name)->util =
strbuf_detach(&remote_info_buf, NULL); strbuf_detach(&remote_info_buf, NULL);
@ -1312,10 +1403,8 @@ static int show_all(void)
result = for_each_remote(get_one_entry, &list); result = for_each_remote(get_one_entry, &list);


if (!result) { if (!result) {
int i;

string_list_sort(&list); string_list_sort(&list);
for (i = 0; i < list.nr; i++) { for (size_t i = 0; i < list.nr; i++) {
struct string_list_item *item = list.items + i; struct string_list_item *item = list.items + i;
if (verbose) if (verbose)
printf("%s\t%s\n", item->string, printf("%s\t%s\n", item->string,
@ -1352,7 +1441,7 @@ static int show(int argc, const char **argv, const char *prefix,
query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES); query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);


for (; argc; argc--, argv++) { for (; argc; argc--, argv++) {
int i; size_t i;
struct strvec *url; struct strvec *url;


get_remote_ref_states(*argv, &info.states, query_flag); get_remote_ref_states(*argv, &info.states, query_flag);
@ -1458,7 +1547,7 @@ static void report_set_head_auto(const char *remote, const char *head_name,
static int set_head(int argc, const char **argv, const char *prefix, static int set_head(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
int i, opt_a = 0, opt_d = 0, result = 0, was_detached; int opt_a = 0, opt_d = 0, result = 0, was_detached;
struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT, struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
b_local_head = STRBUF_INIT; b_local_head = STRBUF_INIT;
char *head_name = NULL; char *head_name = NULL;
@ -1492,7 +1581,7 @@ static int set_head(int argc, const char **argv, const char *prefix,
else if (states.heads.nr > 1) { else if (states.heads.nr > 1) {
result |= error(_("Multiple remote HEAD branches. " result |= error(_("Multiple remote HEAD branches. "
"Please choose one explicitly with:")); "Please choose one explicitly with:"));
for (i = 0; i < states.heads.nr; i++) for (size_t i = 0; i < states.heads.nr; i++)
fprintf(stderr, " git remote set-head %s %s\n", fprintf(stderr, " git remote set-head %s %s\n",
argv[0], states.heads.items[i].string); argv[0], states.heads.items[i].string);
} else } else
@ -1717,7 +1806,7 @@ static int set_branches(int argc, const char **argv, const char *prefix,
static int get_url(int argc, const char **argv, const char *prefix, static int get_url(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
int i, push_mode = 0, all_mode = 0; int push_mode = 0, all_mode = 0;
const char *remotename = NULL; const char *remotename = NULL;
struct remote *remote; struct remote *remote;
struct strvec *url; struct strvec *url;
@ -1745,7 +1834,7 @@ static int get_url(int argc, const char **argv, const char *prefix,
url = push_mode ? push_url_of_remote(remote) : &remote->url; url = push_mode ? push_url_of_remote(remote) : &remote->url;


if (all_mode) { if (all_mode) {
for (i = 0; i < url->nr; i++) for (size_t i = 0; i < url->nr; i++)
printf_ln("%s", url->v[i]); printf_ln("%s", url->v[i]);
} else { } else {
printf_ln("%s", url->v[0]); printf_ln("%s", url->v[0]);
@ -1757,7 +1846,7 @@ static int get_url(int argc, const char **argv, const char *prefix,
static int set_url(int argc, const char **argv, const char *prefix, static int set_url(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
int i, push_mode = 0, add_mode = 0, delete_mode = 0; int push_mode = 0, add_mode = 0, delete_mode = 0;
int matches = 0, negative_matches = 0; int matches = 0, negative_matches = 0;
const char *remotename = NULL; const char *remotename = NULL;
const char *newurl = NULL; const char *newurl = NULL;
@ -1821,7 +1910,7 @@ static int set_url(int argc, const char **argv, const char *prefix,
if (regcomp(&old_regex, oldurl, REG_EXTENDED)) if (regcomp(&old_regex, oldurl, REG_EXTENDED))
die(_("Invalid old URL pattern: %s"), oldurl); die(_("Invalid old URL pattern: %s"), oldurl);


for (i = 0; i < urlset->nr; i++) for (size_t i = 0; i < urlset->nr; i++)
if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0)) if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0))
matches++; matches++;
else else

View File

@ -738,7 +738,8 @@ cleanup:
return ret; return ret;
} }


static int reject_reflog_ent(struct object_id *ooid UNUSED, static int reject_reflog_ent(const char *refname UNUSED,
struct object_id *ooid UNUSED,
struct object_id *noid UNUSED, struct object_id *noid UNUSED,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp UNUSED, timestamp_t timestamp UNUSED,
@ -2207,7 +2208,8 @@ struct stash_entry_data {
size_t count; size_t count;
}; };


static int collect_stash_entries(struct object_id *old_oid UNUSED, static int collect_stash_entries(const char *refname UNUSED,
struct object_id *old_oid UNUSED,
struct object_id *new_oid, struct object_id *new_oid,
const char *committer UNUSED, const char *committer UNUSED,
timestamp_t timestamp UNUSED, timestamp_t timestamp UNUSED,

View File

@ -1039,7 +1039,8 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
commit->object.flags |= TMP_MARK; commit->object.flags |= TMP_MARK;
} }


static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid, static int collect_one_reflog_ent(const char *refname UNUSED,
struct object_id *ooid, struct object_id *noid,
const char *ident UNUSED, const char *ident UNUSED,
timestamp_t timestamp UNUSED, int tz UNUSED, timestamp_t timestamp UNUSED, int tz UNUSED,
const char *message UNUSED, void *cbdata) const char *message UNUSED, void *cbdata)

View File

@ -1525,7 +1525,8 @@ struct grab_nth_branch_switch_cbdata {
struct strbuf *sb; struct strbuf *sb;
}; };


static int grab_nth_branch_switch(struct object_id *ooid UNUSED, static int grab_nth_branch_switch(const char *refname UNUSED,
struct object_id *ooid UNUSED,
struct object_id *noid UNUSED, struct object_id *noid UNUSED,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp UNUSED, timestamp_t timestamp UNUSED,

View File

@ -22,7 +22,8 @@ struct complete_reflogs {
int nr, alloc; int nr, alloc;
}; };


static int read_one_reflog(struct object_id *ooid, struct object_id *noid, static int read_one_reflog(const char *refname UNUSED,
struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz, const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data) const char *message, void *cb_data)
{ {

View File

@ -507,7 +507,8 @@ void reflog_expiry_cleanup(void *cb_data)
free_commit_list(cb->mark_list); free_commit_list(cb->mark_list);
} }


int count_reflog_ent(struct object_id *ooid UNUSED, int count_reflog_ent(const char *refname UNUSED,
struct object_id *ooid UNUSED,
struct object_id *noid UNUSED, struct object_id *noid UNUSED,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED, timestamp_t timestamp, int tz UNUSED,

View File

@ -65,7 +65,8 @@ void reflog_expiry_prepare(const char *refname, const struct object_id *oid,
int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid, int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz, const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data); const char *message, void *cb_data);
int count_reflog_ent(struct object_id *ooid, struct object_id *noid, int count_reflog_ent(const char *refname,
struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz, const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data); const char *message, void *cb_data);
int should_expire_reflog_ent_verbose(struct object_id *ooid, int should_expire_reflog_ent_verbose(struct object_id *ooid,

64
refs.c
View File

@ -1022,7 +1022,6 @@ int is_branch(const char *refname)
} }


struct read_ref_at_cb { struct read_ref_at_cb {
const char *refname;
timestamp_t at_time; timestamp_t at_time;
int cnt; int cnt;
int reccnt; int reccnt;
@ -1052,7 +1051,8 @@ static void set_read_ref_cutoffs(struct read_ref_at_cb *cb,
*cb->cutoff_cnt = cb->reccnt; *cb->cutoff_cnt = cb->reccnt;
} }


static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, static int read_ref_at_ent(const char *refname,
struct object_id *ooid, struct object_id *noid,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp, int tz, timestamp_t timestamp, int tz,
const char *message, void *cb_data) const char *message, void *cb_data)
@ -1072,14 +1072,13 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
oidcpy(cb->oid, noid); oidcpy(cb->oid, noid);
if (!oideq(&cb->ooid, noid)) if (!oideq(&cb->ooid, noid))
warning(_("log for ref %s has gap after %s"), warning(_("log for ref %s has gap after %s"),
cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
} }
else if (cb->date == cb->at_time) else if (cb->date == cb->at_time)
oidcpy(cb->oid, noid); oidcpy(cb->oid, noid);
else if (!oideq(noid, cb->oid)) else if (!oideq(noid, cb->oid))
warning(_("log for ref %s unexpectedly ended on %s"), warning(_("log for ref %s unexpectedly ended on %s"),
cb->refname, show_date(cb->date, cb->tz, refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
DATE_MODE(RFC2822)));
cb->reccnt++; cb->reccnt++;
oidcpy(&cb->ooid, ooid); oidcpy(&cb->ooid, ooid);
oidcpy(&cb->noid, noid); oidcpy(&cb->noid, noid);
@ -1094,7 +1093,8 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
return 0; return 0;
} }


static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid, static int read_ref_at_ent_oldest(const char *refname UNUSED,
struct object_id *ooid, struct object_id *noid,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp, int tz, timestamp_t timestamp, int tz,
const char *message, void *cb_data) const char *message, void *cb_data)
@ -1117,7 +1117,6 @@ int read_ref_at(struct ref_store *refs, const char *refname,
struct read_ref_at_cb cb; struct read_ref_at_cb cb;


memset(&cb, 0, sizeof(cb)); memset(&cb, 0, sizeof(cb));
cb.refname = refname;
cb.at_time = at_time; cb.at_time = at_time;
cb.cnt = cnt; cb.cnt = cnt;
cb.msg = msg; cb.msg = msg;
@ -1840,7 +1839,13 @@ int refs_for_each_namespaced_ref(struct ref_store *refs,


int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data) int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{ {
return do_for_each_ref(refs, "", NULL, fn, 0, return refs_for_each_rawref_in(refs, "", fn, cb_data);
}

int refs_for_each_rawref_in(struct ref_store *refs, const char *prefix,
each_ref_fn fn, void *cb_data)
{
return do_for_each_ref(refs, prefix, NULL, fn, 0,
DO_FOR_EACH_INCLUDE_BROKEN, cb_data); DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
} }


@ -2942,6 +2947,7 @@ struct migration_data {
struct ref_transaction *transaction; struct ref_transaction *transaction;
struct strbuf *errbuf; struct strbuf *errbuf;
struct strbuf sb, name, mail; struct strbuf sb, name, mail;
uint64_t index;
}; };


static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
@ -2974,22 +2980,14 @@ done:
return ret; return ret;
} }


struct reflog_migration_data { static int migrate_one_reflog_entry(const char *refname,
uint64_t index; struct object_id *old_oid,
const char *refname;
struct ref_store *old_refs;
struct ref_transaction *transaction;
struct strbuf *errbuf;
struct strbuf *sb, *name, *mail;
};

static int migrate_one_reflog_entry(struct object_id *old_oid,
struct object_id *new_oid, struct object_id *new_oid,
const char *committer, const char *committer,
timestamp_t timestamp, int tz, timestamp_t timestamp, int tz,
const char *msg, void *cb_data) const char *msg, void *cb_data)
{ {
struct reflog_migration_data *data = cb_data; struct migration_data *data = cb_data;
struct ident_split ident; struct ident_split ident;
const char *date; const char *date;
int ret; int ret;
@ -2997,17 +2995,17 @@ static int migrate_one_reflog_entry(struct object_id *old_oid,
if (split_ident_line(&ident, committer, strlen(committer)) < 0) if (split_ident_line(&ident, committer, strlen(committer)) < 0)
return -1; return -1;


strbuf_reset(data->name); strbuf_reset(&data->name);
strbuf_add(data->name, ident.name_begin, ident.name_end - ident.name_begin); strbuf_add(&data->name, ident.name_begin, ident.name_end - ident.name_begin);
strbuf_reset(data->mail); strbuf_reset(&data->mail);
strbuf_add(data->mail, ident.mail_begin, ident.mail_end - ident.mail_begin); strbuf_add(&data->mail, ident.mail_begin, ident.mail_end - ident.mail_begin);


date = show_date(timestamp, tz, DATE_MODE(NORMAL)); date = show_date(timestamp, tz, DATE_MODE(NORMAL));
strbuf_reset(data->sb); strbuf_reset(&data->sb);
strbuf_addstr(data->sb, fmt_ident(data->name->buf, data->mail->buf, WANT_BLANK_IDENT, date, 0)); strbuf_addstr(&data->sb, fmt_ident(data->name.buf, data->mail.buf, WANT_BLANK_IDENT, date, 0));


ret = ref_transaction_update_reflog(data->transaction, data->refname, ret = ref_transaction_update_reflog(data->transaction, refname,
new_oid, old_oid, data->sb->buf, new_oid, old_oid, data->sb.buf,
msg, data->index++, data->errbuf); msg, data->index++, data->errbuf);
return ret; return ret;
} }
@ -3015,18 +3013,8 @@ static int migrate_one_reflog_entry(struct object_id *old_oid,
static int migrate_one_reflog(const char *refname, void *cb_data) static int migrate_one_reflog(const char *refname, void *cb_data)
{ {
struct migration_data *migration_data = cb_data; struct migration_data *migration_data = cb_data;
struct reflog_migration_data data = {
.refname = refname,
.old_refs = migration_data->old_refs,
.transaction = migration_data->transaction,
.errbuf = migration_data->errbuf,
.sb = &migration_data->sb,
.name = &migration_data->name,
.mail = &migration_data->mail,
};

return refs_for_each_reflog_ent(migration_data->old_refs, refname, return refs_for_each_reflog_ent(migration_data->old_refs, refname,
migrate_one_reflog_entry, &data); migrate_one_reflog_entry, migration_data);
} }


static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf) static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf)

13
refs.h
View File

@ -428,6 +428,8 @@ int refs_for_each_namespaced_ref(struct ref_store *refs,


/* can be used to learn about broken ref and symref */ /* can be used to learn about broken ref and symref */
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data); int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
int refs_for_each_rawref_in(struct ref_store *refs, const char *prefix,
each_ref_fn fn, void *cb_data);


/* /*
* Iterates over all refs including root refs, i.e. pseudorefs and HEAD. * Iterates over all refs including root refs, i.e. pseudorefs and HEAD.
@ -558,10 +560,13 @@ int refs_delete_reflog(struct ref_store *refs, const char *refname);
* The cb_data is a caller-supplied pointer given to the iterator * The cb_data is a caller-supplied pointer given to the iterator
* functions. * functions.
*/ */
typedef int each_reflog_ent_fn( typedef int each_reflog_ent_fn(const char *refname,
struct object_id *old_oid, struct object_id *new_oid, struct object_id *old_oid,
const char *committer, timestamp_t timestamp, struct object_id *new_oid,
int tz, const char *msg, void *cb_data); const char *committer,
timestamp_t timestamp,
int tz, const char *msg,
void *cb_data);


/* Iterate over reflog entries in the log for `refname`. */ /* Iterate over reflog entries in the log for `refname`. */



View File

@ -277,7 +277,8 @@ struct debug_reflog {
void *cb_data; void *cb_data;
}; };


static int debug_print_reflog_ent(struct object_id *old_oid, static int debug_print_reflog_ent(const char *refname,
struct object_id *old_oid,
struct object_id *new_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp, const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data) int tz, const char *msg, void *cb_data)
@ -292,7 +293,7 @@ static int debug_print_reflog_ent(struct object_id *old_oid,
if (new_oid) if (new_oid)
oid_to_hex_r(n, new_oid); oid_to_hex_r(n, new_oid);


ret = dbg->fn(old_oid, new_oid, committer, timestamp, tz, msg, ret = dbg->fn(refname, old_oid, new_oid, committer, timestamp, tz, msg,
dbg->cb_data); dbg->cb_data);
trace_printf_key(&trace_refs, trace_printf_key(&trace_refs,
"reflog_ent %s (ret %d): %s -> %s, %s %ld \"%.*s\"\n", "reflog_ent %s (ret %d): %s -> %s, %s %ld \"%.*s\"\n",

View File

@ -2115,7 +2115,9 @@ static int files_delete_reflog(struct ref_store *ref_store,
return ret; return ret;
} }


static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb, static int show_one_reflog_ent(struct files_ref_store *refs,
const char *refname,
struct strbuf *sb,
each_reflog_ent_fn fn, void *cb_data) each_reflog_ent_fn fn, void *cb_data)
{ {
struct object_id ooid, noid; struct object_id ooid, noid;
@ -2142,7 +2144,7 @@ static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
message += 6; message += 6;
else else
message += 7; message += 7;
return fn(&ooid, &noid, p, timestamp, tz, message, cb_data); return fn(refname, &ooid, &noid, p, timestamp, tz, message, cb_data);
} }


static char *find_beginning_of_line(char *bob, char *scan) static char *find_beginning_of_line(char *bob, char *scan)
@ -2226,7 +2228,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1)); strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp; scanp = bp;
endp = bp + 1; endp = bp + 1;
ret = show_one_reflog_ent(refs, &sb, fn, cb_data); ret = show_one_reflog_ent(refs, refname, &sb, fn, cb_data);
strbuf_reset(&sb); strbuf_reset(&sb);
if (ret) if (ret)
break; break;
@ -2238,7 +2240,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
* Process it, and we can end the loop. * Process it, and we can end the loop.
*/ */
strbuf_splice(&sb, 0, 0, buf, endp - buf); strbuf_splice(&sb, 0, 0, buf, endp - buf);
ret = show_one_reflog_ent(refs, &sb, fn, cb_data); ret = show_one_reflog_ent(refs, refname, &sb, fn, cb_data);
strbuf_reset(&sb); strbuf_reset(&sb);
break; break;
} }
@ -2288,7 +2290,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
return -1; return -1;


while (!ret && !strbuf_getwholeline(&sb, logfp, '\n')) while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
ret = show_one_reflog_ent(refs, &sb, fn, cb_data); ret = show_one_reflog_ent(refs, refname, &sb, fn, cb_data);
fclose(logfp); fclose(logfp);
strbuf_release(&sb); strbuf_release(&sb);
return ret; return ret;
@ -3360,7 +3362,8 @@ struct expire_reflog_cb {
dry_run:1; dry_run:1;
}; };


static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid, static int expire_reflog_ent(const char *refname UNUSED,
struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz, const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data) const char *message, void *cb_data)
{ {

View File

@ -2155,7 +2155,7 @@ static int yield_log_record(struct reftable_ref_store *refs,


full_committer = fmt_ident(log->value.update.name, log->value.update.email, full_committer = fmt_ident(log->value.update.name, log->value.update.email,
WANT_COMMITTER_IDENT, NULL, IDENT_NO_DATE); WANT_COMMITTER_IDENT, NULL, IDENT_NO_DATE);
return fn(&old_oid, &new_oid, full_committer, return fn(log->refname, &old_oid, &new_oid, full_committer,
log->value.update.time, log->value.update.tz_offset, log->value.update.time, log->value.update.tz_offset,
log->value.update.message, cb_data); log->value.update.message, cb_data);
} }

View File

@ -2578,7 +2578,8 @@ struct check_and_collect_until_cb_data {
}; };


/* Get the timestamp of the latest entry. */ /* Get the timestamp of the latest entry. */
static int peek_reflog(struct object_id *o_oid UNUSED, static int peek_reflog(const char *refname UNUSED,
struct object_id *o_oid UNUSED,
struct object_id *n_oid UNUSED, struct object_id *n_oid UNUSED,
const char *ident UNUSED, const char *ident UNUSED,
timestamp_t timestamp, int tz UNUSED, timestamp_t timestamp, int tz UNUSED,
@ -2589,7 +2590,8 @@ static int peek_reflog(struct object_id *o_oid UNUSED,
return 1; return 1;
} }


static int check_and_collect_until(struct object_id *o_oid UNUSED, static int check_and_collect_until(const char *refname UNUSED,
struct object_id *o_oid UNUSED,
struct object_id *n_oid, struct object_id *n_oid,
const char *ident UNUSED, const char *ident UNUSED,
timestamp_t timestamp, int tz UNUSED, timestamp_t timestamp, int tz UNUSED,

View File

@ -1689,7 +1689,8 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
} }
} }


static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid, static int handle_one_reflog_ent(const char *refname UNUSED,
struct object_id *ooid, struct object_id *noid,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp UNUSED, timestamp_t timestamp UNUSED,
int tz UNUSED, int tz UNUSED,

View File

@ -215,7 +215,8 @@ static int cmd_for_each_reflog(struct ref_store *refs,
return refs_for_each_reflog(refs, each_reflog, NULL); return refs_for_each_reflog(refs, each_reflog, NULL);
} }


static int each_reflog_ent(struct object_id *old_oid, struct object_id *new_oid, static int each_reflog_ent(const char *refname UNUSED,
struct object_id *old_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp, const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data UNUSED) int tz, const char *msg, void *cb_data UNUSED)
{ {

View File

@ -1658,4 +1658,77 @@ test_expect_success 'forbid adding superset of existing remote' '
test_grep ".outer. is a superset of existing remote .outer/inner." err test_grep ".outer. is a superset of existing remote .outer/inner." err
' '


test_expect_success 'rename handles unborn HEAD' '
test_when_finished "git remote remove unborn-renamed" &&
git remote add unborn url &&
git symbolic-ref refs/remotes/unborn/HEAD refs/remotes/unborn/nonexistent &&
git remote rename unborn unborn-renamed &&
git symbolic-ref refs/remotes/unborn-renamed/HEAD >actual &&
echo refs/remotes/unborn-renamed/nonexistent >expected &&
test_cmp expected actual
'

test_expect_success 'rename can nest a remote into itself' '
test_commit parent-commit &&
COMMIT_ID=$(git rev-parse HEAD) &&
test_when_finished "git remote remove parent || true" &&
git remote add parent url &&
git update-ref refs/remotes/parent/branch $COMMIT_ID &&
test_when_finished "git remote remove parent/child" &&
git remote rename parent parent/child &&
git for-each-ref refs/remotes/ >actual &&
printf "$COMMIT_ID commit\trefs/remotes/parent/child/branch\n" >expected &&
test_cmp expected actual
'

test_expect_success 'rename can nest a remote into itself with a conflicting branch name' '
test_commit parent-conflict &&
COMMIT_ID=$(git rev-parse HEAD) &&
test_when_finished "git remote remove parent || true" &&
git remote add parent url &&
git update-ref refs/remotes/parent/child $COMMIT_ID &&
test_when_finished "git remote remove parent/child" &&
test_must_fail git remote rename parent parent/child 2>err &&
test_grep "renaming remote references failed" err &&
test_grep "The remote you are trying to rename has conflicting references" err &&
git for-each-ref refs/remotes/ >actual &&
printf "$COMMIT_ID commit\trefs/remotes/parent/child\n" >expected &&
test_cmp expected actual
'

test_expect_success 'rename can unnest a remote' '
test_commit parent-child-commit &&
COMMIT_ID=$(git rev-parse HEAD) &&
test_when_finished "git remote remove parent/child || true" &&
git remote add parent/child url &&
git update-ref refs/remotes/parent/child/branch $COMMIT_ID &&
git remote rename parent/child parent &&
git for-each-ref refs/remotes/ >actual &&
printf "$COMMIT_ID commit\trefs/remotes/parent/branch\n" >expected &&
test_cmp expected actual
'

test_expect_success 'rename moves around the reflog' '
test_commit reflog-old &&
COMMIT_ID=$(git rev-parse HEAD) &&
test_config core.logAllRefUpdates true &&
test_when_finished "git remote remove reflog-old || true" &&
git remote add reflog-old url &&
git update-ref refs/remotes/reflog-old/branch $COMMIT_ID &&
test-tool ref-store main for-each-reflog >actual &&
test_grep refs/remotes/reflog-old/branch actual &&
test-tool ref-store main for-each-reflog-ent refs/remotes/reflog-old/branch >reflog-entries-old &&
test_line_count = 1 reflog-entries-old &&
git remote rename reflog-old reflog-new &&
test-tool ref-store main for-each-reflog >actual &&
test_grep ! refs/remotes/reflog-old actual &&
test_grep refs/remotes/reflog-new/branch actual &&
test-tool ref-store main for-each-reflog-ent refs/remotes/reflog-new/branch >reflog-entries-new &&
cat >expect <<-EOF &&
$(cat reflog-entries-old)
$COMMIT_ID $COMMIT_ID $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1112912173 -0700 remote: renamed refs/remotes/reflog-old/branch to refs/remotes/reflog-new/branch
EOF
test_cmp expect reflog-entries-new
'

test_done test_done

View File

@ -972,7 +972,8 @@ static void wt_longstatus_print_changed(struct wt_status *s)
wt_longstatus_print_trailer(s); wt_longstatus_print_trailer(s);
} }


static int stash_count_refs(struct object_id *ooid UNUSED, static int stash_count_refs(const char *refname UNUSED,
struct object_id *ooid UNUSED,
struct object_id *noid UNUSED, struct object_id *noid UNUSED,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp UNUSED, int tz UNUSED, timestamp_t timestamp UNUSED, int tz UNUSED,
@ -1664,7 +1665,8 @@ struct grab_1st_switch_cbdata {
struct object_id noid; struct object_id noid;
}; };


static int grab_1st_switch(struct object_id *ooid UNUSED, static int grab_1st_switch(const char *refname UNUSED,
struct object_id *ooid UNUSED,
struct object_id *noid, struct object_id *noid,
const char *email UNUSED, const char *email UNUSED,
timestamp_t timestamp UNUSED, int tz UNUSED, timestamp_t timestamp UNUSED, int tz UNUSED,