Частично выбор коммита с помощью Git

Я работаю над двумя разными ветками: выпуск и разработка.

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

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

git cherry-pick bc66559

не помогает.

Когда я делаю

git show bc66559

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


person oliver    schedule 06.10.2009    source источник


Ответы (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 применяется отличие указанной фиксации от ее родительской. Это означает, что checkout может применить не только эту фиксацию, а это может быть больше, чем вы хотите.)

person Cascabel    schedule 06.10.2009
comment
На самом деле, если я последую совету с git 1.7.5.4, «git add -p» скажет «Без изменений», потому что все это уже есть в индексе. Мне нужно выполнить «git reset HEAD» перед «git add» - каким-либо способом избежать этого сброса с помощью какой-либо опции? - person Felix Rabe; 02.01.2012
comment
@FelixRabe: Я действительно удивлен, что в какой-то момент cherry-pick -n, по-видимому, не оставил изменения в стадии постановки - соглашение определенно таково, что --no-commit параметры останавливаются прямо перед фиксацией, т.е. со всеми внесенными изменениями. Добавлю сброс в ответ. - person Cascabel; 02.01.2012
comment
@Blixt То есть, если коммиты, которые находятся в другой ветке, но не в вашей текущей, являются ABCDEF, git checkout -p <F> не просто получает изменения из F, он объединяет все ABCDEF вместе и позволяет вам определите, какую часть вы хотите. Связать это лишь с некоторыми изменениями от F - это боль. С другой стороны, git cherry-pick -n <F> дает вам только изменения из F - и если некоторые из этих изменений конфликтуют, он помогает вам, чтобы вы могли понять, как правильно выполнить слияние. - person Cascabel; 02.10.2014
comment
У меня были проблемы с этим, когда изменением было добавление файла. git reset удалит поэтапные файлы, а add -p просто скажет «нечего добавить». - person Ian Grainger; 06.09.2016
comment
Обратите внимание, что этот метод не сохраняет первоначального автора и дату фиксации. Вы можете установить их с помощью git commit --author="USER <MAIL>" --date="DATE", использовать данные об авторе и дате, указанные в верхней части git show CHERRY_PICK_SHA. - person Tim Visée; 16.10.2020

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

git checkout -p bc66559

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

person Mike Monkiewicz    schedule 29.06.2013

Предполагая, что нужные вам изменения находятся во главе ветки, из которой вы хотите внести изменения, используйте 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
person Jay Swain    schedule 01.02.2010
comment
При этом копируется весь файл, а не только изменения. - person Jeremy List; 26.03.2014
comment
Этот ответ, как и любой другой ответ здесь, имеет большой недостаток: он не сохраняет первоначального автора изменения, вместо этого он совершает фиксацию от вашего имени. Если изменение хорошее, вы крадете чей-то кредит, если изменение плохое, вы поджигаете себя. Кажется, что нет возможности использовать git cherry-pick -p, и жаль, что его все еще нет. - person pfalcon; 29.10.2015

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

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

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

person Christian.D    schedule 24.10.2014
comment
Это проблематично, если текущая версия файла значительно отличается от этой версии. Вам будет предложено множество не относящихся к делу изменений (которые не отображаются в фиксации). Кроме того, действительно нужные изменения могут отображаться в замаскированной форме как отличие от текущего, а не как исходное. Возможно, что исходная разница, которую вы хотите, конфликтует, и ее нужно правильно объединить; у вас не будет такой возможности здесь. - person Kaz; 11.05.2015

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

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

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

person nyanpasu64    schedule 18.08.2019

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

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

Если «частичный выбор вишни» означает «в файлах, выбирая одни изменения, но отбрасывая другие», это можно сделать, введя 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, тогда, если вы забудете сделать (6) сейчас, позже вы узнаете, что это за тайник.

person Kaz    schedule 14.05.2014
comment
Если вы просто выберете вишню, а затем сбросите ... вам нечего будет прятать. Как было сказано выше, вам нужно либо выбрать вариант с --no-commit, либо сбросить --hard HEAD ~. Обратите внимание, что вы поступаете отрицательно (выбираете то, что вам не нужно). Принятое выше решение допускает как положительный, так и отрицательный подход. - person Pierre-Olivier Vares; 02.10.2014

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

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

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

person 无名小路    schedule 27.01.2021