Как сделать git-cherry-pick только изменения для определенных файлов? - PullRequest
480 голосов
/ 19 апреля 2011

Если я хочу объединить ветку Git с изменениями, внесенными только в некоторые файлы, измененные в конкретном коммите, который включает в себя изменения в нескольких файлах, как это может быть достигнуто?

Предположим, что коммит Git с именем stuff содержит изменения в файлах A, B, C и D, но я хочу объединить только изменения stuff в файлы A и B. Это звучит как работа для git cherry-pick, но cherry-pick знает, как объединять только коммиты, а не подмножество файлов.

Ответы [ 10 ]

584 голосов
/ 19 апреля 2011

Я бы сделал это с 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 .
113 голосов
/ 22 апреля 2015

Другие методы не работали для меня, так как коммит имел много изменений и конфликтовал со многими другими файлами.То, что я придумал, было просто

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 -
62 голосов
/ 02 марта 2016

Я обычно использую флаг -p с git checkout из другой ветви, который я считаю более простым и более детальным, чем большинство других методов, с которыми я сталкивался.

В принципе:

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 (Да) n (Нет) и т. д. для каждого фрагмента кода.

Опция -p или patch работает для различных команд в gitвключая git stash save -p, который позволяет вам выбрать, что вы хотите сохранить в своей текущей работе

Я иногда использую эту технику, когда проделал большую работу и хотел бы выделить ее и зафиксировать в более тематических материалах.совершает коммит, используя git add -p и выбирая, что я хочу для каждого коммита:)

41 голосов
/ 19 апреля 2011

Возможно, преимущество этого метода перед ответом Джефроми является то, что вам не нужно помнить, какое поведение 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
25 голосов
/ 04 декабря 2013

Cherry pick - это выбор изменений из определенного «коммита». Самое простое решение - выбрать все изменения определенных файлов - это использовать

 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/

UPDATE:

С помощью этого метода git не будет MERGE файл, он просто отменит любые другие изменения, сделанные в целевой ветви. Вам нужно будет объединить изменения вручную:

$ git diff HEAD filename

11 голосов
/ 30 октября 2017

Используйте git merge --squash branch_name, чтобы получить все изменения из другой ветки и подготовить коммит для вас.Теперь удалите все ненужные изменения и оставьте тот, который вы хотите.И мерзавец не узнает, что произошло слияние.

10 голосов
/ 12 августа 2014

Я бы просто все выбрал, а потом сделал бы:

git reset --soft HEAD^

Тогда я бы отменил изменения, которые мне не нужны, а затем сделал бы новый коммит.

9 голосов
/ 07 августа 2018

Ситуация:

Вы находитесь в своей ветви, скажем, master, и у вас есть коммит в любой другой ветви.Вы должны выбрать только один файл из этого конкретного коммита.

Подход:

Шаг 1: Оформить заказ на нужную ветку.

git checkout master

Шаг 2: Убедитесь, что вы скопировали необходимый хэш коммита.

git checkout commit_hash path\to\file

Шаг 3: Теперь у вас есть изменениянужный файл в нужной ветке.Вам просто нужно добавить и зафиксировать их.

git add path\to\file
git commit -m "Your commit message"
4 голосов
/ 16 февраля 2017

Я нашел другой способ, который предотвращает любое противоречивое слияние при сборке вишни, которое IMO легко запомнить и понять.Так как на самом деле вы выбираете не коммит, а часть его, вам нужно сначала разделить его, а затем создать коммит, который соответствует вашим потребностям, и выбрать его.

Сначала создайте ветку изКоммит, который вы хотите разделить и оформить его:

$ git checkout COMMIT-TO-SPLIT-SHA -b temp

Затем верните предыдущий коммит:

$ git reset HEAD~1

Затем добавьте файлы / изменения, которые вы хотите, в cherry-pick:

$ git add FILE

и зафиксируйте его:

$ git commit -m "pick me"

запишите хеш коммита, давайте назовем его PICK-SHA и вернемся к вашей основной ветке, например, master для принудительной проверки:

$ git checkout -f master

и cherry-pick коммит:

$ git cherry-pick PICK-SHA

теперь вы можете удалить временную ветку:

$ git branch -d temp -f
2 голосов
/ 11 апреля 2018

Объединить ветку в новую (сквош) и удалить ненужные файлы:

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