Git重新基址尝试重新基址在目标提交之前发生的提交

Git重新基址尝试重新基址在目标提交之前发生的提交,git,Git,我运行了git-rebase-I。进行更改后,我运行了git-rebase--continue。Git然后正确地重新设置了15次提交中的15次。成功执行此操作后,我收到以下错误: error: could not apply <bad hash>... <commit message> When you have resolved this problem, run "git rebase --continue". If you prefer to skip this

我运行了git-rebase-I。进行更改后,我运行了
git-rebase--continue
。Git然后正确地重新设置了15次提交中的15次。成功执行此操作后,我收到以下错误:

error: could not apply <bad hash>... <commit message>

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
Could not apply <bad hash>... <commit message>
错误:无法应用。。。
解决此问题后,运行“git-rebase--continue”。
如果您希望跳过此修补程序,请运行“git-rebase--skip”。
要签出原始分支并停止重定基址,请运行“git-rebase--abort”。
无法应用。。。
我检查了提交与
坏散列相关的内容。我发现这个提交发生在
目标哈希之前大约3个月。那么为什么git rebase甚至会涉及到这个提交呢?我认为rebase只针对当前提交到
目标哈希的目标提交

有人知道问题是什么吗?我是否对rebase有一个根本性的误解,或者有什么冲突?

TL;博士 如果没有实际的存储库,很难说清楚,但您可能会在合并过程中重定基址

长的 Rebase不查看提交日期。理解Git rebase(无论是否交互式)的关键在于:

  • 了解树枝如何生长
  • 理解git cherry pick
;及
  • 查看(并在其中选择提交)提交图,尤其是可达性的概念
  • 这些有点贵。关于可达性概念的介绍,请参阅

    理解Git提交 让我们先来看看简单提交的剖析。这里有一个来自Git存储库的Git:

    $ git rev-parse HEAD
    5be1f00a9a701532232f57958efab4be8c959a29
    $ git cat-file -p 5be1f00a9a701532232f57958efab4be8c959a29 | sed 's/@/ /'
    tree 8ccb7d4fa49449a843b00aca64baf99feb10e2ab
    parent e7e80778e705ea3f9332c634781d6d0f8c6eab64
    author Junio C Hamano <gitster pobox.com> 1516742470 -0800
    committer Junio C Hamano <gitster pobox.com> 1516742470 -0800
    
    First batch after 2.16
    
    Signed-off-by: Junio C Hamano <gitster pobox.com>
    
    这个“最后一个”指针就是Git所称的分支(或者更准确地说,分支名称)。分支名称只存储一个特定Git提交的哈希ID:即位于分支顶端的哈希ID。(因此,我们称之为提示提交。)

    要增长分支,如通过
    git commit
    ,git将首先创建新的commit,为其写出
    对象(找到树的散列),然后从已知数据创建其余的commit:树,存储在
    last one
    中的当前commit散列,您作为作者和提交者(使用“now”作为时间戳),以及提交消息。此提交进入存储库,存储库生成一个新的唯一哈希ID

    新提交
    N
    指向分支的上一个提示:

    ...--o--o--o--o   <-- last-one
                   \
                    N
    
    (然后我们可以画出这个,而不需要末端的弯曲)

    樱桃采摘:复制提交 虽然提交是快照,但我们通常喜欢将其视为更改。要将提交视为更改,我们只需先获取提交父级的快照,然后获取提交本身的快照,并进行比较:

    git diff <parent> <child>
    
    这就是cherry pick的作用:它具有复制提交的效果

    重新定基 有几种不同的重定基址用例,但它们都基于一个基本思想:我们可以复制提交。当我们进行复制时,就在实际提交(只读提交)之前,我们可以更改有关新副本的某些内容

    第一个常见的用例是移植一个分支。假设我们没有像上面那样绘制分支1和2,而是像下面这样绘制它们:

              C--D   <-- develop (HEAD)
             /
    ...--A--B--E--F--G   <-- master
    
    现在,我们在这里选择
    C
    ,制作一份
    C'
    副本,该副本位于
    G
    之后,并更新
    tmp
    以指向新副本:

              C--D   <-- develop
             /
    ...--A--B--E--F--G   <-- master
                      \
                       C'  <-- tmp (HEAD)
    
    最后,我们告诉Git将标签
    develope
    从commit
    D
    上剥下来,并将其粘贴到commit
    D'
    上,当Git处于该状态时,也扔掉临时名称,并再次使
    develope
    成为
    HEAD

              C--D   [abandoned]
             /
    ...--A--B--E--F--G   <-- master
                      \
                       C'-D'  <-- develop (HEAD)
    
    这里的
    目标
    通常是另一个分支名称。例如,为了实现上面绘制的rebase,我们将签出
    develope
    并运行
    git-rebase-master
    master
    部分告诉Git从何处开始复制临时分支所在的位置,当临时分支建立时,一个提交一个提交。但是这里缺少了一些重要的东西:git rebase如何知道要复制哪个提交?

    答案在于Git使用的更一般的技巧。您将经常看到并使用它,例如,与
    git log
    :您告诉它从何处开始,也告诉它从何处停止。如果您通过提交散列ID来执行此操作,则可以编写如下内容:

    git log master ^1234567
    
    git log master..develop
    
    它告诉它从
    master
    的顶端开始,但当它到达commit
    1234567
    时停止,不管那是什么。您可以将其改为:

    git log 1234567..master
    
    因为它们的意思是一样的:从
    master
    的顶端开始;停止使用
    1234567

    这里棘手的部分是Git不必直接遇到提交
    1234567
    本身。“stop”指令在Git到达从停止点可以到达的任何提交时停止Git。这让我们可以写以下内容:

    git log master ^1234567
    
    git log master..develop
    
    即使
    master
    包含
    develope
    不包含的提交

    在我们的例子中,
    git-rebase
    使用这个双点符号将提交
    B
    和更早的提交从复制过程中排除。(隐藏起来要复杂得多,但这一切都源于这个想法。)也就是说,我们让Git使用一个名称,
    master
    ,来选择要复制的内容和放置副本的位置:副本按照当前提示的
    master
    ,并复制可从
    HEAD
    访问的提交,但无法从
    主机的顶端访问

    如果有必要,您可以将这两部分分开,有时也是必要的:您可以使用
    git-rebase--on
    来表示副本应该在
    target
    标识的提交之后进行,但是在提交时停止
    停止时(或者从该点可以到达)应该从
    头部进行提交。这使您可以使用以下图形:

                   C--D   <-- important-fix
                  /
              A--B--E   <-- feature1
             /
    ...--o--F--G--H--I   <-- mainline
    
    Git将在
    HEAD
    akagit checkout <somebranch> # first, ensure your HEAD is attached git rebase <target> # then do the rebase-by-copy thing
    git log master ^1234567
    
    git log 1234567..master
    
    git log master..develop
    
                   C--D   <-- important-fix
                  /
              A--B--E   <-- feature1
             /
    ...--o--F--G--H--I   <-- mainline
    
    $ git checkout important-fix
    $ git rebase --onto mainline feature1
    
                   C--D   [abandoned]
                  /
              A--B--E   <-- feature1
             /
    ...--o--F--G--H--I   <-- mainline
                      \
                       C'-D'  <-- important-fix
    
                     D--E
                    /    \
                A--B      G--H   <-- feature
               /    \    /
              /      C--F
             /
    ...--o--o--o--o   <-- mainline
    
                     D--E
                    /    \
                A--B      G--H   [abandoned]
               /    \    /
              /      C--F
             /
    ...--o--o--o--o   <-- mainline
                   \
                    A'-B'-D'-E'-C'-F'-H'   <-- feature
    
    ...--o--A--B--C---F--G   <-- branch (HEAD)
                \    /
                 D--E