web-dev-qa-db-ja.com

特定のファイルへの変更のみをgit-cherry-pickする方法は?

複数のファイルへの変更を含む特定のコミットで変更されたファイルの一部だけに加えられた変更をGitブランチにマージしたい場合、どうすればこれを達成できますか?

stuffと呼ばれるGitコミットが、ファイルABC、およびDに変更を加えたが、stuffの変更のみをファイルAおよびBにマージしたいとします。それはgit cherry-pickの仕事のように思えますが、cherry-pickはコミットの全体をマージする方法を知っているだけで、ファイルのサブセットではありません。

470
Tobias Kienzler

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 .
573
Cascabel

他の方法は私にとってはうまくいきませんでした。コミットは他の多くのファイルに対して多くの変更と衝突をしたからです。私が思いついたのは単純なことです

git show SHA -- file1.txt file2.txt | git apply -

それは実際にはファイルをaddしたりあなたのためにコミットしたりしないので、あなたはそれをフォローする必要があるかもしれません。

git add file1.txt file2.txt
git commit -c SHA

追加をスキップしたい場合は--cachedgit apply引数を使用できます。

git show SHA -- file1.txt file2.txt | git apply --cached -
112

私は通常他のブランチからの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を使ってより多くのトピックベースのコミットをコミットしたいのですが、それぞれのコミットに必要なものを選びます:)

58
Tyrone Wilson

おそらく、この方法が 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
41
Mark Longair

チェリーピックは、特定の「コミット」から変更を選ぶことです。最も簡単な解決策は、特定のファイルのすべての変更を選択することです。

 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ファイル名

25
cminatti

git merge --squash branch_nameを使用すると、これは他のブランチからすべての変更を取得し、あなたのためにコミットを準備します。不要な変更をすべて削除して、必要な変更を残します。そしてgitはマージがあったことを知りません。

11
Indomitable

私はただすべてをチェリーピックし、それからこれをします:

git reset --soft HEAD^

それから、望まない変更を元に戻してから、新しいコミットを行います。

10
funroll

状況:

あなたはあなたのブランチにいます、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"
8
techdreams

私は、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
4
Alexey

ブランチを新しいもの(スカッシュ)にマージして、不要なファイルを削除します。

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
2
nvd