问题
Say I have the following git repo:

I want to specify a git rev-list of all branches (--all
) but excluding a given branch (say, feature-D
), but I want to show common ancestors of feature-D
and the other branches i.e. commit Initial
and 1
.
If I try git rev-list --all ^feature-D
commits Initial
and 1
are excluded:

Of course I can list all branches except for feature-D
explicitly (git rev-list feature-A feature-B feature-C
) to get what I want:

But is there a way to specify a rev-list that obtains the prior result, only by reference to feature-D
?
(Note that this question was inspired by this answer: https://stackoverflow.com/a/20978568/430128)
回答1:
This is a bit indirect but seems to work. We start with:
git rev-list --no-walk --all ^feature-D
which produces a list of all SHA-1s directly pointed to by any ref (including tags, branches, stashes, etc; use --branches
rather than --all
if you want only branches) except those under feature-D
:
$ git log --oneline --decorate --graph --all
* 74e0d3e (feature-D) 7
* 0448a13 6
| * ab3a532 (feature-C) 5
|/
| * 50477c7 (feature-B) 4
| * 28717e5 3
|/
* 2ac5cef (HEAD, master, feature-A) 2
* c6a10b4 1
* 76c511f Initial
$ git rev-list --no-walk --all ^feature-D
ab3a5320e792e945b896634d667df5ace4a8b871
50477c7b28b5479587e45fe97292e71a3c0851c5
28717e5628ad111e8b68323dc485fd190a780446
Now we feed this to git rev-list
again to get the history-walking:
$ git rev-list --no-walk --all ^feature-D | git rev-list --stdin
ab3a5320e792e945b896634d667df5ace4a8b871
50477c7b28b5479587e45fe97292e71a3c0851c5
28717e5628ad111e8b68323dc485fd190a780446
2ac5cefb971c7f5c5be33a77a6db71127982eaf5
c6a10b4568136d65b31b7e262ef7745db4962460
76c511fcf38076e0ea98db73a4923de6fc806b4a
Pipe that to git log --oneline --decorate --graph --stdin
to verify that those are the right commits, if eyeballing it is not sufficiently clear:
* ab3a532 (feature-C) 5
| * 50477c7 (feature-B) 4
| * 28717e5 3
|/
* 2ac5cef (HEAD, master, feature-A) 2
* c6a10b4 1
* 76c511f Initial
(and one side note: if using git log --oneline --decorate --graph
to view your middle version, i.e., git rev-list --all ^feature-D
, you need to add --boundary
to see commit 2; gitk probably adds --boundary
to make it show up, not that I tested this).
There's a defect here: if feature-C
and feature-B
branches did not exist you would not see commits 2 through Initial. I'm not sure, but I think the only real fix for this is to use something much more complex.
Edit: ok, not that much more complex. Start with git for-each-ref
to print branches. Pipe through grep -v ^feature-D$
to eliminate feature-D
. Now you have all the branches you want as arguments:
$ git log --oneline --graph --decorate $(git for-each-ref \
> --format '%(refname:short)' refs/heads/ | grep -v '^feature-D$')
* ab3a532 (feature-C) 5
| * 50477c7 (feature-B) 4
| * 28717e5 3
|/
* 2ac5cef (master, feature-A) 2
* c6a10b4 1
* 76c511f Initial
回答2:
Simple solution
Instead of listing all branches explicitly (either manually or with a complicated program), we can use a regex to include --all
refs and --exclude
a specific one.
According to the man page, the --all
flag will
Pretend as if all the refs in
refs/
are listed on the command line as<commit>
.
Ideally, we would pretend that all of the refs in refs/
except for feature-D are listed on the command line as <commit>
.
So to exclude feature-D
we can use --exclude=refs/heads/feature-D --all
.
Note: The flag order is important.
A note for gitk users:
(Probably relevant since the OP image includes a gitk screenshot.)
I originally came across this question while trying to ignore a branch in gitk and I noticed a small gitk bug that my answer above will trigger. If gitk is started with the above flags, then everything works fine. However, if after starting gitk the the view is modified from within the GUI menu, the flag ordering seems to get changed and cause the branch to reappear. (This will happen if the OK button is pressed even if no actual changes are made.) I was unable to figure out how to fix this while still using the --all
flag, but I have a workaround.
Instead of using --all
, we can use --branches=* --tags=* --remotes=* stash
.
So to exclude feature-D
, we can modify this to say --exclude=refs/heads/feature-D --branches=* --tags=* --remotes=* stash
.
We can then start gitk using gitk --exclude=refs/heads/feature-D --branches=* --tags=* --remotes=* stash
and editing the view through the GUI no longer causes this bug.
来源:https://stackoverflow.com/questions/20979339/use-git-rev-list-to-exclude-a-branch-but-keep-common-ancestors-with-the-include