別のアプローチ
あなたは、Git と Darcs のある種のミラーに取り組んでいると述べています。作業ツリーを履歴からドラッグする代わりに、git fast-importおよびgit fast-exportコマンドを調べて、抽出/提供する必要があるデータを管理するためのより良い方法が提供されているかどうかを確認できます。
ブランチがその上流ブランチに早送りできるかどうかを確認する方法
これには 2 つの部分があります。まず、どのブランチが現在のブランチの「上流」であるかを知るか、決定する必要があります。次に、アップストリームを参照する方法を理解したら、早送りできるかどうかを確認します。
ブランチのアップストリームを見つける
Git 1.7.0 には、ブランチが追跡するブランチ (その「上流」ブランチ) を照会する便利な方法があります。@{upstream}
オブジェクト指定構文は分岐指定子として使用できます。素の名前として、現在チェックアウトされているブランチの上流ブランチを指します。サフィックスとして、現在チェックアウトされていないブランチの上流ブランチを見つけるために使用できます。
1.7.0 より前の Git の場合、ブランチ構成オプションを自分で解析する必要があります (branch.name.remote
およびbranch.name.merge
)。または、標準の命名規則がある場合は、それを使用して上流ブランチの名前を決定できます。
この回答upstream
では、現在のブランチの上流にあるブランチの先端にあるコミットを参照するように記述します。
早送り機能の確認
A が B の祖先である場合にのみ、コミット A のブランチをコミット B に早送りできます。
gyim は、この状態をチェックする 1 つの方法を示しています (B から到達可能なすべてのコミットをリストし、リスト内の A をチェックします)。おそらく、この条件を確認するより簡単な方法は、A が A と B のマージ ベースであることを確認することです。
can_ff() {
a="$(git rev-parse "$1")" &&
test "$(git merge-base "$a" "$2")" = "$a"
}
if can_ff HEAD local-master/master; then
echo can ff to local-master/master
else
echo CAN NOT ff to local-master/master
fi
「コミット遅れ」の数を見つける</h2>
git rev-list ^HEAD upstream | wc -l
これは、HEAD が上流に早送りできることを必要としません(上流が HEAD からどれだけ遅れているかではなく、HEAD が上流にどれだけ遅れているかだけをカウントします)。
コミットを 1 つ進める
一般に、早送り可能な履歴は線形ではない場合があります。以下のヒストリー DAG では、マスターはアップストリームに早送りできますが、A と B は両方とも、マスターからアップストリームに向かう途中で「1 つのコミット フォワード」です。
---o---o master
|\
| A--o--o--o--o--o--o upstream
\ /
B---o---o---o---o
直線的な履歴であるかのように一方をたどることができますが、マージ コミットの直前の祖先までしかたどることができません。
リビジョン ウォーキング コマンドには、--first-parent
マージ コミットの最初の親につながるコミットのみを簡単に追跡できるオプションがあります。これをgit resetと組み合わせると、ブランチを「一度に 1 つのコミットで前方に」効果的にドラッグできます。
git reset --hard "$(git rev-list --first-parent --topo-order --reverse ^HEAD upstream | head -1)"
別の回答へのコメントでは、git resetへの恐怖から表現します。ブランチの破損が心配な場合は、一時ブランチを使用するか、分離された HEAD を名前のないブランチとして使用できます。作業ツリーがクリーンで、ブランチ (または切り離された HEAD) を移動することを気にしない限り、git reset --hard
何も破棄しません。それでも心配なら、作業ツリーにまったく手を加える必要がないgit fast-export の使用を真剣に検討する必要があります。
別の親に従うことはより困難になります。それぞれのマージで「どちらの方向」に進みたいかについてアドバイスできるように、おそらく独自のヒストリー ウォーカーを作成する必要があります。
マージ直前のポイントに移動すると、DAG は次のようになります (トポロジは以前と同じで、移動したのはマスターラベルのみです)。
---o---o--A--o--o--o--o--o master
| \
| o upstream
\ /
B---o---o---o---o
この時点で「コミットを 1 つ進める」とマージに移行します。これにより、B からマージ コミットまでのすべてのコミットが「取り込まれます」( masterから到達可能になります)。「コミットを 1 つ進める」ことで履歴 DAG にコミットが 1 つだけ追加されると仮定すると、このステップはその仮定に違反します。
この場合、本当に何をしたいのかを慎重に検討する必要があります。このように追加のコミットをドラッグするだけで問題ありませんか、それとも、マージ コミットを処理する前に、B の親に「戻って」そのブランチを進めるメカニズムが必要ですか?