Scal (za pomocą squasha) wszystkie zmiany z innej gałęzi jako pojedynczy zatwierdzenie


479

Czy w Git istnieje sposób na połączenie wszystkich zmian z jednej gałęzi do drugiej, ale jednocześnie zmiażdżyć do jednego zatwierdzenia w tym samym czasie?

Często pracuję nad nową funkcją w osobnym oddziale i regularnie zatwierdzam / wypycham - głównie w celu tworzenia kopii zapasowych lub przeniesienia tego, nad czym pracuję, na inną maszynę. Najczęściej te zatwierdzenia mówią „Feature xxx WIP” lub coś zbędnego.

Gdy ta praca zostanie zakończona i chcę połączyć gałąź WIP z powrotem w master, chciałbym odrzucić wszystkie pośrednie zatwierdzenia i mieć tylko jedno czyste zatwierdzenie.

Czy jest na to łatwy sposób?

Alternatywnie, co powiesz na polecenie, które zgniata wszystkie zatwierdzenia na gałęzi od momentu jej rozgałęzienia?

Odpowiedzi:


601

Inną opcją jest w git merge --squash <feature branch>końcu wykonanie git commit.

Z Git Merge

--squash

--no-squash

Utwórz działające drzewo i stan indeksu tak, jakby miało miejsce prawdziwe scalenie (z wyjątkiem informacji o scaleniu), ale tak naprawdę nie wykonuj zatwierdzenia ani nie przesuwaj HEADani nie rejestruj, $GIT_DIR/MERGE_HEADaby spowodować, że następne git commitpolecenie utworzy scalenie. Umożliwia to utworzenie pojedynczego zatwierdzenia na bieżącej gałęzi, którego efekt jest taki sam jak scalenie innej gałęzi (lub więcej w przypadku ośmiornicy).


1
Fajna funkcja! Kocham gita Chociaż na pewno będę tego używał w przyszłości, nadal polecam poznanie twojej bazy rebase -i. Jest to dobra umiejętność na wypadek, gdybyś naprawdę chciał, aby było ich więcej niż tylko jedno zatwierdzenie.
— Will Buck 10'12

4
Uwaga: to działa, ale domyślny komunikat zatwierdzenia zawiera dziennik z łączonej gałęzi. Problem polega na tym, że wygląda podobnie do formatu, który zwykle widzisz, gdzie cały pokazany tekst nie staje się częścią komunikatu zatwierdzenia, ale w tym przypadku tak jest. Więc jeśli nie chcesz tego wszystkiego, musisz ręcznie usunąć wszystko z wiadomości zatwierdzenia. Powinienem był to przetestować przed użyciem ...
— still_dreaming_1

23
Ostrzegamy, że oddział nie będzie postrzegany jako połączony. stackoverflow.com/questions/19308790/…
— Ryan

3
IMHO powinno to się nazywaćrebase --squash
— Andy

więc (ponieważ tak naprawdę nie łączy gałęzi funkcji) byłoby to odpowiednie, gdybyś miał zamiar usunąć gałąź funkcji po zatwierdzeniu. Czy to jest poprawne? (Nie jestem ekspertem od gitów)
— Andrew Spencer

214

Znaleziono to! Polecenie scalania ma --squashopcję

git checkout master
git merge --squash WIP

w tym momencie wszystko jest scalone, możliwe, że jest w konflikcie, ale nie zostaje popełnione. Więc mogę teraz:

git add .
git commit -m "Merged WIP"

2
co robi git add .zrobić?
— Michael Potter,

1
@MichaelPotter Dodaje wszystkie pliki i zmiany
— Daksh Shah

2
git add .dodaje wszystkie niezignorowane pliki w bieżącym katalogu, byłbym ostrożny przy pobieraniu niezamierzonych plików w ten sposób.
— Jake Cobb,

7
Alternatywnie git add .możesz użyć git add -utylko do dodawania plików, które zostały już dodane do drzewa.
— Brandon Ogle

19
Sugerowanie, że „dodaj git”. być także zrobionym jest mylące. Kiedy wykonuję „git merge - quash WIP”, ma już zgniecione zmiany w indeksie. Wszystko, czego potrzeba, to ich popełnić. Wykonanie „git add”. doda zmiany, które znajdują się w katalogu roboczym, ale które nie były częścią gałęzi funkcji. Pytanie brzmiało, jak zatwierdzić zmiany w gałęzi funkcji jako jedno zatwierdzenie.
— John Pankowicz

30

Wypróbuj git rebase -i masterw swoim dziale funkcji. Następnie możesz zmienić wszystkie oprócz jednego „pick” na „squash”, aby połączyć zatwierdzenia. Widzieć zatwierdzanie squashingu za pomocą rebase

Na koniec możesz wykonać scalenie z gałęzi master.


8
Tak, to działa, ale nie chcę kłopotów z interaktywną bazą. Chcę tylko wszystkiego, odkąd gałąź się spłaszczyła.
— Brad Robinson,

2
+1 To zapewnia czystą historię. O wiele łatwiej jest identyfikować i zarządzać zatwierdzeniami jako indywidualne łatki, karty, historie itp.
— Ryan

2

Użycie git merge --squash <feature branch>jako odpowiedzi zaakceptowanej sugeruje załatwienie sprawy, ale nie pokaże scalonej gałęzi jako faktycznie scalonej.

Dlatego jeszcze lepszym rozwiązaniem jest:

  • Utwórz nowy oddział z najnowszego wzorca
  • Połącz <feature branch>się z powyższym za pomocągit merge --squash
  • Scal nowo utworzoną gałąź w master

Ta wiki szczegółowo wyjaśnia procedurę.


0

Stworzyłem własny alias git, aby zrobić dokładnie to. Nazywam togit freebase ! Zabierze twoją istniejącą niechlujną, niemożliwą do odblokowania gałąź funkcji i odtworzy ją, aby stała się nową gałęzią o tej samej nazwie z zatwierdzeniami zgniecionymi w jednym zatwierdzeniu i ponownie opartym na gałęzi, którą określisz (domyślnie master). Na samym końcu pozwoli ci użyć dowolnej wiadomości zatwierdzenia, którą chcesz dla swojej nowej gałęzi „freebased”.

Zainstaluj go, umieszczając następujący alias w .gitconfig:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Użyj go z gałęzi funkcji, uruchamiając: git freebase <new-base>

Testowałem to tylko kilka razy, więc przeczytaj go najpierw i upewnij się, że chcesz go uruchomić. Jako mały środek bezpieczeństwa drukuje początkowy sha1, więc powinieneś być w stanie przywrócić starą gałąź, jeśli coś pójdzie nie tak.

Będę go utrzymywał w moim repozytorium dotfiles na github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig


działało jak błogość! równie dobrze możesz rzucić
— Ilya Sheershoff

-1

git merge --squash <feature branch> jest dobrą opcją. „git commit” informuje o wszystkich komunikatach zatwierdzania gałęzi funkcji z wyborem, aby go zachować.

Dla mniejszego scalania zatwierdzeń.

git merge do x razy --git reset HEAD ^ --soft następnie git commit.

Ryzyko usunięte pliki mogą wrócić.


-5

Możesz to zrobić za pomocą polecenia „rebase”. Nazwijmy gałęzie „główne” i „funkcja”:

git checkout feature
git rebase main

Polecenie rebase odtworzy wszystkie zatwierdzenia na „feature” jako jedno zatwierdzenie z rodzicem równym „main”.

Możesz chcieć biec git merge mainwcześniejgit rebase main jeśli „main” zmieniło się od czasu utworzenia „feature” (lub od ostatniego scalenia). W ten sposób nadal masz pełną historię na wypadek konfliktu scalenia.

Po zmianie bazy możesz połączyć swoją gałąź z główną, co powinno doprowadzić do szybkiego połączenia:

git checkout main
git merge feature

Zobacz stronę rebase Understanding Git Conceptually, aby uzyskać dobry przegląd


To nie działało dla mnie. Właśnie stworzyłem proste repozytorium testowe, z gałęzią WIP, wypróbowałem powyższe i dostałem konflikty scalania (mimo że nie wprowadziłem żadnych zmian w master).
— Brad Robinson,

Jeśli funkcja została utworzona z main (git checkout -b Feature main) i miałeś ostatnie połączenie z main, nie powinieneś dostawać konfliktów z
— bazy

OK, spróbowałem jeszcze raz. Tym razem nie doszło do konfliktów, ale historia nie została zmiażdżona.
— Brad Robinson,

Patrząc jeszcze raz na dokumentację git-merge, masz rację, niektóre zatwierdzenia pozostaną. Jeśli dokonałeś wcześniejszych połączeń z „głównej” do „funkcji”, to rebase usunie niektóre z nich, ale nie wszystkie.
— NamshubWriter,

Pamiętaj tylko, że zmiana bazy może być dość niebezpieczna, jeśli gałąź funkcji została wcześniej opublikowana. Więcej informacji na temat tego SO pytania .
— Robert Rossmann
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.