Message ID | 432bc7cb3a42cf39d0033701c2cc677c9109b3dd.1666988096.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | clone, submodule update: check out submodule branches | expand |
"Glen Choo via GitGitGadget" <gitgitgadget@gmail.com> writes: > From: Glen Choo <chooglen@google.com> > > Teach "git clone" the "--detach" option, which leaves the cloned repo in > detached HEAD (like "git checkout --detach"). In addition, if the clone > is not bare, do not create the local branch pointed to by the remote's > HEAD symref (bare clones always copy all remote branches directly to > local branches, so the branch is still created in the bare case). > > This is especially useful in the "submodule.propagateBranches" workflow, > where local submodule branches are named after the superproject's > branches, so it makes no sense to create a local branch named after the > submodule's remote's branch. Wouldn't it the same thing to do "git clone -n && git checkout --detach"? If this is a pure implementation detail of another command and will never be used directly by end users, I am not sure if we should add a new option to do this. Especially because it is probably not hard to perform internally an equivalent of "checkout --detach" without forking these days, judging from the fact that merges and rebases need to do so.
Junio C Hamano <gitster@pobox.com> writes: > Wouldn't it the same thing to do "git clone -n && git checkout > --detach"? Not exactly. It still creates the initial branch and points HEAD at it. It is so close, which is a bit disappointing, though.
Junio C Hamano <gitster@pobox.com> writes: > Junio C Hamano <gitster@pobox.com> writes: > >> Wouldn't it the same thing to do "git clone -n && git checkout >> --detach"? > > Not exactly. It still creates the initial branch and points HEAD at > it. It is so close, which is a bit disappointing, though. Yes. I was quite hopeful that "git clone -n" would just do the right thing too :/ I'm guessing that changing the behavior of "git clone -n" is a non-option, since there may be users relying on it. So a better way forward is to add the new flag, which I imagine might be useful to certain end users.
On Fri, Oct 28, 2022 at 03:55:25PM -0700, Glen Choo wrote: > So a better way forward is to add the new flag, which I imagine might > be useful to certain end users. Disappointing, though I understand why such a new flag was needed. Do we really care about whether or not the branch exists so long as we are detached from it, though? Thanks, Taylor
Taylor Blau <me@ttaylorr.com> writes: > On Fri, Oct 28, 2022 at 03:55:25PM -0700, Glen Choo wrote: >> So a better way forward is to add the new flag, which I imagine might >> be useful to certain end users. > > Disappointing, though I understand why such a new flag was needed. Do we > really care about whether or not the branch exists so long as we are > detached from it, though? Yes. - With submodule branching, the "main" branch should correspond to the gitlink of the superproject's "main" branch. So when we clone, we can't _already_ have a "main" branch coming from the submodule's remote. - Without submodule branching, submodules are always in detached HEAD (e.g. when updating the worktree recursively) and no submodule recursing functions create branches, _except_ "git clone --recurse-submodules" (which as we've seen, may create the branch corresponding to the submodule's remote). This just looks like an oversight IMO, which is why I noted that even without branching, "git clone --recurse-submodules" should probably also use "--detach" [1]. - Outside of submodules, I can imagine there's at least one person who's performed a clone and then "git branch -D master" (maybe followed by "git checkout -b main"), and "git clone --detach" lets them skip the branch deletion. [1] https://lore.kernel.org/git/5a24d7e9255de407e343ce8bd60edb63293505bb.1666988096.git.gitgitgadget@gmail.com > > Thanks, > Taylor
Hi Glen, Le 2022-10-28 à 16:14, Glen Choo via GitGitGadget a écrit : > From: Glen Choo <chooglen@google.com> > > Teach "git clone" the "--detach" option, which leaves the cloned repo in > detached HEAD (like "git checkout --detach"). In addition, if the clone > is not bare, do not create the local branch pointed to by the remote's > HEAD symref (bare clones always copy all remote branches directly to > local branches, so the branch is still created in the bare case). > > This is especially useful in the "submodule.propagateBranches" workflow, > where local submodule branches are named after the superproject's > branches, so it makes no sense to create a local branch named after the > submodule's remote's branch. > > Signed-off-by: Glen Choo <chooglen@google.com> > --- > Documentation/git-clone.txt | 8 +++++++- > builtin/clone.c | 12 +++++++++--- > t/t5601-clone.sh | 22 ++++++++++++++++++++++ > 3 files changed, 38 insertions(+), 4 deletions(-) > > diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt > index d6434d262d6..6a4e5d31b46 100644 > --- a/Documentation/git-clone.txt > +++ b/Documentation/git-clone.txt > @@ -16,7 +16,7 @@ SYNOPSIS > [--depth <depth>] [--[no-]single-branch] [--no-tags] > [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] > [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] > - [--filter=<filter> [--also-filter-submodules]] [--] <repository> > + [--filter=<filter> [--also-filter-submodules] [--detach]] [--] <repository> > [<directory>] > > DESCRIPTION > @@ -210,6 +210,12 @@ objects from the source repository into a pack in the cloned repository. > `--branch` can also take tags and detaches the HEAD at that commit > in the resulting repository. > > +--detach:: > + If the cloned repository's HEAD points to a branch, point the newly > + created HEAD to the branch's commit instead of the branch itself. > + Additionally, in a non-bare repository, the corresponding local branch > + will not be created. > + "point the newly created HEAD to the branch's tip commit" would be slightly clearer, I think.
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index d6434d262d6..6a4e5d31b46 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -16,7 +16,7 @@ SYNOPSIS [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] - [--filter=<filter> [--also-filter-submodules]] [--] <repository> + [--filter=<filter> [--also-filter-submodules] [--detach]] [--] <repository> [<directory>] DESCRIPTION @@ -210,6 +210,12 @@ objects from the source repository into a pack in the cloned repository. `--branch` can also take tags and detaches the HEAD at that commit in the resulting repository. +--detach:: + If the cloned repository's HEAD points to a branch, point the newly + created HEAD to the branch's commit instead of the branch itself. + Additionally, in a non-bare repository, the corresponding local branch + will not be created. + -u <upload-pack>:: --upload-pack <upload-pack>:: When given, and the repository to clone from is accessed diff --git a/builtin/clone.c b/builtin/clone.c index 547d6464b3c..e624d3f49a2 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -78,6 +78,7 @@ static int option_filter_submodules = -1; /* unspecified */ static int config_filter_submodules = -1; /* unspecified */ static struct string_list server_options = STRING_LIST_INIT_NODUP; static int option_remote_submodules; +static int option_detach; static const char *bundle_uri; static int recurse_submodules_cb(const struct option *opt, @@ -162,6 +163,8 @@ static struct option builtin_clone_options[] = { N_("any cloned submodules will use their remote-tracking branch")), OPT_BOOL(0, "sparse", &option_sparse_checkout, N_("initialize sparse-checkout file to include only files at root")), + OPT_BOOL(0, "detach", &option_detach, + N_("detach HEAD and don't create a local branch")), OPT_STRING(0, "bundle-uri", &bundle_uri, N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")), OPT_END() @@ -613,10 +616,12 @@ static void update_remote_refs(const struct ref *refs, } static void update_head(const struct ref *our, const struct ref *remote, - const char *unborn, const char *msg) + const char *unborn, int should_detach, + const char *msg) { const char *head; - if (our && skip_prefix(our->name, "refs/heads/", &head)) { + if (our && !should_detach && + skip_prefix(our->name, "refs/heads/", &head)) { /* Local default branch link */ if (create_symref("HEAD", our->name, NULL) < 0) die(_("unable to update HEAD")); @@ -1357,7 +1362,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) branch_top.buf, reflog_msg.buf, transport, !is_local); - update_head(our_head_points_at, remote_head, unborn_head, reflog_msg.buf); + update_head(our_head_points_at, remote_head, unborn_head, + option_detach, reflog_msg.buf); /* * We want to show progress for recursive submodule clones iff diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 45f0803ed4d..418cfd54717 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -333,6 +333,28 @@ test_expect_success 'clone checking out a tag' ' test_cmp fetch.expected fetch.actual ' +test_expect_success '--detach detaches and does not create branch' ' + test_when_finished "rm -fr dst" && + git clone --detach src dst && + ( + cd dst && + test_must_fail git rev-parse main && + test_must_fail git symbolic-ref HEAD && + test_cmp_rev HEAD refs/remotes/origin/HEAD + ) +' + +test_expect_success '--detach with --bare detaches but creates branch' ' + test_when_finished "rm -fr dst" && + git clone --bare --detach src dst && + ( + cd dst && + git rev-parse main && + test_must_fail git symbolic-ref HEAD && + test_cmp_rev HEAD refs/heads/main + ) +' + test_expect_success 'set up ssh wrapper' ' cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \ "$TRASH_DIRECTORY/ssh$X" &&