添加原始哈希以在 git rebase 上提交(使用新根)

2024-04-28

我有一个代码库,以前用 SVN 管理,但现在用 git 管理。当代码迁移到 git 时,历史记录就丢失了。

我已经设法恢复 SVN 历史记录 https://stackoverflow.com/questions/79165/,现在我正在努力git-rebase最近的提交超过了顶部。

我有两个分行,git-commits,其中包含自迁移到 git 以来的提交,以及svn-commits其中包含更古老的历史。每个分支包含超过 3000 个提交。

我发现以下命令在旧历史记录之上构建新历史记录(尽管有一些手动合并冲突处理):

git rebase git-commits --root --onto svn-commits --preserve-merges

有几个提交引用了提交哈希值,我知道当变基完成时这些会发生变化。为了使这些信息不会永远丢失,我想将每个提交的原始提交哈希添加到新重新调整的提交的消息中。

这意味着原始提交如下:

commit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Author: Boaty McBoatface <[email protected] /cdn-cgi/l/email-protection>
AuthorDate: Wed Jul 27 00:00:00 1938 +0000
Commit: Boaty McBoatface <[email protected] /cdn-cgi/l/email-protection>
CommitDate: Wed Jul 27 00:00:00 1938 +0000

Reticulate splines

The splines had been derezzed, and needed to be reticulated.

会变成类似的东西

commit bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Author: Boaty McBoatface <[email protected] /cdn-cgi/l/email-protection>
AuthorDate: Wed Jul 27 00:00:00 1938 +0000
Commit:     Meshy <[email protected] /cdn-cgi/l/email-protection>
CommitDate: Wed Nov 16 10:23:31 2016 +0000

Reticulate splines

The splines had been derezzed, and needed to be reticulated.

Original hash: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

这可能吗?也许与git-filter-branch?


首先,请注意:请确保您确实想要这样做,因为git replace(下面简要提到)可用于以保留 ID 的方式将历史缝合在一起。当然,它也有其自身的缺点;搜索使用过它的人的报告。


是的,你可以这样做git filter-branch.

不过,您可能想要combine“rebase new commits atop new conversion”步骤与“...然后编辑所有新提交以也包含其旧 ID”步骤,因为 rebase 的工作方式是copying提交,过滤器分支的工作原理是...copying承诺。 :-)

所有执行此类操作的 Git 命令must复制,因为每个提交的哈希 ID 是提交内容的函数。如果新提交与原始提交有任何不同,它将获得一个新的、不同的 ID。

之间的差异git rebase and git filter-branch关键在于复制哪些提交以及如何执行复制。

变基,当没有完成时--preserve-merges,通过选择非合并提交列表,将每个此类提交转换为变更集(通过减法,或多或少:子项减去父项 = 从父项到子项的增量),然后将此增量添加到--onto指向或指向到目前为止添加的提交。

当你使用--preserve-merges, 变基still选择非合并提交的列表。然后,在有合并提交的地方,rebase重新表演合并(这就是为什么您必须重新解决合并冲突的原因)。它必须重新合并,因为新的基础可能会导致不同的合并,并且因为合并不能变成单个变更集(“子-父”为您提供一个增量,但至少有两个父级,因此至少有两个delta,一般情况下我们不能同时保留两者)。

Filter-branch 使用完全不同的方法。无论是否合并,都会选择要过滤的提交。 (实际选择是通过运行完成的git rev-list,这相当于“管道”git log.) 这个完整的提交 ID 列表被放入一个堆中:一个存储在普通文件中的已排序的拓扑顺序堆,以便父提交始终在其子提交之前得到处理。

然后,对于列表中的每个 ID:

  • 提取原始提交 a lagit checkout,进入没有底层 Git 存储库的临时树。

  • 应用树过滤器来修改树。 (此修改在保存临时树的临时目录中运行。当很多人尝试访问像../../fixed-version。相对路径失败,因为临时树根本不在存储库中。)

  • 重建一组新的 Git 树和 blob 对象来表示新树,即新的提交快照。

  • 将提交消息过滤器应用于消息。

  • 将提交环境过滤器应用于剩余的提交元数据(作者和提交者的内容)。

  • 使用新消息和新树进行新提交。或者,如果您提供提交过滤器,请使用它来进行或不进行提交;此时您还可以使用父过滤器修改新提交的父提交。

  • 最后,记录一个配对:“旧提交 成为新提交 。” (如果您使用提交过滤器跳过提交,则旧哈希会映射到其相应的新祖先,即您的父级)didn't跳过。)这个配对是map.

由于提取+树过滤器+重建部分,这个过程非常慢。因此,如果您don't使用树过滤器,git filter-branch跳过这一部分:无论如何它都会恢复原来的树。为了让您修改新提交的内容,filter-branch 还允许您指定一个索引过滤器(无论如何,提交总是从索引开始工作,因此提取+修改+重建只是更新索引;如果我们可以就地更新,那就快得多)。但是——这里是关键点——出于您的目的,您不需要对每棵树做任何事情。你想要的只是修改血统!这将使您保留原始合并及其源树,无需重新合并。

请注意,--commit-filter描述谈论了map便利函数(shell 函数)。这个“地图”功能使用了我上面提到的地图。默认情况下是自动映射到新复制的提交的新父级。

最后,在复制所有提交之后,如果您提供--tag-name-filter,还复制带注释的标签并映射副本(因此,如果您确实有带注释的标签,则do want a --tag-name-filter cat此处)—filter-branch 命令重写了一些引用,即分支和标记名称。原始引用仍然指向原始提交(和带注释的标签对象),被转储到refs/original/名称空间。 (该过程开始时必须为空,除非您使用--force.) 重写的引用指向新的副本。重写使用相同的映射技术,因此如果有跳过的提交,名称现在指向保留的祖先提交。

(“一些”参考文献?等等,which参考?答案就在文档中,但有点神秘:它谈到了正面参考。参数被传递给git rev-list这样您就可以过滤特定范围的提交,例如,branch~30..branch or branch ^otherbranch。 “积极”引用是主动选择提交的引用,而“消极”引用是限制提交的引用,因此对于branch ^otherbranch我们有一个积极的参考,branch,和一个负数,非其他分支部分。所以这仅重写refs/heads/branch并不是refs/heads/otherbranch.)

这是很多废话,但是……怎么办?

解释以上所有内容的原因是为了指出移植过程是多么简单,当使用git filter-branch,然后展示如何访问地图。

首先,我们只需要明确地更换一份单亲身份证。具体来说,我们希望根提交 in git-commits成为现有的提示提交svn-commits:

$ git rev-parse svn-commits
9999999999999...

(这是理想的新父母),并且:

$ git rev-list --max-parents=0 git-commits
11111111111111...

(这是根提交 - 幸运的话只有一个,否则,现在怎么办?)。

所以,我们想要一个父过滤器也就是说:“如果这是提交 1111111...则 echo 9999999...,否则只需回显参数即可”。默认的父参数位于 stdin 上,作为一系列-p <id>s,ID 已映射。当然,现有的根有no父母,所以标准输入将没有我们想要在这里更改的一个提交的内容。因此:

--parent-filter 'if [ $GIT_COMMIT = 11111... ]; then
  echo -p 999999...; else cat; fi'

这部分的filter-branch将完成我们的重新养育。请注意,与git rebase,所有的树木都被完好无损地保留下来。我们在这里从不将快照转换为增量,我们只是按原样使用它。这意味着不需要重新解决合并冲突。

(旁注:您实际上可以使用名称svn-commits代替硬编码99999...这里。您可以使用名称来代替硬编码11111...也是,但我们不have一个名字。此外,每次查找名称都会给过滤增加一点点延迟。对于一个重新养育孩子的人来说svn-commits,这是一个微小的延迟;不过,为了测试这是否是旧根,这将是一个微小的延迟乘以 3000 次提交。)

(第二个旁注:您还可以通过“移植”或其更现代的版本来进行重新设置,git replace。如果您跑步时移植物或替代物正在生效filter-branch,移植或替换变成永恒的,因为 Git 只是按照指示复制提交,并且指示也在替换之后。)

这仍然留下过滤提交的问题messages, 加上:

Original hash: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

如上所示,原始哈希在$GIT_COMMIT,所以我们需要的是:

--msg-filter 'cat; echo; echo "Original hash: $GIT_COMMIT"'

如果我们想要更花哨,我们甚至可以使用它map便利功能:

--msg-filter 'cat; echo; echo "new commit $(map $GIT_COMMIT) \
filtered to reparent original commit $GIT_COMMIT"'

or something silly like that, but there's no good reason to bother ... unless you want to get really fancy, and see if you can detect old hash IDs in the commit message and rewrite them in place. I'm not sure if this is even a good idea, and won't attempt to provide a bit of shell script for it, but note that all1 of these filters are "eval"-ed as shell fragments. You can invoke other shell scripts from these eval-ed fragments, just remember that all the filtering is going on in a temporary directory.

对参考运行过滤git-commits。过滤完成后,refs/heads/git-commits将指向最后复制的提交,并且refs/original/refs/heads/git-commits将指向原始链(植根于11111...在上面的例子中)。


1Well, almost all. As the documentation says, "with the notable exception of the commit filter, for technical reasons".


Summary

我们需要两个过滤器,--parent-filter(或有效的移植物或替代物),以及--msg-filter。父过滤器说“用我们要移植到的位置的尖端替换移植副本的根部”,这完成了我们的 rebase-without-change-snapshots。消息过滤器说“这个新提交替换了我们在过滤时从变量中扩展的提交$GIT_COMMIT".

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

添加原始哈希以在 git rebase 上提交(使用新根) 的相关文章

  • Accurev 性能如何?

    当前版本 4 7 的性能如何Accurev http www accurev com 每 100mb 每 GB 的结账时间 每 个文件或 mb 的提交时间 当 100 流时 gui 的响应能力 我刚刚进行了 Accurev 的演示 这些流看
  • 如何在Windows Git shell中运行./script.sh?

    也许这很尴尬 但是当我在 Git shell 中工作时 我无法在 Windows 上运行 sh 文件 也许我必须安装一些东西 但我认为 Git 会支持 bash 命令 我知道 Windows 不使用 sh 文件 我正在执行安装步骤游戏结束
  • 如何在gitlab存储库中下载单个文件夹或文件

    我有一个存储库 在此存储库中 有多个文件夹可用 我只需要此存储库中的一个文件夹 我已经尝试遵循命令 但它不起作用 克隆 有没有办法只克隆 git 存储库子目录 https stackoverflow com questions 600079
  • 如何对 git 子模块使用相同的协议?

    在 git 存储库 R 中 我有一个使用以下命令初始化的子模块 git submodule add git mygitserver 现在用户刚刚使用克隆 Rhttps并在运行时出现错误 git submodule init git subm
  • 将新更新从原始 GitHub 存储库提取到分叉的 GitHub 存储库

    我在 GitHub 上分叉了某人的存储库 并希望使用原始存储库中的提交和更新来更新我的版本 这些是在我分叉我的副本后制作的 如何提取在源中所做的更改并将它们合并到我的存储库中 您必须将原始存储库 您分叉的存储库 添加为远程存储库 来自有关分
  • 恢复后如何挑选提交?

    我正在研究我的feature branch并在审核后合并到development待部署 后来 一位同事决定发布一个版本 并将他和我的合并到master 在部署时 他意识到他的代码有错误并恢复了master 在我们的分叉和拉动流程中 这意味着
  • 在 VS Code 中找不到 Git

    由于某种原因 我在 Windows 10 笔记本电脑上运行的 VS Code 中找不到 Git 在我的 Mac 上 当你一直向下滚动时 用户默认设置 中会出现一个 Git 但在我的 Windows 10 笔记本电脑上 它根本不存在 源代码管
  • git 无法暂存文件,将所有文件显示为重复,但字符大小写不是问题

    就我而言 我对我的文件之一进行了简单的一项更改 并想提交我的更改 但注意到 commit am 没有添加 提交该文件 发出 git 后ls files stage 我看到项目中的所有文件可能都显示为重复项 这是其中一个文件的示例 10064
  • Git 提交从 Windows 上的守护程序返回错误 docker/error 响应

    我正在为我的 Laravel 应用程序 BE 运行 docker 我对 readmeme md 文件进行了简单的更新 并尝试将此文件提交并推送到 git 当我尝试提交时 这就是我得到的 gt git c user useConfigOnly
  • Git - 包含来自其他存储库的文件

    对于 Git 我想包含一些常见的 JS CSS 库和 或实用方法 即来自另一个存储库的特定文件 在我的项目中 我希望它们始终是最新的 我真的不想要整个远程存储库 如果我可以处理远程文件的 本地副本 并将更改推送回来 那就太好了 一个有点类似
  • 如何更改 Bitbucket 中的 git 提交消息?

    我需要更改 Bitbucket 中的旧 git 提交消息 我试过git rebase i并重写了我的消息 但是当我拉取并提交时 它只是将旧消息保留在 Bitbucket 中并合并了我的更改 这基本上是 4 个步骤的过程 但如果多个团队成员在
  • Git 版本控制中忽略父目录

    如何忽略父目录 gitignore 我尝试了这种模式 但似乎它们不起作用 如果您想忽略某个文件夹但不想修改现有的 gitignore 请将 gitignore 放入仅包含星号的文件夹中 下面是一个快速的 BASH 示例 用于完成 idea
  • 我有*很多*源文件要添加到 git 存储库,如何使其快速

    我在看here https git scm com docs git fast import寻找更快地将批量文件导入 git 存储库的灵感 但不确定是不是这样 基本上情况是 我有超过 1 亿个文件想要提交到 git 存储库 我已将它们分解为
  • 合并git中2个不同分支中具有相同名称的2个文件

    我目前有一个名为test1在一个名为branch1创建自master另一个文件也命名为test1在一个名为branch2也创建自master 如果我合并 master 中的两个分支 这两个文件中编写的代码会发生什么 As 阿米尔回答了 ht
  • Hudson 结帐卡在“git fetch”处

    我正在使用 git 版本 1 6 2 2 1669 g7eaf8 在 Hudson 1 314 上使用 Hudson Git 插件 0 7 3 当我触发构建时 Hudson 执行 git fetch 但它永远不会返回 我把一只卡在那里14天
  • git分支和标签如何存储在磁盘中?

    我最近检查了我工作中的一个 git 存储库 其中有 10 000 多个分支和 30000 多个标签 新克隆后 存储库的总大小为 12Gigs 我确信没有理由拥有 10000 个分支机构 所以我相信它们会占用磁盘中相当大的空间 所以 我的问题
  • git:如何查明某个分支是否有拉取请求?

    我在 git 分支上 有没有办法查看该分支是否有拉取请求 在这种特殊情况下 Atlassian Stash 用于管理拉取请求 当然我可以使用Stash的Web界面来搜索拉取请求 但我也可以仅使用 git 命令行工具从脚本执行此操作吗 Cor
  • 如何像对待普通目录一样对待嵌套存储库(子模块)?

    我的 WordPress 网站是使用 Git 进行版本控制的 包括wp content plugins 文件夹 现在有一个插件 wp editormd 带有自己的 Git 存储库 wp content plugins wp editormd
  • 有没有办法列出Git中未修改的文件?

    我从另一个来源以 tarball 的形式获取了一些更改 我想知道哪些文件没有更改 目标是 Git 克隆 因此可以轻松查看新增内容和更改内容 有人知道如何获取未更改内容的列表 不包括未跟踪的内容 吗 编辑 换句话说 我希望利用 Git 来查找
  • 从 git 中删除历史记录 - git 命令失败

    我正在尝试从 Git 历史记录中清除项目 bin 目录 我已经将 bin 添加到 gitignore 并运行 git rm cached r bin成功地 现在我尝试使用 GitHub 帮助页面中推荐的命令来清除历史记录 git filte

随机推荐

  • XSD 到 XForms 以及 XForms 到 XSD 转换

    目前我正在努力解决两个问题 我从外部服务器接收到一个 XSD 文件 并且基于该文件我必须生成 XForm 通常 XSD 文件会导入许多其他 XSD 文件等等 我正在使用 XForm 构建器编写 GUI 当用户构建他的自定义 XForm 时
  • Ember 组件在路由或控制器中调用操作

    我有一个组件 其主要目的是显示一行项目 每行都有一个删除按钮 可以删除一行 如何将操作从模板传递到将在路由器中触发操作的组件 这是使用该组件的模板 templates holiday hours hbs each model as holi
  • jquery mobile取消302重定向到外部站点

    我正在尝试将 DotNetOpenAuth 与使用 jquery mobile 的网站集成 我遇到了一个问题 jquery mobile 似乎正在取消到服务器响应的提供方 外部站点 的 302 重定向 我尝试在 mobileinit 事件中
  • 为什么弹性物品会包裹而不是收缩?

    我想知道是否有人可以给我一个关于如何计算 Flexbox 布局的简单介绍 特别是优先级顺序 例如 div style display flex div style height 200px background color lightgre
  • gcc 无效版本(最大)错误添加符号:错误值

    我已经在 Linux x86 x64 上成功构建了几个 32 位静态和共享库 现在我尝试将它们链接到一个可执行文件 但出现以下错误 usr bin ld foo so moddi3 invalid version 21 max 0 foo
  • 在 Mathematica 中创建具有不同颜色边的图形

    我想创建一个图 图论 其中某些边具有与其他边不同的颜色 这将用于突出显示图中从一个顶点到另一个顶点的路径 以下是一些具有不同颜色边缘的示例http demonstrations wolfram com AGraphTheoryInterpr
  • 如何使用Sinon监视导入的函数?

    假设我们想使用 Sinon 测试另一个函数是否调用了一个特定函数 fancyModule js export const fancyFunc gt console log fancyFunc export default const fan
  • 推荐一个适用于 Flex 和 AIR 的 HTML 友好的 RichTextEditor? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Java HashSet 具有自定义相等标准? [复制]

    这个问题在这里已经有答案了 我一直在寻找类似于 Java TreeSet 在实例化时接收自定义比较器的能力 因此我不需要使用对象的默认相等 和哈希码 标准 我能想到的最接近的方法是将我的对象包装在一个私有的自定义类中 但这看起来很老套 这最
  • GSON 预期为 BEGIN_ARRAY,但实际为 BEGIN_OBJECT

    当我仅收到列表中的一项时 我收到此错误 我在服务器端 REST Web 服务中使用 Jersey 只有当列表返回一个元素并且它具有0 elements I get java lang NullPointerException但是当它有多个时
  • 仅使用整数求平方根

    最近 我在某人的编程课上遇到了一个问题 它要求他们仅使用整数来计算平方根 他们用一个整数来表示小数点之前的部分 用另一个整数来表示小数点之后的部分 问题说不允许使用浮点数 然而 经过一段时间的思考 我似乎无法想出一种不使用浮点的方法 我用谷
  • 如何在 Angular 2 中动态更改 :host 中的 CSS?

    如何动态更改组件宿主的 CSS 属性 我有一个组件 在它的 CSS 中我给了它一个样式 host overflow x hidden 在子组件中单击按钮时 我需要添加overflow y hidden到主机组件 我如何实现这种行为 这是一个
  • 为什么 res.end 和 res.send 的字体不同?

    我有以下最小的基本 Express Node js 应用程序 var express require express var app express app get function req res res send Hello app l
  • C++变量声明和初始化规则

    考虑以下声明和初始化类型变量的方法C C c1 C c2 c2 C C c3 C C c4 C 所有这些是否完全等同 或者其中一些可以根据确切的定义而有所不同C 假设它有公共默认值和复制构造函数 这些意味着 C c1 default con
  • 我可以删除 Windows Azure 表存储中的整个分区吗?

    我在分区中有一组行 代表一些缓存的数据 我想刷新该缓存而不关心已经存在的内容 是否可以删除整个分区而无需执行任何选择 不 但您可以删除整个table只需一次调用 因此您可能会考虑将分区改为单独的表 但是 当然 您不能进行跨表查询
  • 打开文件对象的大小

    有没有办法找到当前打开的文件对象的大小 具体来说 我正在使用 tarfile 模块来创建 tarfile 但我不希望 tarfile 超过特定大小 据我所知 tarfile 对象是类似文件的对象 所以我想通用的解决方案会起作用 ls la
  • 测试方法的存在性

    我正在尝试使一些现有的 JS 向后兼容 如果一个方法不存在 我需要重写它 否则只返回现有的方法 这是我到目前为止的代码 this grid getDataSource function if getDataSource undefined
  • 使用useReducer时如何避免耦合?

    为了防止将回调传递给我正在使用的子组件useReducer反而 这避免了子组件在每个父渲染上重新渲染的问题 但缺点似乎是父组件和子组件之间的紧密耦合 通过紧密耦合 我的意思是子级需要明确了解父级定义的减速器所期望的操作的形状 例如 想象一个
  • C# 中是否有相当于 php array_merge 的函数

    如果不是 创建它的最佳方法是什么 注意 合并不仅仅是附加 它融合了相同的键 此功能存在于 List 元素上 在 C 中 数组是固定宽度的项 因此在不创建新数组的情况下无法修改大小 然而 列表却是另一回事 你可以做 List
  • 添加原始哈希以在 git rebase 上提交(使用新根)

    我有一个代码库 以前用 SVN 管理 但现在用 git 管理 当代码迁移到 git 时 历史记录就丢失了 我已经设法恢复 SVN 历史记录 https stackoverflow com questions 79165 现在我正在努力git