12

StackOverflow での「フラット化マージ」についての質問はほとんどなく、通常は「git rebase」という答えが返ってきます。ただし、これらの回答には、コミットの順序という重要なポイントが 1 つ欠けています。

6 月 1 日と 8 月 1 日にコミットされたブランチ A と、7 月 1 日にコミットされたブランチ B があるとます。 )。B を A にマージすると、次の履歴が作成されます (git ログごと):

Merged branch 'B'
Aug 1
Jul 1
Jun 1

今、私が探しているのは、同じ結果を得る方法ですが、マージコミットはありません (したがって、その順序で基礎となる線形履歴があり、そうです、それはコミットを再親化することを意味します)。git rebase はここでは役に立ちません。それを使用すると、次の履歴が表示されます。

Jul 1
Aug 1
Jun 1

また

Aug 1
Jun 1
Jul 1

言い換えれば、git rebase は常に 1 つのブランチを別のブランチの上に積み重ねますが、著者のコミット日付でソートされたコミットを散在させるソリューションを探しています。

どうやら、単純なケースでは、git rebase -i を使用して手動で git rebase を後処理することで必要な調整を行うことができますが、これは大きな履歴では実用的ではないため、自動化されたコマンド/スクリプトを探しています。

使用事例?A と B が同じプロジェクトの異なる部分を表し、たまたま異なるリポジトリにあり、それらをマージしてそれを修正する時が来た場合、線形の履歴を実際の開発順序で展開することを望むのは自然なことです。

4

4 に答える 4

14

しばらく考えた後、非対話的な方法で git rebase --interactive を実行するにはどうすればよいですか? 、この質問に対する完全にスクリプト化されたソリューションも提供します。

1.異なるリポジトリから 2 つのブランチを 1 つのリポジトリに持ってくる (git remote add + git fetch)

2. 1 つのブランチを別のブランチの上に (非対話的に) リベースします (順序が重要です。どのブランチの最初のコミットを統合ブランチの最初のコミットと見なすかを検討してください)。

3.次のスクリプトを準備します ( rebase-reoder-by-date)。

#!/bin/sh
awk '
/^pick/ {
            printf "%s %s ", $1, $2;
            system("echo -n `git show --format='%ai' -s " $2 "`");
            for (i = 3; i <= NF; i++) printf " %s", $i; printf "\n";
        }
' $1 | sort -k3 > $1.tmp
mv $1.tmp $1

4.以下を実行します。GIT_SEQUENCE_EDITOR=./rebase-reoder-by-date git rebase -i <initial commit>

免責事項: これらのすべての操作は、元のリポジトリのコピーに対して実行し、ブランチを組み合わせてレビュー/検証/テストして、それが期待どおりであり、期待どおりのものを含んでいることを確認し、バックアップを手元に置いておく必要があります。

于 2012-09-12T19:47:34.217 に答える
2

[完全に自動化されたソリューションについては、別の回答を参照してください。誰かが同様のタスクを解決するのがそれほど自明ではない場合に備えて、これを最終的な解決策につながるパスの例として残しておきます。]

わかりました、これは質問に対する本当の答え (完全にスクリプト化された自動化されたソリューション) ではありませんが、(インタラクティブなリベース ベースの) 処理を自動化する方法を考え、例を示します。

まず第一に、究極のソリューションgit filter-branch --parent-filterはまさに必要なもののように見えます。ただし、私の git-fu では 1 ライナー、2 ライナー、または 3 ライナーを使用することはできず、すべてのリビジョンを解析するスタンドアロン スクリプトを作成するアプローチはクールではなく、rebase -i よりも手間がかかります。

したがって、コミットの作成者の日付が表示されていれば、 rebase -i を効率的に使用できます。私が最初に考えたのは、 を使用して作成者の日付で始まるコミット メッセージに一時的にパッチを適用しgit filter-branch --msg-filter、 rebase -i を実行してから、メッセージのパッチを解除して元に戻すことでした。

2番目に考えたのは、rebase -iで使用されるリベースコミットリストにパッチを適用するほうがよい理由です。したがって、プロセスは次のようになります。

  1. 通常どおり、ブランチ A と B を異なるリポジトリから 1 つのリポジトリに移動します。
  2. あるブランチを別のブランチに (非対話的に) リベースします。最初のコミット権を得るために、どのブランチをどのブランチにリベースする必要があるかを検討してください (リベースで簡単に書き換えることはできません)。
  3. 始めるgit rebase -i
  4. 別のコンソールで、$REPO/.git/rebase-merge/ に移動します。
  5. 走る:awk '/^pick/ {printf "%s %s ", $1, $2; system("echo -n git show --format='%ai' -s " $2 ""); for (i = 3; i <= NF; i++) printf " %s", $i; printf "\n"; }' git-rebase-todo > git-rebase-todo.new; mv git-rebase-todo.new git-rebase-todo
  6. これは、コミットを並べ替えるのにちょうどいい場所/方法のようです:sort -k3 git-rebase-todo >git-rebase-todo.new; mv git-rebase-todo.new git-rebase-todo
  7. 元のコンソールに切り替えて、エディターで git-rebase-todo ファイルをリロードし、エディターを終了します。

出来上がり!実際、git rebase -i「非インタラクティブ」モードで機能する場合、これは完全にスクリプト化できます。私はHow do I run git rebase --interactive in non-interactive 方法? そのために。

于 2012-09-12T18:52:57.750 に答える
0

マージされるまで別々の開発を別々のラインに残すことの問題は何ですか? それらが別々である場合、それらは別々でした。

履歴をハッキングせずに時系列で履歴を表示する方法はたくさんあります。試しましたgit log --pretty --date-orderか?

于 2012-09-05T05:30:26.767 に答える