如何修复git历史记录并正确合并无关的历史记录

时间:2019-09-20 02:49:37

标签: git

我有一个Git存储库,其中包含两个不相关的历史记录,如下图所示:

* commit a577995ec16ae05c2f81adfdba5ce28e7b8ba150
(A)
|
*   commit d89ddb17122ab9eea72e7006461cb04a5a879770
|\  Merge: 95febfb f85c1bb
| |
| * commit 97b8dc2f7cf7e81d75fee5565423b554d191e4f3
| |
| * commit c86ff8d4695f63c30ba096a5a71ab8f50536a31c
| (B)
|
* commit a577995ec16ae05c2f81adfdba5ce28e7b8ba150
|
* commit 53c3a6a895c2732c8262e6467b586284fbe7c79d
(C)

注意,我在图中已在Git历史记录中标记了A,B和C三个点,以便在本文中可以参考它们。

从C和B开始的两个历史是无关的,并且作为两个完全独立的Git存储库开始了它们的生活。然后以未知的方式合并历史记录(但已知涉及git filter-branch)。

我的问题

如果我在历史记录的(A)点检出,则在git log和其他命令中会错误地显示在C点创建的文件,就像它们是由合并提交fe63b2f添加的一样。因此,诸如git show,git blame之类的git命令以及其他命令都无法告诉我这些文件的真实历史记录。但是它们确实向我展示了在(B)点添加的文件的真实历史记录。

更多观察结果

Git show-名称状态

如注释中所建议,如果我在合并提交上运行它,我会看到:

$ git show --oneline -m --name-status d89ddb17122ab9eea72e7006461cb04a5a879770
d89ddb1 (from 95febfb) Merge branch 'master' of ../jenkins into alex/jenkins
A       files_from_C
A       more_files_from_C
D       jenkins/files_from_B
D       jenkins/more_files_from_B
d89ddb1 (from f85c1bb) Merge branch 'master' of ../jenkins into alex/jenkins
A       files_from_C
A       more_files_from_C

我将实际输出作为要点here

Git日志--name-status --full-history-关注v Git日志

有关在C创建的文件的Git日志的更多信息。一个普通的git日志:

$ git log TODO.md
commit 989011e2dee59f9502c369d8fac58b2b947ab4e6
Author: Alex Harvey <redacted>
Date:   Sat Sep 14 00:51:53 2019 +1000

    Some other commit

commit d89ddb17122ab9eea72e7006461cb04a5a879770
Merge: 95febfb f85c1bb
Author: Alex Harvey <redacted>
Date:   Wed Sep 11 12:18:54 2019 +1000

    Merge branch 'master' of ../jenkins into alex/jenkins

但是使用--all --name-status --full-history --follow --,我可以看到所有历史记录:

$ git log --all --oneline --name-status --full-history --follow -- TODO.md
989011e Add autogenerated helpers documentation
M       TODO.md
8766c98 Remove shunit2/_include.sh
M       TODO.md
15bf859 Remove shunit2/_include.sh
M       TODO.md
65ee7e5 Remove shunit2/_include.sh
M       TODO.md
2c601af Remove unused invalid_ami_stacks variable
M       TODO.md
d347137 Resolve unprintable characters in README
M       TODO.md
dc7068d TODO.md
M       TODO.md
etc

我的问题

有没有一种方法可以编辑此历史记录,以便git show,git blame和其他文件可以揭示所有此回购文件的真实历史记录,无论它们是在(B)还是创建的(C)?

2 个答案:

答案 0 :(得分:1)

根据@torek的观察,我发现了一种“解决”此问题的方法,该方法似乎很简单。

再次使用此示例:

* commit beb7ea3351f50dd29899baa878ea2fa29c437ecc
(A)
|
*   commit ed3fef629f8d7268fe29c37029977443eea46494
|\  Merge: d8cf79f ed3fef6
| |
| * commit 820bea750c86c90443ca1068e08d6b72cbe317ca
| |
| * commit 19efa83244f1e19976b0e543bf391099bcc1b056
| (B)
|
* commit d8cf79f2103b7d25e6c4dbb96bbd3f672d30bae8
|
* commit fc4c8d8cb9df4c3ee892f0f0f691c71526668d55
(C)

我定义:

pointA=beb7ea3351f50dd29899baa878ea2fa29c437ecc
pointC=d8cf79f2103b7d25e6c4dbb96bbd3f672d30bae8
merge_commit=ed3fef629f8d7268fe29c37029977443eea46494

然后我使用git replace:

▶ git replace -f --graft "$pointA" "$pointC" "$merge_commit"

这表示使都成为C点,并且合并提交成为提交A的父项。

我的新图形如下:

▶ git log --graph 
*   commit beb7ea3351f50dd29899baa878ea2fa29c437ecc (HEAD -> master, replaced)
|\  Merge: d8cf79f ed3fef6
| | 
| *   commit ed3fef629f8d7268fe29c37029977443eea46494
| |\  Merge: d8cf79f 820bea7
|/ /  
| * commit 820bea750c86c90443ca1068e08d6b72cbe317ca
| | 
| * commit 19efa83244f1e19976b0e543bf391099bcc1b056
| 
* commit d8cf79f2103b7d25e6c4dbb96bbd3f672d30bae8
| 
* commit fc4c8d8cb9df4c3ee892f0f0f691c71526668d55

我想这比“需要”要复杂得多,但是好的部分是我所有的命令git log,git blame等,都向我显示了B点和C点的文件中已纠正的历史记录。

最后,如@VonC所述,并在@torek的答案here中进行了更详细的解释,这仅替换了本地引用。

由于我想强制推送并强制所有人克隆历史记录的新版本,因此我需要使用以下内容过滤分支:

▶ git filter-branch --tag-name-filter cat -- --all

答案 1 :(得分:0)

您的要旨显示TODO.md文件存在于合并提交d89d中,而在任一合并父级中都不存在,与git loggit show等完全相同告诉你。该文件是在该合并中手动添加的,原因是您必须从合并作者中查找原因。因此,在C根目录与合并之间的某个位置有人创建了TODO.md,而在此目录与合并之间的某个位置有人删除了它(出于某种原因,您必须从该提交的作者那里找出来)。与B根相同。然后,进行合并的人都会在合并期间创建新的TODO.md

这就是发生的事情,那是Git告诉您的事情,这就是记录的历史记录:文件是在合并中添加的。如果删除早期文件的人应该做一些不同的事情,如果这些文件被错误地删除,请返回并从最后一次正确的提交开始,然后进行应做的提交,这就是您“修复”历史记录的方式不需要,您可以记录所需的历史记录。