Canonical way to filter list of commits to those pointed to by branches (preserving order)?
- From
D. Ben Knoble <ben.knoble+github@gmail.com>
- Date
- Jun 10, 2025, 21:29 UTC
- Message-ID
- <20250610212954.51868-1-ben.knoble+github@gmail.com>
Perusing a Git Rev News article [1], I thought there must be a better way to turn the commits between 2 revisions into a list of branch names—better, that is, than parsing git-log output.
I wound up with 3 options, but I wonder if any are canonical or if I'm missing the "standard" approach? My current best attempt leaves me concerned via the documentation.
1. Use join:
join <(git rev-list "$upstream..$base" | sort) \
<(git for-each-ref --format="%(objectname) %(refname:strip=2)" refs/heads | sort) Requires Bash or Zsh due to process substitution, and the |sort pipe loses
topological order. But elegant, from a certain point of view, perhaps.2. Use git-name-rev, but post-process output (because name-rev gives results that aren't refs):
git rev-list "$upstream..$base" | xargs git name-rev --refs='refs/heads/*' |
while read -r sha ref; do
if git check-ref-format --branch "$ref" >/dev/null 2>&1; then
printf '%s %s\n' "$sha" "$ref"
fi
doneNot my favorite, but seems to work
3. Use git-name-rev after filtering with --simplify-by-decoration
git rev-list --simplify-by-decoration "$upstream..$base" | xargs git name-rev
Clearly the most elegant, but only if I can rely on --simplify-by-decoration
not outputting commits not pointed directly to by a branch. But the docs say
"Note that extra commits can be shown to give a meaningful history." Hm. (Of
course, all the git-name-rev solutions are broken in the presence of tags,
too, though for my use case I will just ignore that for now…)[1]: Pushing a whole stack of branches with a single Git command <https://andrewlock.net/pushing-a-whole-stack-of-branches-with-a-single-git-command/>
-- D. Ben Knoble