Как git-cherry-pick изменяет только определенные файлы?


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

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

10 405

10 ответов:

Я бы сделал это с 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

или если вы хотите пропустить добавление, вы можете использовать до git apply

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

возможно преимущество этого метода над 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

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

в принципе:

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

затем вы получаете диалоговое окно с вопросом, какие изменения вы хотите в "blobs" это в значительной степени работает для каждого куска непрерывного изменения кода, который вы можете затем сигнализировать y (Да) n (нет) etc для каждый кусок кода.

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

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

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/

обновление:

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

$ git diff HEAD filename

Я бы просто вишни-забрать все, а затем сделать это:

git reset --soft HEAD^

затем я бы вернул изменения, которые я не хочу, а затем сделал новую фиксацию.

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

Я нашел другой способ, который предотвращает любое конфликтное слияние на вишневом сборе, которое ИМО легко запомнить и понять. Поскольку вы на самом деле не выбираете фиксацию, а часть ее, вам нужно сначала разделить ее, а затем создать фиксацию, которая будет соответствовать вашим потребностям, и выбрать ее.

сначала создайте ветку из фиксации, которую вы хотите разделить, и проверьте ее:

$ 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

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

$ 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

ситуация:

вы на своей ветке, скажем 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"