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

ahe*_*iot 19 git formatting git-filter-branch prettier

我正在尝试使用代码格式化工具格式化整个 repo。这样做时,我想保留有关谁提交了哪一行的信息,以便像这样的命令git blame仍然显示正确的信息。我的意思是它应该显示之前编辑过每一行的作者(在格式化之前)。

有 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
Run Code Online (Sandbox Code Playgroud)

运行它需要很长时间,而且我真的不在乎过去。我只想在不更改每一行的所有权的情况下格式化 master 分支。我怎样才能做到这一点?我尝试使用rev-list最后的和其他过滤器类型,但它仍然不起作用。必须有一种方法来格式化代码库,同时保留每一行的作者信息。

kxr*_*kxr 58

你(们)能做到git blame忽略某些提交,这些提交仅进行批量重新格式化等:

创建一个文件,.git-blame-ignore-revs例如:

 # Format commit 1 SHA:
 1234af5.....
 # Format commit 2 SHA:
 2e4ac56.....
Run Code Online (Sandbox Code Playgroud)

然后做

git config blame.ignoreRevsFile .git-blame-ignore-revs
Run Code Online (Sandbox Code Playgroud)

,这样您就不必--ignore-revs-file每次都使用该选项git blame

投票https://github.com/github/feedback/discussions/5033将该功能添加到 github 的网络指责查看器中。


Mar*_*ger 12

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

我想源代码控制工具可以支持“不重要的更改”的想法,在这种情况下,您将提交标记为装饰性的,然后历史分析将跳过该提交。我不确定该工具如何验证更改确实是表面性的,如果没有某种形式的工具强制执行,该功能肯定会被滥用,导致错误引入可能隐藏在“不重要”的提交中。但我认为这是一个坏主意的真正原因在这里是学术性的 - 底线是,git 没有这样的功能。(我也想不出任何可以这样做的源代码控制工具。)

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

顺便说一下,历史重写实际上有几个缺点。你提到了处理时间,所以让我们先看看:

正如您所指出的,这样做的直接方法filter-branch将非常耗时。您可以采取一些措施来加速它(例如为其工作树提供一个 ramdisk),但tree-filter它涉及处理每个文件的每个版本。

如果你做了一些预处理,你可能会更有效率。例如,您可能能够预处理BLOB数据库中的每一个并创建一个映射(其中 aTREE包含BLOBX,将其替换为BLOBY),然后使用 anindex-filter执行替换。这将避免所有检出和添加操作,并避免重复重新格式化相同的代码文件。这样可以节省大量的 I/O。但是设置起来不是一件小事,而且仍然可能很耗时。

(基于同样的原理可以编写更专业的工具,但 AFAIK 没有人写过。有先例,更专业的工具可以比filter-branch......更快)

即使您找到了一个运行速度足够快的解决方案,请记住,历史重写会干扰您的所有引用。就像任何历史重写一样,repo 的所有用户都需要更新他们的克隆 - 对于这种彻底的事情,我建议这样做的方法是,在开始重写之前将克隆扔掉,然后再重新克隆。

这也意味着如果你有任何依赖于提交 ID 的东西,那也会被破坏。(这可能包括构建基础架构或发布文档等;取决于您的项目实践。)

因此,历史重写是一个非常激烈的解决方案。另一方面,假设格式化代码是不可能的,因为它不是从第 1 天开始就不可能完成似乎也很激烈。所以我的建议是:

在新提交中重新格式化。如果您需要使用git blame, 并且它将您指向发生重新格式化的提交,然后通过git blame在重新格式化提交的父项上再次运行来跟进。

是的,糟透了。一阵子。但是一段给定的历史随着时间的推移往往会变得不那么重要,所以从那里你就让问题逐渐消失到过去。

  • “我不确定该工具如何验证更改是否确实是装饰性的”——对于代码,也许如果该工具能够比较修订版本的抽象语法树而不是文本,它就可以知道它们是逻辑上是等价的,因此是装饰性的。 (2认同)

all*_*ood 7

git blame -w -M 应该忽略空格和移动的代码更改,因此您只需要重新格式化代码并记住在寻找责任人时使用这些选项!

https://coderwall.com/p/x8xbnq/git-don-t-blame-people-for-changed-whitespaces-or-moving-code