5

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

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

这仍然在我的本地仓库中。

4

3 回答 3

3

重建 reflog 可能不像最初看起来那么困难。您可以将 reflog 的提交重新生成到不同的分支中,或者您可以使用它来生成包含 reflog 一部分的git read-tree单个。newbranch

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

假设您希望每次提交都有不同的分支。首先,复制您的存储库。您将在此过程中更改您的 reflog,因此您不妨使用一次性版本。其次,检查您的 reflog 并找到您想要开始的提交。它看起来像HEAD@{n}。假设它是HEAD@{49}。然后,试试这个脚本,用 替换head -50head -<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. 您必须使用它或类似的东西,以免 reflognewbranch按时间倒序应用。肯定有一种方法可以在不同时使用awkand的情况下做到这一点sed,但这有效:

#!/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}

于 2012-06-19T05:47:08.407 回答
1

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

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

所以:

A<--B (master)

现在提交 --amend:

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

现在再次提交 --amend :

 --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
于 2012-06-19T04:27:31.560 回答
0

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

这样您就不会遇到任何冲突,因为您实际上只是用更新的 reflog 树重写了工作区树。

于 2012-06-19T05:51:05.060 回答