From 28b8e61fc63b6776a91e8afd03c7171fbf0779b0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 22 Nov 2006 21:57:14 -0800 Subject: [PATCH 1/5] git-fetch: reuse ls-remote result. This will become necessary to update the dumb protocol transports to fetch from a repository with packed and then pruned tags. Signed-off-by: Junio C Hamano --- git-fetch.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/git-fetch.sh b/git-fetch.sh index eb32476bbdc..170c2cb0480 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -88,6 +88,10 @@ then : >"$GIT_DIR/FETCH_HEAD" fi +# Global that is reused later +ls_remote_result=$(git ls-remote $upload_pack "$remote") || + die "Cannot find the reflist at $remote" + append_fetch_head () { head_="$1" remote_="$2" @@ -233,10 +237,7 @@ reflist=$(get_remote_refs_for_fetch "$@") if test "$tags" then taglist=`IFS=" " && - ( - git-ls-remote $upload_pack --tags "$remote" || - echo fail ouch - ) | + echo "$ls_remote_result" | while read sha1 name do case "$sha1" in @@ -245,6 +246,8 @@ then esac case "$name" in *^*) continue ;; + refs/tags/*) ;; + *) continue ;; esac if git-check-ref-format "$name" then @@ -431,7 +434,7 @@ case "$no_tags$tags" in # effective only when we are following remote branch # using local tracking branch. taglist=$(IFS=" " && - git-ls-remote $upload_pack --tags "$remote" | + echo "$ls_remote_result" | sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \ -e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' | while read sha1 name From 2986c02217f98809d8990e7679edf0f5d99f904d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 22 Nov 2006 22:24:09 -0800 Subject: [PATCH 2/5] git-fetch: fix dumb protocol transport to fetch from pack-pruned ref Earlier, commit walkers downloaded loose refs from refs/ hierarchy of the remote side to find where to start walking; this would not work for a repository whose refs are packed and then pruned. With the previous change, we have ls-remote output from the remote in-core; we can use the value from there without requiring loose refs anymore. Signed-off-by: Junio C Hamano --- git-fetch.sh | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/git-fetch.sh b/git-fetch.sh index 170c2cb0480..06b66b968d6 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -307,22 +307,20 @@ fetch_main () { "`git-repo-config --bool http.noEPSV`" = true ]; then noepsv_opt="--disable-epsv" fi - max_depth=5 - depth=0 - head="ref: $remote_name" - while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null - do - remote_name_quoted=$(@@PERL@@ -e ' - my $u = $ARGV[0]; - $u =~ s/^ref:\s*//; - $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg; - print "$u"; - ' "$head") - head=$(curl -nsfL $curl_extra_args $noepsv_opt "$remote/$remote_name_quoted") - depth=$( expr \( $depth + 1 \) ) - done + + # Find $remote_name from ls-remote output. + head=$( + IFS=' ' + echo "$ls_remote_result" | + while read sha1 name + do + test "z$name" = "z$remote_name" || continue + echo "$sha1" + break + done + ) expr "z$head" : "z$_x40\$" >/dev/null || - die "Failed to fetch $remote_name from $remote" + die "No such ref $remote_name at $remote" echo >&2 "Fetching $remote_name from $remote using $proto" git-http-fetch -v -a "$head" "$remote/" || exit ;; From 5677882be721be5e2706a546d90804da8d8d0bd5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 22 Nov 2006 23:15:00 -0800 Subject: [PATCH 3/5] git-fetch: allow glob pattern in refspec This adds Andy's refspec glob. You can have a single line: Pull: refs/heads/*:refs/remotes/origin/* in your ".git/remotes/origin" and say "git fetch" to retrieve all refs under heads/ at the remote side to remotes/origin/ in the local repository. Signed-off-by: Junio C Hamano --- git-parse-remote.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/git-parse-remote.sh b/git-parse-remote.sh index c325ef761e4..e281b7c6ebd 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -90,6 +90,39 @@ get_remote_default_refs_for_push () { esac } +# Called from canon_refs_list_for_fetch -d "$remote", which +# is called from get_remote_default_refs_for_fetch to grok +# refspecs that are retrieved from the configuration, but not +# from get_remote_refs_for_fetch when it deals with refspecs +# supplied on the command line. $ls_remote_result has the list +# of refs available at remote. +expand_refs_wildcard () { + for ref + do + # a non glob pattern is given back as-is. + expr "z$ref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || { + echo "$ref" + continue + } + from=`expr "z$ref" : 'z\(refs/.*/\)\*:refs/.*/\*$'` + to=`expr "z$ref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'` + echo "$ls_remote_result" | + ( + IFS=' ' + while read sha1 name + do + mapped=${name#"$from"} + if test "z$name" != "z${name#'^{}'}" || + test "z$name" = "z$mapped" + then + continue + fi + echo "${name}:${to}${mapped}" + done + ) + done +} + # Subroutine to canonicalize remote:local notation. canon_refs_list_for_fetch () { # If called from get_remote_default_refs_for_fetch @@ -107,6 +140,8 @@ canon_refs_list_for_fetch () { merge_branches=$(git-repo-config \ --get-all "branch.${curr_branch}.merge") fi + set x $(expand_refs_wildcard "$@") + shift fi for ref do From d945d4be20d577868646f1b676b605cd9fdadf86 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 25 Nov 2006 01:10:10 -0800 Subject: [PATCH 4/5] git-fetch: allow forcing glob pattern in refspec Building on top of the earlier refspec glob pattern enhancement, this allows a glob pattern to say the updates should be forced by prefixing it with '+' as usual, like this: Pull: +refs/heads/*:refs/remotes/origin/* Signed-off-by: Junio C Hamano --- git-parse-remote.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-parse-remote.sh b/git-parse-remote.sh index e281b7c6ebd..19bc3857d17 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -99,13 +99,17 @@ get_remote_default_refs_for_push () { expand_refs_wildcard () { for ref do + lref=${ref#'+'} # a non glob pattern is given back as-is. - expr "z$ref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || { + expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || { echo "$ref" continue } - from=`expr "z$ref" : 'z\(refs/.*/\)\*:refs/.*/\*$'` - to=`expr "z$ref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'` + + from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'` + to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'` + local_force= + test "z$lref" = "z$ref" || local_force='+' echo "$ls_remote_result" | ( IFS=' ' @@ -117,7 +121,7 @@ expand_refs_wildcard () { then continue fi - echo "${name}:${to}${mapped}" + echo "${local_force}${name}:${to}${mapped}" done ) done From 310b86d48091ebb6a71782678769b2cb8fe2ecd5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 25 Nov 2006 01:33:06 -0800 Subject: [PATCH 5/5] fetch-pack: do not barf when duplicate re patterns are given Signed-off-by: Junio C Hamano --- fetch-pack.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/fetch-pack.c b/fetch-pack.c index 0a169dce857..743eab7efaa 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -566,6 +566,29 @@ static int fetch_pack(int fd[2], int nr_match, char **match) return 0; } +static int remove_duplicates(int nr_heads, char **heads) +{ + int src, dst; + + for (src = dst = 0; src < nr_heads; src++) { + /* If heads[src] is different from any of + * heads[0..dst], push it in. + */ + int i; + for (i = 0; i < dst; i++) { + if (!strcmp(heads[i], heads[src])) + break; + } + if (i < dst) + continue; + if (src != dst) + heads[dst] = heads[src]; + dst++; + } + heads[dst] = 0; + return dst; +} + int main(int argc, char **argv) { int i, ret, nr_heads; @@ -617,6 +640,8 @@ int main(int argc, char **argv) pid = git_connect(fd, dest, exec); if (pid < 0) return 1; + if (heads && nr_heads) + nr_heads = remove_duplicates(nr_heads, heads); ret = fetch_pack(fd, nr_heads, heads); close(fd[0]); close(fd[1]);