我怎样才能对我的整个 git 历史记录进行 clang 格式?

2024-02-03

我现在已经完成了我的一个小图书馆。当我开始使用它时,我不知道 clang-format。现在我想用它格式化整个存储库。我知道随着提交哈希值的变化,这会破坏其他人的存储库。然而,由于还没有人使用我的图书馆,这对我来说没问题。

因此,我必须做什么才能为我的历史记录中的每个提交运行 clang-format ?


Git 附带了一个git filter-branch命令是帮助完成此类任务的工具。注意git filter-branch itself 不做这项工作:它只是您可以使用的一个工具,以便you可以完成这项工作。您仍然必须编写自己的命令。您最终可能会使用的是:

git filter-branch --tree-filter '<some command here>' --tag-name-filter cat -- --all

过滤器分支的作用是什么

这里有一个基本问题:任何提交一旦做出,就不能以任何方式更改。Nothing关于提交的信息可以更改:不能更改创建者的姓名、不能更改日期和时间戳、不能更改快照、不能更改其父提交的原始哈希 ID。所以git filter-branch不这样做。

相反,它所做的是提取每个提交(从某些提交集中 - 在您的情况下,您希望这组提交是all提交),一次一个,然后在提取的犯罪。无论这做什么,过滤器分支都会创建一个new从结果提交。

如果新提交与原始提交完全、完全、100% 逐位相同,则这实际上重复使用了原始提交。否则,它会使用新的不同的哈希 ID 进行新的提交。

一旦您进行了新的不同提交,每个后续提交通常至少会略有不同:它将有不同的父级。过滤器分支工具会为您处理这个重新设置父级的过程。所以它所做的两项艰巨的工作是:

  • 提取提交,运行过滤器,然后重新提交
  • 适当更新父链接

剩下的艰巨工作当然是编写和运行过滤器。那个过滤器分支留给你了。

The --tree-filter可能是最容易使用的过滤器,因此也是您想要的过滤器。值得注意的是--index-filter速度要快得多,但如果您的工作是以某种方式修改每次提交中的快照,那么使用起来就会困难得多。 Filter-branch 有很多过滤选项because --tree-filter是最慢的过滤器,因为它只适合改变快照. The --msg-filter例如,可以编辑或替换每次提交中的消息文本。只要你想跑clang-format不过,在每个快照中的所有文件上,坚持--tree-filter.

命令行部分如何工作,更详细

让我们从一个只有三个提交的示例开始,简要了解一下它在实践中是如何工作的。这三个提交有又大又难看的哈希 ID,但我们会称它们为A, B, and C为了简单起见。你从以下开始:

A <-B <-C   <-- master

分行名称master保存提交的哈希IDC,这样我们(和 Git)就可以看到哪个是last犯罪。犯罪C本身保存了commit的hash IDB,并提交B保存提交的哈希IDA,这样 Git 就可以从最后一次提交向后工作到第一次提交。犯罪A没有父母because这是第一个,因此这会让向后跟踪所有内容的操作停止。

To run git filter-branch你可能会使用:

git filter-branch --tree-filter '<command to run>' -- master

最后的事情——master—是你想要的分支名称filter-branch当它列出它应该操作的所有提交时使用。也就是说,它将开始于master然后倒退,直到不能再倒退为止。然后,它将复制每个提交,应用过滤器,然后重新提交。完成后,它将更新的一个分支名称是master.

Using --all告诉它从每个分支(以及标签和其他引用)开始,这可能会在stash参考,有时--branches --tags可能会更好,但是--all至少是传统的)。我们会回到--tag-name-filter稍后也可以选择。现在让我们继续master.

The -- before master是将放置分支名称的部分与其余选项分开,其中一些选项可能类似于有效的分支名称。这就是全部:只是标记“过滤器选项结束,分支名称开始”的样板。

最后我们看一下--tree-filter不看how编写一个树过滤器。这仅仅意味着:运行树过滤器。因此,filter-branch 会将每个提交提取到一个临时目录中,该目录只保存已提交的文件。该临时目录没有.git子目录,以及不是你的工作树。 (它实际上是-d您传递的目录,或者默认情况下,filter-branch 创建的临时目录的子目录。)您的树过滤器应该:

  • 应用您想要的任何更改
  • 到当前工作目录中的每个文件
  • 并递归地,到当前目录的每个子目录中的每个文件

例如,如果您想在每个文件中插入标题行,您可以使用:

find . -type f -print | xargs <command to insert header line in every file>

您可以将此命令放入脚本中,以便在使用前进行测试。如果clang-format有正确的选项(它可能确实如此),您可能根本不需要脚本,只需指定:

--tree-filter 'clang-format <options>'

但无论哪种方式,filter-branch 都会使用 shell 的内置功能exec运行树过滤器。因此,您必须确保您的命令包含有效的 shell 命令,并且没有return or exit其中的 shell 命令(至少在没有首先生成子 shell 的情况下)。如果您要运行的命令is您编写的脚本,请确保可以通过以下方式找到该脚本$PATH,或提供脚本的完整路径名:

--tree-filter "sh $HOME/scripts/filter-script.sh"

例如。

让我们观看一个简单的过滤器的运行过程

我们假设提交A里面有一个文件,README.md。我们假设提交B添加一个新的foo.cc将重新格式化并提交的文件C修改README.md不改变foo.cc根本不。您的过滤器只会更改任何.cc and .h文件,而不是README.md。因此,首先,filter-branch 本身枚举所有提交,并将它们按适当的顺序排列:A, then B, then C, 在这种情况下。

现在的树过滤器操作:

  • 提取提交A;
  • 在保存一个文件的临时目录中运行您的过滤器/脚本/命令README.md;
  • 根据您的命令在临时目录中留下的任何内容进行新的提交。

因为你的命令没有触及README.md,新提交与原始提交完全 100% 完全相同A。因此,过滤器分支重新使用原始提交A.

现在过滤分支移动到提交B。它提取B将两个文件放入(现在为空)临时目录并运行您的命令。这次你的命令改变了foo.cc,虽然它仍然离开README.md独自的。所以现在过滤器分支使用修改后的内容进行新的提交foo.cc。重新使用原始提交的作者姓名和电子邮件等会保留原始元数据,但现在快照已更改,因此现在我们得到一个新的不同的哈希 ID,我们将调用B':

A--B--C   <-- [original master]
 \
  B'   [in progress]

过滤分支现在继续提交C。它将所有文件提取到(重新清空的)临时目录中,因此您拥有相同的两个文件。您的过滤器现在已修改foo.cc与操作 commit 内容时的方式相同B。过滤器分支进行新的提交。新提交的快照已修改foo.cc和相同的README.md as in C-新的foo.cc匹配在B'反而-and它有一个新的父母,B', 代替B:最后一部分是过滤器分支为您处理的内容。所以现在我们有:

A--B--C   <-- [original master]
 \
  B'-C'   [in progress]

此时,我们已经用完了要复制的提交,因此过滤器分支执行最后几个技巧:

  • 如果有标签指向现有提交,and你指定了一个--tag-name-filter, Git 使new指向这些现有提交的副本的标签。任何指向的标签A可以单独留下,但如果标签指向B,filter-branch将其复制到指向的新标签B';如果一个标签指向C,过滤器分支将其复制到指向的新分支C'。这些新标签的名称来自--tag-name-filter:旧名称进入过滤器,出来的是新标签名称。

    如果你没有标签,这一切都无关紧要。

  • 然后,对于您在命令行的分支部分中命名的每个分支,filter-branch 存储该分支的哈希 ID最后复制提交到该分支。所以这里,filter-branch 设置名称master指向C'.

如果出现任何问题,过滤器分支会将所有原始分支和标记名称复制到refs/original/: 老师傅变了refs/original/refs/heads/master。如果一切顺利,你最终会想扔掉refs/original/ names.

上面的最终绘图将是:

A--B--C   <-- refs/original/refs/heads/master
 \
  B'-C'   <-- master

正如 Schwern 的回答一样,如果一切都出现严重错误,您可能希望能够恢复。一种方法是在copy(例如,克隆)存储库,而不是原始存储库。另一种方法是注意,您始终可以将所有更新的引用强制恢复为保存的方式refs/original/(但这通常需要一些编程)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我怎样才能对我的整个 git 历史记录进行 clang 格式? 的相关文章

  • 显示 master 之前/之后有多少提交分支的别名

    新的 Bitbucket Branches 页面非常棒 它显示每个分支领先 落后于 master 的提交数量 是否有显示相同信息的 Git 别名 信息应显示 分店名称 上次更新是什么时候 其背后有多少提交 有多少提交领先于 master 看
  • 有没有一个简单的命令可以将分支转换为标签?

    我即将完成将 哑快照 转换为 git 的繁琐过程 这个过程进展得非常顺利 感谢这个重命名过程 https stackoverflow com questions 6628539 how to tell git that its the sa
  • Gerrit 和 Active Directory

    我正在尝试设置 Gerrit 以使用我们的公司 Active Directory 进行身份验证 我知道很多人都设法让它发挥作用 但它对我来说不起作用 如果我运行一个ldapsearch命令如下我得到了正确的结果 所以我知道我的搜索字符串是正
  • 如何创建名称中带有正斜杠的标签

    当我已经有了类似的标签时 有什么方法可以创建名称中带有正斜杠的 git 标签吗 假设我有 1 16 0 标签 并且我想创建 1 16 0 1 0 0 标签 git tag 1 16 0 1 0 0 error refs tags 1 16
  • 如何诊断和修复 git fatal: 无法读取树

    我在用着git管理项目上的文件 并不断遇到这个问题 当我跑步时git status我收到消息 fatal unable to read tree e2d920161d41631066945a3cbcd1b043de919570 据我了解 我
  • 使用Git记录文件复制操作

    当我使用 git mv 在 git 中移动文件时 状态显示该文件已被重命名 即使我更改了某些部分 它仍然被认为几乎是相同的东西 这很好 因为它让我可以跟踪它的历史记录 当我复制文件时 原始文件有一些历史记录 我想将其与新副本关联起来 我尝试
  • Git:如何正确合并两个功能完全不同的分支?

    想象一下这样一种情况 同一个项目有两个分支 第一个分支的一部分对另一个分支进行了大幅重构 但有一段时间 您需要保持两个分支的功能 因此您需要对两个分支进行错误修复和关键功能添加 有时是以不对称的方式 在某些时候 您必须将重构的分支合并到原始
  • Gitolite git 克隆错误

    我正在尝试在我的服务器 Macos 服务器 上设置 gitolite 我按照此处找到的安装文档中的说明进行操作 http sitaramc github com gitolite doc 1 INSTALL html http sitara
  • Git checkout 不会丢弃我的更改

    我在 Windows XP 上使用 git 1 7 1 和 cygwin 这个问题可以通过例子得到最好的说明 git status On branch master Changed but not updated use git add
  • Git 认为我每次进行小更改时都在重写我的一个文件

    我有一个中等大小的 Java 文件 每次我对一个文件 BuildTable java 进行更改时 Git 都会将其报告为巨大的更改 即使只是一两行 BuildTable java 大约有 200 行 本次提交中的更改仅更改了一行 git d
  • 如何更改 GitHub 上的文件模式?

    git add test file git commit m first commit create mode 100644 test file git push git update index add chmod x test file
  • git 错误:无法处理 https

    当我尝试使用 git clone 时https xxx https xxx我收到以下错误我不处理协议 https 有人可以帮我吗 完整消息 dementrock dementrock A8Se git 克隆https git innosta
  • git-lfs 中的多个文件版本

    我正在尝试估计 GitHub 上我的项目的存储要求 并对 git lfs 如何存储多个版本的文件有一些疑问 git lfs 是否存储多个版本的文件 如果是这样 对文件的每次更改都会导致复制整个文件 还是仅存储差异 所有版本都会计入 gith
  • 为什么“git pull”在我的网络服务器上失败?

    我使用 git 来提取站点代码库的更改 文件内部的更改和文件删除是有效的 但是 当我将新文件或目录 不是空的 添加到存储库时 它不会被本地拉到网络服务器 拉动时不会显示错误消息 但在检查该文件时 它不在那里 在线的 bitbucket re
  • 如何仅根据拉取请求在 Jenkins 中运行阶段?

    我现在有一个基于 Jenkinsfile 的管道 其中包含多个阶段 每次提交到 Github 时都会由 webhook 触发 我想在每次提交时保持 构建 和 单元测试 阶段运行 但仅在分支准备拉取请求时运行 集成测试 阶段 我想要的是 st
  • PHP Github Pull 脚本错误“权限被拒绝(公钥)”

    我已经设置了一个 PHP 脚本来执行 GitHub 拉取 这包含在我的 Github 文件夹中 home mysite public html github github pull php 我的服务器已经有 SSH 公钥 就像我执行git
  • 如何将yarn add/npm install与monorepos一起使用

    我需要从 GitHub 中的私有 monorepo 下载节点包 类似于 monorepoProject subProjectA subProjectB 还有两个子项目A and 子项目B是 typescript 项目 如下图所示 subPr
  • Git worktree prune - 它有什么作用?

    我在用着git 版本 2 14 2 windows 2并调用 git worktree add
  • 如何存储和计算版本控制历史记录?

    考虑这个简单的 python 代码 它演示了一个非常简单的字典版本控制设计 def build current history current for action key value in history assert action in
  • “submodule”似乎是一个 git 命令,但我们无法执行它

    我已经克隆了一个 git 存储库 它是一个 Angular 7 和 NET Core 应用程序 项目中一切正常 但是当我尝试恢复 npm 包时 出现以下错误 Microsoft TeamFoundation Team Explorer Gi

随机推荐

  • 在 iPhone 邮件应用程序上绘制蓝色“未读点”

    有谁有如何绘制苹果邮件应用程序中使用的蓝色 未读点 的示例吗 这个具体来说 使用 Quartz2d 绘制椭圆很简单 但阴影 渐变的巧妙使用使这看起来真正的 3D 我认为邮件中的蓝点实际上是一个图像 我认为位图传送图像会比绘制渐变更快
  • 并行处理批次项目

    我有一个 ItemGroup 并且想要并行处理其所有项目 使用自定义任务或 exe 我可以编写我的任务 exe 来接受整个 ItemGroup 并在内部并行处理其项目 但是 我希望这种并行性能够与 MSBuild 结合使用 maxCpuCo
  • Selenium 缓慢向下滚动

    我正在尝试使用 Python 在 javascript 渲染的网页上进行动态网页抓取 1 但是 只有当我缓慢向下滚动页面时 才会加载元素 我努力了 driver execute script window scrollTo 0 Y 这不起作
  • 如何对 numberDisplay 的所有值求和,不包括类别

    我有一组数据 我想默认将过滤器应用到 numberDisplay 数据是这样的 data category A value 10 category B value 10 category C value 10 category S valu
  • 检查 linq 中的字符串是否为 null 或为空

    我有一个带有空格的字符串 string MyNote Convert ToString Session MyNote if MyNote null MyNote 如果字符串有更多空间 MyNote 不起作用 所以 如何在 C 中使用 lin
  • 从非模板参数化方法返回模板类型

    为了定义模板类 我考虑了三个不同的文件 该声明位于 h文件中 方法实现位于 cpp文件 并且显式实例化包含在 inc文件 通过在 cpp 末尾添加一行 例如 include bar impl inc 现在 这是我的问题 我有两个模板类 例如
  • ActiveMQ从java中删除队列

    如何从java程序中删除activemq中的队列 有类似 session delelteQueue 的东西吗 谢谢M 简单的解决方案 不使用 JMX 将连接转换为 ActiveMQConnection 并使用其 destroyDestina
  • 寻求报告服务认证建议

    我被分配负责修订当前的报告服务验证流程 目的是保持必要的安全级别 并简化授予对各个报告的访问权限的维护 配置 我无权访问域控制器来修改或创建新的 AD 组 我必须与当前存在的组 用户合作 在身份验证方面 我似乎可以选择使用以下任一方法 Wi
  • -Webkit滚动条+溢出+JQuery滚动顶部始终返回零

    我一整天都在研究这个错误 但无法解决它 有一个 JQuery scrollTop 动画脚本 它检测 window scrollTop 值并执行一些动画 如果单击按钮滚动回顶部 this click 函数 html body animate
  • C 中的守护进程 - 有没有一种方法可以实现它们?

    我有一个关于 C 中守护进程的一般性问题 但到目前为止我还没有看到答案 有没有一种方法可以实现对守护进程的控制 例如约定或标准 休息是进一步的解释 我看过多个文档 教授如何在 C 中创建守护进程的基础知识 分叉 关闭文件描述符 更改根目录等
  • 下载文件存储位置和处理使用selenium webdriver和JAVA下载弹出窗口

    请提出一个想法 并进行以下几点实施 1 how to handle the Download popup in IE with Selenium Webdriver with JAVA 2 如何使用JAVA将该xml文件存储在不同的位置 注
  • “响应?”与“响应缺失?”

    定义的意义何在respond to missing 而不是定义respond to 如果重新定义会出现什么问题respond to 某堂课 Without respond to missing http ruby doc org core
  • bash - 导出不起作用

    我错过了一些非常基本的东西 在 Mac OS X 下 我尝试过 chmod 0777 setdir bsh 一定是我的设置有问题 bin bash export proj Users RParadox projects testprojec
  • JButton 文本的抗锯齿

    我在用着字体真棒 http fortawesome github io Font Awesome icon arrow circle left 在 JButton 中创建可单击的图标 但是当尺寸较小时 生成的图标会出现别名 只是作为一点背景
  • 架构 x86_64 的 1 个重复符号

    我不确定我做错了什么 我将项目文件夹移动到另一个文件夹 并将备份文件夹复制到桌面 我尝试打开备份项目并构建 但收到链接器错误 因此 我决定删除备份文件夹并将项目文件夹移回桌面 我无法再编译并收到以下错误 Showing Recent Iss
  • 生成图像的 Base64 字符串以在数据 URI 中使用

    如何生成图像的 Base64 字符串以在数据 URI 中使用 我有一个 Base64 图像编码问题 希望有人可以帮助解决 我正在尝试在我的网页中使用数据 uri 即 img src with org apache commons codec
  • 滞后函数获取最后一个不同的值(redshift)

    我有如下示例数据 想要获得所需的 O P 请帮我一些想法 我希望第 3 4 行的 prev diff value 的 o p 为2015 01 01 00 00 00代替2015 01 02 00 00 00 with dat as sel
  • 如何为所有 div 的每一侧提供相同的空间

    您好 我有一个关于布局的问题 我有一个网站 我在 div 中填充信息 这些 Div 需要彼此相邻 它们之间以及容器 div 两侧之间的空间大小相同 我正在为手机制作它 所以我不知道屏幕的宽度 它应该在所有不同的屏幕分辨率上看起来都很好 目前
  • 使用 Ninject 工厂方法将 IEnumerable 注入到构造函数中

    我正在尝试注入IEnumerable使用 Ninject 进入构造函数 我的构造函数如下所示 public MatrixViewModel IEnumerable
  • 我怎样才能对我的整个 git 历史记录进行 clang 格式?

    我现在已经完成了我的一个小图书馆 当我开始使用它时 我不知道 clang format 现在我想用它格式化整个存储库 我知道随着提交哈希值的变化 这会破坏其他人的存储库 然而 由于还没有人使用我的图书馆 这对我来说没问题 因此 我必须做什么