GIT:如何合并先前从合并提交中删除的更改

GIT: how to merge changes, which were earlier removed from the merged commit

我有两个分支,develop 和 master。我想挑选一些关于从开发到大师的特定功能的提交。但是从 dev 到 master 的 cherry pick 提交数量大约是 106,这意味着我必须检查所有这些以过滤掉相关的。为了避免必须经历每个提交的更改,然后挑选单个或一系列的更改,我想走捷径 :D。我将 develop 合并到 master,合并提交中大约有 115 个文件更改。

我检查了每个文件并删除了那些与该功能无关的更改。对于某些文件,我将它们完全删除,而对于某些文件,我只进行了部分更改并删除了不必要的更改。在完成所有 115 个之后,剩下大约 55 个过滤文件,这些文件与我随后在合并提交中提交的功能相关。

现在,当我查看 master 的 git 日志时,日志显示好像所有 106 个提交都已合并到 master 中,并且在顶部显示我的合并提交名为 'merged develop into master'。 现在我想将 develop 合并到 master 中,以便实际合并我之前从合并提交中删除的剩余文件,git 说虽然两个分支之间都有变化但没有什么可合并的,但由于事实我从合并提交中删除了那些我现在无法将这些更改移动到 master 中。 我是否需要从 master 中删除合并提交,或者有什么方法可以强制完全合并差异? 为了避免任何未来的问题,这里正确的方法应该是什么?

我认为你在这里需要做的是对 develop 分支添加一个小改动(让它成为一个额外的 space)然后切换到 master git merge develop 将添加更改,包括您之前删除的已删除更改 然后 git 推 为了避免将来出现问题,我认为每个功能都应该在一个分支上,一旦完成将合并到 master

很遗憾,您的快捷方式被误用了 "merge"。当您尝试合并两个 b运行 时,遇到冲突,手动解决它们,然后提交合并,您是在告诉 Git 合并这两个 b[= 的 "correct" 方式136=]ches(和 all 在这两个 b运行ches 上的提交)是 you 选择手动解决的方式犯罪。如果您从 develop "re-merge",Git 不会否决您的手动冲突解决,因为您已经告诉 Git 正确的合并是什么,它不会尝试反驳你(好吧,除非它真的很困惑)。 Git 无法区分您为解决这两个合并所做的更改与您想要 "save for later".

所做的更改之间的区别

必须重置错误的合并,但这里是您可以相对自动地完成此操作的方法,无需大惊小怪。您提到自合并以来您在 master 上又进行了一次提交。如果那根本不存在,你可以跳过几个步骤,但我在下面给出了更通用的解决方案,如果你在 master 和 [=17= 上添加了额外的提交,它也可以工作].

我假设如下。

  • 当您创建 "bad merge" 时,您将 develop 合并到 master(即,您在 master 和 运行 git merge develop而不是相反)。
  • 您不太关心历史在这一点上的表现,您只想获得 "bad merge" 之前 develop 的 "lost" 变化(加上此后的其他更改(如果有的话)已成功合并到 master.
  • 您尚未在任何地方发布 masterdevelop,因此没有其他存储库依赖它们的历史记录。
  • 您目前 master 在干净的树中签出。

与任何混乱的 Git 操作一样,在此处对您的存储库进行完整备份(cp -agit clone mirror)是个不错的主意。

首先,我们来命名错误的合并。在您的日志中找到它的散列并为它创建一个标签。 (在您的情况下,它是 master^,但更普遍的情况是您可能需要搜索它。)

git tag bad_merge 8354cbeb
git log bad_merge  # !! double check that this points to the bad merge !!

现在,我们将检查一个新的 fix_merge b运行ch。我们将从 bad_merge:

开始
git checkout -b fix_merge bad_merge

然后,我们将 b运行ch 回滚到 "bad merge" 之前的 master 状态,但保持工作目录不变(因此它包含您手动编辑以将第一个功能添加到 master):

git reset HEAD^

我们将重新提交这些手动编辑:

git add -A
git commit -m 'fix_merge: add first feature to master'

现在,我们要做一个有点复杂的变基。 (如果自错误合并以来您在 master 上没有任何提交,则此步骤将是不必要的。)

git checkout master
git branch master_backup   # make a copy in case something goes wrong
git rebase --onto fix_merge bad_merge master

这 t运行 将 master b运行ch 从 之后 错误合并到其当前状态(即,bad_mergemaster) ONTO 我们修复的 b运行ch fix_merge 之后的树部分。 rebase之后,master会指向t运行splanted b运行ch。应该没有冲突,因为 bad_mergefix_merge 中的树完全匹配;它只是被重写的提交历史,因为一个有合并而一个没有。

我们现在有以下情况:

  • master 的历史,而不是从 develop 合并,现在只有一次提交用于您为添加第一个功能所做的手动编辑,加上自错误合并以来您在 master 上完成的额外工作。它缺少的是从 develop.

  • (严重)合并的历史
  • develop b运行ch 现在拥有第一个功能的(复杂)历史,加上您在错误合并之前开发但想要 "save for later",加上您自那以后所做的额外工作(您的情况没有,但此解决方案也适用于这些工作)。

如果您从 develop 中挑选第一个功能,这或多或少会是这样,除了它是在一次提交中挑选的,而不是多次提交。现在,如果您将 develop 合并到 master 中:

git checkout master    # probably already there, but make sure
git merge develop

并解决任何冲突——可能会有很多冲突,因为 Git 正在尝试匹配 develop b运行 中第一个功能的所有个人提交ch 与 master 中的大型整体提交,因此这是一个潜在的丑陋合并——然后您可以提交合并:

git commit

你最终应该 master 成功地与来自 develop 的所有更改合并,包括在错误提交之前和之后。

在这一点上,您可能要考虑将 master 合并回 develop 或完全放弃 develop 并从 [=18 重新 b运行ch =].