Połączyć pierwsze dwa commity z repozytorium Git?

197

Załóżmy, że masz historię zawierającą trzy zatwierdzenia A, B i C :

A-B-C

Chciałbym połączyć dwa zatwierdzenia A i B z jednym zatwierdzeniem AB :

AB-C

próbowałem

git rebase -i A

co otwiera mój edytor z następującą zawartością:

pick e97a17b B
pick asd314f C

Zmieniam to na

squash e97a17b B
pick asd314f C

Następnie Git 1.6.0.4 mówi:

Cannot 'squash' without a previous commit

Czy istnieje sposób, czy jest to po prostu niemożliwe?

chrześcijanin
źródło

Odpowiedzi:

168

Używaj git rebase -i --root od wersji Git 1.7.12 .

W interaktywnym pliku rebase zmień drugą linię zatwierdzenia B na squash i pozostaw pozostałe linie do wyboru :

pick f4202da A
squash bea708e B
pick a8c6abc C

To połączy dwa zatwierdzenia A i B z jednym zatwierdzeniem AB .

Znaleziono w tej odpowiedzi .

kostmo
źródło
126

Próbowałeś:

git rebase -i A

Możesz zacząć w ten sposób, jeśli będziesz kontynuować, editzamiast squash:

edit e97a17b B
pick asd314f C

następnie uruchomić

git reset --soft HEAD^
git commit --amend
git rebase --continue

Gotowe.

David Lichteblau
źródło
4
Jeśli robisz to w celu cichego naprawienia github gist, będziesz musiał dodać -m „initial” do zatwierdzenia. ;-)
Bruno Bronosky,
1
git rebase --abortzacząć od nowa i zrobić to we właściwy sposób (nie zgniatając pierwszego zatwierdzenia w edytorze)
oma
66

Abyło początkowym zatwierdzeniem, ale teraz chcesz Bbyć początkowym zatwierdzeniem. git commity są całymi drzewami, a nie różnicami, nawet jeśli są normalnie opisane i postrzegane w kategoriach wprowadzanych różnic.

Ten przepis działa, nawet jeśli istnieje wiele zatwierdzeń między A i B oraz B i C.

# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout <sha1_for_B>

# reset the branch pointer to the initial commit,
# but leaving the index and working tree intact.
git reset --soft <sha1_for_A>

# amend the initial tree using the tree from 'B'
git commit --amend

# temporarily tag this new initial commit
# (or you could remember the new commit sha1 manually)
git tag tmp

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after B onto the new initial commit
git rebase --onto tmp <sha1_for_B>

# remove the temporary tag
git tag -d tmp
CB Bailey
źródło
1
powoduje to ogromny interaktywny rebase, gdy robięgit rebase --onto tmp <sha1_for_B>
Alex
Biorąc pod uwagę, że miałem zupełnie nowe repozytorium z tylko dwoma zatwierdzeniami (które chciałem połączyć w jedno), to zadziałało idealnie dla mnie. Dziękuję @CB Bailey
RominRonin
10

W przypadku interaktywnego rebase, musisz to zrobić przed A, aby lista była:

pick A
pick B
pick C

zostać:

pick A
squash B
pick C

Jeśli A jest początkowym zatwierdzeniem, musisz mieć inne wstępne zatwierdzenie, zanim A. Git pomyśli o różnicach, zadziała na różnicy między (A i B) i (B i C). Stąd squash nie działa w twoim przykładzie.

Loki
źródło
9

W przypadku, gdy masz setki lub tysiące zatwierdzeń, skorzystaj z odpowiedzi kostmo z

git rebase -i --root

może być niepraktyczne i powolne, tylko ze względu na dużą liczbę zatwierdzeń, które skrypt rebase musi przetworzyć dwa razy , raz, aby wygenerować listę interaktywnego edytora rebase (gdzie wybierasz, jaką akcję podjąć dla każdego zatwierdzenia), a raz, aby faktycznie wykonać ponowne zastosowanie zobowiązań.

Oto alternatywne rozwiązanie, które pozwoli uniknąć kosztów czasowych generowania listy edytorów interaktywnych baz danych , nie wykorzystując w pierwszej kolejności interaktywnej bazy danych. W ten sposób jest podobny do rozwiązania Charlesa Baileya . Po prostu tworzysz gałąź osieroconą z drugiego zatwierdzenia, a następnie bazujesz na niej wszystkie zatwierdzenia potomków:

git checkout --orphan orphan <second-commit-sha>
git commit -m "Enter a commit message for the new root commit"
git rebase --onto orphan <second-commit-sha> master

Dokumentacja

Społeczność
źródło
0

Polecenie git dla drużyny: git rebase -i HEAD ~ [liczba zatwierdzeń]

Powiedzmy, że masz poniżej historię zatwierdzeń git:


wybierz 5152061 feat: Dodano obsługę zapisywania obrazu. (A)
Wybierz 39c5a04 Poprawka: poprawki błędów. (B)
Wybierz poprawkę 839c6b3: konflikt rozwiązany. (DO)

Teraz chcesz zgnieść A i B do AB, wykonaj poniższe czynności:


wybierz 5152061 feat: Dodano obsługę zapisywania obrazu. (A)
s 39c5a04 Poprawka: poprawki błędów. (B)
Wybierz poprawkę 839c6b3: konflikt rozwiązany. (DO)

Uwaga: do zatwierdzenia squasha możemy użyć squasha lub s. Końcowy wynik to:
wybierz 5152061 wyczyn: Dodano obsługę zapisywania obrazu. (AB)
wybierz poprawkę 839c6b3: konflikt rozwiązany. (DO)

Sumit
źródło
-1

Musisz wykonać trochę magii z wiersza poleceń.

git checkout -b a A
git checkout B <files>
git commit --amend
git checkout master
git rebase a

To powinno dać ci oddział, który ma AB i C jako zatwierdzenia.

Bombe
źródło
Ponieważ stare i nowe początkowe zatwierdzenia nie mają wspólnego przodka, możesz mieć niepotrzebne konflikty, ponieważ git próbuje zastosować całą historię mistrza do, nawet jeśli mają wspólne drzewo. Korzystając z opcji --onto w celu uzyskania git rebase, możesz powiedzieć gitowi właściwe miejsce, aby rozpocząć stosowanie.
CB Bailey,