Частично вишневый коммит с Git

Я работаю над 2 разными ветками: релиз и разработка.

Я заметил, что мне все еще нужно интегрировать некоторые изменения, которые были внесены в ветку релиза, обратно в ветку разработки.

Проблема в том, что мне не нужны все коммиты, только некоторые фрагменты в определенных файлах, поэтому просто

git cherry-pick bc66559

не делает трюк.

Когда я делаю

git show bc66559

Я могу видеть разницу, но не знаю, как правильно применить ее частично к моему текущему рабочему дереву.

8 ответов

Решение

Главное, что вам здесь нужно, это git add -p (-p это синоним --patch). Это обеспечивает интерактивный способ регистрации контента, позволяя вам решить, должен ли каждый ханк входить, и даже позволяет вам вручную редактировать патч, если это необходимо.

Чтобы использовать его в сочетании с вишней:

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(Спасибо Тиму Хенигану за напоминание о том, что у git-cherry-pick есть опция --no-commit, и спасибо Феликсу Рабу за то, что он указал, что вам нужно выполнить сброс! Если вы хотите оставить некоторые вещи вне коммита Вы могли бы использовать git reset <path>... удалить только эти файлы.)

Конечно, вы можете указать конкретные пути add -p если необходимо. Если вы начинаете с патча, вы можете заменить cherry-pick с apply,


Если вы действительно хотите git cherry-pick -p <commit> (эта опция не существует), вы можете использовать

git checkout -p <commit>

Это будет отличать текущий коммит от указанного вами коммита и позволит вам применять фрагменты из этого дифференцирования индивидуально. Эта опция может быть более полезной, если коммит, в который вы вносите, имеет конфликты слияния в части фиксации, в которой вы не заинтересованы. (Обратите внимание, однако, что checkout отличается от cherry-pick: checkout пытается применить <commit>содержание целиком, cherry-pick применяет diff указанного коммита от его родителя. Это означает, что checkout может применить больше, чем просто этот коммит, который может быть больше, чем вы хотите.)

Я знаю, что отвечаю на старый вопрос, но похоже, что есть новый способ сделать это с интерактивной проверкой:

git checkout -p bc66559

Можно ли в интерактивном режиме выбрать фрагменты из другого комита git?

Предполагая, что необходимые изменения находятся во главе ветки, из которой вы хотите внести изменения, используйте git checkout

для одного файла:

git checkout branch_that_has_the_changes_you_want path/to/file.rb

для нескольких файлов просто цепочка:

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

Опираясь на ответ Майка Монкевича, вы также можете указать один или несколько файлов для извлечения из предоставленной ветки sha1/.

git checkout -p bc66559 -- path/to/file.java 

Это позволит вам в интерактивном режиме выбрать изменения, которые вы хотите применить к вашей текущей версии файла.

Если вы хотите указать список файлов в командной строке и выполнить все это одной атомарной командой, попробуйте:

git apply --3way <(git show -- list-of-files)

--3way: Если патч не применяется корректно, Git создаст конфликт слияния, чтобы вы могли запустить git mergetool, Опуская --3way заставит Git отказаться от патчей, которые не применяются чисто.

Использовать git format-patch чтобы вырезать часть коммита, которая вам небезразлична, и git am применить его к другой ветке

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch

Если "частично вишня" означает "в файлах, выбирая некоторые изменения, но отбрасывая другие", это можно сделать, введя git stash:

  1. Сделайте полную вишню.
  2. git reset HEAD^ преобразовать весь выбранный вишневый коммит в неустановленные рабочие изменения.
  3. Сейчас git stash save --patch: интерактивно выберите нежелательный материал для хранения.
  4. Git откатывает спрятанные изменения из вашей рабочей копии.
  5. git commit
  6. Выбросьте тайник нежелательных изменений: git stash drop,

Совет: если вы дадите имя ненужным изменениям: git stash save --patch junk тогда, если вы забудете сделать (7) сейчас, позже вы узнаете тайник, какой он есть.

На самом деле, лучшим решением этого вопроса является использование checkoutхвалить

      git checkout <branch> <path1>,<path2> ..

Например, предположим, что вы находитесь в master и хотите, чтобы изменения с dev1 на project1/Controller/WebController1.javaа также project1/Service/WebService1.java, вы можете использовать это:

      git checkout dev1 project1/Controller/WebController1.java project1/Service/WebService1.java

Это означает, что основная ветвь обновляется только с dev1 по этим двум путям.

Другие вопросы по тегам