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

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!


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

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

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)$

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ń


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>

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.