Owen Chen
Owen Chen

Reputation: 1720

git log after(contains) commit? (with --graph)

I knew that

Is there any way to conceptually direct output of the former command to the latter?
i.e. git branch --contains <REVISION> | git log --branches=

The goal is to filter branches when using git log --decorate --graph --oneline [OTHER_OPTIONS]

Thanks~

Upvotes: 1

Views: 185

Answers (1)

torek
torek

Reputation: 487993

Is there any way to conceptually direct output of [one] command [as arguments to another]?

The shell (sh or bash or whatever shell command interpreter you use) generally has a method of doing that.

There are two common spellings, one using backquotes which is convenient for very short items, and one using $(...) which is better in general because it nests properly.

The problem with git branch --contains is that it formats its output improperly: it will print * if one of the branch names that it prints, that contains the given commit, is the current branch. You must either do something to remove the asterisk, or use a more command-oriented command. The latter is better in general but requires that your Git not be too old (2.6 or later): replace git branch --contains <rev> with git for-each-ref --contains=<rev> --format='%(refname)' ref/heads.

Now, you can't turn this into a set of glob patterns for --branches= for git log, but you don't need to, because all --branches=<glob> does is tell git log to start from the references that match refs/heads/<glob>, and the git for-each-ref is already going to produce a complete list of such references. So all you need to do is pass that complete list of references on to git log.

Since shells also expand $name as a variable holding some name, I'll use that below instead of <...>, which is otherwise ambiguous (it could mean a literal less-than sign etc). This gives:

git log $log_args $(git for-each-ref --contains=$rev --format='%(refname)')

If your git for-each-ref is too old to handle --contains, you must use git branch --contains and strip off the first two columns, e.g.:

git log $log_args $(git branch --contains $rev | cut -c3-)

This has a flaw because git branch does not prefix the branch names with refs/heads. If you have a branch named xyzzy and a tag also named xyzzy, git branch knows to use the branch name, and --branches=xyzzy would know to use the branch rather than the tag, but just naming xyzzy on the command line will get you the tag, because in general tags have higher priority than branches. (See the gitrevisions documentation, which lists the six steps taken to resolve a name: try it as a tag is step 3 and try it as a branch is step 4. The tag has higher priority.) To fix that—to avoid this xkcd—you need to fancy it up some more:

git log $log_args $(git branch --contains $rev | cut -c3- | sed s,^,refs/heads,)

for instance. (And of course, see also this xkcd.)

Upvotes: 2

Related Questions