Git 在合并过程中忽略删除的文件夹?

Git ignore deleted folders during a merge?

开发人员一直在开发从 master 分支出来的某些功能分支 f1

由于repo的模块化不好(系统是模块化的,但生活在一个整体的repo中)等原因,开发者决定删除"a bunch of irrelevant stuff"(与他的功能无关的其他模块)在f1支线。功能单元测试成功,但分支现在包含系统的整个其他模块的所有这些删除。

在忽略文件夹删除的情况下将 f1 合并回 master 的最简单、最轻松的方法是什么?假设在 f1 中修改的一些文件也在 master.

的演变中被修改

附加要求 f1 分支的工作可能需要在合并后继续一段时间。我不太确定到目前为止提出的答案会如何影响它。

假设源历史的质量是重中之重,我建议重写 F1 的历史以排除删除。任何 "painless fix" 都会留下奇怪的删除和添加,这将使未来对项目演变的分析变得复杂。

(顺便说一句,删除 "parts of the project I'm not working on" 的做法在客观上是不正确的。请参阅 "sparse checkout" 以获得客观上不正确的潜在解决方案。)

拥有 F1 分支副本的开发人员越多,任何人基于 F1 分支所做的更改(如果有的话)越多,历史重写就越乏味是。但是,如果这是一个仅由一个开发人员处理的功能分支,并且没有将该功能的合并推送到源,那么它可能会相当简单。

如果F1本身是线性的,一个变基就可以了。例如

x -- x -- x -- x <--(master)
      \
       A -- B -- C <--(F1)

因为 master..F1(可从 F1 访问但无法从 master 访问的提交集;ABC 在本例中)不包括任何合并,并且没有其他分支基于 master..F1 中的任何提交,这是变基的简单情况。

git rebase -i master f1

您将看到一个 "TODO" 列表,其中包含 F1 上的每个提交的条目。将第一个提交的命令从 pick 更改为 edit。退出编辑器,变基开始。

在暂时接受 A "as is" 后,rebase 会暂停并提示您。现在您需要放回已删除的文件。您可以使用类似 git show --name-status 的内容来识别已删除的文件,并使用 git checkout HEAD^ -- path/to/deleted/file/or/directory 来恢复已删除的内容。

恢复所有文件后,git commit --amend。然后继续rebase。

还有其他方法也可以使用;这是最简单的情况之一。

rebase 后,如果 F1 曾经被推送过,那么你可能需要强制推送它。 git push -f 此时任何在本地存储库中拥有 F1 副本的人都需要恢复(请参阅 git rebase 文档中的 "recover from upstream rebase")。如果有人基于 F1 工作过,他们将不得不将其重新设置为新的 F1.

您应该能够完成对新 F1 的合并,而不会出现删除问题。

我希望我的 git-fu 达到标准。
假设MERGE_SOURCE是你要合并的分支,这里F1PRESERVED_PATHS是需要恢复的路径列表:

# Find out the commit from which F1 forked
MERGE_SPLIT_POINT=`git merge-base HEAD ${MERGE_SOURCE}`

# Rewrite the branch's history to unstage all changes
# (including removals) of the preserved paths
git filter-branch \
    --index-filter 'git reset ${MERGE_SPLIT_POINT} -- ${PRESERVED_PATHS}' \
    -- ${MERGE_SPLIT_POINT}..${MERGE_SOURCE}

# Regular merge with the resulting new branch
git merge ${MERGE_SOURCE}