From 687b8be8bb75b97e917dc744f91890270913041d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 10 Mar 2006 04:19:07 -0800 Subject: [PATCH 1/9] fetch,parse-remote,fmt-merge-msg: refs/remotes/* support We can now easily fetch and merge things from heads in the refs/remotes/ hierarchy in remote repositories. The refs/remotes/ hierarchy is likely to become the standard for tracking foreign SCMs, as well as the location of Pull: targets for tracking remote branches in newly cloned repositories. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-fetch.sh | 10 ++++++++-- git-fmt-merge-msg.perl | 8 ++++++++ git-parse-remote.sh | 8 ++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/git-fetch.sh b/git-fetch.sh index 0346d4a45c..c0eb96752e 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -94,6 +94,9 @@ append_fetch_head () { # remote-nick is the URL given on the command line (or a shorthand) # remote-name is the $GIT_DIR relative refs/ path we computed # for this refspec. + + # the $note_ variable will be fed to git-fmt-merge-msg for further + # processing. case "$remote_name_" in HEAD) note_= ;; @@ -103,6 +106,9 @@ append_fetch_head () { refs/tags/*) note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')" note_="tag '$note_' of " ;; + refs/remotes/*) + note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')" + note_="remote branch '$note_' of " ;; *) note_="$remote_name of " ;; esac @@ -147,10 +153,10 @@ fast_forward_local () { else echo >&2 "* $1: storing $3" fi - git-update-ref "$1" "$2" + git-update-ref "$1" "$2" ;; - refs/heads/*) + refs/heads/* | refs/remotes/*) # $1 is the ref being updated. # $2 is the new value for the ref. local=$(git-rev-parse --verify "$1^0" 2>/dev/null) diff --git a/git-fmt-merge-msg.perl b/git-fmt-merge-msg.perl index afe80e6321..5986e5414a 100755 --- a/git-fmt-merge-msg.perl +++ b/git-fmt-merge-msg.perl @@ -75,6 +75,7 @@ while (<>) { $src{$src} = { BRANCH => [], TAG => [], + R_BRANCH => [], GENERIC => [], # &1 == has HEAD. # &2 == has others. @@ -91,6 +92,11 @@ while (<>) { push @{$src{$src}{TAG}}, $1; $src{$src}{HEAD_STATUS} |= 2; } + elsif (/^remote branch (.*)$/) { + $origin = $1; + push @{$src{$src}{R_BRANCH}}, $1; + $src{$src}{HEAD_STATUS} |= 2; + } elsif (/^HEAD$/) { $origin = $src; $src{$src}{HEAD_STATUS} |= 1; @@ -123,6 +129,8 @@ for my $src (@src) { } push @this, andjoin("branch ", "branches ", $src{$src}{BRANCH}); + push @this, andjoin("remote branch ", "remote branches ", + $src{$src}{R_BRANCH}); push @this, andjoin("tag ", "tags ", $src{$src}{TAG}); push @this, andjoin("commit ", "commits ", diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 5f158c613f..63f22818e6 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -86,14 +86,14 @@ canon_refs_list_for_fetch () { local=$(expr "$ref" : '[^:]*:\(.*\)') case "$remote" in '') remote=HEAD ;; - refs/heads/* | refs/tags/*) ;; - heads/* | tags/* ) remote="refs/$remote" ;; + refs/heads/* | refs/tags/* | refs/remotes/*) ;; + heads/* | tags/* | remotes/* ) remote="refs/$remote" ;; *) remote="refs/heads/$remote" ;; esac case "$local" in '') local= ;; - refs/heads/* | refs/tags/*) ;; - heads/* | tags/* ) local="refs/$local" ;; + refs/heads/* | refs/tags/* | refs/remotes/*) ;; + heads/* | tags/* | remotes/* ) local="refs/$local" ;; *) local="refs/heads/$local" ;; esac From dfeff66ed9a3931d60f3cd600ad8c14b5cc3d9e5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 20 Mar 2006 00:21:10 -0800 Subject: [PATCH 2/9] revamp git-clone. This does two things. * A new flag --reference can be used to name a local repository that is to be used as an alternate. This is in response to an inquiry by James Cloos in the message on the list . * A new flag --use-separate-remote stops contaminating local branch namespace by upstream branch names. The upstream branch heads are copied in .git/refs/remotes/ instead of .git/refs/heads/ and .git/remotes/origin file is set up to reflect this as well. It requires to have fetch/pull update to understand .git/refs/remotes by Eric Wong to further update the repository cloned this way. For the former change, git-fetch-pack is taught a new flag --all to fetch from all the remote heads. Nobody uses the git-clone-pack with this change, so we could deprecate the command, but removal of the command will be left to a separate round. Signed-off-by: Junio C Hamano --- fetch-pack.c | 18 +++-- git-clone.sh | 184 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 166 insertions(+), 36 deletions(-) diff --git a/fetch-pack.c b/fetch-pack.c index 535de10660..a3bcad016f 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -7,8 +7,9 @@ static int keep_pack; static int quiet; static int verbose; +static int fetch_all; static const char fetch_pack_usage[] = -"git-fetch-pack [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory ..."; +"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory ..."; static const char *exec = "git-upload-pack"; #define COMPLETE (1U << 0) @@ -266,8 +267,9 @@ static void filter_refs(struct ref **refs, int nr_match, char **match) for (prev = NULL, current = *refs; current; current = next) { next = current->next; if ((!memcmp(current->name, "refs/", 5) && - check_ref_format(current->name + 5)) || - !path_match(current->name, nr_match, match)) { + check_ref_format(current->name + 5)) || + (!fetch_all && + !path_match(current->name, nr_match, match))) { if (prev == NULL) *refs = next; else @@ -376,7 +378,11 @@ static int fetch_pack(int fd[2], int nr_match, char **match) goto all_done; } if (find_common(fd, sha1, ref) < 0) - fprintf(stderr, "warning: no common commits\n"); + if (!keep_pack) + /* When cloning, it is not unusual to have + * no common commit. + */ + fprintf(stderr, "warning: no common commits\n"); if (keep_pack) status = receive_keep_pack(fd, "git-fetch-pack", quiet); @@ -426,6 +432,10 @@ int main(int argc, char **argv) use_thin_pack = 1; continue; } + if (!strcmp("--all", arg)) { + fetch_all = 1; + continue; + } if (!strcmp("-v", arg)) { verbose = 1; continue; diff --git a/git-clone.sh b/git-clone.sh index 4ed861d576..9db678beef 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -9,7 +9,7 @@ unset CDPATH usage() { - echo >&2 "Usage: $0 [--bare] [-l [-s]] [-q] [-u ] [-o ] [-n] []" + echo >&2 "Usage: $0 [--reference ] [--bare] [-l [-s]] [-q] [-u ] [-o ] [-n] []" exit 1 } @@ -40,22 +40,72 @@ Perhaps git-update-server-info needs to be run there?" do name=`expr "$refname" : 'refs/\(.*\)'` && case "$name" in - *^*) ;; - *) - git-http-fetch -v -a -w "$name" "$name" "$1/" || exit 1 + *^*) continue;; esac + if test -n "$use_separate_remote" && + branch_name=`expr "$name" : 'heads/\(.*\)'` + then + tname="remotes/$branch_name" + else + tname=$name + fi + git-http-fetch -v -a -w "$tname" "$name" "$1/" || exit 1 done <"$clone_tmp/refs" rm -fr "$clone_tmp" + http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" } +# Read git-fetch-pack -k output and store the remote branches. +copy_refs=' +use File::Path qw(mkpath); +use File::Basename qw(dirname); +my $git_dir = $ARGV[0]; +my $use_separate_remote = $ARGV[1]; + +my $branch_top = ($use_separate_remote ? "remotes" : "heads"); +my $tag_top = "tags"; + +sub store { + my ($sha1, $name, $top) = @_; + $name = "$git_dir/refs/$top/$name"; + mkpath(dirname($name)); + open O, ">", "$name"; + print O "$sha1\n"; + close O; +} + +open FH, "<", "$git_dir/CLONE_HEAD"; +while () { + my ($sha1, $name) = /^([0-9a-f]{40})\s(.*)$/; + next if ($name =~ /\^\173/); + if ($name eq "HEAD") { + open O, ">", "$git_dir/REMOTE_HEAD"; + print O "$sha1\n"; + close O; + next; + } + if ($name =~ s/^refs\/heads\///) { + store($sha1, $name, $branch_top); + next; + } + if ($name =~ s/^refs\/tags\///) { + store($sha1, $name, $tag_top); + next; + } +} +close FH; +' + quiet= use_local=no local_shared=no no_checkout= upload_pack= bare= -origin=origin +reference= +origin= origin_override= +use_separate_remote= while case "$#,$1" in 0,*) break ;; @@ -68,7 +118,14 @@ while *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) local_shared=yes; use_local=yes ;; *,-q|*,--quiet) quiet=-q ;; + *,--use-separate-remote) + use_separate_remote=t ;; 1,-o) usage;; + 1,--reference) usage ;; + *,--reference) + shift; reference="$1" ;; + *,--reference=*) + reference=`expr "$1" : '--reference=\(.*\)'` ;; *,-o) git-check-ref-format "$2" || { echo >&2 "'$2' is not suitable for a branch name" @@ -100,9 +157,24 @@ then echo >&2 '--bare and -o $origin options are incompatible.' exit 1 fi + if test t = "$use_separate_remote" + then + echo >&2 '--bare and --use-separate-remote options are incompatible.' + exit 1 + fi no_checkout=yes fi +if test -z "$origin_override$origin" +then + if test -n "$use_separate_remote" + then + origin=remotes/master + else + origin=heads/origin + fi +fi + # Turn the source into an absolute path if # it is local repo="$1" @@ -130,6 +202,28 @@ yes) GIT_DIR="$D/.git" ;; esac +if test -n "$reference" +then + if test -d "$reference" + then + if test -d "$reference/.git/objects" + then + reference="$reference/.git" + fi + reference=$(cd "$reference" && pwd) + echo "$reference/objects" >"$GIT_DIR/objects/info/alternates" + (cd "$reference" && tar cf - refs) | + (cd "$GIT_DIR/refs" && + mkdir reference-tmp && + cd reference-tmp && + tar xf -) + else + echo >&2 "$reference: not a local directory." && usage + fi +fi + +rm -f "$GIT_DIR/CLONE_HEAD" + # We do local magic only when the user tells us to. case "$local,$use_local" in yes,yes) @@ -165,24 +259,14 @@ yes,yes) } >"$GIT_DIR/objects/info/alternates" ;; esac - - # Make a duplicate of refs and HEAD pointer - HEAD= - if test -f "$repo/HEAD" - then - HEAD=HEAD - fi - (cd "$repo" && tar cf - refs $HEAD) | - (cd "$GIT_DIR" && tar xf -) || exit 1 + git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" ;; *) case "$repo" in rsync://*) rsync $quiet -av --ignore-existing \ - --exclude info "$repo/objects/" "$GIT_DIR/objects/" && - rsync $quiet -av --ignore-existing \ - --exclude info "$repo/refs/" "$GIT_DIR/refs/" || exit - + --exclude info "$repo/objects/" "$GIT_DIR/objects/" || + exit # Look at objects/info/alternates for rsync -- http will # support it natively and git native ones will do it on the # remote end. Not having that file is not a crime. @@ -205,6 +289,7 @@ yes,yes) done rm -f "$GIT_DIR/TMP_ALT" fi + git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" ;; http://*) if test -z "@@NO_CURL@@" @@ -217,37 +302,71 @@ yes,yes) ;; *) cd "$D" && case "$upload_pack" in - '') git-clone-pack $quiet "$repo" ;; - *) git-clone-pack $quiet "$upload_pack" "$repo" ;; - esac || { - echo >&2 "clone-pack from '$repo' failed." + '') git-fetch-pack --all -k $quiet "$repo" ;; + *) git-fetch-pack --all -k $quiet "$upload_pack" "$repo" ;; + esac >"$GIT_DIR/CLONE_HEAD" || { + echo >&2 "fetch-pack from '$repo' failed." exit 1 } ;; esac ;; esac +test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp" + +if test -f "$GIT_DIR/CLONE_HEAD" +then + # Figure out where the remote HEAD points at. + perl -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" +fi cd "$D" || exit -if test -f "$GIT_DIR/HEAD" && test -z "$bare" +if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD" then - head_points_at=`git-symbolic-ref HEAD` + head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"` + # Figure out which remote branch HEAD points at. + case "$use_separate_remote" in + '') remote_top=refs/heads ;; + *) remote_top=refs/remotes ;; + esac + head_points_at=$( + ( + echo "master" + cd "$GIT_DIR/$remote_top" && + find . -type f -print | sed -e 's/^\.\///' + ) | ( + done=f + while read name + do + test t = $done && continue + branch_tip=`cat "$GIT_DIR/$remote_top/$name"` + if test "$head_sha1" = "$branch_tip" + then + echo "$name" + done=t + fi + done + ) + ) case "$head_points_at" in - refs/heads/*) - head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'` + ?*) mkdir -p "$GIT_DIR/remotes" && echo >"$GIT_DIR/remotes/origin" \ "URL: $repo -Pull: $head_points_at:$origin" && - git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) && - (cd "$GIT_DIR" && find "refs/heads" -type f -print) | +Pull: refs/heads/$head_points_at:refs/$origin" && + case "$use_separate_remote" in + t) git-update-ref HEAD "$head_sha1" ;; + *) git-update-ref "refs/$origin" $(git-rev-parse HEAD) + esac && + (cd "$GIT_DIR" && find "$remote_top" -type f -print) | while read ref do - head=`expr "$ref" : 'refs/heads/\(.*\)'` && - test "$head_points_at" = "$head" || + head=`expr "$ref" : 'refs/\(.*\)'` && + name=`expr "$ref" : 'refs/[^\/]*/\(.*\)'` && + test "$head_points_at" = "$name" || test "$origin" = "$head" || - echo "Pull: ${head}:${head}" + echo "Pull: refs/heads/${name}:$remote_top/${name}" done >>"$GIT_DIR/remotes/origin" esac @@ -256,6 +375,7 @@ Pull: $head_points_at:$origin" && git-read-tree -m -u -v HEAD HEAD esac fi +rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD" trap - exit From 2f8acdb38e513e4b983209563faf4c1d38c4013e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 20 Mar 2006 18:45:47 -0800 Subject: [PATCH 3/9] core.warnambiguousrefs: warns when "name" is used and both "name" branch and tag exists. Signed-off-by: Junio C Hamano --- cache.h | 1 + config.c | 5 +++++ environment.c | 1 + sha1_name.c | 23 ++++++++++++++++++++--- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 1f962809b0..255e6b5cc7 100644 --- a/cache.h +++ b/cache.h @@ -165,6 +165,7 @@ extern void rollback_index_file(struct cache_file *); extern int trust_executable_bit; extern int assume_unchanged; extern int only_use_symrefs; +extern int warn_ambiguous_refs; extern int diff_rename_limit_default; extern int shared_repository; extern const char *apply_default_whitespace; diff --git a/config.c b/config.c index 7dbdce1966..95ec34923d 100644 --- a/config.c +++ b/config.c @@ -232,6 +232,11 @@ int git_default_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.warnambiguousrefs")) { + warn_ambiguous_refs = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "user.name")) { strncpy(git_default_name, value, sizeof(git_default_name)); return 0; diff --git a/environment.c b/environment.c index 16c08f0697..5d29b92bd5 100644 --- a/environment.c +++ b/environment.c @@ -14,6 +14,7 @@ char git_default_name[MAX_GITNAME]; int trust_executable_bit = 1; int assume_unchanged = 0; int only_use_symrefs = 0; +int warn_ambiguous_refs = 0; int repository_format_version = 0; char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8"; int shared_repository = 0; diff --git a/sha1_name.c b/sha1_name.c index d67de18ba5..74c479c5e6 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -240,9 +240,13 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) "refs", "refs/tags", "refs/heads", + "refs/remotes", NULL }; const char **p; + const char *warning = "warning: refname '%.*s' is ambiguous.\n"; + char *pathname; + int already_found = 0; if (len == 40 && !get_sha1_hex(str, sha1)) return 0; @@ -252,10 +256,23 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) return -1; for (p = prefix; *p; p++) { - char *pathname = git_path("%s/%.*s", *p, len, str); - if (!read_ref(pathname, sha1)) - return 0; + unsigned char sha1_from_ref[20]; + unsigned char *this_result = + already_found ? sha1_from_ref : sha1; + pathname = git_path("%s/%.*s", *p, len, str); + if (!read_ref(pathname, this_result)) { + if (warn_ambiguous_refs) { + if (already_found && + !memcmp(sha1, sha1_from_ref, 20)) + fprintf(stderr, warning, len, str); + already_found++; + } + else + return 0; + } } + if (already_found) + return 0; return -1; } From 47874d6d9a7f49ade6388df049597f03365961ca Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 21 Mar 2006 00:14:13 -0800 Subject: [PATCH 4/9] revamp git-clone (take #2). This builds on top of the previous one. * --use-separate-remote uses .git/refs/remotes/$origin/ directory to keep track of the upstream branches. * The $origin above defaults to "origin" as usual, but the existing "-o $origin" option can be used to override it. I am not yet convinced if we should make "$origin" the synonym to "refs/remotes/$origin/$name" where $name is the primary branch name of $origin upstream, nor if so how we should decide which upstream branch is the primary one, but that is more or less orthogonal to what the clone does here. Signed-off-by: Junio C Hamano --- git-clone.sh | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 9db678beef..3b5475340d 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -9,7 +9,7 @@ unset CDPATH usage() { - echo >&2 "Usage: $0 [--reference ] [--bare] [-l [-s]] [-q] [-u ] [-o ] [-n] []" + echo >&2 "Usage: $0 [--use-separate-remote] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [-o ] [-n] []" exit 1 } @@ -61,8 +61,9 @@ use File::Path qw(mkpath); use File::Basename qw(dirname); my $git_dir = $ARGV[0]; my $use_separate_remote = $ARGV[1]; +my $origin = $ARGV[2]; -my $branch_top = ($use_separate_remote ? "remotes" : "heads"); +my $branch_top = ($use_separate_remote ? "remotes/$origin" : "heads"); my $tag_top = "tags"; sub store { @@ -127,7 +128,12 @@ while *,--reference=*) reference=`expr "$1" : '--reference=\(.*\)'` ;; *,-o) - git-check-ref-format "$2" || { + case "$2" in + */*) + echo >&2 "'$2' is not suitable for an origin name" + exit 1 + esac + git-check-ref-format "heads/$2" || { echo >&2 "'$2' is not suitable for a branch name" exit 1 } @@ -165,14 +171,9 @@ then no_checkout=yes fi -if test -z "$origin_override$origin" +if test -z "$origin" then - if test -n "$use_separate_remote" - then - origin=remotes/master - else - origin=heads/origin - fi + origin=origin fi # Turn the source into an absolute path if @@ -317,7 +318,7 @@ test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp" if test -f "$GIT_DIR/CLONE_HEAD" then # Figure out where the remote HEAD points at. - perl -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" + perl -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" fi cd "$D" || exit @@ -328,8 +329,18 @@ then # Figure out which remote branch HEAD points at. case "$use_separate_remote" in '') remote_top=refs/heads ;; - *) remote_top=refs/remotes ;; + *) remote_top="refs/remotes/$origin" ;; esac + + # What to use to track the remote primary branch + if test -n "$use_separate_remote" + then + origin_tracking="remotes/$origin/master" + else + origin_tracking="heads/$origin" + fi + + # The name under $remote_top the remote HEAD seems to point at head_points_at=$( ( echo "master" @@ -349,25 +360,26 @@ then done ) ) + + # Write out remotes/$origin file. case "$head_points_at" in ?*) mkdir -p "$GIT_DIR/remotes" && - echo >"$GIT_DIR/remotes/origin" \ + echo >"$GIT_DIR/remotes/$origin" \ "URL: $repo -Pull: refs/heads/$head_points_at:refs/$origin" && +Pull: refs/heads/$head_points_at:refs/$origin_tracking" && case "$use_separate_remote" in t) git-update-ref HEAD "$head_sha1" ;; *) git-update-ref "refs/$origin" $(git-rev-parse HEAD) esac && - (cd "$GIT_DIR" && find "$remote_top" -type f -print) | - while read ref + (cd "$GIT_DIR/$remote_top" && find . -type f -print) | + while read dotslref do - head=`expr "$ref" : 'refs/\(.*\)'` && - name=`expr "$ref" : 'refs/[^\/]*/\(.*\)'` && + name=`expr "$dotslref" : './\(.*\)'` && test "$head_points_at" = "$name" || test "$origin" = "$head" || echo "Pull: refs/heads/${name}:$remote_top/${name}" - done >>"$GIT_DIR/remotes/origin" + done >>"$GIT_DIR/remotes/$origin" esac case "$no_checkout" in From c51d13692d4e451c755dd7da3521c5db395df192 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 21 Mar 2006 01:42:04 -0800 Subject: [PATCH 5/9] get_sha1_basic(): try refs/... and finally refs/remotes/$foo/HEAD This implements the suggestion by Jeff King to use refs/remotes/$foo/HEAD to interpret a shorthand "$foo" to mean the primary branch head of a tracked remote. clone needs to be told about this convention as well. Signed-off-by: Junio C Hamano --- sha1_name.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sha1_name.c b/sha1_name.c index 74c479c5e6..3adaec3167 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -235,18 +235,21 @@ static int ambiguous_path(const char *path, int len) static int get_sha1_basic(const char *str, int len, unsigned char *sha1) { - static const char *prefix[] = { - "", - "refs", - "refs/tags", - "refs/heads", - "refs/remotes", + static const char *fmt[] = { + "/%.*s", + "refs/%.*s", + "refs/tags/%.*s", + "refs/heads/%.*s", + "refs/remotes/%.*s", + "refs/remotes/%.*s/HEAD", NULL }; const char **p; const char *warning = "warning: refname '%.*s' is ambiguous.\n"; char *pathname; int already_found = 0; + unsigned char *this_result; + unsigned char sha1_from_ref[20]; if (len == 40 && !get_sha1_hex(str, sha1)) return 0; @@ -255,11 +258,9 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) if (ambiguous_path(str, len)) return -1; - for (p = prefix; *p; p++) { - unsigned char sha1_from_ref[20]; - unsigned char *this_result = - already_found ? sha1_from_ref : sha1; - pathname = git_path("%s/%.*s", *p, len, str); + for (p = fmt; *p; p++) { + this_result = already_found ? sha1_from_ref : sha1; + pathname = git_path(*p, len, str); if (!read_ref(pathname, this_result)) { if (warn_ambiguous_refs) { if (already_found && From 5ceb05f82edc49ad5e6b0ad98d633c124a567309 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 21 Mar 2006 01:58:26 -0800 Subject: [PATCH 6/9] clone: record the remote primary branch with remotes/$origin/HEAD This matches c51d13692d4e451c755dd7da3521c5db395df192 commit to record the primary branch of the remote with a symbolic ref remotes/$origin/HEAD. The user can later change it to point at different branch to change the meaning of "$origin" shorthand. Signed-off-by: Junio C Hamano --- git-clone.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 3b5475340d..5953e18a5b 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -45,7 +45,7 @@ Perhaps git-update-server-info needs to be run there?" if test -n "$use_separate_remote" && branch_name=`expr "$name" : 'heads/\(.*\)'` then - tname="remotes/$branch_name" + tname="remotes/$origin/$branch_name" else tname=$name fi @@ -370,7 +370,7 @@ then Pull: refs/heads/$head_points_at:refs/$origin_tracking" && case "$use_separate_remote" in t) git-update-ref HEAD "$head_sha1" ;; - *) git-update-ref "refs/$origin" $(git-rev-parse HEAD) + *) git-update-ref "refs/$origin" $(git-rev-parse HEAD) ;; esac && (cd "$GIT_DIR/$remote_top" && find . -type f -print) | while read dotslref @@ -379,7 +379,13 @@ Pull: refs/heads/$head_points_at:refs/$origin_tracking" && test "$head_points_at" = "$name" || test "$origin" = "$head" || echo "Pull: refs/heads/${name}:$remote_top/${name}" - done >>"$GIT_DIR/remotes/$origin" + done >>"$GIT_DIR/remotes/$origin" && + case "$use_separate_remote" in + t) + rm -f "refs/remotes/$origin/HEAD" + git-symbolic-ref "refs/remotes/$origin/HEAD" \ + "refs/remotes/$origin/$head_points_at" + esac esac case "$no_checkout" in From 4c2e98d6ce47aa9fcc1598c68e630f371cd4f8cb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 22 Mar 2006 00:23:16 -0800 Subject: [PATCH 7/9] git-clone: typofix. The traditional one created refs/origin by mistake, not refs/heads/origin. Also it mistakenly failed to prevent $origin from being listed twice in remotes/origin file. Signed-off-by: Junio C Hamano --- git-clone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 5953e18a5b..6887321972 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -370,14 +370,14 @@ then Pull: refs/heads/$head_points_at:refs/$origin_tracking" && case "$use_separate_remote" in t) git-update-ref HEAD "$head_sha1" ;; - *) git-update-ref "refs/$origin" $(git-rev-parse HEAD) ;; + *) git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) ;; esac && (cd "$GIT_DIR/$remote_top" && find . -type f -print) | while read dotslref do name=`expr "$dotslref" : './\(.*\)'` && test "$head_points_at" = "$name" || - test "$origin" = "$head" || + test "$origin" = "$name" || echo "Pull: refs/heads/${name}:$remote_top/${name}" done >>"$GIT_DIR/remotes/$origin" && case "$use_separate_remote" in From 84a9b58c421f9b2d1cc6c195ed441fac48e60392 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 23 Mar 2006 23:41:18 -0800 Subject: [PATCH 8/9] sha1_name: warning ambiguous refs. This makes sure that many commands that take refs on the command line to honor core.warnambiguousrefs configuration. Earlier, the commands affected by this patch did not read the configuration file. Signed-off-by: Junio C Hamano --- blame.c | 1 + cat-file.c | 1 + ls-tree.c | 1 + merge-base.c | 1 + name-rev.c | 1 + read-tree.c | 1 + rev-parse.c | 2 ++ send-pack.c | 2 ++ sha1_name.c | 5 ++--- tar-tree.c | 1 + unpack-file.c | 1 + update-ref.c | 1 + 12 files changed, 15 insertions(+), 3 deletions(-) diff --git a/blame.c b/blame.c index 9c97aeca45..270ca52c3a 100644 --- a/blame.c +++ b/blame.c @@ -752,6 +752,7 @@ int main(int argc, const char **argv) int found_rename; const char* prefix = setup_git_directory(); + git_config(git_default_config); for(i = 1; i < argc; i++) { if(options) { diff --git a/cat-file.c b/cat-file.c index 1a613f3ee5..761111eb0f 100644 --- a/cat-file.c +++ b/cat-file.c @@ -100,6 +100,7 @@ int main(int argc, char **argv) int opt; setup_git_directory(); + git_config(git_default_config); if (argc != 3 || get_sha1(argv[2], sha1)) usage("git-cat-file [-t|-s|-e|-p|] "); diff --git a/ls-tree.c b/ls-tree.c index d005643ee0..58663ff969 100644 --- a/ls-tree.c +++ b/ls-tree.c @@ -87,6 +87,7 @@ int main(int argc, const char **argv) struct tree *tree; prefix = setup_git_directory(); + git_config(git_default_config); if (prefix && *prefix) chomp_prefix = strlen(prefix); while (1 < argc && argv[1][0] == '-') { diff --git a/merge-base.c b/merge-base.c index e73fca7453..07f5ab4d1c 100644 --- a/merge-base.c +++ b/merge-base.c @@ -237,6 +237,7 @@ int main(int argc, char **argv) unsigned char rev1key[20], rev2key[20]; setup_git_directory(); + git_config(git_default_config); while (1 < argc && argv[1][0] == '-') { char *arg = argv[1]; diff --git a/name-rev.c b/name-rev.c index 0c3f547622..bad8a53777 100644 --- a/name-rev.c +++ b/name-rev.c @@ -127,6 +127,7 @@ int main(int argc, char **argv) int as_is = 0, all = 0, transform_stdin = 0; setup_git_directory(); + git_config(git_default_config); if (argc < 2) usage(name_rev_usage); diff --git a/read-tree.c b/read-tree.c index 1c3b09beff..eaff444196 100644 --- a/read-tree.c +++ b/read-tree.c @@ -717,6 +717,7 @@ int main(int argc, char **argv) merge_fn_t fn = NULL; setup_git_directory(); + git_config(git_default_config); newfd = hold_index_file_for_update(&cache_file, get_index_file()); if (newfd < 0) diff --git a/rev-parse.c b/rev-parse.c index f90e999e60..19a5ef7f48 100644 --- a/rev-parse.c +++ b/rev-parse.c @@ -166,6 +166,8 @@ int main(int argc, char **argv) unsigned char sha1[20]; const char *prefix = setup_git_directory(); + git_config(git_default_config); + for (i = 1; i < argc; i++) { struct stat st; char *arg = argv[i]; diff --git a/send-pack.c b/send-pack.c index c8ffc8d537..409f188503 100644 --- a/send-pack.c +++ b/send-pack.c @@ -362,6 +362,8 @@ int main(int argc, char **argv) pid_t pid; setup_git_directory(); + git_config(git_default_config); + argv++; for (i = 1; i < argc; i++, argv++) { char *arg = *argv; diff --git a/sha1_name.c b/sha1_name.c index 3adaec3167..4f92e12a8d 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -236,7 +236,7 @@ static int ambiguous_path(const char *path, int len) static int get_sha1_basic(const char *str, int len, unsigned char *sha1) { static const char *fmt[] = { - "/%.*s", + "%.*s", "refs/%.*s", "refs/tags/%.*s", "refs/heads/%.*s", @@ -263,8 +263,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) pathname = git_path(*p, len, str); if (!read_ref(pathname, this_result)) { if (warn_ambiguous_refs) { - if (already_found && - !memcmp(sha1, sha1_from_ref, 20)) + if (already_found) fprintf(stderr, warning, len, str); already_found++; } diff --git a/tar-tree.c b/tar-tree.c index e478e13e28..92035f51d8 100644 --- a/tar-tree.c +++ b/tar-tree.c @@ -380,6 +380,7 @@ int main(int argc, char **argv) struct tree_desc tree; setup_git_directory(); + git_config(git_default_config); switch (argc) { case 3: diff --git a/unpack-file.c b/unpack-file.c index 07303f8bb3..3accb974dd 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -30,6 +30,7 @@ int main(int argc, char **argv) usage("git-unpack-file "); setup_git_directory(); + git_config(git_default_config); puts(create_temp_file(sha1)); return 0; diff --git a/update-ref.c b/update-ref.c index e6fbddbab6..ba4bf5153e 100644 --- a/update-ref.c +++ b/update-ref.c @@ -25,6 +25,7 @@ int main(int argc, char **argv) int fd, written; setup_git_directory(); + git_config(git_default_config); if (argc < 3 || argc > 4) usage(git_update_ref_usage); From 1b371f567d9b0094918e128262577b76994eef74 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 23 Mar 2006 23:42:40 -0800 Subject: [PATCH 9/9] sha1_name: make core.warnambiguousrefs the default. Signed-off-by: Junio C Hamano --- environment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.c b/environment.c index 5d29b92bd5..6df647862c 100644 --- a/environment.c +++ b/environment.c @@ -14,7 +14,7 @@ char git_default_name[MAX_GITNAME]; int trust_executable_bit = 1; int assume_unchanged = 0; int only_use_symrefs = 0; -int warn_ambiguous_refs = 0; +int warn_ambiguous_refs = 1; int repository_format_version = 0; char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8"; int shared_repository = 0;