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?

Brad Robinson
źródło

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

fseto
źródło
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"
Brad Robinson
źródło
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.

fseto
źródło
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ę.

raratiru
źródło
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

Stephen Crosby
źródło
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ć.

Arjun Mullick
źródło
-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

NamshubWriter
źródło
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