複数のファイルへの変更を含む特定のコミットで変更されたファイルの一部だけに加えられた変更をGitブランチにマージしたい場合、どうすればこれを達成できますか?
stuff
と呼ばれるGitコミットが、ファイルA
、B
、C
、およびD
に変更を加えたが、stuff
の変更のみをファイルA
およびB
にマージしたいとします。それはgit cherry-pick
の仕事のように思えますが、cherry-pick
はコミットの全体をマージする方法を知っているだけで、ファイルのサブセットではありません。
cherry-pick -n
(--no-commit
)を使用して、コミットする前に結果を検査(および修正)することができます。
git cherry-pick -n <commit>
# unstage modifications you don't want to keep, and remove the
# modifications from the work tree as well.
# this does work recursively!
git checkout HEAD <path>
# commit; the message will have been stored for you by cherry-pick
git commit
ほとんどの修正が望まないもので、個々のパスをチェックアウトするのではなく(中央のステップ)、すべてを元に戻してから、必要なものを追加することができます。
# unstage everything
git reset HEAD
# stage the modifications you do want
git add <path>
# make the work tree match the index
# (do this from the top level of the repo)
git checkout .
他の方法は私にとってはうまくいきませんでした。コミットは他の多くのファイルに対して多くの変更と衝突をしたからです。私が思いついたのは単純なことです
git show SHA -- file1.txt file2.txt | git apply -
それは実際にはファイルをadd
したりあなたのためにコミットしたりしないので、あなたはそれをフォローする必要があるかもしれません。
git add file1.txt file2.txt
git commit -c SHA
追加をスキップしたい場合は--cached
にgit apply
引数を使用できます。
git show SHA -- file1.txt file2.txt | git apply --cached -
私は通常他のブランチからのgitチェックアウトで-p
フラグを使います。
原則:
git checkout <other_branch_name> <files/to/grab in/list/separated/by/spaces> -p
例:
git checkout mybranch config/important.yml app/models/important.rb -p
その後、「blob」にどのような変更を加えるかを尋ねるダイアログが表示されます。これは、コードの連続する部分ごとにy
(Yes)n
(No)などのシグナルを送ることができます。
-p
またはpatch
オプションは、あなたが現在の仕事から隠したいものを選ぶことを可能にするgit stash save -p
を含む、gitのさまざまなコマンドに対して機能します。
私は多くの仕事をしてきたときにこのテクニックを使い、それを分離してgit add -p
を使ってより多くのトピックベースのコミットをコミットしたいのですが、それぞれのコミットに必要なものを選びます:)
おそらく、この方法が Jefromiの答え より優れているのは、 git resetのどの動作を覚えておく必要がないかということです は正しいものです:)
# Create a branch to throw away, on which we'll do the cherry-pick:
git checkout -b to-discard
# Do the cherry-pick:
git cherry-pick stuff
# Switch back to the branch you were previously on:
git checkout -
# Update the working tree and the index with the versions of A and B
# from the to-discard branch:
git checkout to-discard -- A B
# Commit those changes:
git commit -m "Cherry-picked changes to A and B from [stuff]"
# Delete the temporary branch:
git branch -D to-discard
チェリーピックは、特定の「コミット」から変更を選ぶことです。最も簡単な解決策は、特定のファイルのすべての変更を選択することです。
git checkout source_branch <paths>...
例では:
$ git branch
* master
Twitter_integration
$ git checkout Twitter_integration app/models/avatar.rb db/migrate/20090223104419_create_avatars.rb test/unit/models/avatar_test.rb test/functional/models/avatar_test.rb
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: app/models/avatar.rb
# new file: db/migrate/20090223104419_create_avatars.rb
# new file: test/functional/models/avatar_test.rb
# new file: test/unit/models/avatar_test.rb
#
$ git commit -m "'Merge' avatar code from 'Twitter_integration' branch"
[master]: created 4d3e37b: "'Merge' avatar code from 'Twitter_integration' branch"
4 files changed, 72 insertions(+), 0 deletions(-)
create mode 100644 app/models/avatar.rb
create mode 100644 db/migrate/20090223104419_create_avatars.rb
create mode 100644 test/functional/models/avatar_test.rb
create mode 100644 test/unit/models/avatar_test.rb
出典と詳しい説明 http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/
更新:
この方法では、gitはファイルをマージせず、目的のブランチで行われた他の変更を上書きするだけです。変更を手動でマージする必要があります。
$ git diff HEADファイル名
git merge --squash branch_name
を使用すると、これは他のブランチからすべての変更を取得し、あなたのためにコミットを準備します。不要な変更をすべて削除して、必要な変更を残します。そしてgitはマージがあったことを知りません。
私はただすべてをチェリーピックし、それからこれをします:
git reset --soft HEAD^
それから、望まない変更を元に戻してから、新しいコミットを行います。
状況:
あなたはあなたのブランチにいます、master
としましょう、そしてあなたは他のブランチにあなたのコミットをしています。その特定のコミットから1つのファイルだけを選ぶ必要があります。
アプローチ:
ステップ1:必要なブランチをチェックアウトしてください。
git checkout master
ステップ2:必要なコミットハッシュをコピーしたことを確認してください。
git checkout commit_hash path\to\file
ステップ3:これで必要なファイルの変更が目的のブランチに追加されました。追加してコミットするだけです。
git add path\to\file
git commit -m "Your commit message"
私は、IMOが覚えやすく理解しやすいように、チェリーピッキングで競合するマージを防ぐ別の方法を見つけました。実際にはコミットを選択するのではなく、その一部を選択しているので、まずそれを分割してから、ニーズに合ったコミットを作成して選択する必要があります。
まず、分割したいコミットからブランチを作成してチェックアウトします。
$ git checkout COMMIT-TO-SPLIT-SHA -b temp
その後、前のコミットを元に戻します。
$ git reset HEAD~1
それからチェリーピックしたいファイル/変更を追加します。
$ git add FILE
そしてそれをコミットします。
$ git commit -m "pick me"
コミットハッシュに注意して、それをPICK-SHAと呼び、メインブランチに戻りましょう。例えばチェックアウトを強制するために使います。
$ git checkout -f master
コミットをチェリーピックします。
$ git cherry-pick PICK-SHA
これで、一時ブランチを削除できます。
$ git branch -d temp -f
ブランチを新しいもの(スカッシュ)にマージして、不要なファイルを削除します。
git checkout master
git checkout -b <branch>
git merge --squash <source-branch-with-many-commits>
git reset HEAD <not-needed-file-1>
git checkout -- <not-needed-file-1>
git reset HEAD <not-needed-file-2>
git checkout -- <not-needed-file-2>
git commit