5

ブランチを別のブランチと同一になるように更新する方法がわかりません。次に例を示します。

git init test; cd test
echo apple >a; echo banana >b; git add a b; git commit -m 'A1/a:apple;b:banana'
echo carrot >c; git add c; git commit -m 'A2/c:carrot'
git checkout -b second HEAD^1
echo beets >b; echo dandelion >d; git add b d; git commit -m 'B1/b:beets;d:dandelion'

この時点で、私の履歴は次のようになります。

A1-----A2     (master, contains a:apple, b:banana, c:carrot)
 \
  \----B1     (second, contains a:apple, b:beets, d:dandelion)

ここで、「second」ブランチにコミットを追加して、その内容を「master」ブランチと一致させたいと思います。つまり、次のようになります。

A1-----A2
 \
  \----B1--?--B2     (desired contents a:apple, b:banana, c:carrot)

私の質問は、これを行うためにどの git コマンドを実行すればよいかということです。私が思いついた最も近いものは次のとおりです。

git checkout master .
git commit -m B2

ただし、これにより b がバナナにリセットされ、c が復元されますが、ファイル d は削除されません。私は、私が望むことを行うバリエーションを思いつくことができませんでしたgit resetgit revert私の実際のリポジトリでは、ブランチの履歴はこの例よりも複雑であり、ブランチにはマージが含まれている可能性があるため、のバージョンを実行したいとは思いません。

どんな助けでも大歓迎です!

4

5 に答える 5

2

現在のブランチはsecond. に不満がある場合git reset --HARD master(が公開されている場合は強制プッシュが必要になるため)、 (またはB1 などのすべてのコミットを一覧表示したくない場合second) によって B1 を元に戻すことができます。git revert B1git revert master..secondgit merge master

@StevenPenny のアイデアとours戦略を使用して、このソリューションを思いつきました。

git checkout master
git checkout -b transfer_second_to_master
git merge -s ours second
git checkout second
git merge transfer_second_to_master
git branch -d transfer_second_to_master

それは一種の戦略のエミュレーションであり、theirs戦略の反転として行われますours。そして今git diff master secondは何も与えません。これは、ブランチが同一であることを意味します。

于 2013-04-03T23:55:47.610 に答える
2

The simple way

You almost had the right answer. The solution is to first remove all of the files before checking out from master.

git checkout second
git rm -rf .
git checkout master .
git commit -m B2

This will create a new commit with a new message, author, and timestamp. If you all that to be the same, your best bet is...

Using git-reparent (shameless plug)

Download git-reparent, install it in your $PATH, and then

git checkout second
git branch parent
git reset --hard master
git reparent -p parent
git branch -d parent

Explanation:

  1. Switch to the branch we want to modify (second).
  2. Save a pointer (parent) to the current commit.
  3. Point the commit that we want to end up at (master).
  4. Modify the current branch (second) to have the contents of the current commit but have the given parents (parent).
  5. Delete our saved pointer (parent).
于 2013-04-04T03:31:04.137 に答える
1

これは次の仕事のように聞こえます git merge

git checkout master
git merge -s ours second

より詳しい情報

これにより任意の数のヘッドが解決されますが、マージの結果のツリーは常に
現在のブランチ ヘッドのものであり、他のすべての変更を効果的に無視します。
枝。これは、サイドの古い開発履歴に取って代わるために使用されることを意図しています
枝。
于 2013-04-03T23:56:26.427 に答える
1

A1-----A2     (master, contains a:apple, b:banana, c:carrot)
 \
  \----B1     (second, contains a:apple, b:beets, d:dandelion)
  • 現在のブランチ: 2 番目
  • git status: 掃除

バリアント 1: マスターへの参照なし (非常に醜い)

git read-tree -m -u master
git commit -m 'B2: copy of A2'
git diff master

後:

A1-----A2      (master, contains a:apple, b:banana, c:carrot)
 \
  \----B1---B2 (second, contains a:apple, b:banana, c:carrot)
  • 現在のブランチ: 2 番目 (ff)
  • git status: 掃除
  • diff状態までmaster:きれい

バックオフが機能することを確認します。

git reset --hard HEAD^
git clean -f
git branch -avv

前の状態を再度表示します。

この亜種は何をしますか?

  • git read-tree指定された他のコミット (ここmaster) を INDEX に読み込みます
  • オプション-uが指定されると、それに応じてワークツリーを更新します
  • 次に、これは通常どおり B1 にコミットされます
  • ただし、「マージされた」ツリーへの参照は追加されません。

バリアント 2: master へのマージ参照を表示する (推奨!)

すみません、正しい方法がわかりませんでした。回避策は次のとおりです。

最初: ダミーのマージを行う

git merge -s ours -m 'B2 dummy' master

2 番目: マージを正しいデータに修正する

git read-tree -m -u master
git commit --amend -m 'B2: copy of A2'

3番目: 本当に一致することを確認しますmaster:

git diff master

後:

A1-------A2    (master, contains a:apple, b:banana, c:carrot)
 \         \
  \----B1---B2 (second, contains a:apple, b:banana, c:carrot)
  • 現在のブランチ: 2 番目 (ff、マージ済み、最初の親: B1)
  • git status: 掃除
  • diff状態までmaster:きれい

バックオフが機能することを確認します。

git reset --hard HEAD^
git clean -f
git branch -avv

必要に応じて、前の状態を再度表示します。

これはどのように作動しますか:

  • git read-tree -m -u masterマージ情報をリセットするため、残念ながら、マージを開始してツリーを読み取り、後でこのマージをコミットすることはできません。
  • -uただし、これはワークツリーの更新に不可欠であるため、オプションを使用したいと考えています。しかし、 required または同様のもの-u-m、マージ モードから抜け出します。
  • そのため、前にダミーのマージを実行します (そしてours、マージの競合を防ぐために戦略を使用しますが、これはまさに私たちが望んでいる間違ったことです)。
  • 次に、必要に応じてマスターから状態を読み取りgit read-treeます
  • そして今amend、最終的に正しいインデックスの内容とマージします。
  • これにより、元のマージ情報が保持されます。
  • ffこれはアップストリームによることに注意してください。

これの何が問題なのですか?

  • git commitアトミックであることを意味します。あなたが正しい状態を持っているかどうかのどちらかです。
  • ただし、これにより、競合状態 (停電) によってローカルの git リポジトリが望ましくない状態になる可能性がある非アトミックな状況が発生します。
  • これは、この戦略が自動化されたセットアップで使用される場合には不適切です。たとえば、リリース (B1) の後、現在のアップストリーム (マスター) を使用して再起動し、次のリリース (B2 以降) を作成する必要があります。
  • したがって、バリアント 2 は、これに対する決定的な最後の言葉と見なすことはできません。はい、何とか機能しますが、きれいでもなく、完璧でもありません。

それを行うための他のソリューションは、複雑すぎるようです。しかし、おそらく私は少し監督しましたか?

  • 完全に理解できない git-plumbing コマンドを使用して、正しい commit-object を自分で作成するか、理解して使用するのが簡単なソリューションには行きません。

  • または、非常に複雑なサブブランチを実行してから、サブブランチに早送りしてから削除します。これにより、何かが壊れた場合に複雑なクリーンアップが必要になるなど、より複雑なことが発生するため、二重のノーゴーです。

  • または、ワークツリーをインデックスに更新するために必要なコマンドを見つけます (これ-ugit read-tree master、通常どおり) コミットの前 (!) に発生する必要があるためです。

TODO

これは、サブモジュールで完全にテストされていません。それらが追加、削除、置換などされ、更新さ.gitmodules.git/modules/ているか、いくつかのものをブロックしている場合。すごい話。

于 2016-03-11T17:53:29.677 に答える