4

所以我只是为我们的一个文件打了补丁,我看到了一些不应该存在的代码(加上这个流氓代码导致的网页错误)。该代码是几个月前在补丁中添加的,然后在大约一个月前被该提交的还原删除。所以它真的不应该在那里。

我尝试了几种方法来追踪它的来源:

  1. git blame:奇怪的是,向我展示了添加代码的原始提交的提交标记和消息,就好像还原从未发生过一样。
  2. git log -- 文件名:显示了我预期会出现的所有提交,包括还原,但之后没有任何内容表明它应该重新出现。
  3. 手动检查补丁(二等分):代码在还原后直接重新出现在提交中,但是当我检查该补丁时,它的日志完全不同,并且没有还原。

最后的观察让我得出结论,有问题的补丁是一个拙劣的合并,但提交消息没有提到合并,我们的团队通常保留 git 生成的合并消息。

看起来是这样吗?在解决冲突期间做出错误的选择是否重新引入了代码?如果是这样,有没有更快的方法来找到这种东西?例如,git blame 说代码来自我原来的补丁。但是有没有办法让它直接告诉我它在恢复后在补丁 X 中重新引入?如果 git 不知道在合并期间受到影响,它如何跟踪每段代码的来源?它是否能够告诉我有人在合并冲突期间弄乱了那段代码?我认为合并本身应该出现在指责中。

4

2 回答 2

4

这看起来像是一个确定的案例

git合并,然后revert,再revert再revert

意思是:你不应该真的像以前那样恢复合并提交。取而代之的是“重置--hard”到之前的点。其他低级技术确实适用,但我只建议在您绝对无法承受非快进推送的情况下查看这些技术(git 重置为较早的提交将导致在推送以后的新工作时“强制”推送)。

revert 所做的是恢复内容。但是,原始合并提交仍会将合并源显示为父提交。这个傻瓜会认为远程分支已完全合并,即使内容已被还原(!)。伴随着所有可能的恶劣后果。

git show-branch mybranch previouslymergedbranch`

git log --no-walk $(git merge-base -a mybranch previouslymergedbranch)

向您展示关系应该很有启发性


@Tesserex 好的......,我说“看起来像”:)

仍然有可能你已经被 git[1] 的奇妙但必然不完美的合并跟踪(碱基检测)所困扰。也许您可以在合并时查看 show-branch 和 merge-base 的输出。如果这是最后一次合并,您可以

git rev-list --merges --parents -1 mybranch

这应该返回三个 sha1: <mergecommit> <mergetarget> <mergesource>。这里,mergecommit 只是发生合并的时候,mergetarget 是'mybranch',mergesource 是'previouslymergedbranch',所以你可以运行上面的命令。

有可能弹性提交(您已恢复)仍在等待合并(根据 git),因此已全部合并,撤消您的“恢复”撤消......这可能由于多种原因而发生(例如原始提交已手动传输或存在冲突的樱桃选择,使得 git 无法检测到该提交已应用于合并目标)

我什至不确定 git 是否会在合并(提交序列)中间主动检测非冲突(“纯”)cherrypick;虽然它肯定可以:

git log --left-right --oneline --cherry-pick --graph --boundary mergetarget...mergesource

这将向您展示 git 在合并时两个 ref 之间的“提交”中的增量。git-log 的手册页解释说 --cherry-pick 告诉 git 从输出中消除提交,即使它们具有不同的提交 ID(哈希),但差异对于所有意图和目的都是相同的。


[1] OT:这是个难题:我们可以让软件更智能,但只要有泄漏的抽象,就会有麻烦:

  • git中的合并跟踪不是密封的
  • git 合并补丁集以重放提交,但仅将所有数据存储在快照中;这在恢复合并提交时会出现,例如,当使用嫁接来“伪造”历史关系时

一般的经验法则似乎是:最精致的工具会导致更少的问题。然而,当抽象中断时,狗屎将只是精致的品种:)

于 2011-04-06T21:39:53.773 回答
0

我遇到了这个问题,在未与 master 合并的分支上添加了一个文件,后来又将其删除,但 master 已合并回功能分支,并且在切换到该分支和从该分支切换时该文件不断重新出现。我用 rebase squashing 两个提交来修复它,这两个提交添加和删除了“幻像”文件。我使用了我不久前编写的脚本来查找提交时的“丢失文件”或可能已删除它们的分支。

这是我用来查找文件的脚本:

git-find-file () {
    for branch in $(git log --all --oneline --no-color  -- "$1" | cut -c 1-9)
    do
        git branch --contains $branch
        echo "found $1 in $branch"
    done
}
于 2021-07-08T15:22:45.843 回答