如何将一组修改后的提交(存储在 reflog 中)转换为真正的提交



我正在做一个重构,每次我取得任何像样的进展时都会不断修改。它进行得非常顺利,我意识到能够向人们展示我如何处理如此巨大的重构(很多小步骤,只是轻推代码,每个点都有一个绿色的测试套件)会很好。

提交都在我的 reflog 中。有没有办法将每个修改后的提交转换为自己的真实提交(抱歉,不知道术语),以便用户可以看到每个步骤,而不仅仅是第 81 行和第 57 行的聚合步骤?我不需要提交或任何东西的唯一消息,只需要它们被捕获在历史记录中。

这一切都仍在我的本地存储库中。

重建 reflog 可能并不像最初出现的那样困难。您可以将 reflog 的提交重新生成为不同的分支,也可以使用 git read-tree 生成包含 reflog 一部分的单个newbranch

每个分支解决方案一个提交:

假设您希望每个提交都有不同的分支。首先,复制存储库。您将在此过程中更改您的 reflog,因此您不妨使用一次性版本。其次,检查您的 reflog 并找到要开始的提交。它看起来像HEAD@{n}.假设它是HEAD@{49}.然后,尝试此脚本,将head -50替换为 head -<n + 1> ,无论您的情况如何:

#!/bin/sh
reflog=$(git reflog | head -50 | awk '{ print $1 }')
i=0
for ref in $reflog; do
    git checkout -B "reflog_$i" $ref
    i=$(expr $i + 1)
done

这是一次抓取你的 reflog 的提交历史记录,然后迭代它,在此过程中生成reflog_$i分支。您可以根据需要挑选、合并或操作它们。如果这只是为了演示,您可以编写一个简短的脚本,在分支上执行git checkout,运行测试套件,并全程显示绿色。请记住,reflog_1代表最新的历史; reflog_<n+1>最古老的。

#!/bin/sh
for i in $(seq 50 1); do
    git checkout "reflog_$i"
    ./test-suite.sh
done

解释提交方法时将其扔在投影仪上,这将是一个很好的背景。

如果要组合所有分支,可以运行此 ruby 脚本按顺序应用它们(或用您熟悉的任何语言创建等效项)。让我重申一下,您应该备份您的目录,因为这具有相当大的破坏性。

#!/usr/bin/env ruby
n = 50
n.downto 0 do |i|
  system "
    git read-tree reflog_#{i}
    git commit -m 'Refactoring #{n - i}'
    git checkout -- .
    git br -D refog_#{i}
  "
end

使用 git read-tree将所有提交放在同一个分支上

首先,复制存储库。然后使用如下所示的脚本。根据第一个解决方案中的讨论,将两个<n + 1>更改为 reflog 中您想要的任何深度,加上一个。请注意要sed的附加管道。您必须使用它或类似的东西,以免 reflog 按时间倒序应用于newbranch。肯定有一种方法可以在不使用awksed的情况下做到这一点,但这有效:

#!/bin/sh
reflog=$(git reflog | head -<n + 1> | awk '{ print $1 }' | sed -n '1!G;h;$p')
git checkout -B newbranch HEAD@{<n + 1>}
for ref in $reflog; do
    git read-tree "$ref"
    git commit --no-verify -m "Adding commit $ref"
    git checkout -- .
done

最终结果将是newbranch,它应该包含HEAD@{0}HEAD@{n}之间的所有提交,基于提交HEAD@{n+1}

这是可能的,但可能很难。

每次你做一个--amend,你基本上"扔掉"了以前的提交,并用新的修正提交替换了它,它包含了以前的更改以及修改后的任何内容。

所以:

A<--B (master)

现在提交 --修改:

  ---B
 /
A<--C (master)

现在提交 --再次修改:

 --B
/
A<--D (master)

 --C

提交 B 和 C 仍然存在。 但是,它们不会被任何东西指向,最终将被垃圾回收。

因此,要获得所需的图表:

git checkout master
git reset --hard A
git cherry-pick B
git cherry-pick C
git cherry-pick D

叶:

A<--B'<--C'<--D' (master)

注意素数(撇号)符号 - 表示它们是具有新哈希的新提交)

现在,我不确定的一件事是你是否会有冲突。 我相信你会的,因为每个后面的提交都包含一些与以前的提交相同的更改,因为它们已被修改。 如果是这样,您必须解决这些问题。

请记住,考虑到 git 的工作方式,如果您尝试这样做并且它不起作用,那么回到您现在的位置是一个简单的问题:

git reset --hard D

您可以从第一个 reflog 条目创建一个新分支,然后对于每个 reflog 条目,将树签出到工作区,然后提交它。

这样你就不会有任何冲突,因为你基本上只是用一个更新的reflog树重写工作区树。

相关内容

  • 没有找到相关文章

最新更新