"fetch --all" in a git bare repository doesn't synchronize local branches to the remote ones

gburri picture gburri · Apr 6, 2011 · Viewed 10.2k times · Source

I'm trying to synchronize periodically a git bare repository, my local branches are created using the "--track" option. here is my config (without unnecessary things):

[core]
        bare = true
[remote "origin"]
        url = [email protected]:Ummon/D-LAN.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
[branch "website"]
        remote = origin
        merge = refs/heads/website

I must use the 'cp' command to update the local branches:

 git fetch --all
 cp -r refs/remotes/origin/* refs/heads

Is there a more elegant solution?

Answer

sehe picture sehe · Apr 6, 2011

Instead of copying the ref files around (bad bad!) use git update-ref

Note that you can have what you wanted pretty easily to a bare repository when pushing instead of pulling.

Use this:

 git clone --mirror . /tmp/bareclone

to create the bare repository that you want to keep completely in synch Now, to synch all the branches to the bareclone mirror, use

 git push /tmp/bareclone --mirror

NOTE that this will also remove any heads that aren't in the source repo but (still) are in the bareclone. Also note that you can use send-pack instead of push there because this interface is rather lowlevel and actually implemented by send-pack

HTH


As the commenter noted, I slighly avoided the subject that it doesn't seem possible at once to do the inverse. However, you can get a long ways towards the goal by doing something slightly advanced like:

1. Simple, safe and pretty unexciting.

git fetch $url -- $(git ls-remote -h $url |
    while read sha ref; do echo "$ref:refs/remotes/fetched/${ref#refs/heads/}"; done)

Set `url=git://your.server/project.git' e.g.

I made sure that the refs are created in a moderately safe location. The effect very similar to doing.

git remote add fetched $url --fetch

So there is nothing much, but it shows you how to use plumbing commands to achieve it, so we can now adapt them to our needs:

2. Fetch directly into local branches (heads)

Now if you are sure you know what you're doing you can use the following style to get the branches duplicated locally:

git init --bare .
git fetch $url -- $(git ls-remote -h $url |
    while read sha ref; do echo "$ref:$ref"; done)

Note: if you want to force update (e.g. when there is no fast-forward pull because of an upstream rebase, reset, filter-branch, or amended commit (in general -- any rewritten history) replace echo "$ref:$ref" by echo "+$ref:$ref"; (Thanks Dov)

3. The full monty

This could also be combined, so you can have a remote definition too. I'd recommend that because it will mean that the local branches are actually tracking the ones from the remotes, and you'll have better insulation/recovery options if you accidentally clobber some of the local commits on these branches with these powerful fetch commands

git init --bare .
git remote add fetched $url --fetch
git for-each-ref --format='%(refname:short)' -- 'refs/remotes/fetched/' |
    while read ref; do git branch -t "$(basename "$ref")" "$ref"; done

Have fun, HTH