views:

1248

answers:

2

I have a git repository with (at present) three branches:

  • head is the stable version (not to be confused with git HEAD)
  • experimental is experimental code; it's supposed to compile
  • norman is my sandbox; code in it might be broken

The "master" git repo is on a file server that is backed up. But I have replicas on a local disk, on a machine at home, and on my laptop. (I'm prepared to write code any time, any where).

git branch -a shows:

  experimental
  head
* norman
  tufts/HEAD
  tufts/experimental
  tufts/head
  tufts/norman

the Tufts branches are the remote branches on the "master" repo. The local branches are supposed to track; git config -l | grep -w remote says:

remote.tufts.url=linux.cs.tufts.edu:/r/ghc/git/experimental.git
remote.tufts.fetch=+refs/heads/*:refs/remotes/tufts/*
branch.experimental.remote=tufts
branch.head.remote=tufts
branch.norman.remote=tufts

Here's my question: how do I update all local branches from their remote counterparts simultaneously, using a single git command? git-fetch doesn't quite do the trick; it updates what it knows about the contents of each remote branch, but it doesn't merge them into the local. And apparently git-pull updates only the currently checked out branch. I want to update all branches at once. Can it be done?

(I'm not wild about

for i in `git branch | sed 's/^.//'`; do git checkout $i ; git pull; done

partly because it's not obvious to me what happens to modified files in my working directory while all this is going on, and partly because I'd need yet more shell code to save and restore the info about what branch I'm currently on.)

I found one (not very closely related) question:

+1  A: 

This issue is not solved (yet), at least not easily / without scripting: see this post on git mailing list by Junio C Hamano explaining situation and providing call for simple solution.

Jakub Narębski
+1  A: 

If refs/heads/master can be fast-forwarded to refs/remotes/foo/master, the output of

git merge-base refs/heads/master refs/remotes/foo/master

should return the SHA1 id that refs/heads/master points to. With this, you can put together a script that automatically updates all local branches that have had no diverting commits applied to them.

This little shell script (I called it git-can-ff) illustrates how it can be done.

#!/bin/sh

set -x

usage() {
    echo "usage: $(basename $0) <from-ref> <to-ref>" >&2
    exit 2
}

[ $# -ne 2 ] && usage

FROM_REF=$1
TO_REF=$2

FROM_HASH=$(git show-ref --hash $FROM_REF)
TO_HASH=$(git show-ref --hash $TO_REF)
BASE_HASH=$(git merge-base $FROM_REF $TO_REF)

if [ "$BASE_HASH" = "$FROM_HASH" -o \
     "$BASE_HASH" = "$FROM_REF" ]; then
    exit 0
else
    exit 1
fi
hillu
Man page for git-merge-base suggests it is not for Paduan learners...
Norman Ramsey
What do you imply by that comment?
hillu
I myself am not capable of writing the script hillu suggests, and I am not confident enough of my git knowledge to use git-merge-base.
Norman Ramsey
I'm afraid I don't understand the model well enough to exploit the script so kindly provided. It's enough to make a person want to switch to mercurcial.
Norman Ramsey
I personally found Tommi Virtanen's article "Git for computer scientists" quite helpful in getting familiar with git's model and terminology.
hillu
I think this has a typo. It should be say:TO_HASH=$(git show-ref --hash $TO_REF)
phord