Jak zgniatać zatwierdzenia w jeden patch za pomocą git format-patch?

163

Mam osiem zatwierdzeń w gałęzi, które chciałbym wysłać e-mailem do osób, które nie są jeszcze oświecone. Do tej pory wszystko, co robię, daje mi 8 plików łatek lub zaczyna dostarczać mi pliki łat dla każdego zatwierdzenia w historii gałęzi, od początku czasu. Użyłem git rebase --interactive, aby zmiażdżyć zatwierdzenia, ale teraz wszystko, czego próbuję, daje mi zyliony poprawek od początku czasu. Co ja robię źle?

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master
skiphoppy
źródło
Jestem ciekawy, jakiej metody ostatecznie użyjesz spośród poniższych propozycji. Daj nam znać;)
VonC
4
Użyję git diff zgodnie z sugestią Rob Di Marco. Ale nie pracuję przez dwa tygodnie, ponieważ wczoraj wieczorem byłem świadkiem narodzin mojej drugiej córeczki, więc minie trochę czasu, zanim go użyję! :)
skiphoppy
2
Bardzo chciałbym zobaczyć łatkę formatu git - Squash Master HEAD
schoetbi
1
Spróbuj master..HEAD, aby określić zakres obrotów.
Konrad Kleine

Odpowiedzi:

186

Polecam zrobić to na jednorazowej gałęzi w następujący sposób. Jeśli twoje zatwierdzenia znajdują się w gałęzi "nowe linie" i już przełączyłeś się z powrotem na gałąź "master", to powinno załatwić sprawę:

[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

Mam nadzieję że to pomoże!

Adam Alexander
źródło
2
To jest to, czego używam, gdy chcę zachować historię lokalnie (na wypadek, gdybym musiał edytować poprawkę). W przeciwnym razie po prostu używam rebase -i i zgniatam zatwierdzenia.
sebnow
5
dla mnie działało bardziej niezawodnie, w git comit -m "My squashed commits"przeciwnym razie dodałoby inne nieśledzone pliki
Sebastian
Dodatkowo możesz przełączyć się na określone zatwierdzenie zamiast głównego i zrobić to, aby utworzyć łatkę z zatwierdzenia na zatwierdzenie:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry M.
131

Wystarczy dodać jeszcze jedno rozwiązanie do puli: Jeśli zamiast tego użyjesz tego:

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

Wtedy nadal będzie to 8 łatek ... ale wszystkie będą w jednym pliku łatek i zostaną zastosowane jako jeden z:

git am < my_new_patch.diff
Taryn East
źródło
13
Podoba mi się to rozwiązanie. Warto zauważyć, że czasami może stworzyć dużo większy patch niż metoda opisana przez @Adama Alexandra. Dzieje się tak, ponieważ niektóre pliki mogą być edytowane więcej niż jeden raz za pomocą zatwierdzeń. Ta metoda traktuje każde zatwierdzenie osobno, nawet jeśli jakiś plik został przywrócony. Ale w większości przypadków nie stanowi to problemu.
gumik
1
Ta opcja jest świetna, jeśli próbujesz uniknąć łączenia! (np. chcesz pominąć niektóre zatwierdzenia). Możesz nadal git rebase -i ...i zgniatać je wszystkie do jednego.
Jorge Orpinel
21

Zawsze używam git diff, więc w twoim przykładzie coś takiego

git diff master > patch.txt
Rob Di Marco
źródło
15
Poza tym, że tracisz wszystkie komunikaty o zatwierdzeniach i metadane. Piękno git format-patch polega na tym, że można zrekonstruować całą gałąź z zestawu łat.
mcepl
metoda create-branch-and-squash ma tę zaletę, że łączy wszystkie komunikaty o
zmianach
w rzeczywistości połączoną wiadomość można zrobić za pomocą git log, zobacz moją odpowiedź na przykład
woojoo666
2
Niezła opcja, ale weź pod uwagę, że „git diff” nie może zawierać różnic binarnych (może jest taka opcja).
Santiago Villafuerte
18

To jest adaptacja odpowiedzi Adama Aleksandra, na wypadek gdybyś zmiany dotyczyły gałęzi głównej. Wykonaj następujące czynności:

  • Tworzy nową gałąź jednorazowego użytku "tmpsquash" z punktu, który chcemy (poszukaj klucza SHA z uruchomionym "git --log" lub z gitg. Wybierz zatwierdzenie, które chcesz być tmpsquash head, zatwierdzenia, które są później w master, będą zgniecione zatwierdzenia).
  • Łączy zmiany z master na tmpsquash.
  • Zatwierdza zgniecione zmiany w tmpsquash.
  • Tworzy łatkę ze zgniecionymi zatwierdzeniami.
  • Wraca do gałęzi głównej

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)$
rec
źródło
Wprowadzanie zmian w mistrzu jest anty-wzorcem, jeśli nie będziesz zmuszać ich do oddalenia się. A jeśli tak, prawdopodobnie nie musisz generować dla nich plików łatek.
ivan_pozdeev
18

Jak już wiesz, git format-patch -8 HEADotrzymasz osiem poprawek.

Jeśli chcesz, aby 8 zatwierdzeń pojawiło się jako jedno i nie masz nic przeciwko przepisywaniu historii swojej gałęzi ( o-o-X-A-B-C-D-E-F-G-H), możesz:

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

lub, co byłoby lepszym rozwiązaniem, powtórz wszystkie 8 zatwierdzeń z X(zatwierdzenie przed 8 zatwierdzeniami) na nowej gałęzi

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

W ten sposób masz tylko jedno zatwierdzenie w gałęzi "dostawa", które reprezentuje wszystkie twoje ostatnie 8 zatwierdzeń

VonC
źródło
git merge masterpo prostu przewija do przodu i nie miażdży zatwierdzeń w jednym. Zmień na, git merge --squash masteraby wszystkie zatwierdzenia zostały zgniecione i widoczne w obszarze scenicznym. Twój przepływ będzie działał z tą zmianą. (Używam git w wersji 2.1.0.)
Stunner
5

Łata formatu między dwoma tagami:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>
kashesandr
źródło
5

Najłatwiejszym sposobem jest użycie git diffi dodanie, git logjeśli chcesz połączyć komunikat o zatwierdzeniu, który wyprowadzi metoda squash. Na przykład, aby utworzyć łatkę między zatwierdzeniem abcda 1234:

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

Następnie podczas nakładania plastra:

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

Nie zapomnij o --binaryargumentach git diffdotyczących plików nietekstowych, np. Obrazów lub filmów.

woojoo666
źródło
0

Na podstawie odpowiedzi Adama Alexandra:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
Julien W
źródło