简体   繁体   English

为什么 git rebase 不显示我想压缩的提交?

[英]Why git rebase doesn't show commits I want to squash?

I'm getting ready to initiate a pull request on a branch I'm working on.我正准备在我正在处理的分支上发起拉取请求。 On github, I see that I'm 5 commits ahead of master, so I'd like to squash my commits into one.在 github 上,我看到我比 master 早了 5 个提交,所以我想将我的提交压缩为一个。 I run a git log to see what the previous commits are:我运行一个 git log 来查看以前的提交是什么:

git log --oneline

4363273 Updated Order_Entry with bulk UPDATE command
e7e0c64 Updated Order Entry module and Orders Schema
2cff23e Merge branch 'order_schema'
104b2ce Orders Schema
f7d57cf Order Entry updated to handle and log responses from LC
afa1b7b Merge pull request #18 from project/bugfix/mockvenue
4b2c8d8 Return correct string in mock venue API

Now I think I want to squash those top 5 commits listed above (4363273-f7d57cf).现在我想我想压缩上面列出的前 5 个提交 (4363273-f7d57cf)。 So I then run:所以我然后运行:

git rebase -i HEAD~5

4363273 Updated Order_Entry with bulk UPDATE command
pick 44768b2 Add script to run simulation on a strategy
pick f82ec8d Implement mock venue
pick f7d57cf Order Entry updated to handle and log responses from LC
pick 4b2c8d8 Return correct string in mock venue API
pick 104b2ce Orders Schema
pick 4363273 Updated Order_Entry with bulk UPDATE command

How come the list of commits shown after running git rebase doesn't match the first 5 commits when I run git log.为什么运行 git rebase 后显示的提交列表与运行 git log 时的前 5 个提交不匹配。 Particularly, why do e7e0c64 and 2cff23e appear in git log but not git rebase?特别是,为什么 e7e0c64 和 2cff23e 出现在 git log 而不是 git rebase 中?

* 4363273 Updated Order_Entry with bulk UPDATE command
*   e7e0c64 Updated Order Entry module and Orders Schema
|\
| *   2cff23e Merge branch 'order_schema'
| |\
| | * 104b2ce Orders Schema
| * |   afa1b7b Merge pull request #18 from project/bugfix/mockvenue
| |\ \
| | |/
| |/|
| | * 4b2c8d8 Return correct string in mock venue API
| |/
* | f7d57cf Order Entry updated to handle and log responses from LC
|/
*   8ed2260 Merge pull request #17 from project/mockvenue

在此处输入图片说明

Your graph shows numerous merges.您的图表显示了许多合并。 This is the source of the issue.这是问题的根源。 It's worth noting here that HEAD~5 means "five steps backwards following --first-parent ".这里值得注意的是HEAD~5意思是“在--first-parent倒退--first-parent ”。


Let's cover a bit of background first.让我们先介绍一下背景。 Generally speaking, you can't rebase a merge, and rebase usually doesn't try (it usually just discards them).一般来说,你不能对合并进行 rebase,并且 rebase 通常不会尝试(它通常只是丢弃它们)。 Using git rebase -p will try to preserve merges, and will often succeed, but it's very difficult to use interactively (because the edit script does not have a representation for merges).使用git rebase -p将尝试保留合并,并且通常会成功,但是交互使用非常困难(因为编辑脚本没有合并的表示)。

We can see more once we understand how rebase works.一旦我们了解了 rebase 的工作原理,我们就可以看到更多。 Suppose that we have a commit graph like this:假设我们有一个像这样的提交图:

          B - C - D   <-- other-branch
        /
... - A
        \
          E - F - G   <-- your-branch
  1. Rebase takes a series of commits, and turns them into changesets / patches. Rebase 接受一系列提交,并将它们转换为变更集/补丁。 That is, if you have commits E , F , and G that follow commit A , git must produce a diff from A to E , then from E to F , and finally from F to G .也就是说,如果你有提交EFG随后提交A ,git的产生必须从DIFF AE ,然后从EF ,终于从FG These represent "how to convert from the base commit" (which is currently A ) "to the tip, as a sequence of modifications."这些代表“如何从基本提交”(当前为A )“转换为提示,作为一系列修改”。

  2. Then, rebase turns to the new base commit, in this case commit D , and applies these patches in sequence.然后,rebase 转向新的基础提交,在本例中为提交D ,并按顺序应用这些补丁。 The change from A to E , as applied to D , makes a new commit E' .应用于DAE的更改会进行新的提交E' The change from E to F , applied to E' , makes a new commit F' .应用于E'EF的更改进行了新的提交F' The final change becomes G' .最后的变化变成G'

Changing a commit to a patch (by comparing it with its parent) and then applying the patch is literally a git cherry-pick .更改对补丁的提交(通过将其与其父级进行比较)然后应用补丁实际上是一个git cherry-pick In other words, rebase is just a series of cherry-pick operations, picking commits E , F , and G onto a new branch extending from D .换句话说, rebase只是一系列挑选操作,将提交EFG挑选到从D延伸的新分支上。 The new commit graph would look like this:新的提交图如下所示:

          B - C - D   <-- other-branch
        /           \
... - A               E' - F' - G'   <-- your-branch
        \
          E - F - G   [reflog only]

If we try to do this same thing with a merge commit, we run into a problem.如果我们尝试通过合并提交来做同样的事情,我们就会遇到问题。 A merge has two (or more) parents, and cannot be cherry-picked without human assistance: you must tell git cherry-pick which parent is the one to diff against.合并有两个(或更多)父节点,并且在没有人工帮助的情况下无法进行挑选:您必须告诉git cherry-pick哪个父节点是要区分的父节点。

What git rebase -p does is redo the merge, rather than attempt a cherry-pick. git rebase -p所做的是重做合并,而不是尝试挑选。 The rebase documentation has this example, in which you might rebase A onto Q :变基文档有这个例子,你可以在其中变基AQ

                  X
                   \
                A---M---B
               /
       ---o---O---P---Q

They do not show the result but it should look like this (ideally, with the original A--M--B sequence greyed-out):它们没有显示结果,但它应该是这样的(理想情况下,原始A--M--B序列变灰):

                  X--------
                   \       \
                A---M---B   |
               /            |
       ---o---O---P---Q     |
                       \    |
                        A'--M'--B'

Note that new commit M' has to be a merge between A' and (unchanged) commit X .请注意,新提交M'必须是A'和(未更改的)提交X之间的合并。 This works if the merge is a normal (non-"evil") merge but is obviously a bit tricky, at the least.如果合并是正常(非“邪恶”)合并,则此方法有效,但至少显然有点棘手。


Let's get back to your particular situation, where git log --graph has given the text below (which I've modified just a bit).让我们回到您的特定情况,其中git log --graph给出了下面的文本(我只是对其进行了一些修改)。 It's a bit hard to turn sideways (the other graphs above have predecessor commits on the left, and successors on the right, while the git log --graph output has predecessors below and successors above), but I'll take a quick stab at it, by adding single-letter codes for each commit:侧身有点困难(上面的其他图表左侧是前任提交,右侧是后继提交,而git log --graph输出有下面的前任和上面的继任者),但我会快速尝试一下它,通过为每个提交添加单字母代码:

H   * 4363273 Updated Order_Entry with bulk UPDATE command
G   *   e7e0c64 Updated Order Entry module and Orders Schema
    |\
F   | *   2cff23e Merge branch 'order_schema'
    | |\
E   | | * 104b2ce Orders Schema
D   | * |   afa1b7b Merge pull request #18 from project/bugfix/mockvenue
    | |\ \
    | | |/
    | |/|
C   | | * 4b2c8d8 Return correct string in mock venue API
    | |/
B   * | f7d57cf Order Entry updated to handle and log responses from LC
    |/
A   *   8ed2260 Merge pull request #17 from project/mockvenue

Now with A as the leftmost commit and H as the rightmost:现在A作为最左边的提交, H作为最右边:

    C---D
   /___/ \
  //__--E-F
 ///       \
A-----B-----G--H

The direct (first-parent) line of ancestry goes from H to G , then to B , then to A .祖先的直接(第一亲)血统从HG ,然后到B ,然后到A This means that HEAD~5 is a commit we can't even see (two to the left of A ), and git rebase -i HEAD~5 should list all of these commits except for merges ( D , F and G ).这意味着HEAD~5是我们甚至看不到的提交( A左侧的两个),并且git rebase -i HEAD~5应该列出所有这些提交,除了合并( DFG )。 That would be five commits: A , B , C , E , and H .这将是五个提交: ABCEH But based on its log message, A is also a merge.但根据其日志消息, A也是一个合并。 We're missing information here and can't draw the complete graph (which is just as well since the compact form has a lot of lines in it).我们在这里缺少信息并且无法绘制完整的图形(这也很好,因为紧凑形式中有很多线)。

In any case, this is in fact what's happening.无论如何,这实际上就是正在发生的事情。 The rebase command finds commits to cherry-pick by listing every commit reachable from the tip commit ( HEAD , which is commit H ) that is not reachable from the first excluded commit ( HEAD~5 , a commit two steps to the left of A , so we can't see it). rebase命令通过列出从第一个排除的提交( HEAD~5A左侧两步的提交)无法到达的提示提交( HEAD ,即提交H )中可到达的每个提交来查找对cherry-pick的提交,所以我们看不到它)。 It then throws out merge commits and will cherry-pick each remaining commit to build a new, linear branch.然后它抛出合并提交,并会挑选每个剩余的提交来构建一个新的线性分支。

Whether this makes sense, and which commits you should cherry-pick, are not something anyone else can answer for you.这是否有意义,以及您应该挑选哪些提交,其他人无法为您回答。

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

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