Gitで特定のコミットをマージする方法


1035

私はGitHubのリポジトリからブランチを分岐し、私に固有の何かをコミットしました。現在、元のリポジトリにはにあった優れた機能がありましたHEAD

以前のコミットなしでのみマージしたい。私は何をすべきか?すべてのコミットをマージする方法を知っています:

git branch -b a-good-feature
git pull repository master
git checkout master
git merge a-good-feature
git commit -a
git push

githubに関連してこれを実行しようとしている場合は、この記事で手順を説明します。markosullivan.ca/how-to-handle-a-pull-request-from-github
johndpope

回答:


1176

git cherry-pick」がここであなたの答えになるはずです。

既存のコミットによって導入された変更を適用します。

この投稿でチェリーピックの結果についてのbdonlanの回答を忘れずに読んでください:
「ブランチからすべてのコミットをプルし、指定されたコミットを別のコミットにプッシュしてください」

A-----B------C
 \
  \
   D

になる:

A-----B------C
 \
  \
   D-----C'

このコミットの問題は、gitがコミットの前にすべての履歴を含めると見なしていることです。

C 'には別のSHA-1IDがあります。
同様に、あるブランチから別のブランチへのコミットを選択するチェリーでは、基本的にパッチを生成してから適用するため、同様に履歴が失われます。

このコミットIDの変更により、gitのマージ機能が他のものに影響します(ただし、控えめに使用すると、これについて説明するヒューリスティックが存在します)。
さらに重要なのは、関数の依存関係を無視することです。Cが実際にBで定義された関数を使用した場合は、決してわかりません


1
@ openid000:「より細かい枝」:これは確かにbdonlanが彼の回答で示唆したとおりです。
VonC、2009年

8
注:「git rebase」もSHA-1を変更します。「git rebaseとgitマージ(stackoverflow.com/questions/804115/git-rebase-vs-git-merge)と「git workflow」(stackoverflow.com/questions/457927/…)も参照してください。「合法的である。
VonC

1
「きめの細かいブランチ」、「チェリーピック」、「リベース」の間に、gitを使用してブランチ内のコードを管理するためのすべての可能性があります。
VonC、2009年

@VonC "細かい枝"はい。2つのブランチがあり、1つのブランチで特定の視覚化モジュールをアップグレードしました。このモジュールは他のすべてのコードとは独立していたため、これらの変更を他のブランチにも適用するのにチェリーピックが便利
でした

1
ただし、マージすると、コミットC 'とCの両方がコミット履歴で優先されます。
Rahul Shah

738

git cherry-pickを使用して、単一のコミットを単独で現在のブランチに適用できます。

例: git cherry-pick d42c389f


68
チェリーピッキングに関する以前の投稿の+1(stackoverflow.com/questions/880957/…)。私は自由にそれを抜粋して、上記の自分の答えをコピーしました。
VonC、2009年

4
おそらくgit cherry-pick d42cまたはgit cherry-pick d42c3 動作します。Gitはスマートです。;)
guneysus、2015

2
致命的:悪いリビジョン
Ievgen Naida

2
このコマンドを実行したところ、うまくいったようですが、git statusを実行すると、「コミットするものは何もない、作業ツリーがクリーン」と表示されます。bitbucket Webページのコミットページを更新しても、表示されません。しかし、git logを実行すると表示されます。変更されたコードが表示されます。追加の手順を実行する必要があるかどうか誰かが説明できますか?
Ray

1
残念ながら、これは質問の答えにはなりません。実際にはマージは作成されません。を指す祖先はありませんd42c389f。おそらく、OPはそれ自体がマージの作成を気にしていなかったかもしれませんが、違いが時々問題になります。
LarsH

29

例を挙げて理解してみましょう:

X <commit-id>を指すブランチ(masterなど)があり、Y <sha1>を指す新しいブランチがあります。

ここでY <コミット-ID> = <マスター>ブランチのコミット-いくつかのコミット

ここで、Yブランチについて、マスターブランチと新しいブランチ間のコミットをギャップクローズする必要があると言います。以下は、実行できる手順です。

ステップ1:

git checkout -b local origin/new

ここで、localはブランチ名です。任意の名前を付けることができます。

ステップ2:

  git merge origin/master --no-ff --stat -v --log=300

マスターブランチから新しいブランチにコミットをマージし、マージされる最大<n>個の実際のコミットからの1行の説明を含むログメッセージのマージコミットを作成します。

Gitマージの詳細とパラメーターについては、以下を参照してください。

git merge --help

また、特定のコミットをマージする必要がある場合は、以下を使用できます。

git cherry-pick <commit-id>

Y3D文のの定義を変更しましたか?「私はYを指す新しいブランチを持っている」と「Yブランチを今言う」は、Yは以前はコミット
でした

マージしたいブランチの特定のコミットポイントからそれを行う方法
Kulbhushan Singh

3

私のユースケースでは、CI CDに対する同様のニーズがありました。開発ブランチとマスターブランチでgitフローを使用しました。開発者は、変更を直接マージして開発したり、機能ブランチからのプルリクエストを介して自由にマージしたりできます。ただし、マスターするには、Jenkinsを介して自動化された方法で、developブランチからの安定したコミットのみをマージします。

この場合、チェリーピックを実行することは適切なオプションではありません。ただし、commit-idからローカルブランチを作成してから、そのローカルブランチをマスターにマージし、mvn clean verify(mavenを使用)を実行します。成功した場合、localCheckout = trueオプションとpushChanges = falseを指定したmavenリリースプラグインを使用して、製品バージョンのアーティファクトをネクサスにリリースします。最後にすべてが成功したら、変更とタグをoriginにプッシュします。

サンプルコードスニペット:

手動で行った場合、マスターにいると仮定します。ただし、ジェンキンスでは、リポジトリをチェックアウトすると、デフォルトのブランチ(構成されている場合はマスター)になります。

git pull  // Just to pull any changes.
git branch local-<commitd-id> <commit-id>  // Create a branch from the given commit-id
git merge local-<commit-id>  // Merge that local branch to master.
mvn clean verify   // Verify if the code is build able
mvn <any args> release:clean release:prepare release:perform // Release artifacts
git push origin/master  // Push the local changes performed above to origin.
git push origin <tag>  // Push the tag to origin

これにより、大胆不敵なマージまたは紛争地獄を完全に制御できます。

より良いオプションがある場合は、遠慮なくアドバイスしてください。


3

主要な回答は、特定のコミットからの変更を現在のブランチに適用する方法を説明しています。それが「どのようにマージするか」であなたが意味することであるならば、彼らが提案するように、ちょうどチェリーピックを使ってください。

しかし、実際にマージが必要な場合、つまり、2つの親持つ新しいコミット(現在のブランチの既存のコミットと、変更を適用したいコミット)が必要な場合、チェリーピックはそれを実現しません。

たとえば、ビルドプロセスでgitの祖先を利用して最新のタグに基づいてバージョン文字列を自動的に設定する場合(を使用git describe)、真のマージ履歴があることが望ましい場合があります。

チェリーピックの代わりに、実際のを実行してgit merge --no-commitから、手動でインデックスを調整して、不要な変更を削除できます。

あなたがブランチにいて、ブランチAの先端にあるコミットをマージしたいとしますB

git checkout A
git merge --no-commit B

これで、2つの親を持つコミットを作成する準備が整いました。現在のヒントは、AとのコミットですB。ただし、Bブランチでの以前のコミットからの変更を含め、必要以上の変更が適用される場合があります。これらの不要な変更を元に戻し、コミットする必要があります。

(作業ディレクトリとインデックスの状態をマージ前の状態に戻す簡単な方法があるかもしれません。そうすれば、最初に必要なコミットをチェリーピックするためのクリーンなスレートが得られます。しかし、私はきれいなスレートを達成する方法がわからない。git checkout HEADそしてgit reset HEAD、両方のこの方法の目的を破って、マージ状態を削除します。)

したがって、不要な変更を手動で元に戻します。たとえば、

git revert --no-commit 012ea56

不要なコミットごとに012ea56

調整が終わったら、コミットを作成します。

git commit -m "Merge in commit 823749a from B which tweaked the timeout code"

これで、必要な変更のみが可能になり、祖先ツリーにBから技術的にマージされたことが示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.