tags:

views:

144

answers:

4

I have a local repository cloned from a bare remote repository. The following command lists al the remote repository's branches.

$ git ls-remote <remote>

74bd3eb190edb39db04f6c0c4dbbb9e1e96bc6db    refs/remotes/test
85de54d6ae813c624b9623983e6b0a4948dae0fe    refs/remotes/trunk

I want to checkout and track that remote's remote branch trunk. How do I do that?

Note that this is different from checking out a remote repository's local branch. This is how the remote repository looks like.

$ git branch -a

master
remotes/test
remotes/trunk

After running git fetch < remote > to fetch all of the remote repository's branches, I get this output in the local repository.

$ git branch -r

repo/HEAD -> repo/master
repo/master
A: 

git.exe checkout --track -b trunk refs/remotes/trunk

too
The problem here is that the remote branch doesn't have local branches which track its remote branches.
Hans Sjunnesson
That's supposed to spell "the remote repository doesn't have"...
Hans Sjunnesson
+2  A: 

Good question! I know that this works; can't think of anything else that does off the top of my head:

git fetch origin refs/remotes/trunk
git checkout FETCH_HEAD
# or make a branch to check out
git checkout -b remote-trunk FETCH_HEAD

It's odd, by the way, that those remote refs aren't of the form refs/remotes/<remote-name>/<branch-name>... maybe I misunderstood the names, but the method does work.

Jefromi
+2  A: 

You can fetch any ref from any remote (as long as the server is willing to give it to you). The key to fetching refs outside refs/heads/ is to supply full ref paths that start with refs/. If desired, you can even pull from repositories that are not configured as remotes (git fetch can take a URL instead of a remote name).

By default, configured remotes will only fetch from the remote repository’s refs/heads/ namespace, so they will not pick up anything inside refs/remotes/. But, you could refer to a ref inside it by using a complete ref like refs/remotes/trunk (remotes/trunk might also work, but might also be ambiguous).

If the fetched refspec does not specify a destination ref, it will be stored in the special FETCH_HEAD ref.


Fetch a repository’s refs/remote/trunk into FETCH_HEAD and check it out as a detached HEAD:

git fetch remote-name-or-url refs/remotes/trunk &&
git checkout FETCH_HEAD

Same, but create a named, local branch instead of using a detached HEAD:

git fetch remote-name-or-url refs/remotes/trunk &&
git checkout -b trunk-from-remote FETCH_HEAD

Same, but directly into a local branch:

git fetch remote-name-or-url refs/remotes/trunk:trunk-from-remote &&
git checkout trunk-from-remote

If you are working with a configured remote, you can rewrite its remote.<remote-name>.fetch configuration and add an extra entry to automate fetching from both refs/heads/ and refs/remotes/.

# fetch branchs of remote into remote-name/heads/*
git config remote.remote-name.fetch '+refs/heads/*:refs/remotes/remote-name/heads/*' &&
# fetch remotes of remote into remote-name/remotes/*
git config --add remote.remote-name.fetch '+refs/remotes/*:refs/remotes/remote-name/remotes/*'

To avoid possible collisions, the above example configures fetch to store refs into disjoint namespaces (…/heads/ and …/remotes/). You can pick different names if you like. If you are sure there will be no conflicts, you can even stuff them both directly under refs/remotes/remote-name/.

Chris Johnsen
Can I set this up so it automatically pulls the remote's remote branch into a tracking local branch? Or am I better off making sure the remote have local tracking branches of its own, which I then track locally?
Hans Sjunnesson
@Hans: I have rewritten the answer. I de-emphasized the “unconfigured remote” aspect that was probably not so important to you and added a bit at the end about automating the fetch.
Chris Johnsen
How do I set up a local branch to track one of those remote remote branches? I do a proper 'git checkout -b trunk --track repo/remotes/trunk', but then a 'git pull repo' won't understand my branch.trunk.merge config. I have to do a 'git pull repo refs/remotes/trunk:refs/remotes/repo/remotes/trunk' for it to work.
Hans Sjunnesson
That `git pull repo` and `git pull` both work for me in the configuration (Git 1.7.0.4 and 1.7.1+pu). Are you getting an error? What problem are you seeing?What do `git config --get-all remote.repo.fetch` and `git config --get-regexp 'branch\.trunk\.*'` show?Except the line breaks that will be eaten by being in a comment, mine say`+refs/heads/*:refs/remotes/repo/heads/*``+refs/remotes/*:refs/remotes/repo/remotes/*`and`branch.trunk.remote repo``branch.trunk.merge refs/remotes/trunk`respectively.
Chris Johnsen
I got it working. I had set up fetching the heads of the remote wrong, which probably meant git couldn't figure out what refs/remotes/trunk referred to.
Hans Sjunnesson
+1  A: 

Actually, I've found a satisfying solution to this. Adding a remote sets up a refspec to fetch and pull its local heads. I set up another remote which I call /repo-remotes/ which fetch the remote's remote refs. The .git/config file ends up looking like this

[remote "repo"]
  url = ssh://git@<hostname>:<port>/repo
  fetch = +refs/heads/*:refs/remotes/repo/*

[remote "repo-remotes"]
  url = ssh://git@<hostname>:<port>/repo
  fetch = +refs/remotes/*:refs/remotes/repo-remotes/*

I can then do this.

$ git fetch repo-remotes
$ git checkout -b remote-trunk --track remotes/repo-remotes/trunk

Which sets up a local branch tracking the remote repository's remote branch /trunk/.

Hans Sjunnesson
No need for a second remote, just add an extra fetch configuration.
Chris Johnsen