On Tue, Dec 11, 2007 at 07:12:54PM -0800, Junio C Hamano wrote: > * HEAD discovery > > The code can be lifted from the scripted version and transplanted to > git-remote. And to make "origin" and other remotes added by "git > remote add", this logic needs to be moved to "git remote". A rough first attempt appended. Cleaning up in "remote rm" is a bit of a pain once a remote can contain symbolic-refs. Would it make sense to add something like a "git update-ref -D <refname>" that deletes anything at that path with no checking? Thanks for outlining these remote improvements, by the way, I really look forward to them. I'll do what I can, but will probably be much too slow.... --b. commit fecdb5c0d118767c216302e2c91950cca04f9a26 Author: J. Bruce Fields <bfields@xxxxxxxxxxxxxx> Date: Fri Dec 21 19:55:09 2007 -0500 git-remote: make add -f guess HEAD, as clone does Has a few ugly bits. Signed-off-by: J. Bruce Fields <bfields@xxxxxxxxxxxxxx> diff --git a/git-remote.perl b/git-remote.perl index d13e4c1..3299029 100755 --- a/git-remote.perl +++ b/git-remote.perl @@ -270,12 +270,57 @@ sub show_remote { return 0; } +sub guess_head { + my ($subdir, $head_sha1) = @_; + my $found = 0; + + for ($git->command('for-each-ref', "$subdir")) { + chomp; + m|^([0-9a-f]{40})\s[a-z]+\s$subdir/(.*)$| || die(); + my ($sha1, $ref) = ($1, $2); + + if ($sha1 eq $head_sha1) { + $found = $ref; + # prefer "master" if it matches: + if ($ref eq "master") { + last; + } + } + } + return $found +} + +sub fix_head { + my ($remote) = @_; + + my $subdir = "refs/remotes/$remote"; + my $head_sha1 = $git->command(qw(rev-parse --verify), "$subdir/HEAD"); + chomp($head_sha1); + + unlink($git->repo_path."/$subdir/HEAD"); + my $found = guess_head($subdir, $head_sha1); + if (!$found) { + # Just leave it as a a bare sha1 + $git->command("update-ref", "$subdir/HEAD", "$head_sha1"); + return; + } + $git->command("symbolic-ref", "$subdir/HEAD", "$subdir/$found"); + $git->command("config", "branch.$found.remote", "$remote"); + $git->command("config", "branch.$found.merge", "refs/heads/$found"); +} + sub add_remote { my ($name, $url, $opts) = @_; if (exists $remote->{$name}) { print STDERR "remote $name already exists.\n"; exit(1); } + + # Tricky!: magic HEAD setup should only be done when + # "mirror", "master", and "track" options aren't given. + # And for orthagonality perhaps we should also provide a + # "track head" optio., compatible with "track" but not + # the other two.... $git->command('config', "remote.$name.url", $url); my $track = $opts->{'track'} || ["*"]; @@ -286,7 +331,17 @@ sub add_remote { "+refs/heads/$_:refs/remotes/$name/$_"); } if ($opts->{'fetch'}) { - $git->command('fetch', $name); + if (!$opts->{'mirror'} && !$opts->{'master'} + && !$opts->{'track'}) { + my $refspec = "+refs/heads/*:refs/remotes/$name/*"; + + # XXX: can there be a remote refs/heads/HEAD?? + $git->command('fetch', $name, $refspec, + "HEAD:refs/remotes/$name/HEAD"); + fix_head($name); + } else { + $git->command('fetch', $name); + } } if (exists $opts->{'master'}) { $git->command('symbolic-ref', "refs/remotes/$name/HEAD", @@ -338,11 +393,11 @@ sub rm_remote { } }; - my @refs = $git->command('for-each-ref', - '--format=%(refname) %(objectname)', "refs/remotes/$name"); - for (@refs) { - ($ref, $object) = split; - $git->command(qw(update-ref -d), $ref, $object); + # Ugh: update-ref doesn't work on symref (as "HEAD" may be), + # but the following won't work on packed refs, for example. + for ($git->command('for-each-ref', + '--format=%(refname)', "refs/remotes/$name")) { + unlink($git->repo_path."/$_"); } return 0; } diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 636aec2..5576f2a 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -69,7 +69,7 @@ test_expect_success 'add another remote' ' tokens_match "origin second" "$(git remote)" && check_remote_track origin master side && check_remote_track second master side another && - check_tracking_branch second master side another && + check_tracking_branch second HEAD master side another && git for-each-ref "--format=%(refname)" refs/remotes | sed -e "/^refs\/remotes\/origin\//d" \ -e "/^refs\/remotes\/second\//d" >actual && - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html