1

概要

問題を掘り下げるほど、問題の概要がわかりやすくなります。gitインフラストラクチャを使用して、実際にはアプリケーションドメイン内のツリーであるDAGの頂点の親を取得するにはどうすればよいですか。

よく読んでください。どんなアイデアでも大歓迎です(git固有)。

質問

半自動コマンドを使用して作成したスクリプトによって履歴が作成されたリポジトリがあります。

ここに画像の説明を入力してください

そのため、コマンドの実行時に、必要に応じて、たとえば黄色で色付けされたタグなど、あらゆる種類の情報を履歴に自動的に入れることができます。

このすべての重要な要件は、マージの競合が発生したときに発生することです(スクリプトの目的は、ユーザーにマージの競合を認識させ、他のユーザーと連絡を取り、解決策を見つけることです。問題-マージの競合が発生した場合に問題が発生します。スクリプトでユーザー間のコミュニケーションを促進したいと思います)

それを念頭に置いて、マージコミットを元に戻したいとしましょう。install-defこれは、この画像のように、競合していないマージに最適です。私はgit revert -m 1 install-def(例えば)使用する必要があります。

install-abcこれらのコミット(マージコミット)を正確に元に戻したいので、元に戻す必要がある場合、手順はより複雑になります。これは、install-abcからの「灰色の」子ですremotes/hacklet/abc/master

profile/myfirstprofileつまり、とのみの線形履歴を取得しremotes/hacklet/def/masterます。

ほぼすべてのコミットに任意のタグで注釈を付けることができると仮定して、半自動化されたスクリプトでこれを実現するための最も簡単で安全な方法は何ですか?スクリプトはbashで記述されているため、 DAG (または、さらに言えば、再帰)に関連することを何もする必要がないことが望ましいです。

「元に戻す」は「アンインストール」を行います。git revert -m 1 ...の状況でコミットを元に戻すために機能しますinstall-defが、次のようにinstall-abcなります。

error: could not revert 18cff49... using hacklet/abc/master in profile
myfirstprofile hint: after resolving the conflicts, mark the corrected
paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and
commit the result with 'git commit'

profileブランチにはそのようなinstall-コミットを多数含めることができます。そのうちの1つだけを削除したいと思います。「インストール」も「プロファイル」もネストできません。

:「モジュール」と「サブツリー」について知っています。わざわざ言及しないでください。ここで行っているのはアプリケーションドメインに固有のものであり(gitはアプリケーションの一部です)、これは開発サイクルでgitを使用することではありません。これらの2つの機能を徹底的に分析しましたが、スクリプトのアプリケーションドメインに適合していません。


補遺1

私はこの情報を含めるためにハッキングしました。これにより、私は簡単に考えることができます。

ここに画像の説明を入力してください

これが過度に複雑になっていると思われる場合は、そうではありません。基本的に同じパターンが何度も繰り返されます。

ここに画像の説明を入力してください

ここでは、のみstart-profileinstall-abcおよびinstall-foo競合は発生していません。しかし、木の構造は「同じ」ように見えます。

そして最後の1つは、すべての競合(最初の、を除くinstall-abc)があります。これは、gitkのカラフルな出力が好きだからです。

ここに画像の説明を入力してください

さらにもう1つですが、競合はまったくありません。

ここに画像の説明を入力してください

profile/myfirstprofile:ブランチでタグ付けされていない個々のコミットが存在する場合があります。そのような場合、それらのコミットは保持されるべきです。本当に他に何も「アンインストール」されるべきではありませんが、に属するものはコミットしinstall-THINGます。


補遺2

before-install-対応するものはで見つけることができると私は理解しましたがgit describe --tags $(git rev-list -1 install-abc)。でも:

タグが与えられた場合、子のコミットinstall-defを見つける方法-最後の画像ではこれは?before-install-ghi

最後のメモ(中間のタグなしコミット)を考慮すると、これらの「子と親」のコミットを見つけるには、install-THING「アンインストール」したいものがなくても、一緒に貼り付けるのが適切ですか?

PS:有向非巡回グラフで指示された単語が何を意味するのかは本当に理解していますが、gitインフラストラクチャと概念を使用して、gitに固有の方法があるはずです。

:何かを「アンインストール」するたびにツリーを繰り返す必要はありません。

4

2 に答える 2

1

この説明は一般的なgitの用語をヘッジしていないため複雑ですが、私が知る限り、あなたは3つの質問のうちの1つを尋ねています(確かに#3です)。

  1. 「以前の分岐コミットにリセットするにはどうすればよいですか?」
  2. 「ブランチをリセットしたり、履歴内の以前のコミットをチェックアウトしたりせずに、マージコミットの親に戻すにはどうすればよいですか?」
  3. 「後のダウンストリームコミットが、元に戻すマージ親に基づいている場合、どうすればマージコミットを元に戻すことができますか?」

この説明については、次のグラフを検討してください。

G
|
F
|\
D E
|/ 
C
|
B
|
A

まず、いくつかの用語:

コミット「D」と「E」は、マージコミットであるコミット「F」の「マージ親」です。表示されるグラフには、ほとんどの場合、用語では「左」と「右」、git用語では「最初」と「2番目」の2つの親がありますが、マージで持つことができる親の数に制限はありません。技術的には、いわゆる「タコのマージ」が可能であり、3人以上の親である可能性があります。実際にはめったに使用されません。

マージの親は^、gitの構文を使用して正規に記述されます。質問を理解しやすくするため、この構文を使用してください。最初の親は、、^12番目の親は^2です。言い換えると:

F^1 is equivalent to D
F^2 is equivalent to E

あなたの質問の最も紛らわしい側面は、あなたが到達しようとしている状態を理解することです。それでは、考えられる3つの問題について説明しましょう。


「以前の分岐コミットにリセットするにはどうすればよいですか?」

コミット「D」に到達しようとしていて、「E」、「F」、または「G」によって導入された変更を気にしないとします。Let_Me_Beの答えを使用して:

git reset --hard D

代わりに「E」に到達したい場合も同じように機能しますが、「D」、「F」、または「G」によって導入された変更を保持することについてはまったく気にしませんでした。


「ブランチをリセットしたり、履歴内の以前のコミットをチェックアウトしたりせずに、マージコミットの親に戻すにはどうすればよいですか?」

代わりに、もっと複雑なものが必要だとします。「E」または「G」の変更を失うことなく、「D」の変更を元に戻したいとします。「F」も「G」も「D」の変更に基づいていない限り、これも簡単な操作です。その場合:

git revert -m 2 'F'

コマンド構文は、「マージコミット'F'を元に戻し、2番目の親をメインラインにする」ことを意味します。結果の履歴(ここでも「G」は「D」に基づいていないと仮定)は、「D」がマージされなかったかのように見えますが、もちろん実際の履歴は次のようになります。

H
|
G
|
F
|\
D E
|/ 
C
|
B
|
A

ここで、「H」は復帰コミットです。「F」を元に戻し、「D」をメインラインとして使用する場合は、コマンドで指定された親番号を変更するだけです( 「最初の親」git revert -m 1 'F'の使用に注意してください)。1


「後のダウンストリームコミットが、元に戻すマージ親に基づいている場合、どうすればマージコミットを元に戻すことができますか?」

わかった。これは最も難しい状況です。これを頻繁に行う場合、コンテキストに関係なく、gitは問題の解決策ではありません。Gitは、可能であれば、競合の解決について完全に不可知論者であり続けようとします。それが全体のポイントです。マージの競合がソフトウェアによって解決できれば、それは解決します。それらがワークフローで定期的に発生する場合は、ワークフローが問題であり、VCSではありません。

履歴の改訂を避けたい場合(つまりgit rebase、可能であっても完全に自動化するのはおかしいでしょう)、復帰の競合を解決する唯一の方法は、'D'コードに基づいて後続のコミットを復帰させることです。言い換えると:

git revert G
git revert -m 1 F

その後、必要に応じて「gitcherry-pickG」(元の「G」コミットハッシュ)を使用して「G」を再適用できますが、適用がスムーズに行われない可能性があります。結果の履歴は次のようになります。

J - Reapplication of G
|
I - Revert of F
|
H - Revert of G
|
G
|
F
|\
D E
|/ 
C
|
B
|
A

この回答があなたの状況を最もよく表している場合は、アプリケーションをgit以外の場所で探すことを強くお勧めします。あなたがしていることは人間の間でかなり壊れたバージョン管理ワークフローになるので、それはあなたが望むことを簡単に行うようには設計されていません。私はあなたのアプリがすべてのエッジケースを捕らえる能力に懐疑的です。競合自体がかなり予測可能であっても、インテリジェントな競合解決を行うことは簡単な問題ではありません。もちろん私は間違っている可能性があります。

于 2012-08-13T18:32:46.777 に答える
0

これは推測であり、答えです(私はまだ質問に非常に混乱しているため)。

しかし、私の推測では、あなたはこれをしたいと思っています:

git reset --hard start_myfirstprofile
git merge remotes/hacklet/def/master

合体前の状態に戻したい場合。

git reset HEAD~1

正しいブランチで問題ないはずです。

于 2012-08-13T10:27:56.327 に答える