如何在不修改git历史记录的情况下在源代码上运行代码格式化程序?

如何在不修改git历史记录的情况下在源代码上运行代码格式化程序?,git,formatting,git-filter-branch,prettier,Git,Formatting,Git Filter Branch,Prettier,我正在尝试使用代码格式化工具格式化整个回购协议。在这样做的过程中,我希望保留关于谁提交了哪一行的信息,以便像git-dull这样的命令仍然显示正确的信息。我的意思是,它应该显示作者以前编辑过每一行(在格式化之前) 有一个git filter branch命令,它允许您从一开始就对repo的每个版本运行一个命令 git filter-branch --tree-filter '\ npx prettier --write "src/main/web/app/**/**.{js, jsx}" |

我正在尝试使用代码格式化工具格式化整个回购协议。在这样做的过程中,我希望保留关于谁提交了哪一行的信息,以便像
git-dull
这样的命令仍然显示正确的信息。我的意思是,它应该显示作者以前编辑过每一行(在格式化之前)

有一个git filter branch命令,它允许您从一开始就对repo的每个版本运行一个命令

git filter-branch --tree-filter '\
  npx prettier --write "src/main/web/app/**/**.{js, jsx}" || \
  echo "Error: no JS files found or invalid syntax"' \
  -- --all

这将需要永远运行,我真的不在乎过去。我只想在不改变每一行所有权的情况下格式化主分支。我该怎么做?我尝试在末尾使用
rev list
和其他过滤器类型,但仍然不起作用。必须有一种方法来格式化代码库,同时保留每行的作者信息。

您试图做的是不可能的。您不能在某个时间点更改一行代码,而让git报告对该行代码的最新更改是在该时间点之前发生的


我认为源代码管理工具可以支持“不重要的更改”的想法,即将提交标记为修饰,然后历史分析将跳过该提交。我不确定该工具将如何验证更改是否真的是表面的,如果没有某种形式的工具强制,该功能肯定会被误用,导致错误引入可能隐藏在“不重要”的提交中。但实际上,我认为这是一个坏主意的原因在这里是学术性的——底线是,git没有这样的特性。(我想不出有哪种源代码管理工具可以做到这一点。)

您可以继续更改格式。您可以保留过去更改的可见性。您可以避免编辑历史记录。但是你不能同时做这三件事,所以你必须决定牺牲哪一件

顺便说一句,重写历史实际上有一些不利因素。您提到了处理时间,让我们先来看看:

正如您所注意到的,使用
过滤器分支执行此操作的简单方法将非常耗时。您可以做一些事情来加速它(比如为它的工作树提供一个ramdisk),但它是一个
树过滤器
,它涉及到处理每个文件的每个版本

如果您做了一些预处理,您可能会更有效率。例如,您可以预处理数据库中的每个
BLOB
,并创建映射(其中
树包含
BLOB
X,将其替换为
BLOB
Y),然后使用
索引过滤器执行替换。这将避免所有签出和添加操作,并避免重复重新格式化相同的代码文件。因此,这节省了大量I/O。但这是一件非常重要的事情,而且可能仍然很耗时

(基于同样的原理,可以编写更专业的工具,但恐怕还没有人编写过。有先例表明,更专业的工具可以比
过滤器分支
更快。)

即使你找到了一个运行速度足够快的解决方案,也要记住,重写历史记录会干扰你所有的参考文献。像任何历史重写一样,repo的所有用户都有必要更新他们的克隆。对于这种彻底的更新,我建议的方法是,在开始重写之前扔掉克隆,然后再重新克隆

这也意味着,如果您有任何依赖于提交ID的内容,那么它也将被破坏。(这可能包括构建基础设施或发布文档等,具体取决于项目的实践。)

因此,重写历史是一个相当激进的解决方案。另一方面,假设格式化代码是不可能的,因为它不是从第一天开始就完成的,这似乎是极端的。因此,我的建议是:

在新提交中重新格式化。如果您需要使用
git-gull
,并且它将您指向发生重新格式化的提交,那么接下来在重新格式化提交的父级上再次运行
git-gull

是啊,糟透了。有一段时间。但是,一段特定的历史往往会随着年龄的增长而变得不那么重要,因此,从那时起,你就让问题逐渐消失在过去

必须有一种方法来格式化代码库,同时保留每行的作者信息

您可以做的一件事是从以前的某个提交分支,重新格式化代码,然后将
master
重设到分支。这将保留您开始提交后所有更改的作者身份

这就是你的想法,但是有一些重要的原因你不应该这么做:

  • 重定共享分支的基址是个坏主意。事实上,您甚至关心保留更改的作者身份,这可能意味着有许多人在积极地处理代码。如果你去重新设置主分支的基础,那么你回购的每个分支或克隆都会有一个具有旧历史的主分支,这必然会引起混乱和痛苦,除非你非常小心地管理流程,确保每个人都知道你在做什么,并适当地更新他们的副本。更好的方法可能是不重新设置master的基础,而是将master的提交合并到您的分支中。然后,让每个人开始使用新分支,而不是
    master

  • 合并冲突。在重新格式化整个代码库时,您可能会对几乎每个文件中的大量行进行更改。当您合并后续提交时,无论是通过
    rebase
    还是
    merge
    ,您都可能需要解决大量冲突
    --skip <REV[+]>
        revision to not display (EXPERIMENTAL)