有人问我是否可以修改 git 历史记录中包含其他开发人员不适当措辞的项目的一组签入注释。
有人可以告诉我如何实现这一点(或确认这是否不可能)?我是 TFS 的管理员,所以访问权限不是问题。我们的 TFS 使用 SQL Express 和 GIT 作为源代码控制。TFS 版本为 15.117.26714.0
我们在本地机器上使用 Visual Studio 2017 和 Team Explorer 插件。
有人问我是否可以修改 git 历史记录中包含其他开发人员不适当措辞的项目的一组签入注释。
有人可以告诉我如何实现这一点(或确认这是否不可能)?我是 TFS 的管理员,所以访问权限不是问题。我们的 TFS 使用 SQL Express 和 GIT 作为源代码控制。TFS 版本为 15.117.26714.0
我们在本地机器上使用 Visual Studio 2017 和 Team Explorer 插件。
可以做到,但可能会很麻烦。根据审计规则的性质,您可能会考虑 git notes 是否提供更好的解决方案。(如果您只是缺少信息,并且如果您的审核员会同意,那么添加注释可以让您在最小的干扰下放入附加信息。如果您需要删除信息 - 如果有人输入密码或组织上不可接受的语言, 或任何信息 - 那么这将无济于事。)
您可能会注意到,其他一些源代码控制系统允许您更自由地编辑提交消息。我不想在此基础上为我的团队做出源代码控制工具的决定,但如果这是您的团队经常需要的,这是一个考虑因素。或者,更好的办法是弄清楚是否需要调整任何东西,这样就不会成为未来的频繁要求。
(在某种程度上,这可能是关于提交消息中需要和/或禁止的内容的培训问题。您可能能够使用挂钩设置某种护栏 - 如果您的托管环境,预接收挂钩是最重要的将让您配置一个,并且预先提交钩子为开发人员提供了一个很好的便利,以确保任何错误“快速失败”。)
问题是提交消息是提交的一个组成部分。当您修改提交的消息(我们称之为P
)时,您实际上是在创建一个新的提交 ( P'
)。此外,如果您有一个提交C
并且您想将其父级从 更改P
为P'
,那么您必须将其替换为新的提交C'
。
修改提交与用新提交替换它们之间的区别听起来并不大,但实际上这意味着您正在从已发布分支的历史记录中删除原始提交,这就是问题所在。
要进行清理,请从任何克隆开始。假设我们有以下内容,其中未命名为“x”的提交有错误的提交消息。
x -- x -- x -- A <--(master)(origin/master)
\
x -- x - x -- B -- x <--(branch1)(origin/branch1)
\ /
x -- C -- x <--(branch2)(origin/branch2)
修复A
不是太难。
git checkout master
git commit --amend
将显示一个编辑器,您可以重写提交消息。(或者您可以包含git commit
诸如-m
指定提交消息之类的选项。)然后您就有了
A' <--(master)
/
x -- x -- x -- A <--(origin/master)
\
x -- x - x -- B -- x <--(branch1)(origin/branch1)
\ /
x -- C -- x <--(branch2)(origin/branch2)
请注意,它A
仍然存在并且origin/master
仍然指向它。这个很重要。这意味着当您要更新时,origin
您必须说
git push -f
这将“破坏”其他所有人的克隆。有关问题和典型清理过程的更多信息,请参阅“从上游 Rebase 恢复”下的git rebase
文档 ( https://git-scm.com/docs/git-rebase );但还要注意,如果结果证明这会重写大部分 repo,您可能希望遵循如下的转换过程:
origin
,因为无论如何,你已经清理了一个提交。到B
. 这次它不是分支提示,所以amend
不是要使用的东西。而是做一个rebase
.
git rebase -i branch1~2 branch1
您将获得一个“待办事项”列表,其中显示了在branch1
. 找到 的条目B
并将行的开头从 更改pick
为reword
。然后让 rebase 继续,当它到达时,B
它会给你一个提交消息的编辑器。最后你有
A' <--(master)
/
x -- x -- x -- A <--(origin/master)
\
x --- x --- x -- B -- x <--(origin/branch1)
\ / \
\ / B' -- x' <--(branch1)
\ /
x - C -- x <--(branch2)(origin/branch2)
A
不比;差太多。您由于重新设置而重写了x
提交,但最终它仍然只是强制推送的另一个参考。
现在呢C
?好吧,C
可以从多个 ref 访问,并且对于其中一个提交,它们之间有一个合并。这些因素使得rebase
正确使用变得更加困难。在这种情况下,您可能需要使用git filter-branch
. (如果您有任何案例让您使用filter-branch
,那么您可能会考虑只做一个filter-branch
来完成所有重写,而不是搞乱个人rebase
或amend
操作。)
问题在于如何编写msg-filter
. 您可以编写一个脚本来检查提交 ID,对于每个已知的“错误”提交输出相应的新提交消息,而对于其他所有内容,只需cat
返回原始消息。或者你可以为每个提交启动一个编辑器,如果没有太多的提交不实用的话。或者介于两者之间(为每个 ID 在某个列表中的提交启动一个编辑器)。有太多的方法和太多的原因会影响使用哪种方法,无法在此答案中详细说明。
假设你整理了一个过滤器脚本,你会做类似的事情
git filter-branch --msg-filter=my-filter-script -- --all
The full diagram for this result gets messy, but basically for the local branches C
is replaced with C'
, everything that can reach C
is similarly replaced, and each branch from which C
is reachable needs to be force pushed.
从命令行,您可以使用
git rebase -i <sha-hash of the first commit to edit>~
(注意末尾的波浪号。您必须按字面意思输入。)
键入此内容后,将打开一个文本编辑器,其中包含所有提交的列表以及如何处理它们的命令。该命令默认为pick
. 对于您要编辑的内容,请选择reword
。然后保存文件并关闭文本编辑器。现在,对于您选择改写的每个提交,编辑器将再次打开并允许您编辑提交消息。编辑后,只需保存并关闭即可。
请注意,这将从您开始时重写整个 git 历史记录。之前已将此历史记录提取到本地存储库的任何人都需要git fetch
然后git reset --hard <branch name>
. 如果他们没有这样做,那么有问题的提交将在他们继续工作时保留在 repo 中。