Skip to content

Instantly share code, notes, and snippets.

@joechrysler
Last active August 18, 2025 16:52
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.

@dimitarvp
Copy link

In August 2025, only what @jpbochi has given us here works, both in repositories with master and main as their "root" branch. Here's what I added to my ~/.gitconfig:

[alias]
  main = !git log --pretty=format:'%D' HEAD^ | grep 'origin/' | head -n1 | sed 's@origin/@@' | sed 's@,.*@@'
  sync = !git stash --include-untracked && git pull origin $(git main) --rebase && git push --force-with-lease && git stash pop

(The latter is for syncing up with upstream root branch when other colleagues merge PRs, to avoid diverging too much from it and minimize conflicts.)

So you can just do:

git main

# And if you want to sync up with your root branch (but not your parent one, mind you)
git sync

My GIT is version 2.50.1.

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