Załóżmy, że mam następującą historię zatwierdzeń w mojej gałęzi tylko lokalnej:
A -- B -- C
Jak wstawić nowe zatwierdzenie między Aa B?
Załóżmy, że mam następującą historię zatwierdzeń w mojej gałęzi tylko lokalnej:
A -- B -- C
Jak wstawić nowe zatwierdzenie między Aa B?
Odpowiedzi:
To jeszcze łatwiejsze niż w odpowiedzi OP.
git rebase -i <any earlier commit>. Spowoduje to wyświetlenie listy zatwierdzeń w skonfigurowanym edytorze tekstu.a1b2c3d). W edytorze dla tego wiersza zmień pickna edit.a1b2c3d), tak jakby zostało właśnie zatwierdzone .git commit( NIE zmieniaj, w przeciwieństwie do większości edit). Tworzy to nowe zatwierdzenie po tym, które wybrałeś.git rebase --continue. Powoduje to odtworzenie kolejnych zatwierdzeń, pozostawiając nowe zatwierdzenie wstawione we właściwym miejscu.Uważaj, bo to odmieni historię i złamie każdego, kto spróbuje pociągnąć.
A -- B -- C -- Dpożądana A -- D -- B -- C.
Dmoże być zatwierdzeniem wszędzie. Załóżmy, że mamy A - B - Ci mamy pewne zmiany, Dktórych nie ma nawet w tej gałęzi. Znamy jego SHA, jednak możemy to zrobić git rebase -i HEAD~3. Teraz między wierszami Ai B pickwstawiamy nową pick linię, która mówi pick SHA, podając skrót żądanego D. Nie musi to być pełny hash, tylko skrócony. git rebase -ipo prostu wiśnia wybiera wszystkie zatwierdzenia wymienione w pickwierszach w buforze; nie muszą to być oryginalne, wymienione dla Ciebie.
breaksłowa kluczowego w edytorze w osobnym wierszu między dwoma zatwierdzeniami (lub w pierwszym wierszu, aby wstawić zatwierdzenie przed określonym zatwierdzeniem).
Okazuje się być całkiem proste, odpowiedź znaleźć tutaj . Załóżmy, że jesteś na gałęzi branch. Wykonaj następujące kroki:
utwórz tymczasową gałąź z zatwierdzenia po tym, jak chcesz wstawić nowy zatwierdzenie (w tym przypadku zatwierdzenie A):
git checkout -b temp A
wprowadź zmiany i zatwierdź je, tworząc zatwierdzenie, nazwijmy to N:
git commit -a -m "Message"
(lub git addnastępuje git commit)
przebuduj zatwierdzenia, które chcesz mieć po nowym zatwierdzeniu (w tym przypadku zatwierdzeniach Bi C) na nowe zatwierdzenie:
git rebase temp branch
(być może trzeba użyć -p, aby zachować scala, gdyby nie było w ogóle - dzięki a już istniejącym komentarzu przez Ciekawy )
usuń tymczasową gałąź:
git branch -d temp
Po tym historia wygląda następująco:
A -- N -- B -- C
Jest oczywiście możliwe, że podczas przebudowy pojawią się pewne konflikty.
Jeśli twoja gałąź nie jest lokalna - wprowadzi to przepisywanie historii, więc może spowodować poważne problemy.
git push --forcezmian musiałem zmienić zdalne repozytorium.
git rebase temp branch -Xtheirs. Pomocna odpowiedź na wstrzyknięcie w skrypcie!
git rebase temp branch, ale wcześniej git branch -d tempwszystko, co musisz zrobić, to naprawić i scalić konflikty i problemy git rebase --continue, tj. Nie trzeba niczego zatwierdzać itp.
Jeszcze łatwiejsze rozwiązanie:
Utwórz nowe zatwierdzenie na końcu, D. Teraz masz:
A -- B -- C -- D
Następnie uruchomić:
$ git rebase -i hash-of-A
Git otworzy twój edytor i będzie wyglądał tak:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Po prostu przenieś D na górę w ten sposób, a następnie zapisz i zakończ
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
Teraz będziesz mieć:
A -- D -- B -- C
Zakładając, że historia zatwierdzeń to preA -- A -- B -- C, jeśli chcesz wstawić zatwierdzenie między Ai B, kroki są następujące:
git rebase -i hash-of-preA
Git otworzy twój edytor. Treść może wyglądać następująco:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Zmień pierwszą pickna edit:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Zapisz i wyjdź.
Zmodyfikuj swój kod, a następnie git add . && git commit -m "I"
git rebase --continue
Teraz twoja historia zatwierdzania Git to preA -- A -- I -- B -- C
Jeśli napotkasz konflikt, Git zatrzyma się na tym zatwierdzeniu. Możesz użyć git diffdo zlokalizowania znaczników konfliktów i ich rozwiązania. Po rozwiązaniu wszystkich konfliktów musisz użyć, git add <filename>aby powiedzieć Gitowi, że konflikt został rozwiązany, a następnie ponownie uruchomić git rebase --continue.
Jeśli chcesz cofnąć zmianę bazy, użyj git rebase --abort.
Oto strategia, która pozwala uniknąć robienia „hackowania edycji” podczas rebase, co jest widoczne w innych odpowiedziach, które przeczytałem.
Używając git rebase -i, otrzymujesz listę zatwierdzeń od tego zatwierdzenia. Po prostu dodaj „przerwę” na początku pliku, co spowoduje, że rebase przestanie działać w tym momencie.
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
Po uruchomieniu git rebasezatrzyma się teraz w miejscu „przerwy”. Możesz teraz edytować swoje pliki i normalnie tworzyć zmiany. Następnie możesz kontynuować rebase za pomocą git rebase --continue. Może to powodować konflikty, które będziesz musiał naprawić. Jeśli się zgubisz, nie zapomnij, że zawsze możesz przerwać używanie git rebase --abort.
Tę strategię można uogólnić, aby wstawić zatwierdzenie w dowolnym miejscu, po prostu wstaw „przerwę” w miejscu, w którym chcesz wstawić zatwierdzenie.
Po przepisaniu historii nie zapomnij o tym git push -f. Obowiązują zwykłe ostrzeżenia, że inne osoby pobierają Twój oddział.
rebasetutaj. Nie ma dużej różnicy, czy utworzysz zatwierdzenie podczas rebase, czy wcześniej.
Wiele dobrych odpowiedzi już tutaj. Chciałem tylko dodać rozwiązanie „bez rebase” w 4 prostych krokach.
Podsumowanie
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
Wyjaśnienie
(Uwaga: jedną z zalet tego rozwiązania jest to, że nie dotykasz swojej gałęzi aż do ostatniego kroku, kiedy jesteś w 100% pewien, że jesteś w porządku z końcowym wynikiem, więc masz bardzo przydatny krok „wstępnego potwierdzenia” pozwalające na testowanie AB .)
Stan początkowy (założyłem masternazwę twojego oddziału)
A -- B -- C <<< master <<< HEAD
1) Zacznij od wskazania HEAD we właściwym miejscu
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(Opcjonalnie tutaj, zamiast odłączać HEAD, moglibyśmy utworzyć tymczasową gałąź, z git checkout -b temp Aktórą musielibyśmy usunąć na końcu procesu. Oba warianty działają, rób tak, jak wolisz, ponieważ wszystko inne pozostaje takie samo)
2) Utwórz nowe zatwierdzenie D do wstawienia
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Następnie przynieś kopie ostatnich brakujących zatwierdzeń B i C (byłaby ta sama linia, gdyby było więcej zatwierdzeń)
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(w razie potrzeby wygodne badanie AB)
Nadszedł czas, aby sprawdzić swój kod, przetestować wszystko, co powinno zostać przetestowane, a także porównać / porównać / sprawdzić, co masz i co otrzymasz po operacjach.
4) W zależności od wyników testów pomiędzy Ci C', albo jest OK, albo jest KO.
(ALBO) 4-OK) Na koniec przesuń ref zmaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(LUB) 4-KO) Po prostu zostaw masterbez zmian
Jeśli utworzyłeś tymczasową gałąź, po prostu usuń ją za pomocą git branch -d <name>, ale jeśli wybrałeś odłączoną trasę HEAD, w tym momencie nie jest wymagana żadna akcja, nowe zatwierdzenia będą kwalifikować się do czyszczenia pamięci zaraz po ponownym podłączeniu HEADzgit checkout master
W obu tych przypadkach (OK lub KO), w tym momencie po prostu sprawdź masterponownie, aby ponownie podłączyć HEAD.