当重命名的文件很常见时,可以选择git cherry pick

当重命名的文件很常见时,可以选择git cherry pick,git,git-rebase,cherry-pick,renaming,git-cherry-pick,Git,Git Rebase,Cherry Pick,Renaming,Git Cherry Pick,我想从一个分支到另一个分支挑选单个提交。 我希望文件重命名非常常见,但仍然希望能够在没有人为干预的情况下应用更改 因为内置的cherry-pick命令不能检测重命名(至少在我的测试用例中是这样),特别是当与对重命名文件的修改结合使用时 我试了一下,最后想出了一个解决方案,包括两个重基操作 假设我有一个名为target的分支,它指向我要应用cherry pick的提交。 我要挑选的提交由名为source的分支指向 然后执行以下命令: 创建与源指向同一提交的分支sourceTemp(因为我想保留分支

我想从一个分支到另一个分支挑选单个提交。 我希望文件重命名非常常见,但仍然希望能够在没有人为干预的情况下应用更改

因为内置的cherry-pick命令不能检测重命名(至少在我的测试用例中是这样),特别是当与对重命名文件的修改结合使用时

我试了一下,最后想出了一个解决方案,包括两个重基操作

假设我有一个名为target的分支,它指向我要应用cherry pick的提交。 我要挑选的提交由名为source的分支指向

然后执行以下命令:

  • 创建与源指向同一提交的分支sourceTemp(因为我想保留分支源)
  • git rebase--strategy=“recursive”--strategy option=“rename threshold=30”target sourceTemp
    (可能使用另一个阈值;测试文件非常小,因此更改相对较大)
  • git-rebase——到目标sourceTemp~sourceTemp
  • 这仅应用分支目标中上次提交引入的更改

    我还将测试放在github上:

    我想知道的是,这种方法是否可行,或者它是否只在我的简单测试环境中起作用

    更新:替代方法

    我将补丁重新设置为目标的合并基:

    起始情况

        A - B     <--- target
       /
      M 
       \
        C - D     <--- source
    

    A-B您的
    rename threshold
    方法对于您正在尝试的操作是可行的。除非您的分支是永远不会合并的分叉项目,否则在分支之间定期挑选的书面文档永远不会是可持续的工作流。如果是这样的话,走吧,祝你好运。如果您希望将分支合并回一个有凝聚力的整体,我建议您更改代码的流动方式。以下是一些关于这方面的优秀资源:

  • 在分支之间进行常规的樱桃采摘会生成具有不同SHA1散列的相同更改集。在足够长的时间内进行足够大的扩展,跟踪代码变得很困难,理解您的历史变得几乎不可能,合并分支会让您感觉昏昏欲睡,在一个非常糟糕的时刻醒来

    基于你对这个答案的评论,你的用例听起来像是一个可行的樱桃采摘。在这种情况下,我建议使用一种稍微不那么费力的方法将修补程序集应用于重命名的文件:

    git checkout branchB
    git diff <commit>~1 <commit> |
        sed 's:<path_on_branchA>:<path_on_branchB>:g' |
        git apply
    
    git签出分支
    git-diff~1|
    sed's:::g'|
    git应用程序
    
    其中,
    是要从
    branchA
    移动到
    branchB
    的提交。使用此方法,您将无法获得提交元数据,也就是说,它只会应用更改,而不会提交更改。但是,您可以使用
    sed
    gitam
    轻松地操作
    git格式补丁的输出。这取决于你想做什么


    这将为您节省生成临时分支、选择正确的重命名阈值和重定基址的麻烦。它永远不会像直接的
    git merge
    那样干净,但我以前使用过它,一旦掌握了窍门,它就非常容易了。

    git-rebase
    使用与
    git-merge
    相同的重命名检测逻辑,甚至使用相同的选项
    --strategy option=“rename-threshold=30”
    来控制它

    这里发生的事情是,首先将整个源分支重设到目标分支上(如
    sourceTemp
    ),然后选择最后一次提交到
    target
    。顺便说一句,
    git-rebase-on-target src~src
    与在
    target
    上执行
    git-cherry-pick src
    相同:在
    src
    上执行一次提交,并将其应用于
    target


    与直接挑选相比,您的工作流的变化在于,您逐渐处理源分支上的提交,这可能比一步完成所有操作更容易捕获重命名。如果您直接选择,则必须通过查看
    target
    src~
    之间的差异来识别重命名,这可能是一个漫长的过程;当第一次对整个源分支重定基时,重命名会以小步进行处理。

    有时,文件分歧太大,因此任何重命名算法都无法准确确定重命名,因此我使用“锤子方法”

    git checkout target
    
    # Make an artificial merge to link target and source's parent
    git merge source^ --strategy=ours
    
    # Equivalent to cherry-pick but includes rename detection
    git merge source --no-ff
    
    # ... fix all merge conflicts and finish the merge
    
    # Get rid of those artificial merges preserving file changes
    git reset --soft HEAD~2
    
    # Make a commit to store cherry-picked files
    git commit -m "Cherry-pick source branch"
    

    我知道樱桃采摘、重定基槽和这类材料应小心使用,而不是标准操作。如果我想同时维护多个“主”分支(因为确实有多个软件产品),并且我想包含一个从一个项目到其他项目的补丁,你会有什么建议?它们是你不想合并的不同分支吗?如果是这样,你的方法也不错。我个人会为每个项目维护不同的存储库,而不是不同的分支,并使用github或gitorious的合并请求之类的东西,或者如果我没有一个奇特的git服务器,只使用
    git diff | sed-e的/one file/one other/'| git apply
    。真的,这对你来说是最有意义的。如果你打算合并这些项目,我只想向你挥手告别。是的,我不打算完全合并它们。它们代表了一系列机器变体的软件。因为它们的机器硬件不能“合并”;-),他们的软件也不会这样。但我想以某种方式管理软件的公共部分。由于软件必须以特定的方式进行布局,所以我没有完全的方法选择。该软件是一种早期的Pascal软件,因此有时需要复制粘贴调整不同的版本。对于这些文件,我希望能够进行cherry-pick
    git checkout branchB
    git diff <commit>~1 <commit> |
        sed 's:<path_on_branchA>:<path_on_branchB>:g' |
        git apply
    
    git checkout target
    
    # Make an artificial merge to link target and source's parent
    git merge source^ --strategy=ours
    
    # Equivalent to cherry-pick but includes rename detection
    git merge source --no-ff
    
    # ... fix all merge conflicts and finish the merge
    
    # Get rid of those artificial merges preserving file changes
    git reset --soft HEAD~2
    
    # Make a commit to store cherry-picked files
    git commit -m "Cherry-pick source branch"
    
    git checkout target
    
    # get list of files modified in source branch
    git diff source^ source --name-only
    
    # ... (A) rename corresponding target files to match source's ones (possibly write script to automate this)
    
    git add -A
    git commit -m "Temporarily rename files for cherry-pick purposes"
    
    # There is no need for rename detection anymore
    git cherry-pick source
    
    # ... resolve all conflicts and finish the cherry-pick
    
    # ... rename files back, reverting (A) step. Note that you cannot use `git revert` here
    
    git add -A
    git commit -m "Rename files back"
    
    # Get rid of the artificial commits made but preserve file changes
    git reset --soft HEAD~3
    
    # Make a commit to store cherry-picked files
    git commit -m "Cherry-pick source branch"