将旧版本(不受版本控制)添加到 git 存储库作为标记提交

Add an old version (out of version control) to the git repository as a tagged commit

我有一个系统 sys/master 的 git 存储库,它是我在系统创建一段时间后创建的。我有一个系统备份 sys_bk 是在创建存储库之前完成的。

在不影响系统最新版本的情况下,将sys_bk版本作为标记版本添加到当前存储库的推荐方法是什么?

仅供参考,sys_bksys/master 之间的差异很大。

我想到的最简单的方法是利用 git 的 git checkout --orphan <branch> 命令,这样您就可以创建一个没有父级的分支以及 sys_bk 文件夹的内容作为初始提交。

示例工作流程:

  • git checkout --orphan sys_bk(签出一个没有父节点的新分支)
  • git rm -rf .(从工作目录中删除所有文件)
  • cp /path/to/sys_bk/* ./(移动 sys_bk 个文件到工作目录)
  • git add --all .(将所有新 sys_bk 文件添加到索引)
  • git commit -m "Add sys_bk"

我认为这里真正没有答案的问题是,您希望这个新(/旧)提交如何出现在历史记录中?今天你的历史开始于晚些时候

D -- E -- F <--(master)

现在你有一些旧版本 A。一些用户(jof 在他的回答中,StephenNewell 和 torek 在评论中)提到了将 A 添加到您的 repo 的方法。这会让你得到类似

的东西
D -- E -- F <--(master)

A <--(sys_bk)

然后 StephenNewell 建议合并不相关的历史记录,但我真的怀疑那是你想要做的。您指定不更改项目的当前版本,因此充其量它是一种特殊类型的邪恶合并。基本上你最终会得到

D -- E -- F -- M <--(master)
              /
             A <--(sys_bk)

M 处的内容 (TREE) 不会是该历史记录的 default/expected 合并结果;相反,它将是 F 处的 TREE 的副本。因此,合并可能会导致麻烦,而且它并没有很好地反映 A 在项目历史中的真实位置。

一个选择是让历史不相关。您可以保留用于将 A 带入回购的 sys_bk 分支,and/or 您可以标记 A (这听起来像您打算做的),并且它会被保存下来,供任何愿意寻找它的人使用。 (好吧,如果您保留分支而不仅仅是一个标签,可见性可能是最简单的;这取决于您如何记录您正在做的事情。)

另一件需要考虑的合理事情是使 A 看起来像 D 的 parent。有几种方法可以解决这个问题,各有利弊。

改写历史

重写历史以物理连接 A 作为 D 的 parent(大致)是您支付成本 up-front 的选项,然后一切从此工作顺利。但是取决于有多少人分享你的 repo,up-front 成本可能会相当大,并且每个人都支付它,无论他们是否关心 A

如果您想使用此选项,请参阅 git filter-branch--parent-filter 选项的文档。最后你会得到类似

的东西
A -- d -- e -- f <--(master)

我正在使用 d 来识别 TREED 完全相同的新提交。 (关于它的一切都像 D,除了它有一个 parent - A - 而 D 没有 parent。)这与典型的略有不同"rewritten commit" 来自 rebase - 特别是在 d 的情况下 - 这就是为什么我使用 lower-case 而不是素数表示法。但结果是一样的:这些都是新的提交。

这意味着,假设 master(and/or 任何其他参考)已经被推送到远程,您将必须 "force push" - git push -f - 用新的引用覆盖那些引用,或者只是丢弃遥控器并在其位置放置一个新的。无论哪种方式,每个其他用户都将处于损坏状态,他们必须小心纠正以避免撤消您所做的事情(请参阅 git rebase 文档中的 "Recovering from Upstream Rebase")。

Object替换

一种侵入性较小的方法是更新单个存储库 "as needed",使它们的行为就好像 AD 的 parent。在这种情况下,任何不关心将 A 视为 D 的 parent 的人都完全不受影响。不利的一面是 (a) 它需要在每个需要它的 repo 上进行设置,并且 (b) 它有一些已知的 bugs/quirks - 请参阅 git replace 文档。

为方便起见,您需要复制一份提交 D。您以类似于历史重写的方式执行此操作,除了您创建一个新分支来重写并保留所有其他分支。

所以你会计算出一个引用 D 的表达式。 (也许你得到它的提交 ID,或者在我们的例子中我们可以使用 master~2。)

git checkout master~2
git checkout -b sys_bk_replacement

然后 运行 git filter-branch 与完全重写的方式大致相同,但仅指定 sys_bk_replacement 分支(不是 --all 因为你可能会完全重写)。这会给你

D -- E -- F <--(master)

A <--(sys_bk)
 \
  d <--(sys_bk_replacement)

并且任何想要 A 看起来像 D 的 parent 的人都可以使用 git replaced 替换为 D