代码之家  ›  专栏  ›  技术社区  ›  Chris Harris

如何将修补程序应用到以前的修订版?

git
  •  8
  • Chris Harris  · 技术社区  · 15 年前

    A - B - C - D
    

    在B和C之间,我修改了一堆文件,包括一个特定的文件,称之为foo.txt。

    然后,在修订版D上,我修改了同一个文件foo.txt。

    与此同时,我的一个朋友在B上截取了我的目录快照,决定用某种方式修改foo.txt。我们将其称为修订版E。如果它们是同一存储库的一部分,它们将如下所示:

    A - B - C - D
         \
          E
    

    由于我也处理过foo.txt,我不能直接将补丁应用到D,diff的上下文不匹配,它希望我在B或B附近。

    似乎我想创建上面提到的假设存储库树,然后在这个存储库中的D和E之间进行合并,以便以正确的顺序将我的更改C和D一起回放。

    所以我的问题是:

    • 这是根据历史“基线”应用更改的最合理方法吗?
    • 如何在git中干净地完成此任务?
    3 回复  |  直到 15 年前
        1
  •  8
  •   Cascabel    15 年前

    你确实想利用git的合并功能。仍然有一些可能性。最能说明实际情况的可能是合并,但是一个方法导致了 E 应用于 D 也没那么糟。让我们谈谈怎么做!

    git format-patch 是的),那么 git am 能够尝试三方合并!diff中的blob SHA1记录如下:

    diff --git a/foo.txt b/foo.txt
    index ca1df77..2c98844 100644
    

    git am --3way <patch> . 不幸的是, 吉特·阿姆 git diff 而不是 git格式修补程序 ,你得稍微犹豫一下。您可以自己添加:

    From: Bobby Tables <bobby@drop.org>
    Date: 2 Nov 2010
    Subject: [PATCH] protect against injection attack
    
    <original diff>
    

    吉特·阿姆 git commit --amend 把它修好。(您也可以尝试使用 git apply --build-fake-ancestor=foo.txt <patch> ,但它实际上并不以用户友好的方式工作。我认为欺骗 吉特·阿姆

    如果修补程序不包含任何blob sha1(即,它是用diff创建的,而不是git命令),请再次告诉您的朋友如何使用git,我确信您可以 仍然

    git ls-tree <SHA1 of B>:<directory containing foo.txt>
    

    它会是名单上的一个。(我知道有一个直接的方法,但我现在想不出来)然后可以添加一个假的git diff头。假设其哈希值为abcdef12:

    diff --git a/foo.txt b/foo.txt
    index abcdef12..
    

    Git实际上不需要任何东西,只需要第一个散列;尽管Git diff输出将具有最终散列和模式, am 不是在找它,所以你可以离开它。(是的,我刚测试过这个。我以前没做过!)

    A - B - C - D - E' ,其中 E' 是你朋友的补丁,但应用于 ;这是在 , B ,还有你朋友的补丁。

    最后,如果你不想到处乱搞,你可以照你说的做:

    git checkout -b bobby <SHA1 of B>
    # apply the patch
    git commit --author="Bobby Tables <bobby@drop.org>"
    git checkout master
    git merge bobby
    # or `git cherry-pick bobby` to grab the single commit and apply to master
    # or `git rebase bobby master` to rebase C and D onto B
    
        2
  •  1
  •   Charlotte    15 年前

    我已经看了一眼,我发誓一定有办法在git中自动完成这项工作,但现在你最好的选择可能是照你说的做。

    B 有身份证 12345... :

    $ git checkout 12345
    Note: checking out '12345....'.
    
    You are in 'detached HEAD' state. 
    [...]
    $ git checkout -b friends_change
    $ git apply < patchfile.patch
    $ git status
    [... something interesting ...]
    $ git commit -m "Applying friend's patches to foo"
    $ git checkout master
    $ git merge friends_change
    

    $ git rebase friends_change
    

    这将创建如下树:

    A - B - C - D (old master)
         \
          E - C' - D' (new master)
    
        3
  •  0
  •   barefootcoder    7 年前

    我有一个和这个问题非常相似的问题,这些答案对我指出正确的方向很有帮助。然而,在我的案例中,我真正想得到的是:

    A - B - E - C - D
    

    首先,这些承诺都还没有被推到任何地方,所以重新调整是安全的。如果提交已经被推送,因此可能被分发,我就不会尝试这样做。

    git checkout -b temporary <B-sha1>^
    git am <E-patchfile>
    git log --oneline -1
    

    现在复制粘贴SHA1并提交消息。

    git checkout <orig-branch>
    git rebase -i <B-sha1>^
    

    现在,在适当的位置(应该是第2行)添加以下行:

    pick <E-sha1> <E-commit-msg>
    

    省省吧,让回扣做它的事情,解决任何冲突,你通常会。最后:

    git branch -d temporary
    

    因为分支删除不会使补丁提交悬空,所以不需要使用 git branch -D ,并使用 -d

    希望这对其他人在类似我的情况下有帮助。