Pytanie Squash mój ostatni X popełnia razem używając Gita


Jak zmiażdżyć moje ostatnie X commits w jeden commit używając Git?


2322
2018-03-04 04:11


pochodzenie


Podobne pytanie: stackoverflow.com/questions/7275508/... - koppor
Związane z: Git - łączenie wielokrotnych zatwierdzeń przed przesuwaniem.
@matt TortoiseGit to Twoje narzędzie. Zapewnia pojedynczą funkcję "Połącz z jednym zatwierdzeniem", która wywoła wszystkie kroki automatycznie w tle. Niestety tylko dostępna dla systemu Windows. Zobacz moją odpowiedź poniżej. - Matthias M
@Thomas: wyjaśnij, jak "dobrze używać git", gdy trzeba wykonywać recenzje na temat popełnionego kodu, a my musimy aktualizować na podstawie komentarzy z recenzji i ponownie zatwierdzać, ale nie chcemy naciskać na zmianę opartą na opiniach? - Jeff Learman
Do zgniatania do pierwszego zobowiązania zobacz to - stackoverflow.com/questions/1657017/... - goelakash


Odpowiedzi:


Posługiwać się git rebase -i <after-this-commit> i zamień "pick" na drugim i kolejnym commitowaniu na "squash" lub "fixup", jak opisano w instrukcja.

W tym przykładzie <after-this-commit> jest hash SHA1 lub względna lokalizacja z HEAD bieżącej gałęzi, z której zatwierdzane są analizy dla polecenia rebase. Na przykład, jeśli użytkownik chce wyświetlić 5 zatwierdzeń z bieżącego HEAD w przeszłości, polecenie jest git rebase -i HEAD~5.


1268
2018-03-04 04:18



To, jak sądzę, nieco lepiej odpowiada na to pytanie stackoverflow.com/a/5201642/295797 - Roy Truelove
Co jest rozumiane przez <after-this-commit>? - jtheletter
<after-this-commit> jest zatwierdzeniem X + 1, tzn. rodzicem najstarszego zatwierdzenia, które chcesz zgnieść. - joozek
Odpowiedź była zbyt lakoniczna, by zrozumieć jednoznacznie. Przykład pomógłby. - Ian Ollmann
Różnica między tym rebase -i podejście i reset --soft jest, rebase -ipozwala mi zatrzymać autora zatwierdzenia, podczas gdy reset --soft pozwala mi ponownie. Czasami muszę zgrupować zatwierdzenia żądań ściągnięcia, ale zachować informacje o autorze. Czasami muszę zresetować soft na moich własnych zobowiązaniach. Awansuj do obu wspaniałych odpowiedzi. - zionyx


Możesz to zrobić dość łatwo bez git rebase lub git merge --squash. W tym przykładzie usuniemy 3 ostatnie poprawki.

Jeśli chcesz napisać nową wiadomość zatwierdzenia od zera, wystarczy:

git reset --soft HEAD~3 &&
git commit

Jeśli chcesz rozpocząć edycję nowego komunikatu zatwierdzenia połączeniem istniejących komunikatów zatwierdzenia (to jest podobnym do tego, jakie jest pobranie / squash / squash / ... / squash git rebase -i pojawi się lista instrukcji), następnie musisz wyodrębnić te wiadomości i przekazać je git commit:

git reset --soft HEAD~3 && 
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"

Obie te metody powodują zgniecenie ostatnich trzech zmian w jednym nowym zatwierdzeniu w ten sam sposób. Miękki reset powoduje tylko ponowne wskazanie HEAD do ostatniego zatwierdzenia, którego nie chcesz zgniatać. Ani indeks, ani drzewo robocze nie są dotykane przez miękki reset, pozostawiając indeks w pożądanym stanie dla twojego nowego zatwierdzenia (to znaczy ma już wszystkie zmiany z zatwierdzeń, które zamierzasz "wyrzucić").


2603
2018-03-05 04:19



Ha! Podoba mi się ta metoda. To ten, który zamyka ducha problemu. Szkoda, że ​​wymaga tak dużo voodoo. Coś takiego powinno zostać dodane do jednego z podstawowych poleceń. Możliwie git rebase --squash-recent, lub nawet git commit --amend-many. - Adrian Ratnapala
@ A-B-B: Jeśli twój oddział ma zestaw "upstream", możesz go użyć branch@{upstream} (Lub tylko @{upstream} dla bieżącego oddziału; w obu przypadkach ostatnią część można skracać @{u}; widzieć gitrevisions). Może się różnić od Twój "Ostatnie zatwierdzenie pushed" (np. Jeśli ktoś inny pchnął coś, co zostało zbudowane na najnowszym push, a następnie je pobrałeś), ale wydaje się, że może być zbliżone do tego, co chcesz. - Chris Johnsen
Ta kinda-sorta mnie wymagała push -f ale poza tym było cudownie, dzięki. - 2rs2ts
@ 2rs2ts git push -f brzmi groźnie. Uważaj, aby atakować tylko lokalnie. Nigdy nie dotykaj pchniętych zobowiązań! - Matthias M
Dziękuję za dostarczenie rozwiązania, które nie wymaga ręcznego wpisywania squasha / fixup dla każdego pojedynczego zatwierdzenia, w przeciwieństwie do wszystkich interaktywnych sugestii rebase gdzie indziej. - Antimony


Możesz użyć git merge --squash za to, co jest nieco bardziej eleganckie niż git rebase -i. Załóżmy, że jesteś mistrzem i chcesz zmiażdżyć ostatnie 12 komend w jednym.

OSTRZEŻENIE: Najpierw upewnij się, że zatwierdziłeś swoją pracę - sprawdź to git status jest czysty (od git reset --hard wyrzuci zmiany etapowe i niezarządzane)

Następnie:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

The dokumentacja dla git merge opisuje --squash opcja bardziej szczegółowo.


Aktualizacja: jedyna prawdziwa zaleta tej metody nad prostszą git reset --soft HEAD~12 && git commit sugerowane przez Chrisa Johnsena w jego odpowiedź jest to, że otrzymujesz komunikat zatwierdzenia wstępnie wypełniony każdą wiadomością zatwierdzającą, którą zgniatasz.


575
2018-03-04 06:10



Mówisz, że jest bardziej "elegancki" niż git rebase -i, ale nie podajesz powodu, dlaczego. Ostrożnie - na ten temat, ponieważ wydaje mi się, że w rzeczywistości jest odwrotnie, a to jest hack; nie wykonujesz więcej poleceń niż jest to konieczne tylko po to, aby wymusić git merge do robienia jednej z rzeczy, które git rebase jest specjalnie zaprojektowany? - Mark Amery
@ Mark Andrew: Są różne powody, dla których powiedziałem, że jest to bardziej eleganckie. Na przykład nie wiąże się to z niepotrzebnym tworzeniem edytora, a następnie wyszukiwaniem i zamianą ciągu znaków w pliku "do zrobienia". Za pomocą git merge --squash jest również łatwiejszy w użyciu w skrypcie. Zasadniczo rozumowanie było takie, że nie potrzebujesz "interaktywności" git rebase -i w ogóle za to. - Mark Longair
Kolejną zaletą jest to, że git merge --squash jest mniej prawdopodobne, że spowoduje konflikty scalania w przypadku ruchów / usunięć / nazw w porównaniu do przekierowania, szczególnie jeśli łączysz się z lokalnym odgałęzieniem. (zrzeczenie się: na podstawie tylko jednego doświadczenia, popraw mnie, jeśli nie jest to prawdą w ogólnym przypadku!) - Cheezmeister
Zawsze jestem bardzo niechętny, jeśli chodzi o twarde resetowania - zamiast tego użyłbym tagu temporalnego HEAD@{1} po prostu być po bezpiecznej stronie, np. gdy przepływ pracy zostanie przerwany na godzinę z powodu awarii zasilania itp. - Tobias Kienzler
@B T: Zniszczyłeś swój commit? :( Nie jestem pewien, co przez to rozumiesz. Wszystko, co popełniłeś, łatwo będziesz mógł odzyskać z refela gita. Jeśli miałeś niewykonaną pracę, ale pliki były wystawiane, powinieneś być w stanie uzyskać ich zawartość z powrotem, chociaż to będzie więcej pracy. Jeśli twoja praca nie była nawet wystawiona, obawiam się, że niewiele można zrobić; dlatego odpowiedź z góry brzmi: "Najpierw sprawdź, czy status git jest czysty (ponieważ git reset --hard wyrzuci zmiany etapowe i niezaprogramowane)". - Mark Longair


Zalecam unikanie git reset kiedy to możliwe - szczególnie dla nowicjuszy Git. Chyba, że ​​naprawdę potrzebujesz zautomatyzować proces oparty na numer popełnienia, jest mniej egzotyczny sposób ...

  1. Umieść zobowiązanie, które ma zostać "zgniecione" na działającej gałęzi (jeśli jeszcze nie jest) - użyj do tego gitk
  2. Sprawdź gałąź docelową (np. "Master")
  3. git merge --squash (working branch name)
  4. git commit

Komunikat zatwierdzenia zostanie wstępnie wypełniony w oparciu o squash.


136
2018-03-14 23:24



Jest to najbezpieczniejsza metoda: bez resetowania soft / hard (!!) lub reflog użyte! - TeChn4K
Byłoby wspaniale, gdybyś rozszerzył (1). - Adam
@Adam: Zasadniczo oznacza to użycie interfejsu GUI programu gitk aby oznaczyć linię kodu, którą zgniatasz, a także oznaczyć bazę, na której chcesz zgnieść. W normalnym przypadku obie te etykiety już istnieją, więc krok (1) można pominąć. - nobar
Zauważ, że ta metoda nie oznacza, że ​​gałąź robocza jest w pełni scalona, ​​więc jej usunięcie wymaga wymuszenia usunięcia. :( - Kyrstellaine
Dla (1) znalazłem git branch your-feature && git reset --hard HEAD~N najwygodniejszy sposób. Jednak wiąże się to z ponownym resetowaniem git, którego ta odpowiedź próbowała uniknąć. - eis


Oparte na Odpowiedź Chrisa Johnsena,

Dodaj globalny alias "squash" z bash: (lub Git Bash w systemie Windows)

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'

... lub przy użyciu wiersza poleceń systemu Windows:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"


Twój ~/.gitconfig powinien teraz zawierać ten alias:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"


Stosowanie:

git squash N

... Który automatycznie zgniata razem ostatni N zobowiązuje, włącznie.

Uwaga: Wynikowy komunikat zatwierdzenia jest kombinacją wszystkich zgniecionych zatwierdzeń, w kolejności. Jeśli jesteś z tego powodu niezadowolony, zawsze możesz git commit --amendzmodyfikować ręcznie. (Lub edytuj alias, aby pasował do twoich upodobań.)


97
2018-02-19 19:21



Interesujące, ale wolałbym raczej napisać wiadomość o zatwierdzeniu "zgniecionym", jako opisowe podsumowanie moich wielokrotnych zatwierdzeń, niż automatycznie wpisane dla mnie. Więc wolę określić git squash -m "New summary." i mają N określane automatycznie jako liczba nieprzerwanych zatwierdzeń. - A-B-B
@ A-B-B To brzmi jak osobne pytanie. (Nie sądzę, że jest to dokładnie to, o co prosił OP, nigdy nie czułem potrzeby w moim przepływie pracy git squasha). - EthanB
To jest całkiem słodkie. Osobiście chciałbym wersji, która używa wiadomości zatwierdzenia z pierwszego ze zgniecionych commits. Byłoby dobrze na takie rzeczy jak poprawki w białych przestrzeniach. - funroll
@funroll Zgoda. Po prostu upuszczenie ostatniego msg jest dla mnie ogromną potrzebą. Powinniśmy być w stanie to zaprojektować ... - Steve Clay
@ A-B-B możesz użyć git commit --amend w celu dalszej zmiany wiadomości, ale ten alias pozwala dobrze zacząć od tego, co powinno znaleźć się w komunikacie zatwierdzenia. - dashesy


Jeśli używasz TortoiseGit, możesz skorzystać z tej funkcji Combine to one commit:

  1. Otwórz menu kontekstowe TortoiseGit
  2. Wybierz Show Log
  3. Zaznacz odpowiednie zatwierdzenia w widoku dziennika
  4. Wybierz Combine to one commit z menu kontekstowego

Combine commits

Ta funkcja automatycznie wykonuje wszystkie niezbędne kroki pojedynczego git. Niestety tylko dostępne dla systemu Windows.


46
2017-11-06 12:51



O ile mi wiadomo, nie zadziała to w przypadku zatwierdzeń scalania. - Thorkil Holm-Jacobsen
Chociaż nie jest to komentowane przez żadne inne, działa to nawet w przypadku commitów, których nie ma na HEAD. Na przykład, musiałem zmiażdżyć niektóre zatwierdzenia WIP, które zrobiłem z bardziej rozsądnym opisem, zanim nacisnęłam. Pięknie pracował. Oczywiście nadal mam nadzieję, że nauczę się, jak to zrobić za pomocą poleceń. - Charles Roberto Canato


Dzięki ten poręczny blog Zauważyłem, że możesz użyć tego polecenia, aby zgnieść 3 ostatnie zatwierdzenia:

git rebase -i HEAD~3

Jest to przydatne, ponieważ działa nawet w lokalnym oddziale bez informacji śledzenia / zdalnego repo.

Polecenie otworzy interaktywny edytor rebase, który następnie pozwala na zmianę kolejności, squash, reword, itp., Jak na normalne.


46
2018-05-17 06:19





Oparte na Ten artykuł Znalazłem tę metodę łatwiej dla mojego usecase.

Mój oddział "dev" wyprzedził "origin / dev" o 96 commitów (więc te zatwierdzenia nie zostały jeszcze przekazane do zdalnego).

Chciałem zmiażdżyć te commits w jeden przed popchnięciem zmiany. Preferuję zresetować gałąź do stanu "origin / dev" (pozostawi to wszystkie zmiany z 96 commitów bez zmian), a następnie zatwierdzę zmiany na raz:

git reset origin/dev
git add --all
git commit -m 'my commit message'

29
2018-05-22 00:41



Dokładnie to, czego potrzebowałem. Wykonaj skasowanie commitów z mojej gałęzi z funkcjami, a potem wybieram cherry, żeby zatwierdzić mojego mistrza. - David Victor
To nie powoduje zgniatania poprzednich zatwierdzeń! - Igor Ganapolsky
czy mógłbyś rozwinąć to nieco dalej @igorGanapolsky? - trudolf
@trudolf To nie jest tak naprawdę zgniatanie (wybieranie pojedynczych komend do squasha). To więcej, niż wszystkie zmiany na raz. - Igor Ganapolsky
tak, więc zmiażdży wszystkie twoje zobowiązania w jeden. Gratulacje! - trudolf


Aby to zrobić, możesz użyć następującej komendy git.

 git rebase -i HEAD~n

n (= 4 tutaj) to numer ostatniego zatwierdzenia. Potem masz następujące opcje,

pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....

Aktualizuj jak poniżej,

p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....

Aby uzyskać szczegółowe informacje, kliknij przycisk Połączyć

Powodzenia!!


24
2018-04-06 05:26





1) Określ skrót skrótu zatwierdzenia

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....

2) Jeśli chcesz zgnieść (scalić) ostatnie dwa zatwierdzenia

# git rebase -i deab3412 

3) To otwiera a nano edytor do scalania. I wygląda to tak, jak poniżej

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....

4) Zmień nazwę słowa pick do squash który jest obecny wcześniej abcd1234. Po zmianie nazwy powinien wyglądać jak poniżej.

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....

5) Teraz zapisz i zamknij nano redaktor. naciśnij ctrl + o i naciśnij Enter zapisać. A następnie naciśnij ctrl + x wyjść z edytora.

6) Następnie nano edytor otwiera się ponownie w celu aktualizacji komentarzy, w razie potrzeby zaktualizuj go.

7) Teraz z powodzeniem zgnieciony, możesz to sprawdzić, sprawdzając logi.

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....

8) Teraz naciśnij, aby ponownie rozpocząć. Uwaga, aby dodać + podpisać przed nazwą oddziału.

# git push origin +master

Uwaga: Jest to oparte na użyciu git on ubuntu muszla. Jeśli używasz innego systemu operacyjnego (Windows lub Mac) następnie powyższe polecenia są takie same, z wyjątkiem edytora. Możesz dostać innego edytora.


22
2018-01-10 14:19



Dzięki za najlepszy przewodnik! - Jeremie Ges
Aktualizuje tylko ostatnie dwa zatwierdzenia, nawet ja zresetowałem do ID zatwierdzenia do 6. ostatniego zatwierdzenia, nie wiem dlaczego - Carlos Liu