23

The GitHub web interface has a nice feature telling me whether a branch is even with the master branch.

Is there a command-line equivalent of this feature? I work with multiple repositories and I'm looking for a quick way to see whether branches are even or require attention.

Here are screenshot of the GitHub web interface, for those wondering about this feature:

enter image description here

enter image description here

jub0bs
  • 60,866
  • 25
  • 183
  • 186
Nathan H
  • 48,033
  • 60
  • 165
  • 247
  • What does "even" mean? Does it mean that both branches are the same? Or that the branch is up-to-date with master (but the branch might contain new commits that aren't on master)? Or something else? – Nadine Aug 13 '15 at 08:20
  • I'm assuming that "even" means the two branches are current with each other. Either this, or the branches don't owe each other any money ^ ^ – Tim Biegeleisen Aug 13 '15 at 08:21
  • The definition on the github website is that neither branches are behind the other, with regards to commits. I think that @TimBiegeleisen's answer only check files and not commits, but good enough. – Nathan H Aug 13 '15 at 08:34
  • It is possible that two branches could have identical file sets but have different commits. Imagine making a change to one file, committing, then reverting (which also makes a new commit). Now the file sets are the same, but the commits differ. – Tim Biegeleisen Aug 13 '15 at 08:38
  • Indeed, and I assume your answer only checks files right? If you also have a solution for commits, feel free to edit your answer? – Nathan H Aug 13 '15 at 08:39
  • Funny terminology - it's much clearer what you mean with the screenshots :) – AD7six Aug 13 '15 at 08:45

5 Answers5

28

GitHub terminology

Branch A and branch B are even.

is GitHub parlance for

Branch A and Branch B point to the same commit.

Are the two branches even?

If you're only interested in whether the two branches are even or not, without any additional details (e.g. commit count), a script-friendly way is to simply test the SHAs of their tips for equality:

[ "$(git rev-parse <refA>)" = "$(git rev-parse <refB>)" ]

After running this command, the value of $? is 0 if <ref1> and <ref2> are even, and 1 otherwise. Because this command only involves the plumbing Git command git-rev-parse, it can safely be used programmatically.

Is one branch ahead of or behind the other branch?

If you want to emulate GitHub's functionality, e.g. print

foo is n commits ahead of bar

etc., you can use the following script:

#!/bin/sh

# git-checkeven.sh
#
# Check whether two revisions are even, and, otherwise, to what extent
# the first revision is ahead of / behind the second revision
#
# Usage: git checkeven <revA> <revB>
#
# To make a Git alias called 'checkeven' out of this script,
# put the latter on your search path, and run
#
#   git config --global alias.checkeven '!sh git-checkeven.sh'

if [ $# -ne 2 ]; then
    printf "usage: git checkeven <revA> <revB>\n\n"
    exit 2
fi

revA=$1
revB=$2

if ! git merge-base --is-ancestor "$revA" "$revB" && \
  ! git merge-base --is-ancestor "$revB" "$revA"
then
  printf "$revA and $revB have diverged\n"
  exit 1
fi

nA2B="$(git rev-list --count $revA..$revB)"
nB2A="$(git rev-list --count $revB..$revA)"

if [ "$nA2B" -eq 0 -a "$nB2A" -eq 0 ]
then
  printf "$revA is even with $revB\n"
  exit 0
elif [ "$nA2B" -gt 0 ]; then
  printf "$revA is $nA2B commits behind $revB\n"
  exit 1
else
  printf "$revA is $nB2A commits ahead of $revB\n"
  exit 1
fi

Test

Assume a toy repo with the following history:

         * [develop]
        /
... -- * [main, master]
        \
         * [release]

Then, after defining a Git alias called checkeven that calls the script above, you get...

$ git checkeven main develop
main is 1 commits behind develop
$ git checkeven develop main
develop is 1 commits ahead of main
$ git checkeven master main
master is even with main
$ git checkeven develop release
develop and release have diverged
jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 2
    No problem! Thanks for the script! – Clay Ellis Jun 16 '21 at 23:50
  • I'd be very interested if this wasn't the case, but according to this article (https://blog.thoughtram.io/git/2014/11/18/the-anatomy-of-a-git-commit.html) a commit ID contains it's parent. Therefore the chances of two branches having the same commit as their HEAD without having the same commit history is extremely low. – TastyWheat May 04 '22 at 14:04
  • @TastyWheat I don't understand what your comment is referring to... Can you clarify? – jub0bs May 04 '22 at 14:10
  • 1
    Note that it can happen that both branches are "ahead" of each other (when both have commits that the other doesn't have), and this script in its current shape won't report it. In git parlance it is said that they have diverged. – urxvtcd May 05 '22 at 15:37
  • @urxvtcd That's true. I'll modify the script to add support for that. – jub0bs May 05 '22 at 15:47
21

To compare the files of a branch called branch located on GitHub against master on the same repository, you can use git diff:

git diff origin/branch origin/master

The following will work to compare the commits between the two branches:

git log --left-right --graph --cherry-pick --oneline origin/branch...origin/master

As mentioned in my comment above, it is possible that two branches can have identical files but different commits.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • This looks promising. Does it automatically checks remotely or should I fetch first? – Nathan H Aug 13 '15 at 08:21
  • You _do_ have to do a `git fetch` first, as the comparisons will be made on the local copies of the remote branches. – Tim Biegeleisen Aug 13 '15 at 08:22
  • 1
    since it doesn't sound like he's interested in details - you can use `git diff --name-only` for the first example. – AD7six Aug 13 '15 at 08:43
  • Have a look at [this SO article](http://stackoverflow.com/questions/7566416/different-commits-between-two-branches), which is chock full of things like this. Your question seemed different enough to not be a duplicate. – Tim Biegeleisen Aug 13 '15 at 08:46
4

Short answer

if [ $(git rev-parse develop) == $(git rev-parse feature/SPRINT_WSMR_UPDATES) ]; 
then 
    echo "branches are the same"
fi

Explaination

git rev-parse develop will return the hash of the branch.

# git rev-parse develop
c400a9bfb08458f693a1cd05cf7999f6c5b523d2

You can use the hash to compare the two branches. This is a lot of fun when you are using submodules to do something special when the branches are the same. For instance, if you want to switch to the develop branch if the feature branch is the same for all of your submodules ....

Using With Submodules

git submodule foreach '[ $(git rev-parse develop) == $(git rev-parse feature/SPRINT_WSMR_UPDATES) ] && git checkout develop || : '

break it down

  • git submodule foreach 'cmd' will run cmd in every submodule.
  • [ $(git rev-parse develop) == $(git rev-parse feature/SPRINT_WSMR_UPDATES) ] tests the truth of "does develop's hash match the feature's hash?".
  • && git checkout develop will only run if the truth statement is true.
  • || : ensures that the whole command will return true so that the foreach command will not terminate when the branches are different.
shrewmouse
  • 5,338
  • 3
  • 38
  • 43
2

Compare the commit hashes

If you want to check whether two branches are exactly equivalent, just compare the commit hash:

-> git branch -v
  master                       0ccca51 Commencing the awesome
                               ^^^^^^^

-> git fetch
-> git branch -v -r
  origin/master                0ccca51 Commencing the awesome
                               ^^^^^^^
  origin/other                 0ccca51 Commencing the awesome
                               ^^^^^^^

If the commit hashes match - the branches are neither ahead nor behind one another, they are exactly the same.

Community
  • 1
  • 1
AD7six
  • 63,116
  • 12
  • 91
  • 123
0

You can check the equality of all branches local and remote with git branch --remotes --list --all -vv this will show you all of the branches and where they sit. Here in my repo you see that they are all @ 1ba393b

git branch --remotes --list --all -vv

* Develop              1ba393b [origin/Develop] Merge remote-tracking branch into Master
Master                 1ba393b [origin/Master] Merge remote-tracking branch into Master
Release                1ba393b [origin/Release] Merge remote-tracking branch into Master
remotes/origin/Develop 1ba393b Merge remote-tracking branch into Master
remotes/origin/HEAD    -> origin/master
remotes/origin/Master  1ba393b Merge remote-tracking branch into Master
remotes/origin/Release 1ba393b Merge remote-tracking branch into Master

As other have hinted to You could turn this into a git alias. I don't use bash very much I operate in windows command or in PowerShell. The following works there. Your environment may need a small syntactical sprinkle to execute the "More Info" link to SO post below will speak to some of those. Creating your alias in git vs a script or batch means the alias is available no matter what shell you are using.

git config --global alias.equal '!git branch --remotes --list --all -vv' 

will make you an shortcut to do the equality check via git equal alias.equal could be alias.{anyAvailable}. More Info.

hth

Joe Johnston
  • 2,794
  • 2
  • 31
  • 54