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

163

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

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master
skiphoppy
источник
Мне интересно, какой метод вы в конечном итоге будете использовать среди предложенных ниже. Дайте нам знать;)
VonC
4
Я буду использовать git diff в соответствии с предложением Роба Ди Марко. Но я две недели не работаю, только что стал свидетелем рождения моей второй девочки прошлой ночью, так что пройдет какое-то время, прежде чем я ее использую! :)
skiphoppy
2
Я хотел бы увидеть git format-patch - мастер
сквоша
1
Попробуйте master..HEAD, чтобы указать диапазон оборотов.
Конрад Кляйн

Ответы:

186

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

[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

Надеюсь это поможет!

Адам Александр
источник
2
Это то, что я использую, когда я хочу сохранить историю локально (на случай, если мне нужно отредактировать патч). В противном случае я просто использую rebase -i и подавляю коммиты.
sebnow
5
для меня это работало более надежно, git comit -m "My squashed commits"иначе добавило бы другие неотслеживаемые файлы
Себастьян
Кроме того, вы можете переключиться на определенный коммит вместо мастера и сделать это, чтобы создать патч из коммита для фиксации:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Берри М.
131

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

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

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

git am < my_new_patch.diff
Тарын Восток
источник
13
Мне нравится это решение. Стоит отметить, что иногда он может создать патч намного большего размера, чем метод, описанный @Adam Alexander. Это связано с тем, что некоторые файлы можно редактировать более одного раза с помощью коммитов. Этот метод обрабатывает каждый коммит отдельно, даже если какой-то файл был возвращен. Но в большинстве случаев это не проблема.
Gumik
1
Этот вариант хорош, если вы пытаетесь избежать слияния! (например, вы хотите пропустить некоторые коммиты). Вы можете все еще git rebase -i ...и раздавить их всех до одного.
Хорхе Орпинель
21

Я всегда использую Git Diff, так что в вашем примере, что-то вроде

git diff master > patch.txt
Роб Ди Марко
источник
15
Кроме того, что вы теряете все сообщения и метаданные. Прелесть git format-patch заключается в том, что можно восстановить целую ветку из набора патчей.
mcepl
Преимущество метода create-branch-and-squash состоит в объединении всех сообщений фиксации в одно, но этот метод намного быстрее, если вы хотите написать собственное сообщение фиксации
woojoo666
на самом деле, комбинированное сообщение может быть сделано с помощью git log, см. мой ответ для примера
woojoo666
2
Хороший вариант, но учтите, что «git diff» не может включать двоичные различия (возможно, есть вариант сделать это).
Сантьяго Вильяфуэрте
18

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

  • Создает новую одноразовую ветку "tmpsquash" из той точки, которую мы хотим (ищите ключ SHA, выполняющий "git --log" или с помощью gitg. Выберите коммит, которым вы хотите быть в голове tmpsquash, коммиты, которые после этого в 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)$
запись
источник
Внесение изменений в мастер - это анти-паттерн, если вы не будете подталкивать их к удалению. И если вы захотите, вам, вероятно, не нужно создавать файлы патчей для них.
ivan_pozdeev
18

Как вы уже знаете, a 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

Таким образом, у вас есть только один коммит в ветке «delivery», и он представляет все ваши последние 8 коммитов

VonC
источник
git merge masterпросто делает быструю перемотку вперед и не сводит коммитов в один. Перейдите на, git merge --squash masterчтобы получить все коммиты раздавленными и видимыми в области постановки. Ваш поток будет работать с этим изменением. (Я использую GIT версии 2.1.0.)
Stunner
5

Формат-патч между двумя тегами:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>
kashesandr
источник
5

Самый простой способ - использовать 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при работе с нетекстовыми файлами, например изображениями или видео.

woojoo666
источник
0

Основываясь на ответе Адама Александра:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
Жюльен В.
источник