fetch set_head: fix non-mirror remotes in bare repositories
In b1b713f722 (fetch set_head: handle mirrored bare repositories, 2024-11-22) it was implicitly assumed that all remotes will be mirrors in a bare repository, thus fetching a non-mirrored remote could lead to HEAD pointing to a non-existent reference. Make sure we only overwrite HEAD if we are in a bare repository and fetching from a mirror. Otherwise, proceed as normally, and create refs/remotes/<nonmirrorremote>/HEAD instead. Reported-by: Christian Hesse <list@eworm.de> Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Bence Ferdinandy committed
Jan 26, 2025 at 23:02 UTC
93dc16483a312b77c0b6533a6c2705d1df3e3687
3 files changed
+32
-5
builtin/fetch.c
+5
-5
@@ -1619,7 +1619,7 @@ static void report_set_head(const char *remote, const char *head_name,
1619
1620
static int set_head(const struct ref *remote_refs, struct remote *remote)
1621
{
1622
- int result = 0, create_only, is_bare, was_detached;
1622
+ int result = 0, create_only, baremirror, was_detached;
1623
struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
1624
b_local_head = STRBUF_INIT;
1625
int follow_remote_head = remote->follow_remote_head;
@@ -1655,9 +1655,9 @@ static int set_head(const struct ref *remote_refs, struct remote *remote)
1655
1656
if (!head_name)
1657
goto cleanup;
1658
- is_bare = is_bare_repository();
1659
- create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !is_bare;
1660
- if (is_bare) {
1658
+ baremirror = is_bare_repository() && remote->mirror;
1659
+ create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !baremirror;
1660
+ if (baremirror) {
1661
strbuf_addstr(&b_head, "HEAD");
1662
strbuf_addf(&b_remote_head, "refs/heads/%s", head_name);
1663
} else {
@@ -1665,7 +1665,7 @@ static int set_head(const struct ref *remote_refs, struct remote *remote)
1665
strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote->name, head_name);
1666
}
1667
/* make sure it's valid */
1668
- if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) {
1668
+ if (!baremirror && !refs_ref_exists(refs, b_remote_head.buf)) {
1669
result = 1;
1670
goto cleanup;
1671
}
t/t5505-remote.sh
+10
@@ -589,6 +589,16 @@ test_expect_success 'add --mirror setting HEAD' '
589
)
590
'
591
592
+test_expect_success 'non-mirror fetch does not interfere with mirror' '
593
+ test_when_finished rm -rf headnotmain &&
594
+ (
595
+ git init --bare -b notmain headnotmain &&
596
+ cd headnotmain &&
597
+ git remote add -f other ../two &&
598
+ test "$(git symbolic-ref HEAD)" = "refs/heads/notmain"
599
+ )
600
+'
601
+
602
test_expect_success 'add --mirror=fetch' '
603
mkdir mirror-fetch &&
604
git init -b main mirror-fetch/parent &&
t/t5510-fetch.sh
+17
@@ -84,6 +84,23 @@ test_expect_success "fetch test remote HEAD" '
84
branch=$(git rev-parse refs/remotes/origin/main) &&
85
test "z$head" = "z$branch"'
86
87
+test_expect_success "fetch test remote HEAD in bare repository" '
88
+ test_when_finished rm -rf barerepo &&
89
+ (
90
+ cd "$D" &&
91
+ git init --bare barerepo &&
92
+ cd barerepo &&
93
+ git remote add upstream ../two &&
94
+ git fetch upstream &&
95
+ git rev-parse --verify refs/remotes/upstream/HEAD &&
96
+ git rev-parse --verify refs/remotes/upstream/main &&
97
+ head=$(git rev-parse refs/remotes/upstream/HEAD) &&
98
+ branch=$(git rev-parse refs/remotes/upstream/main) &&
99
+ test "z$head" = "z$branch"
100
+ )
101
+'
102
+
103
+
104
test_expect_success "fetch test remote HEAD change" '
105
cd "$D" &&
106
cd two &&