tags:

views:

178

answers:

4

I would like to extract the information that is printed after a git status, which looks like:

# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.

Of course I can parse the output of git status but this is not recommended since this human readable output is liable to change.

There are two problems:

  1. How to know the remote tracked branch? It is often origin/branch but need not be.
  2. How to get the numbers? How to know whether it is ahead/behind? By how many commits? And what about the diverged branch case?
+5  A: 

git rev-list origin..HEAD will show the commits that are in your current branch, but not origin -- i.e., whether you're ahead of origin and by which commits.

git rev-list HEAD..origin will show the opposite.

If both commands show commits, then you have diverged branches.

jamessan
Thanks, the `rev-list` seems to work as expected, but `branch -r` does not give remote tracked branch accurately. I do not have the `origin/HEAD` that you wrote, yet there is a remote tracked branch, and I can get the number of commits with `rev-list`.
Olivier
Hmm, it does seem that `branch -r` doesn't do what I thought. Updated.
jamessan
+3  A: 

There doesn't seem to be an easy way to find the tracking branch in general, without parsing lots more git config than is practical in a few shell commands. But for many cases this will go a long way:

# work out the current branch name
currentbranch=$(expr $(git symbolic-ref HEAD) : 'refs/heads/\(.*\)')
[ -n "$currentbranch" ] || die "You don't seem to be on a branch"
# look up this branch in the configuration
remote=$(git config branch.$currentbranch.remote)
remote_ref=$(git config branch.$currentbranch.merge)
# convert the remote ref into the tracking ref... this is a hack
remote_branch=$(expr $remote_ref : 'refs/heads/\(.*\)')
tracking_branch=refs/remotes/$remote/$remote_branch
# now $tracking_branch should be the local ref tracking HEAD
git rev-list $tracking_branch..HEAD

Another, more brute-force, approach:

git rev-list HEAD --not --remotes

jamessan's answer explains how to find the relative differences between $tracking_branch and HEAD using git rev-list. One fun thing you can do:

git rev-list --left-right $tracking_branch...HEAD

(note three dots between $tracking_branch and HEAD). This will show commits on both "arms" with a distinguishing mark at the front: "<" for commits on $tracking_branch, and ">" for commits on HEAD.

araqnid
Ecxellent! The three dots with `--left-right` is definitely an improvement on jamessan's answer. For the remote, I suppose the only robust way to go is, as you suggest, to read the git config...
Olivier
+1  A: 

You can try git branch -v -v. With -v flag given twice, it outputs names of upstream branches. Sample output:

* devel  7a5ff2c [origin/devel: ahead 1] smaller file status overlay icons
  master 37ca389 [origin/master] initial project check-in.

I think this format is more stable than git status output.

max
`git status` has the `--porcelain` flag which provides stable output, but it doesn't show the ahead/behind information.
jamessan
excellent! I had never noticed this double option with git branch... it's pretty unusual to have a command with a double option, isn't it? Thanks for the tip
Olivier
A: 

git log origin..HEAD with more info

insidepower
nah, this doesn't work.
Olivier
isn't it works like the git rev-list origin..HEAD ? if any commit shown, it means we are ahead... (and we can easily see the commits info)if any commit show when do a "git log HEAD..origin" it means we are behind... you can get a cleaner output with below (and perhaps with wc -l for the counting)git log origin..master --pretty=oneline. I am still learning git too, git branch -v -v is a good and short answer :)
insidepower