简体   繁体   English

使用git rev-list排除分支,但保留包含分支的共同祖先

[英]Use git rev-list to exclude a branch, but keep common ancestors with the included branches

Say I have the following git repo: 说我有以下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 ie commit Initial and 1 . 我想指定所有分支( --all )的git rev-list但是不包括给定的分支(比如feature-D ),但是我想显示 feature-D和其他分支的共同祖先,即提交Initial1

If I try git rev-list --all ^feature-D commits Initial and 1 are excluded: 如果我尝试git rev-list --all ^feature-D提交Initial1被排除在外:

--all ^ feature-D

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: 当然,我可以明确列出除feature-D之外的所有分支( git rev-list feature-A feature-B feature-C )以获得我想要的东西:

feature-A feature-B feature-C

But is there a way to specify a rev-list that obtains the prior result, only by reference to feature-D ? 但有没有办法指定一个获取先前结果的转录列表,只能通过引用feature-D

(Note that this question was inspired by this answer: https://stackoverflow.com/a/20978568/430128 ) (请注意,这个问题的灵感来自于这个答案: https//stackoverflow.com/a/20978568/430128

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 : 它产生一个由任何ref直接指向的所有SHA-1的列表(包括标签,分支, --branches等;使用--branches而不是--all如果你只想要分支) 除了 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来获取历史记录:

$ 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: 管道git log --oneline --decorate --graph --stdin验证那些是正确的提交,如果眼球不够清楚:

* 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, ie, 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). (并且一方面注意:如果使用git log --oneline --decorate --graph来查看你的中间版本,即git rev-list --all ^feature-D ,你需要添加--boundary来查看commit 2 ; gitk可能会添加--boundary以使其显示,而不是我测试了这个)。

There's a defect here: if feature-C and feature-B branches did not exist you would not see commits 2 through Initial. 这里有一个缺陷:如果feature-Cfeature-B分支不存在,你将看不到提交2到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. git for-each-ref开始打印分支。 Pipe through grep -v ^feature-D$ to eliminate feature-D . 管道通过grep -v ^feature-D$来消除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

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. 我们可以使用正则表达式来包含--all refs和--exclude一个特定的分支,而不是明确地列出所有分支(手动或使用复杂的程序)。

According to the man page, the --all flag will 根据手册页, - --all标志将

Pretend as if all the refs in refs/ are listed on the command line as <commit> . 假装refs/中的所有引用都在命令行中列为<commit>

Ideally, we would pretend that all of the refs in refs/ except for feature-D are listed on the command line as <commit> . 理想情况下,我们假装refs/ 除feature-D之外的所有引用都在命令行中列为<commit>

So to exclude feature-D we can use --exclude=refs/heads/feature-D --all . 因此,要排除feature-D我们可以使用--exclude=refs/heads/feature-D --all

Note: The flag order is important. 注意:标志顺序很重要。


A note for gitk users: gitk用户的注释:

(Probably relevant since the OP image includes a gitk screenshot.) (可能相关,因为OP图像包含gitk屏幕截图。)

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. 我最初在尝试忽略gitk中的一个分支时遇到了这个问题,我注意到一个小的gitk错误,我上面的回答会触发。 If gitk is started with the above flags, then everything works fine. 如果使用上面的标志启动gitk,那么一切正常。 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. 但是,如果在启动gitk之后从GUI菜单中修改了视图,则标志排序似乎会发生变化并导致分支重新出现。 (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. (即使没有进行实际更改,如果按下OK按钮也会发生这种情况。)我仍然无法弄清楚如何在仍然使用--all标志的情况下解决这个问题,但我有一个解决方法。

Instead of using --all , we can use --branches=* --tags=* --remotes=* stash . 而不是使用--all ,我们可以使用--branches=* --tags=* --remotes=* stash

So to exclude feature-D , we can modify this to say --exclude=refs/heads/feature-D --branches=* --tags=* --remotes=* stash . 因此,要排除feature-D ,我们可以将其修改为--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. 然后我们可以使用gitk --exclude=refs/heads/feature-D --branches=* --tags=* --remotes=* stash启动gitk gitk --exclude=refs/heads/feature-D --branches=* --tags=* --remotes=* stash并通过GUI编辑视图不再导致此错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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