5

私はリファクタリングを行っていましたが、まともな進歩を遂げるたびに修正を続けていました. それは非常に順調に進んでおり、私がこのような大規模なリファクタリングをどのように処理したかを人々に示すことができれば素晴らしいと思いました (多くの小さなステップ、コードを微調整するだけ、すべてのポイントでグリーン テスト スイートを使用)。

コミットはすべて私のreflogにあります。ユーザーが81行目と57行目の集約されたものだけでなく、各ステップを見ることができるように、これらの修正されたコミットのそれぞれを独自の実際のコミットに変える方法はありますか? コミットなどに一意のメッセージは必要ありません。履歴に記録されているだけです。

これはすべてまだ私のローカルレポにあります。

4

3 に答える 3

3

reflogの再構築は、最初に表示されるほど難しくない場合があります。reflogのコミットを個別のブランチに再生成することも、 reflogの一部を含むgit read-treeシングルを生成するために使用することもできますnewbranch

ブランチソリューションごとに1つのコミット:

コミットごとに個別のブランチが必要だとします。まず、リポジトリをコピーします。このプロセスで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

まず、リポジトリをコピーします。次に、次のようなスクリプトを使用します。最初のソリューションの説明に従って、2つ<n + 1>をreflogで必要な深さに変更し、さらに1つ変更します。への追加のパイプに注意してくださいsed。reflogがnewbranch時系列の逆順に適用されないように、それまたはそのようなものを使用する必要があります。awkとの両方を使用せずにこれを行う方法は確かにあります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

最終結果はになります。これには、commitに基づいて、との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)

(プライム (アポストロフィー) 記号に注意してください - それらが新しいハッシュを持つ新しいコミットであることを示します)

さて、私が確信していないことの 1 つは、競合が発生するかどうかです。その後の各コミットには、以前のコミットと同じ変更がいくつか含まれているため、修正されていると思います。もしそうなら、それらを解決する必要があります。

git の仕組みを考えると、これを試してうまくいかない場合、現在の場所に戻るのは次の簡単なことです。

git reset --hard D
于 2012-06-19T04:27:31.560 に答える
0

最初の reflog エントリから新しいブランチを作成し、各 reflog エントリに対して、ツリーを作業領域に git チェックアウトしてコミットすることができます。

この方法では、基本的にワークエリア ツリーを新しい reflog ツリーで書き換えるだけなので、競合が発生することはありません。

于 2012-06-19T05:51:05.060 に答える