Search code examples
gitmergecontains

How to list all git branches created from any commit of a particular branch


There are several questions that are close to what I'm asking, but not quite the same.

I want to list all branches, created off of a git branch at any point in that branch's history.

Answers to similar questions include using git branch --contains [branch-name], but that doesn't accomplish what I'm after.

Consider the following (simple) example & tree:

$ git init
$ git checkout -b master
$ touch master.txt
$ git add .
$ git commit -m "Initial master commit"
$ git checkout -b develop
$ touch develop.txt
$ git add .
$ git commit -m "Initial develop commit"
$ git checkout -b feature/a
$ touch a.txt
$ git add .
$ git commit -m "feature/a commit"
$ git checkout develop
$ git checkout -b feature/b
$ touch b.txt
$ git add .
$ git commit -m "feature/b commit"

master
      \
       \         feature/a
        \       /
         develop
                \
                 feature/b

If I want to get all branches that contain the develop branch, I can do git branch --contains develop and I'll get the following result:

$ git branch --contains develop

  develop
  feature/a
  feature/b

Cool. But let's use a more real-world example (-'s are commits) where there are multiple feature branches that are merged in at different times:

$ git checkout develop
$ git merge feature/a
$ git branch -d feature/a

master
      \
       \         feature/a
        \       /         \
         develop           -
                \
                 feature/b

In this case, feature/a was completed, merged into develop, and then deleted. And now the latest commit for develop is ahead of feature/b, which is still being worked on. Now, if I run git branch --contains develop, I get the following:

$ git branch --contains develop

  develop

Not cool. What I'd like to see is both develop and feature/b, as feature/b was branched off of an older commit of develop.

I have a complicated project with plenty of feature, bugfix, enhancement, etc. branches that have been made off of various points in develop's lifetime, and not all of them have been pulled in, and right now git branch --contains develop is pretty useless in telling me what branches are outstanding.


Solution

  • I realized what an answer was as I was wrapping up writing the question (yay for getting thoughts down on "paper").

    The command git branch --contains develop is only considering the latest commit of the develop branch, so you need to get the first commit SHA of the develop branch.

    Unfortunately, this is where things get tricky. From Pro Git § 3.1 Git Branching - What a Branch Is:

    A branch in Git is simply a lightweight movable pointer to [a] commit.

    Since a branch is just a lightweight pointer, git has no explicit notion of its history or creation date.

    I spent way too long hacking together a way to get a branch's original commit SHA and finally came up with one, but there are some prerequisites/limitations.

    • You need to know what branch you want the original commit SHA for (in our case, develop)
    • You need to know the branch it was branched off of and that branch cannot be ahead of it (in our case, master) - this is definitely not ideal, but anyone is welcome to provide a better answer :)
    $ git branch --contains $(git rev-list master..develop | tail -1)
    
      develop
      feature/b
    

    If you're curious, the stuff in the $() is how I get the earliest commit SHA from the git rev list (better approach than original thanks to comment from @alfunx).