我有一个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 --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)?
答案 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 log
和git show
等完全相同告诉你。该文件是在该合并中手动添加的,原因是您必须从合并作者中查找原因。因此,在C根目录与合并之间的某个位置有人创建了TODO.md
,而在此目录与合并之间的某个位置有人删除了它(出于某种原因,您必须从该提交的作者那里找出来)。与B根相同。然后,进行合并的人都会在合并期间创建新的TODO.md
。
这就是发生的事情,那是Git告诉您的事情,这就是记录的历史记录:文件是在合并中添加的。如果删除早期文件的人应该做一些不同的事情,如果这些文件被错误地删除,请返回并从最后一次正确的提交开始,然后进行应做的提交,这就是您“修复”历史记录的方式不需要,您可以记录所需的历史记录。