Как сквошировать коммиты в один патч с помощью git format-patch?

У меня есть восемь коммитов в ветке, которые я хотел бы отправить по электронной почте некоторым людям, которые еще не освоили git. Пока что все, что я делаю, либо дает мне 8 файлов патчей, либо начинает давать мне файлы патчей для каждого коммита в истории ветки с незапамятных времен. Я использовал git rebase --interactive, чтобы раздавить коммиты, но теперь все, что я пробую, дает мне миллионы патчей с самого начала. Что я делаю неправильно?

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master

person skiphoppy    schedule 05.03.2009    source источник
comment
Мне любопытно, какой метод вы в конечном итоге будете использовать среди предложений ниже. Дайте нам знать ;)   -  person VonC    schedule 06.03.2009
comment
Я буду использовать git diff, как предложил Роб Ди Марко. Но я не работаю на две недели, так как только что стал свидетелем рождения моей второй девочки прошлой ночью, так что пройдет некоторое время, прежде чем я воспользуюсь им! :)   -  person skiphoppy    schedule 06.03.2009
comment
Я хотел бы увидеть git format-patch --squash master HEAD   -  person schoetbi    schedule 10.03.2011
comment
Попробуйте master..HEAD указать диапазон оборотов.   -  person Konrad Kleine    schedule 04.08.2014


Ответы (8)


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

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch
person Adam Alexander    schedule 05.03.2009
comment
Это то, что я использую, когда хочу хранить историю локально (на случай, если мне нужно отредактировать патч). В противном случае я просто использую rebase -i и разжимаю коммиты. - person sebnow; 09.03.2009
comment
для меня это работало более надежно с git comit -m "My squashed commits", иначе добавлялись бы другие неотслеживаемые файлы - person Sebastian; 26.02.2014
comment
Кроме того, вы можете переключиться на конкретную фиксацию вместо главной и сделать это, чтобы создать патч от фиксации до фиксации: git checkout 775ec2a && git checkout -b patch && git merge --squash branchname - person Berry M.; 07.11.2017

Просто чтобы добавить еще один раствор в горшок: если вы используете это вместо этого:

git format-patch master --stdout > my_new_patch.diff

Тогда это по-прежнему будет 8 патчей ... но все они будут в одном файле патчей и будут применяться как один с:

git am < my_new_patch.diff
person Taryn East    schedule 12.12.2009
comment
Мне нравится это решение. Стоит отметить, что иногда он может создавать намного больший патч, чем метод, описанный @Adam Alexander. Это связано с тем, что некоторые файлы могут редактироваться более одного раза с помощью коммитов. Этот метод обрабатывает каждую фиксацию отдельно, даже если некоторый файл был отменен. Но в большинстве случаев это не проблема. - person gumik; 29.06.2012
comment
Этот вариант отлично подходит, если вы пытаетесь избежать слияния! (например, вы хотите пропустить некоторые коммиты). Вы все еще можете git rebase -i ... и раздавить их всех до одного. - person Jorge Orpinel Pérez; 27.05.2017

Я всегда использую git diff, поэтому в вашем примере что-то вроде

git diff master > patch.txt
person Rob Di Marco    schedule 05.03.2009
comment
За исключением того, что вы теряете все сообщения и метаданные фиксации. Прелесть git format-patch в том, что из набора патчей можно реконструировать целую ветку. - person mcepl; 10.08.2011
comment
метод create-branch-and-squash имеет преимущество объединения всех сообщений фиксации в одно, но этот метод намного быстрее, если вы хотите написать собственное сообщение фиксации - person woojoo666; 03.09.2015
comment
на самом деле объединенное сообщение можно создать с помощью git log, см. пример мой ответ - person woojoo666; 03.09.2015
comment
Хороший вариант, но учтите, что 'git diff' не может включать двоичные различия (возможно, есть возможность сделать это). - person Santiago Villafuerte; 16.02.2016

Как вы уже знаете, git format-patch -8 HEAD даст вам восемь исправлений.

Если вы хотите, чтобы ваши 8 коммитов отображались как один, и не возражаете переписать историю своей ветки (o-o-X-A-B-C-D-E-F-G-H), вы можете:

git rebase -i
// squash A, B, C, D, E ,F, G into H

или, что было бы лучше, воспроизвести все ваши 8 коммитов из X (коммит перед вашими 8 коммитами) в новой ветке

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

Таким образом, у вас будет только одна фиксация в ветке "доставка", и она будет представлять все ваши последние 8 коммитов.

person VonC    schedule 05.03.2009
comment
git merge master просто выполняет быструю перемотку вперед и не делает коммитов в одно целое. Измените на git merge --squash master, чтобы все коммиты были сжаты и видны в промежуточной области. Ваш поток будет работать с этим изменением. (Я использую git версии 2.1.0.) - person Stunner; 13.01.2016

Это адаптация ответа Адама Александра, если ваши изменения находятся в основной ветке. Для этого сделайте следующее:

  • Создает новую одноразовую ветку «tmpsquash» из нужной нам точки (ищите ключ SHA, запускающий «git --log» или с помощью gitg. Выберите коммит, который вы хотите стать tmpsquash head, коммиты, которые будут после этого в master, будут сжатые коммиты).
  • Объединяет изменения от master к tmpsquash.
  • Сохраняет сжатые изменения в tmpsquash.
  • Создает патч со сжатыми коммитами.
  • Возвращается в основную ветку

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$
person rec    schedule 17.10.2010
comment
Внесение изменений в мастер - это анти-шаблон, если вы не будете подталкивать их к удалению. И если вы это сделаете, вам, вероятно, не нужно создавать для них файлы исправлений. - person ivan_pozdeev; 15.04.2016

Самый простой способ - использовать git diff и добавить git log, если вы хотите объединенное сообщение фиксации, которое выводит метод squash. Например, чтобы создать патч между фиксацией abcd и 1234:

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

Затем при нанесении патча:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

Не забывайте --binary аргумент для git diff при работе с нетекстовыми файлами, например. изображения или видео.

person woojoo666    schedule 03.09.2015

Патч формата между двумя тегами:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>
person kashesandr    schedule 02.09.2013

На основе ответа Адама Александра:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
person Julien W    schedule 30.12.2012