[PATCH v13 9/9] fetch set_head: handle mirrored bare repositories

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When adding a remote to bare repository with "git remote add --mirror",
running fetch will fail to update HEAD to the remote's HEAD, since it
does not know how to handle bare repositories. On the other hand HEAD
already has content, since "git init --bare" has already set HEAD to
whatever is the default branch set for the user. Unless this - by chance
- is the same as the remote's HEAD, HEAD will be pointing to a bad
symref. Teach set_head to handle bare repositories, by overwriting HEAD
so it mirrors the remote's HEAD.

Note, that in this case overriding the local HEAD reference is
necessary, since HEAD will exist before fetch can be run, but this
should not be an issue, since the whole purpose of --mirror is to be an
exact mirror of the remote, so following any changes to HEAD makes
sense.

Also note, that although "git remote set-head" also fails when trying to
update the remote's locally tracked HEAD in a mirrored bare repository,
the usage of the command does not make much sense after this patch:
fetch will update the remote HEAD correctly, and setting it manually to
something else is antithetical to the concept of mirroring.

Signed-off-by: Bence Ferdinandy <bence@xxxxxxxxxxxxxx>
---

Notes:
    v10: - new patch
         - handles the issue discovered in
           https://lore.kernel.org/git/D4ZAELFWJMKN.S88LJ6YK31LZ@xxxxxxxxxxxxxx/T/
    
    v11: no change
    
    v12: no change
    
    v13: properly print the previous head if it was detached

 builtin/fetch.c   | 16 +++++++++++-----
 t/t5505-remote.sh | 10 ++++++++++
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 3d70cd1add..5e37b9c00f 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1608,7 +1608,7 @@ static const char *strip_refshead(const char *name){
 
 static int set_head(const struct ref *remote_refs)
 {
-	int result = 0, updateres;
+	int result = 0, updateres, is_bare;
 	struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
 		b_local_head = STRBUF_INIT;
 	const char *remote = gtransport->remote->name;
@@ -1641,15 +1641,21 @@ static int set_head(const struct ref *remote_refs)
 
 	if (!head_name)
 		goto cleanup;
-	strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote);
-	strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name);
+	is_bare = is_bare_repository();
+	if (is_bare) {
+		strbuf_addstr(&b_head, "HEAD");
+		strbuf_addf(&b_remote_head, "refs/heads/%s", head_name);
+	} else {
+		strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote);
+		strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name);
+	}
 		/* make sure it's valid */
-	if (!refs_ref_exists(refs, b_remote_head.buf)) {
+	if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) {
 		result = 1;
 		goto cleanup;
 	}
 	updateres = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
-					"fetch", &b_local_head, 1);
+					"fetch", &b_local_head, !is_bare);
 	if (updateres == -1) {
 		result = 1;
 		goto cleanup;
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 660310239c..4cc5df2e61 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -557,6 +557,16 @@ test_expect_success 'add --mirror && prune' '
 	)
 '
 
+test_expect_success 'add --mirror setting HEAD' '
+	mkdir headmirror &&
+	(
+		cd headmirror &&
+		git init --bare -b notmain &&
+		git remote add --mirror -f origin ../one &&
+		test "$(git symbolic-ref HEAD)" = "refs/heads/main"
+	)
+'
+
 test_expect_success 'add --mirror=fetch' '
 	mkdir mirror-fetch &&
 	git init -b main mirror-fetch/parent &&
-- 
2.47.0.296.gda1ecfef29.dirty





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux