Skip to content

Instantly share code, notes, and snippets.

@joechrysler
Last active April 8, 2024 13:36
Show Gist options
  • Save joechrysler/6073741 to your computer and use it in GitHub Desktop.
Save joechrysler/6073741 to your computer and use it in GitHub Desktop.
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.
@eirnym
Copy link

eirnym commented Jan 28, 2023

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:

  1. first grep greps not only stas, but also the latest line
  2. 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.
  3. 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

@geeksmith
Copy link

First, thank you for this gist -- it's exactly what I was looking for. I have two suggestions to improve it:

  1. To account for a branch commit distance larger than 9, the final sed command should be:
    's/[\^~][[:digit]]*//'
  2. The last two sed commands could be a done with a single sed invocation and two '-e' arguments, one for each command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment