All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Harald Nordgren <haraldnordgren@gmail.com>,
	Harald Nordgren <haraldnordgren@gmail.com>
Subject: [PATCH] remote: add --set-head option to 'git remote add'
Date: Sat, 25 Apr 2026 11:19:38 +0000	[thread overview]
Message-ID: <pull.2283.git.git.1777115978088.gitgitgadget@gmail.com> (raw)

From: Harald Nordgren <haraldnordgren@gmail.com>

Mirror the behavior 'git clone' applies to its first remote: after
fetching, set refs/remotes/<name>/HEAD to the remote's default branch.

Equivalent to running:

    git remote add -f <name> <url>
    git remote set-head <name> -a

The new option implies --fetch.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
    remote: add --set-head option to 'git remote add'
    
    When using GitHub's gh tool to fork a repo, it seems that set-head isn't
    run on the upstream remote. So its default branch is not recorded
    locally, meaning that 'git log fork' will not work.
    
    With git remote add --set-head upstream , the default branch is set in
    the same step and things can work out of the box after a small change on
    'gh' that I will do as a next step.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2283%2FHaraldNordgren%2Fset_head-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2283/HaraldNordgren/set_head-v1
Pull-Request: https://github.com/git/git/pull/2283

 Documentation/git-remote.adoc |  9 ++++++++-
 builtin/remote.c              | 26 ++++++++++++++++++++++++--
 t/t5505-remote.sh             |  8 ++++++++
 3 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-remote.adoc b/Documentation/git-remote.adoc
index eaae30aa88..0ef49c4164 100644
--- a/Documentation/git-remote.adoc
+++ b/Documentation/git-remote.adoc
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [synopsis]
 git remote [-v | --verbose]
-git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=(fetch|push)] <name> <URL>
+git remote add [-t <branch>] [-m <master>] [-f] [--set-head] [--[no-]tags] [--mirror=(fetch|push)] <name> <URL>
 git remote rename [--[no-]progress] <old> <new>
 git remote remove <name>
 git remote set-head <name> (-a | --auto | -d | --delete | <branch>)
@@ -73,6 +73,13 @@ multiple branches without grabbing all branches.
 With `-m <master>` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
 up to point at remote's _<master>_ branch. See also the set-head command.
 +
+With `--set-head` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
+up to point at the remote's default branch, mirroring the behavior of
+`git clone`. This is equivalent to running `git remote set-head <name> -a`
+after the remote is added, and implies `-f` so that the remote's refs are
+available locally. It cannot be combined with `-m <master>` or with a push
+mirror.
++
 When a fetch mirror is created with `--mirror=fetch`, the refs will not
 be stored in the `refs/remotes/` namespace, but rather everything in
 `refs/` on the remote will be directly mirrored into `refs/` in the
diff --git a/builtin/remote.c b/builtin/remote.c
index de989ea3ba..8273b425a5 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -23,7 +23,7 @@
 
 static const char * const builtin_remote_usage[] = {
 	"git remote [-v | --verbose]",
-	N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
+	N_("git remote add [-t <branch>] [-m <master>] [-f] [--set-head] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
 	N_("git remote rename [--[no-]progress] <old> <new>"),
 	N_("git remote remove <name>"),
 	N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
@@ -174,10 +174,21 @@ static int check_remote_collision(struct remote *remote, void *data)
 	return 0;
 }
 
+static int set_head_auto_for_remote(const char *name)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&cmd.args, "remote", "set-head", "--auto", name, NULL);
+	cmd.git_cmd = 1;
+	if (run_command(&cmd))
+		return error(_("Could not set up HEAD for %s"), name);
+	return 0;
+}
+
 static int add(int argc, const char **argv, const char *prefix,
 	       struct repository *repo UNUSED)
 {
-	int fetch = 0, fetch_tags = TAGS_DEFAULT;
+	int fetch = 0, fetch_tags = TAGS_DEFAULT, set_head_auto = 0;
 	unsigned mirror = MIRROR_NONE;
 	struct string_list track = STRING_LIST_INIT_NODUP;
 	const char *master = NULL;
@@ -195,6 +206,8 @@ static int add(int argc, const char **argv, const char *prefix,
 		OPT_STRING_LIST('t', "track", &track, N_("branch"),
 				N_("branch(es) to track")),
 		OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
+		OPT_BOOL(0, "set-head", &set_head_auto,
+			 N_("set refs/remotes/<name>/HEAD according to remote (implies --fetch)")),
 		OPT_CALLBACK_F(0, "mirror", &mirror, "(push|fetch)",
 			N_("set up remote as a mirror to push to or fetch from"),
 			PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt),
@@ -211,6 +224,12 @@ static int add(int argc, const char **argv, const char *prefix,
 		die(_("specifying a master branch makes no sense with --mirror"));
 	if (mirror && !(mirror & MIRROR_FETCH) && track.nr)
 		die(_("specifying branches to track makes sense only with fetch mirrors"));
+	if (set_head_auto && master)
+		die(_("--set-head and --master are mutually exclusive"));
+	if (set_head_auto && mirror && !(mirror & MIRROR_FETCH))
+		die(_("--set-head makes no sense with a push mirror"));
+	if (set_head_auto)
+		fetch = 1;
 
 	name = argv[0];
 	url = argv[1];
@@ -269,6 +288,9 @@ static int add(int argc, const char **argv, const char *prefix,
 			result = error(_("Could not setup master '%s'"), master);
 	}
 
+	if (set_head_auto && set_head_auto_for_remote(name))
+		result = 1;
+
 out:
 	strbuf_release(&buf);
 	strbuf_release(&buf2);
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e592c0bcde..043c86315f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -81,6 +81,14 @@ test_expect_success 'add another remote' '
 	)
 '
 
+test_expect_success 'add remote with --set-head implies --fetch and sets HEAD' '
+	test_when_finished "git -C test remote remove third" &&
+	git -C test remote add --set-head third ../two &&
+	echo refs/remotes/third/main >expect &&
+	git -C test symbolic-ref refs/remotes/third/HEAD >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'setup bare clone for server' '
 	git clone --bare "file://$(pwd)/one" srv.bare &&
 	git -C srv.bare config --local uploadpack.allowfilter 1 &&

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
gitgitgadget

             reply	other threads:[~2026-04-25 11:19 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-25 11:19 Harald Nordgren via GitGitGadget [this message]
2026-04-25 17:20 ` [PATCH] remote: add --set-head option to 'git remote add' Ben Knoble
2026-04-25 18:07   ` gh Harald Nordgren
2026-04-25 21:58 ` [PATCH] remote: add --set-head option to 'git remote add' Junio C Hamano
2026-04-25 22:06   ` Jeff King
2026-04-26  8:21     ` Harald Nordgren
  -- strict thread matches above, loose matches on Subject: below --
2026-04-26  7:07 Wrong subject line Kristoffer Haugsbakk
2026-04-26 15:15 ` [PATCH] remote: add --set-head option to 'git remote add' Harald Nordgren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pull.2283.git.git.1777115978088.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=haraldnordgren@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.