Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Find the nearest parent branch of the current git branch
#!/usr/bin/env zsh
git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/.*\[\(.*\)\].*/\1/' \
| sed 's/[\^~].*//'
# How it works:
# 1| Display a textual history of all commits.
# 2| Ancestors of the current commit are indicated
# by a star. Filter out everything else.
# 3| Ignore all the commits in the current branch.
# 4| The first result will be the nearest ancestor branch.
# Ignore the other results.
# 5| Branch names are displayed [in brackets]. Ignore
# everything outside the brackets, and the brackets.
# 6| Sometimes the branch name will include a ~2 or ^1 to
# indicate how many commits are between the referenced
# commit and the branch tip. We don't care. Ignore them.
@pforhan

This comment has been minimized.

Copy link

@pforhan pforhan commented Oct 24, 2013

the ack commands can be seamlessly replaced with grep, making usage (at least on macs) easier. You also seem to have an extra backtick at the end of line 5.

Lastly, git show-branch can kick out a lot of extra warnings. do a git show-branch 2>/dev/null to avoid.

In summary:

branch=`git rev-parse --abbrev-ref HEAD`
git show-branch -a 2>/dev/null | grep '\*' | grep -v "$branch" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
@pforhan

This comment has been minimized.

Copy link

@pforhan pforhan commented Oct 25, 2013

This also doesn't quite work right if you have any uncommitted work in your workspace. I haven't tracked it down quite, but my release branch isn't even present in any of the show-branch output.

@vitormv

This comment has been minimized.

Copy link

@vitormv vitormv commented Jan 27, 2014

Is that last " ` " supposed to be there, at the very end of the line? It gives an error for me, but works well enough without one.

@rcdailey

This comment has been minimized.

Copy link

@rcdailey rcdailey commented Feb 18, 2014

The grep solution is the only one that works for me using bash (msysgit on Windows).

@ZuBB

This comment has been minimized.

Copy link

@ZuBB ZuBB commented Feb 23, 2016

Does anyone knows why this does not work?

2016-02-23-132438_3840x1080_scrot

@haoyangnz

This comment has been minimized.

Copy link

@haoyangnz haoyangnz commented May 11, 2016

@ZuBB

I suspect the parent branch's last commit is a merge, making the column show - not *.

Try:

vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Obviously you can combine this into a single line if you wish.

@VipSaran

This comment has been minimized.

Copy link

@VipSaran VipSaran commented Sep 26, 2017

Thanks for this.

How can it be combined into an alias?

@benmcginnis

This comment has been minimized.

Copy link

@benmcginnis benmcginnis commented Nov 16, 2017

@VipSaran you can make a bash file called git-parent.sh and if it's executable and in your $PATH, then the command git parent will use that file.

@greenrd

This comment has been minimized.

Copy link

@greenrd greenrd commented Feb 13, 2018

This doesn't give the correct answer for me. I think it's necessary to verify the answer by trying an interactive rebase on the answer it gives you, and if it gives you a load of commits that aren't in your branch, it's the wrong answer and you have to guess another branch and try an interactive rebase again.

@ivanwills

This comment has been minimized.

Copy link

@ivanwills ivanwills commented Mar 26, 2018

This has an issue if there are square brackets in the comments here is my alternative

git show-branch -a 2>/dev/null \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| perl -ple 's/\[[A-Za-z]+-\d+\][^\]]+$//; s/^.*\[([^~^\]]+).*$/$1/'

(I couldn't get the sed equivalent regexp)

@prachikhadke

This comment has been minimized.

Copy link

@prachikhadke prachikhadke commented Mar 26, 2018

This script does not work. E.g. I merged a branch1 to master and then created branch2 from master. Ideally parent of branch2 is master, but this script always return branch1 as the parent which is not true. It is doing so because branches are all pointers and branch2 is pointing to the merge commit (from branch1 to master). even though that merge commit has 2 parents, only branch1 is returned.

@SrinivasRachakonda236

This comment has been minimized.

Copy link

@SrinivasRachakonda236 SrinivasRachakonda236 commented Jan 22, 2019

It's not working for me, it is returning only one branch name as parent branch for all 800 branches in my repo I don't know why..?
But in reality it's not true, all branches have different parents. Any suggestions to get actual (nearest parent branch not ancestor parent branch) parent branch name of current branch.
Many Thanks...

@verdverm

This comment has been minimized.

Copy link

@verdverm verdverm commented Jun 19, 2019

This did not work for me when I had done something like develop > release-v1.0.0 > feature-foo, it would go all the way back to develop, note there was a rebase involved, not sure if that is compounding my issue...

The following did give the correct commit hash for me

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
@jpbochi

This comment has been minimized.

Copy link

@jpbochi jpbochi commented Dec 11, 2019

Here's another version: git log --pretty=format:'%D' HEAD^ | grep 'origin/' | head -n1 | sed 's@origin/@@' | sed 's@,.*@@'

The seds at the end are useful to transform something like origin/develop, origin/HEAD, develop into simply develop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.