-
-
Save joechrysler/6073741 to your computer and use it in GitHub Desktop.
#!/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. |
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.
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.
The grep solution is the only one that works for me using bash (msysgit on Windows).
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.
Thanks for this.
How can it be combined into an alias?
@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.
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.
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)
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.
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...
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"
Here's another version: git log --pretty=format:'%D' HEAD^ | grep 'origin/' | head -n1 | sed 's@origin/@@' | sed 's@,.*@@'
The sed
s at the end are useful to transform something like origin/develop, origin/HEAD, develop
into simply develop
.
Does the star in step 2 always come in the first char?
If so,
| grep '*' \
can be replaced by:
| grep '^*' \
which only searches for the star at the first position,
so it will be more precise.
git log --pretty=format:'%D' HEAD^ | grep 'origin/' | head -n1 | sed 's@origin/@@' | sed 's@,.*@@'
This did the trick for me, thanks!
This does not return master
branch name when master branch is the parent of the branch I check.
git log --decorate
| grep 'commit'
| grep 'origin/'
| head -n 2
| tail -n 1
| awk '{ print $2 }'
| tr -d "\n"
This seems to work for me. However I'm not totally gathering why it wouldn't show return the latest commit that has 'origin' in the first couple lines of the current branch 🤔 @verdverm
@JackHowa we ended up recording the source branch at time of creation in a json file. This is exact and reliable. We have found many new and interesting uses for a "branch-config" (./bfg/*.json
). Trying to figure it out from git was too troublesome.
that makes sense; we're leaning the same way. thanks @verdverm
@joechrysler It's not working for me on Windows 10, Could you please guide me?
Thanks!
In my case I see output as shown below, so all scripts above don't work correctly. Thus I enchanted a random script to show a correct branch. This is usually happening for me when I do cleanup and make many single-commit branches which I merge to the main one.
git show-branch -a \
| grep '\(\*\|^-.*\[\)' \
| grep -v '\['`git rev-parse --abbrev-ref HEAD`'\([\^]\|~\d\+\)\?\]' \
| head -n1 \
| sed 's/.*\[\([^\^~]*\).*\].*/\1/;'
What I enchanced:
- first grep greps not only stas, but also the latest line
- second grep eliminates only branches with exact name. Match also includes cases like
^
and~1231
.
Pattern doesn't use advantage of-E
for better compatibility between various systems and grep implementations. - few sed's at the end were collapsed into a single one, taking advantage of eagerness of
*
operator.
git show-branch
outputs I have in my repositories:
$ git show-branch -a
! [main] test2
* [t] test3
! [t2] test2
! [upstream/HEAD] Merge pull request #640 from repo/branch
! [upstream/main] Merge pull request #640 from repo/branch
-----
+ [main] test2
* [t] test3
* [t^] test2
* [t~2] test2
+ [t2] test2
*+ [t~3] test1
----- [upstream/HEAD] Merge pull request #640 from repo/branch
$ git show-branch
! [main] test2
! [t] test3
* [t2] test2
---
+ [main] test2
+ [t] test3
+ [t^] test2
+ [t~2] test2
* [t2] test2
+* [t~3] test1
--- [main^] Merge pull request #640 from repo/branch
First, thank you for this gist -- it's exactly what I was looking for. I have two suggestions to improve it:
- To account for a branch commit distance larger than 9, the final sed command should be:
's/[\^~][[:digit]]*//'
- The last two sed commands could be a done with a single sed invocation and two '-e' arguments, one for each command.
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 agit show-branch 2>/dev/null
to avoid.In summary: