From: Ralf Thielow <ralf.thielow@gmail.com>
To: gitster@pobox.com
Cc: pclouds@gmail.com, git@vger.kernel.org,
Ralf Thielow <ralf.thielow@gmail.com>
Subject: [PATCHv5] clone --single: limit the fetch refspec to fetched branch
Date: Mon, 17 Sep 2012 21:21:46 +0200 [thread overview]
Message-ID: <1347909706-22888-1-git-send-email-ralf.thielow@gmail.com> (raw)
In-Reply-To: <CACsJy8BGBwNp-oDsnB1QObrVLU54rtDmGGBF=Muww8ZJjfZScA@mail.gmail.com>
After running "git clone --single", the resulting repository has the
usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
refspec installed, which means that a subsequent "git fetch" will
end up grabbing all the other branches.
Update the fetch refspec to cover only the singly cloned ref instead
to correct this.
Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
changes in v5:
- extract a function to write refspec config
- handle --mirror option (test added)
- install correct refspec if the value of --branch is a tag (test added)
Thanks to Junio for:
- refactor tests
- add tests for created refs
I'm not happy about using "our_head_points_to" for the remote
part of the refspec. Junio already complaint about that. As far
as I can see it's the only way of getting the information that
it's a tag. Also the condition "is this a tag" might not be the
best way.
builtin/clone.c | 66 +++++++++++++++-----
t/t5709-clone-refspec.sh | 156 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 208 insertions(+), 14 deletions(-)
create mode 100755 t/t5709-clone-refspec.sh
diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..431635c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -610,6 +610,55 @@ static void write_config(struct string_list *config)
}
}
+static void write_refspec_config(const char* src_ref_prefix,
+ const struct ref* our_head_points_at,
+ const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+ struct strbuf key = STRBUF_INIT;
+ struct strbuf value = STRBUF_INIT;
+
+ if (option_mirror || !option_bare) {
+ if (option_single_branch && !option_mirror) {
+ if (option_branch) {
+ if (strstr(our_head_points_at->name, "refs/tags/"))
+ strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+ our_head_points_at->name);
+ else
+ strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+ branch_top->buf, option_branch);
+ } else if (remote_head_points_at) {
+ strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+ branch_top->buf,
+ skip_prefix(remote_head_points_at->name, "refs/heads/"));
+ }
+ /*
+ * otherwise, the next "git fetch" will
+ * simply fetch from HEAD without updating
+ * any remote tracking branch, which is what
+ * we want.
+ */
+ } else {
+ strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+ }
+ /* Configure the remote */
+ if (value.len) {
+ strbuf_reset(&key);
+ strbuf_addf(&key, "remote.%s.fetch", option_origin);
+ git_config_set_multivar(key.buf, value.buf, "^$", 0);
+ strbuf_reset(&key);
+
+ if (option_mirror) {
+ strbuf_addf(&key, "remote.%s.mirror", option_origin);
+ git_config_set(key.buf, "true");
+ strbuf_reset(&key);
+ }
+ }
+ }
+
+ strbuf_release(&key);
+ strbuf_release(&value);
+}
+
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
@@ -755,20 +804,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
- if (option_mirror || !option_bare) {
- /* Configure the remote */
- strbuf_addf(&key, "remote.%s.fetch", option_origin);
- git_config_set_multivar(key.buf, value.buf, "^$", 0);
- strbuf_reset(&key);
-
- if (option_mirror) {
- strbuf_addf(&key, "remote.%s.mirror", option_origin);
- git_config_set(key.buf, "true");
- strbuf_reset(&key);
- }
- }
-
strbuf_addf(&key, "remote.%s.url", option_origin);
git_config_set(key.buf, repo);
strbuf_reset(&key);
@@ -853,6 +888,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
"refs/heads/master");
}
+ write_refspec_config(src_ref_prefix, our_head_points_at,
+ remote_head_points_at, &branch_top);
+
if (is_local)
clone_local(path, git_dir);
else if (refs && complete_refs_before_fetch)
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..af45182
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ # Make two branches, "master" and "side"
+ echo one >file &&
+ git add file &&
+ git commit -m one &&
+ echo two >file &&
+ git commit -a -m two &&
+ git tag two &&
+ echo three >file &&
+ git commit -a -m three &&
+ git checkout -b side &&
+ echo four >file &&
+ git commit -a -m four &&
+ git checkout master &&
+
+ # default clone
+ git clone . dir_all &&
+
+ # default --single that follows HEAD=master
+ git clone --single-branch . dir_master &&
+
+ # default --single that follows HEAD=side
+ git checkout side &&
+ git clone --single-branch . dir_side &&
+
+ # explicit --single that follows side
+ git checkout master &&
+ git clone --single-branch --branch side . dir_side2 &&
+
+ # default --single with --mirror
+ git clone --single-branch --mirror . dir_mirror &&
+
+ # --single that does not know what branch to follow
+ git checkout two^ &&
+ git clone --single-branch . dir_detached &&
+
+ # explicit --single with tag
+ git clone --single-branch --branch two . dir_tag &&
+
+ # advance both "master" and "side" branches
+ git checkout side &&
+ echo five >file &&
+ git commit -a -m five &&
+ git checkout master &&
+ echo six >file &&
+ git commit -a -m six
+'
+
+test_expect_success 'refspec contains all branches by default' '
+ echo "+refs/heads/*:refs/remotes/origin/*" > expect &&
+ git --git-dir=dir_all/.git config --get remote.origin.fetch > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'refspec contains all refs with option --mirror' '
+ echo "+refs/*:refs/*" > expect &&
+ git --git-dir=dir_mirror config --get remote.origin.fetch > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'refspec contains tag ref' '
+ echo "+refs/tags/two:refs/tags/two" > expect &&
+ git --git-dir=dir_tag/.git config --get remote.origin.fetch > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'refspec contains only master with option --single-branch and remotes HEAD point to master' '
+ echo "+refs/heads/master:refs/remotes/origin/master" > expect &&
+ git --git-dir=dir_master/.git config --get remote.origin.fetch > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'refspec contains only foo with option --single-branch and remotes HEAD point to side' '
+ echo "+refs/heads/side:refs/remotes/origin/side" > expect &&
+ git --git-dir=dir_side/.git config --get remote.origin.fetch > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'refspec contains one branch after using option --single-branch with --branch' '
+ echo "+refs/heads/side:refs/remotes/origin/side" > expect &&
+ git --git-dir=dir_side2/.git config --get remote.origin.fetch > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'no refspec is written if remotes HEAD is detached' '
+ > expect &&
+ git --git-dir=dir_detached/.git config --get remote.origin.fetch > actual
+ test_cmp expect actual
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+ (
+ cd dir_all && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # follow both master and side
+ git for-each-ref refs/heads >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+ (
+ cd dir_master && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow master
+ git for-each-ref refs/heads/master >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+ (
+ cd dir_side && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow side
+ git for-each-ref refs/heads/side >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+ (
+ cd dir_side2 && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow side
+ git for-each-ref refs/heads/side >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+ (
+ cd dir_detached && git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ )
+ # nothing
+ >expect &&
+ test_cmp expect actual
+'
+
+test_done
--
1.7.12.397.ge29f79e.dirty
next prev parent reply other threads:[~2012-09-17 19:22 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-09-13 18:38 is this behaviour expected for "git clone --single-branch"? Ralf Thielow
2012-09-13 18:45 ` Junio C Hamano
2012-09-13 18:48 ` Ralf Thielow
2012-09-14 5:09 ` [PATCH] clone: fix refspec on "--single-branch" option Ralf Thielow
2012-09-14 5:35 ` Junio C Hamano
2012-09-14 6:48 ` Junio C Hamano
2012-09-14 13:10 ` Nguyen Thai Ngoc Duy
2012-09-14 14:25 ` Ralf Thielow
2012-09-14 16:02 ` Junio C Hamano
2012-09-14 18:11 ` [PATCHv2] " Ralf Thielow
2012-09-14 19:22 ` Junio C Hamano
2012-09-14 21:13 ` [PATCHv3] " Ralf Thielow
2012-09-14 22:45 ` Junio C Hamano
2012-09-16 8:13 ` [PATCHv4] clone --single: limit the fetch refspec to fetched branch Ralf Thielow
2012-09-17 4:48 ` Junio C Hamano
2012-09-17 12:06 ` Nguyen Thai Ngoc Duy
2012-09-17 12:11 ` Nguyen Thai Ngoc Duy
2012-09-17 19:21 ` Ralf Thielow [this message]
2012-09-17 20:18 ` [PATCHv5] " Junio C Hamano
2012-09-17 21:04 ` Ralf Thielow
2012-09-17 21:39 ` Junio C Hamano
2012-09-18 14:08 ` Ralf Thielow
2012-09-18 16:57 ` Junio C Hamano
2012-09-18 19:14 ` [PATCHv6] " Ralf Thielow
2012-09-18 19:42 ` Junio C Hamano
2012-09-18 19:45 ` Junio C Hamano
2012-09-19 16:45 ` [PATCHv7] " Ralf Thielow
2012-09-19 23:26 ` Junio C Hamano
2012-09-20 18:04 ` [PATCHv8] " Ralf Thielow
2012-09-20 21:17 ` Junio C Hamano
2012-09-19 7:36 ` [PATCHv6] " Nguyen Thai Ngoc Duy
2012-09-19 8:24 ` Ralf Thielow
2012-09-17 20:09 ` [PATCHv4] " Junio C Hamano
2012-09-18 1:04 ` Nguyen Thai Ngoc Duy
2012-09-18 3:56 ` Junio C Hamano
2012-09-17 13:25 ` Ralf Thielow
2012-09-17 20:08 ` Junio C Hamano
2012-09-18 1:02 ` Nguyen Thai Ngoc Duy
2012-09-14 18:42 ` [PATCH] clone: fix refspec on "--single-branch" option Junio C Hamano
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=1347909706-22888-1-git-send-email-ralf.thielow@gmail.com \
--to=ralf.thielow@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=pclouds@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.