git在特定分支上提交

时间:2016-09-27 07:47:52

标签: git

我正在寻找特定分支的提交。我的树看起来如下:

feature/X     C--E--F
             /       \
master  -A--B--D---G--H--I--J->

如何获得提交C,E和F? 我试过的是:

git rev-list feature/X ^master

但这没有提交。我假设在特殊情况下问题是feature / X与master的后合并。这就是为什么提交C,E和F也可以从主人那里访问的原因,不是吗?那么 - 如何处理这种情况,任何想法?

此致 托马斯

3 个答案:

答案 0 :(得分:1)

一般来说,一旦合并,提交来自哪个分支的详细信息就会丢失。您所拥有的只是提交由当前分支覆盖。

但是,我可以找到一种这样的方式。 首先,您找到合并发生的位置。这可以使用git log --merges -1来查找最近合并到主人(在您的情况下为H)。我假设的featureX分支就在F后面。这个提交有2个父母。由于featureX已合并为母版,因此您可以使用H^获取目标分支父级。

然后,您可以找到H^F之间的差异,git log H^..featureX,它应该为您提供从featureX可以访问的所有提交,并省略可从H^到达的提交{1}}即。 CEF

举个例子,这是一个回购。 example

如果完成,那么,我应该得到所有"更新X"提交。

首先,我们得到合并提交。

% git log --merges -1 --oneline
e8928b9 Merge branch 'X'

然后我们得到了有问题的日志。功能分支在我的仓库中称为X

% git log e8928\^..X --oneline
92a1f58 Updates x 10
f56306d Updates x 9
54d2253 Updates x 8
a8ba58b Updates x 7
10d08c5 Updates x 6
625d267 Updates x 5
96671d4 Updates x 4
5031498 Updates x 3
41770ea Updates x 2
442033b Updates x 1

这充其量只是hackish。我对寻找真正的解决方案非常感兴趣。

答案 1 :(得分:1)

有一点点hackish,但是工作单行:

git rev-list "$(git rev-list feature/X..master | tail -n 1)^"..feature/X

答案 2 :(得分:1)

重新绘制它可能会有所帮助:

feature/X     C--E--F
             /       \
master  -A--B--D---G--H--I--J->

这样:

        C--E--F           <-- feature/X
       /       \
<--A--B--D---G--H--I--J   <-- master

原因是箭头确实指向后方,feature/X指向分支feature/X提示,即提交Fmaster指向master的提示提交(我在此假设为J,但可能会有更多给出您的原始图纸)

正如您所指出的那样,feature/X ^master(也可以拼写为master..feature/X)失败,因为通过从提交开始,F可以从master访问提交master其中J点(H)并向后工作。当我们点击提交master时,我们同时向后通过父母一起工作,因此删除C--E--F中可到达的所有提交的请求也会消除H序列。

要阻止这种情况发生,我们必须从feature/X之前的某个点开始删除提交,即第一次合并之前的一个点,将master的提示带入G。任何提交DBgit rev-list feature/X ^$hash 都可以。也就是说,如果我们有这些提交的任何一个的哈希值,那么:

D

会做到这一点。

qzb's method找到提交^,然后使用后缀J来标识其第一个也是唯一的父级。它的工作原理是列出masterF的提示)可以从feature/Xgit rev-list的提示)无法访问的每个提交。需要注意的是:D可能会对提交进行排序,因此| tail -1实际上可能不会列在最后,但D会假定列表以提交git rev-list&#39结尾; s hash。

因此,这取决于提交中存储的日期戳。如果它们是按顺序制作的(因此随着提交的及时向前移动,日期都会增加),这不是问题。通常他们这样做。但有时您可以在&#34;错误&#34;中添加提交。日期顺序,由于时钟设置不正确,或提交在不同的计算机上进行,不同意它是什么时间,或其他什么。

我们可以通过告诉--topo-order使用--topo-order来强制日期假设,这会强制它以 graph 顺序列出提交(使用图拓扑中的部分顺序) 。因此,使用此方法时,请添加H

Noufal Ibrahim的方法通过使用git log来查找提交git rev-list。使用git log会更好一些,H=$(git rev-list --merges -1 master) # H stands for Hash, and also for "commit H" :-) 采用与git log相同的选项,但只打印哈希(这就是我们想要的):

HEAD

(请注意,我们必须指定图表行走的起点,而H默认为从H开始。获取提交H的哈希值还不够,因为我们必须向后爬一个父级。由于G两个父母,我们必须小心地从F爬到git merge(而不是H)。

幸运的是,每当我们与git merge feature/X合并时,Git都会确保新合并提交的 first 父级是当前分支上的提交。也就是说,当我们通过运行master进行提交master时,我们在分支G上,名称H意味着提交G。因此$H^1第一个父级是$H^,因此GH=$(git rev-list --merges -1 master) git rev-list feature/X ^${H}^ 标识提交H

$H

^周围的花括号在技术上并不是必需的,只是为了清晰起见:我们展开G,然后在扩展后放置^(以识别提交git rev-list) ,以及扩展前的另一个$yes ^$no(告诉$no..$yes我们将其用作排除说明符。)

由于H=$(git rev-list --merges -1 master) git rev-list ^${H}^..feature/X 可以写成H,我们也可以将其写为:

tail -1

这个方法效率更高一些(我们只列举一个提交--topo-order,而不是使用--topo-order来获取某个潜在长链的最后一次提交)并且不受日期顺序的影响问题(但我们在上面看到了如何修复H)。

顺便说一句,在查找提交A时,这也应该使用H,原因相同:我们不希望Git排序并进行其他合并({{1例如,在feature/X前面。

剩余的缺陷

qzb注意到其中一条:F指向提交 o--o---o--o--o <-- feature / \ / \ ...--o--o--o---o--o--o---o <-- master ,如果过去有更多合并,我们不一定&#34;知道在哪里停止&#34;。那就是:

feature

通过以这种特殊的方式绘制这个特定的图表,我们明确了所有提交沿着&#34; top line&#34;是那些在feature上完成的,master被合并到master两次,而feature被合并回master一次。 (顺便提一下,这种&#34;交叉合并&#34;会让你陷入困境。它不是错误的,但一般来说你应该小心将A合并到B和B中A.在某些情况下,这会为合并产生多个合并基础,这可能很棘手。)但Git并不清楚,还有其他方法来绘制图形,这也会使我们自己的眼睛模糊不清。 (此外,如果你允许&#34;快进&#34;合并(而不是非快进,实际合并提交,合并),一般来说,解开分支历史是不可能的。再次,它不是错误,你只需要准备好处理它。)

如果H过去提交 C--E--F <-- feature/X / \ <--A--B--D---G--H--I--J <-- master / <-o--o--o <-- feature/Y 上的合并,则两种方法都会出现更重要的问题。也就是说,假设到目前为止我们绘制的字母图仍然有点误导,事实上它应该是这样的:

H=$(git rev-list --topo-order --merges -1 master)

现在,如果我们这样做:

$H

我们最终会设置I以指向提交H,而不是提交master。原因很简单:我们要求从I开始并向后工作的最新(拓扑)提交,这也是合并提交。那个提交I^。但H提交H,排除git rev-list会使后续C--E--F排除提交D

这种做法似乎已经毁灭了;我们可以回到定位提交$(git rev-list feature/X..master | tail -n 1) 吗?不,因为qzb的诀窍:

I
当Git按下feature/Y第二个父级,即通过--topo-order时,

停止工作,并开始列出所有那些提交。如果没有--topo-order,我们将获得最早的提交。对于I^1,我们仍然没有被告知首先处理哪个链(I^2 vs A)。如果该链在提交A或更早的时候连接回来,我们可能会获得提交D的哈希 - 或更早,而不是提交I的哈希。

我们可以通过注明引入feature/Y的其他合并feature/Y并排除F来解决这个问题,以便Git 在该链上竞争。但这开始变得复杂。那么,我们真正需要的不是最近的合并,而是引入提交H 的合并(即&#34;找到我提交--ancestry-path&#34;)。有办法实现吗?事实证明,有。我们想要的是--ancestry-path

feature/X选项删除了不是被排除提交的后代的提交。由于master已合并到H,我们肯定知道在F F的后代之后存在一些提交(实际上F) } -ie,master是其父母之一 - 也是git rev-list --ancestry-path --topo-order ^feature/X master 的祖先。所以:

H

告诉Git列出提交IJI以及其他提交。也就是说,我们不会在合并tail -1引入的其他提交中竞争:这些提交将被修剪。

如果我们丢弃除最后一次提交之外的所有提交(再次使用--merges),并选择使用tail加快某些操作,以便在使用H之前放弃任何非合并,即使IJ是合并,我们也会找到提交H=$(git rev-list --ancestry-path --topo-order \ --merges ^feature/X master | tail -1) git rev-list ^$H^..feature/X

--ancestry-path

这是两种方法的混合:我们使用H查找从tail -1开始的提交,使用H删除所有 commit {{ 1}},然后使用^$H^排除提交 - G - 及更早。