Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git log --branches with prefix

Tags:

git

git-log

I want to log all changes on a specific set of branches to see the relationshop between them, and I found that:

git log --graph --oneline --topo-order --decorate --simplify-by-decoration `git branch --list -a origin/foo/*`

does exactly what I want (i.e. log changes on all branches that are prefixed with foo/*).

But now I am curious about the --branches option of git log. It seems like that should work in a similar way, but if I use --branches=origin/foo/* or --branches=remotes/origin/foo* or even --branches=foo the output is very different (only very few and irrelevant commits are showing).

The documentation say:

--branches[=<pattern>]
Pretend as if all the refs in refs/heads are listed on the command line as
<commit>. If <pattern> is given, limit branches to ones matching given shell
glob. If pattern lacks ?, *, or [, /* at the end is implied.

What is the difference ? My problem is already solved since I can use the first version - but I am asking this since I am curious. ( And also adding a git alias is slightly simpler if use of back ticks can be avoided. )

This question discusses related topics - but I could not see any info about my specific issue.

like image 339
Zitrax Avatar asked Mar 12 '23 06:03

Zitrax


1 Answers

Explanation

Now that's a perfect case of "you need to know git's internals to understand the documentation". Which we would need less of.

The documentation for --branches states it works on "refs in refs/heads". Remote-tracking references aren't in refs/heads, they're in refs/remotes. Because of that, when looking for "origin/foo/*", no branch will be found. So git log will revert to its default behaviour, which is to start discovering commits from HEAD.

Solution

You need to use the --remotes option, which is similar to --branches but works for refs in refs/remotes. So that becomes:

git log --graph --oneline --topo-order --decorate --simplify-by-decoration --remotes='origin/foo/*'

Alternatively, you can use --glob, which works on all branches, but then you need to prepend heads/ or remotes/, or use a wildcard. For instance:

git log --graph --oneline --topo-order --decorate --simplify-by-decoration --glob='refs/*/foo/*'

About your first command

On a side note, your first command won't work in all cases, because you're using git branch, which is a porcelain command, inside your backticks. It may break in the future because the output of porcelain commands is subject to change. In fact, it does break already on some cases like when you're listing HEAD. For instance:

git log --graph --oneline --topo-order --decorate --simplify-by-decoration $(git branch --list -a 'origin/*')

This command gave me an error, saying it couldn't recognize -> as an argument. That's because of the output of git branch:

remotes/origin/HEAD -> origin/master
remotes/origin/master

To make your command work in all cases and be future-proof, you can use git for-each-ref (which is a plumbing command), like so:

git log --graph --oneline --topo-order --decorate --simplify-by-decoration $(git for-each-ref --format='%(refname)' 'refs/remotes/origin/*')
like image 82
Pikrass Avatar answered Mar 15 '23 08:03

Pikrass