What git branch --contains
does is:
- Resolve
HEAD
to a commit hash. If you're on branch br
, this resolves the name br
to a commit hash. (Let some variable h represent this hash.)
For all branch names:
- Resolve the name to a commit hash. Let's call this b for the branch-hash.
- Test ancestor-ness: is b an ancestor of h?
- If b is an ancestor of h, print this branch's name.
The command is now complete: it has listed the names of branches whose branch-tip commit is contained in this branch.
Your problem is very similar, but simpler. You want to resolve the name origin/dev
to some hash h. Then, for some subset of your branch names—the feature names you care about—you want to:
- Resolve the name to a hash ID b.
- Test ancestor-ness: is b an ancestor of h? (In other words: s this branch's tip commit contained within
origin/dev
by being an ancestor of the tip commit of origin/dev
?)
- If so, print the name.
There is a command that implements this "is-ancestor" test, but it's a bit surprising: it's git merge-base
. The command:
git merge-base $b $h
reports success (exits zero) if $b is an ancestor of $h, and reports failure (exits nonzero) if not. The "is ancestor" test it implements is the same one that git branch --contains
uses so this directly provides the answer you want.
The remaining problem is to find the desired branch name(s). The git for-each-ref
command is literally designed to do just that.
Hence:
hname=origin/dev
h=$(git rev-parse $hname) || die "cannot get commit hash ID for $hname"
git for-each-ref --format='%(refname:short) %(objectname)' refs/heads/feature |
while read name b; do
if git merge-base --is-ancestor $h $b; then
echo $name is contained within $hname
fi
done
(note: untested). The refs/heads/feature
here represents branches named feature/*
; if you have a different pattern you need to match, use that different pattern, or use refs/heads
itself and put something in the loop to skip "uninteresting" branch names, or whatever it takes.
See the documentation for git merge-base
and git for-each-ref
(and git rev-parse
, for that matter) for details.