write first for-merge ref to FETCH_HEAD first
The FETCH_HEAD refname is supposed to refer to the ref that was fetched and should be merged. However all fetched refs are written to .git/FETCH_HEAD in an arbitrary order, and resolve_ref_unsafe simply takes the first ref as the FETCH_HEAD, which is often the wrong one, when other branches were also fetched. The solution is to write the for-merge ref(s) to FETCH_HEAD first. Then, unless --append is used, the FETCH_HEAD refname behaves as intended. If the user uses --append, they presumably are doing so in order to preserve the old FETCH_HEAD. While we are at it, update an old example in the read-tree documentation that implied that each entry in FETCH_HEAD only has the object name, which is not true for quite a while. [jc: adjusted tests] Signed-off-by: Joey Hess <joey@kitenet.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
ec330158ec
commit
96890f4c42
160
builtin/fetch.c
160
builtin/fetch.c
@ -377,6 +377,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
const char *what, *kind;
|
||||
struct ref *rm;
|
||||
char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
|
||||
int want_merge;
|
||||
|
||||
fp = fopen(filename, "a");
|
||||
if (!fp)
|
||||
@ -393,84 +394,95 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
goto abort;
|
||||
}
|
||||
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
struct ref *ref = NULL;
|
||||
/*
|
||||
* The first pass writes objects to be merged and then the
|
||||
* second pass writes the rest, in order to allow using
|
||||
* FETCH_HEAD as a refname to refer to the ref to be merged.
|
||||
*/
|
||||
for (want_merge = 1; 0 <= want_merge; want_merge--) {
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
struct ref *ref = NULL;
|
||||
|
||||
if (rm->peer_ref) {
|
||||
ref = xcalloc(1, sizeof(*ref) + strlen(rm->peer_ref->name) + 1);
|
||||
strcpy(ref->name, rm->peer_ref->name);
|
||||
hashcpy(ref->old_sha1, rm->peer_ref->old_sha1);
|
||||
hashcpy(ref->new_sha1, rm->old_sha1);
|
||||
ref->force = rm->peer_ref->force;
|
||||
}
|
||||
commit = lookup_commit_reference_gently(rm->old_sha1, 1);
|
||||
if (!commit)
|
||||
rm->merge = 0;
|
||||
|
||||
commit = lookup_commit_reference_gently(rm->old_sha1, 1);
|
||||
if (!commit)
|
||||
rm->merge = 0;
|
||||
if (rm->merge != want_merge)
|
||||
continue;
|
||||
|
||||
if (!strcmp(rm->name, "HEAD")) {
|
||||
kind = "";
|
||||
what = "";
|
||||
}
|
||||
else if (!prefixcmp(rm->name, "refs/heads/")) {
|
||||
kind = "branch";
|
||||
what = rm->name + 11;
|
||||
}
|
||||
else if (!prefixcmp(rm->name, "refs/tags/")) {
|
||||
kind = "tag";
|
||||
what = rm->name + 10;
|
||||
}
|
||||
else if (!prefixcmp(rm->name, "refs/remotes/")) {
|
||||
kind = "remote-tracking branch";
|
||||
what = rm->name + 13;
|
||||
}
|
||||
else {
|
||||
kind = "";
|
||||
what = rm->name;
|
||||
}
|
||||
|
||||
url_len = strlen(url);
|
||||
for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
|
||||
;
|
||||
url_len = i + 1;
|
||||
if (4 < i && !strncmp(".git", url + i - 3, 4))
|
||||
url_len = i - 3;
|
||||
|
||||
strbuf_reset(¬e);
|
||||
if (*what) {
|
||||
if (*kind)
|
||||
strbuf_addf(¬e, "%s ", kind);
|
||||
strbuf_addf(¬e, "'%s' of ", what);
|
||||
}
|
||||
fprintf(fp, "%s\t%s\t%s",
|
||||
sha1_to_hex(rm->old_sha1),
|
||||
rm->merge ? "" : "not-for-merge",
|
||||
note.buf);
|
||||
for (i = 0; i < url_len; ++i)
|
||||
if ('\n' == url[i])
|
||||
fputs("\\n", fp);
|
||||
else
|
||||
fputc(url[i], fp);
|
||||
fputc('\n', fp);
|
||||
|
||||
strbuf_reset(¬e);
|
||||
if (ref) {
|
||||
rc |= update_local_ref(ref, what, ¬e);
|
||||
free(ref);
|
||||
} else
|
||||
strbuf_addf(¬e, "* %-*s %-*s -> FETCH_HEAD",
|
||||
TRANSPORT_SUMMARY_WIDTH,
|
||||
*kind ? kind : "branch",
|
||||
REFCOL_WIDTH,
|
||||
*what ? what : "HEAD");
|
||||
if (note.len) {
|
||||
if (verbosity >= 0 && !shown_url) {
|
||||
fprintf(stderr, _("From %.*s\n"),
|
||||
url_len, url);
|
||||
shown_url = 1;
|
||||
if (rm->peer_ref) {
|
||||
ref = xcalloc(1, sizeof(*ref) + strlen(rm->peer_ref->name) + 1);
|
||||
strcpy(ref->name, rm->peer_ref->name);
|
||||
hashcpy(ref->old_sha1, rm->peer_ref->old_sha1);
|
||||
hashcpy(ref->new_sha1, rm->old_sha1);
|
||||
ref->force = rm->peer_ref->force;
|
||||
}
|
||||
|
||||
|
||||
if (!strcmp(rm->name, "HEAD")) {
|
||||
kind = "";
|
||||
what = "";
|
||||
}
|
||||
else if (!prefixcmp(rm->name, "refs/heads/")) {
|
||||
kind = "branch";
|
||||
what = rm->name + 11;
|
||||
}
|
||||
else if (!prefixcmp(rm->name, "refs/tags/")) {
|
||||
kind = "tag";
|
||||
what = rm->name + 10;
|
||||
}
|
||||
else if (!prefixcmp(rm->name, "refs/remotes/")) {
|
||||
kind = "remote-tracking branch";
|
||||
what = rm->name + 13;
|
||||
}
|
||||
else {
|
||||
kind = "";
|
||||
what = rm->name;
|
||||
}
|
||||
|
||||
url_len = strlen(url);
|
||||
for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
|
||||
;
|
||||
url_len = i + 1;
|
||||
if (4 < i && !strncmp(".git", url + i - 3, 4))
|
||||
url_len = i - 3;
|
||||
|
||||
strbuf_reset(¬e);
|
||||
if (*what) {
|
||||
if (*kind)
|
||||
strbuf_addf(¬e, "%s ", kind);
|
||||
strbuf_addf(¬e, "'%s' of ", what);
|
||||
}
|
||||
fprintf(fp, "%s\t%s\t%s",
|
||||
sha1_to_hex(rm->old_sha1),
|
||||
rm->merge ? "" : "not-for-merge",
|
||||
note.buf);
|
||||
for (i = 0; i < url_len; ++i)
|
||||
if ('\n' == url[i])
|
||||
fputs("\\n", fp);
|
||||
else
|
||||
fputc(url[i], fp);
|
||||
fputc('\n', fp);
|
||||
|
||||
strbuf_reset(¬e);
|
||||
if (ref) {
|
||||
rc |= update_local_ref(ref, what, ¬e);
|
||||
free(ref);
|
||||
} else
|
||||
strbuf_addf(¬e, "* %-*s %-*s -> FETCH_HEAD",
|
||||
TRANSPORT_SUMMARY_WIDTH,
|
||||
*kind ? kind : "branch",
|
||||
REFCOL_WIDTH,
|
||||
*what ? what : "HEAD");
|
||||
if (note.len) {
|
||||
if (verbosity >= 0 && !shown_url) {
|
||||
fprintf(stderr, _("From %.*s\n"),
|
||||
url_len, url);
|
||||
shown_url = 1;
|
||||
}
|
||||
if (verbosity >= 0)
|
||||
fprintf(stderr, " %s\n", note.buf);
|
||||
}
|
||||
if (verbosity >= 0)
|
||||
fprintf(stderr, " %s\n", note.buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user