简体   繁体   中英

git scripting: How to list all git branches containing a commit

I can list all branches containing a certain commit using git branch --list --contains just fine. But as explained in the related question on how to list all branches , this is a porcelain command that should not be used in scripts.

The latter question suggests to use the plumbing command git for-each-ref , but that does not support --contains .

What is the correct plumbing interface to list all branches that contain a certain commit.

Update 18 months later (April 2017) : with Git 2.13 (Q2 2017), git for-each-ref --no-contains <SHA1> is finally supported!

See commit 7505769 , commit 783b829 , commit ac3f5a3 , commit 1e0c3b6 , commit 6a33814 , commit c485b24 , commit eab98ee , commit bf74804 (24 Mar 2017), commit 7ac04f1 , commit 682b29f , commit 4612edc , commit b643827 (23 Mar 2017), and commit 17d6c74 , commit 8881d35 , commit b084060 , commit 0488792 (21 Mar 2017) by Ævar Arnfjörð Bjarmason ( avar ) .
(Merged by Junio C Hamano -- gitster -- in commit d1d3d46 , 11 Apr 2017)


Original answer

Starting git 2.7 (Q4 2015) you will get a more complete version of git for-each-ref , which now support the --contains

git for-each-ref --contains <SHA1>

With the doc:

--contains [<object>]:

Only list tags which contain the specified commit (HEAD if not specified).


See commit 4a71109 , commit ee2bd06 , commit f266c91 , commit 9d306b5 , commit 7c32834 , commit 35257aa , commit 5afcb90 , ..., commit b2172fd (07 Jul 2015), and commit af83baf (09 Jul 2015) by Karthik Nayak ( KarthikNayak ) .
(Merged by Junio C Hamano -- gitster -- in commit 9958dd8 , 05 Oct 2015)

Some features from " git tag -l " and " git branch -l " have been made available to " git for-each-ref " so that eventually the unified implementation can be shared across all three, in a follow-up series or two.

* kn/for-each-tag-branch:
  for-each-ref: add '--contains' option
  ref-filter: implement '--contains' option
  parse-options.h: add macros for '--contains' option
  parse-option: rename parse_opt_with_commit()
  for-each-ref: add '--merged' and '--no-merged' options
  ref-filter: implement '--merged' and '--no-merged' options
  ref-filter: add parse_opt_merge_filter()
  for-each-ref: add '--points-at' option
  ref-filter: implement '--points-at' option  

One possible solution using the plumbing commands git-for-each-ref and git merge-base (the latter suggested by Joachim himself):

#!/bin/sh

# git-branchesthatcontain.sh
#
# List the local branches that contain a specific revision
#
# Usage: git branchthatcontain <rev>
#
# To make a Git alias called 'branchesthatcontain' out of this script,
# put the latter on your search path, and run
#
#   git config --global alias.branchesthatcontain \
#       '!sh git-branchesthatcontain.sh'

if [ $# -ne 1 ]; then
    printf "%s\n\n" "usage: git branchesthatcontain <rev>"
    exit 1
fi

rev=$1

git for-each-ref --format='%(refname:short)' refs/heads | \
    while read ref; do
        if git merge-base --is-ancestor "$rev" "$ref"; then
            printf "%s\n" "$ref"
        fi;
    done

exit $?

The script is available at Jubobs/git-aliases on GitHub.

(Edit: thanks to coredump for showing me how to get rid of that nasty eval .)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM