Właśnie przeczytałem poprawianie pojedynczego pliku w poprzednim zatwierdzeniu w git, ale niestety zaakceptowane rozwiązanie „zmienia kolejność” zatwierdzeń, co nie jest tym, czego chcę. Oto moje pytanie:
Od czasu do czasu zauważam błąd w moim kodzie podczas pracy nad (niepowiązaną) funkcją. Szybko git blame
ujawnia, że błąd został wprowadzony kilka zatwierdzeń temu (robię dość dużo, więc zwykle nie jest to ostatnie zatwierdzenie, które wprowadziło błąd). W tym momencie zwykle robię to:
git stash # temporarily put my work aside
git rebase -i <bad_commit>~1 # rebase one step before the bad commit
# mark broken commit for editing
vim <affected_sources> # fix the bug
git add <affected_sources> # stage fixes
git commit -C <bad_commit> # commit fixes using same log message as before
git rebase --continue # base all later changes onto this
Jednak zdarza się to na tyle często, że powyższa sekwencja staje się irytująca. Zwłaszcza „interaktywna rebase” jest nudna. Czy jest jakiś skrót do powyższej sekwencji, który pozwala mi zmienić dowolne zatwierdzenie w przeszłości za pomocą wprowadzonych zmian? Doskonale zdaję sobie sprawę, że to zmienia historię, ale popełniam błędy tak często, że naprawdę chciałbym mieć coś takiego
vim <affected_sources> # fix bug
git add -p <affected_sources> # Mark my 'fixup' hungs for staging
git fixup <bad_commit> # amend the specified commit with staged changes,
# rebase any successors of bad commit on rewritten
# commit.
Może inteligentny skrypt, który może przepisać zmiany przy użyciu narzędzi hydraulicznych?
rebase -i
?rebase --onto tmp bad-commit master
. Jak napisano, będzie próbował zastosować złe zatwierdzenie do stanu ustalonego zatwierdzenia.Odpowiedzi:
ZAKTUALIZOWANA ODPOWIEDŹ
Jakiś czas temu dodano nowy
--fixup
argument, dogit commit
którego można użyć do skonstruowania zatwierdzenia z komunikatem dziennika odpowiednim dlagit rebase --interactive --autosquash
. Więc najprostszym sposobem naprawienia przeszłego zatwierdzenia jest teraz:ORYGINALNA ODPOWIEDŹ
Oto mały skrypt w Pythonie, który napisałem jakiś czas temu, który implementuje
git fixup
logikę, na którą liczyłem w moim pierwotnym pytaniu. Skrypt zakłada, że wprowadziłeś pewne zmiany, a następnie stosuje je do danego zatwierdzenia.UWAGA : Ten skrypt jest specyficzny dla systemu Windows; wyszukuje
git.exe
i ustawiaGIT_EDITOR
zmienną środowiskową za pomocąset
. Dostosuj to w razie potrzeby do innych systemów operacyjnych.Za pomocą tego skryptu mogę precyzyjnie zaimplementować przepływ pracy `` napraw uszkodzone źródła, poprawki scen, uruchom git fixup '', o który prosiłem:
źródło
git stash
igit stash pop
wokół swojej rebase, aby nie wymagać już czystego katalogu roboczegogit stash
igit stash pop
: masz rację, ale niestetygit stash
jest znacznie wolniejszy w systemie Windows niż w systemie Linux lub OS / X. Ponieważ mój katalog roboczy jest zwykle czysty, pominąłem ten krok, aby nie spowalniać polecenia.git rebase -i --fixup
i zostało zmienione na podstawie ustalonego zatwierdzenia jako punktu wyjścia, więc argument sha nie był potrzebny w moim przypadku.git config --global rebase.autosquash true
Co robię to:
Twój edytor otworzy się z listą ostatnich 5 zatwierdzeń, gotowych do wtrącenia. Zmiana:
...do:
Zapisz i zamknij edytor, a poprawka zostanie umieszczona z powrotem w zatwierdzeniu, do którego należy.
Gdy zrobisz to kilka razy, we śnie zrobisz to w kilka sekund. Interaktywne ponowne bazowanie to funkcja, która naprawdę sprzedała mnie na git. Jest to niezwykle przydatne w tym i nie tylko ...
źródło
--autosquash
przełącznikiem dlagit rebase
, który automatycznie zmienia kolejność kroków w edytorze. Zobacz moją odpowiedź na skrypt, który wykorzystuje to do zaimplementowaniagit fixup
polecenia.Trochę za późno na imprezę, ale tutaj jest rozwiązanie, które działa tak, jak sobie wyobrażał autor.
Dodaj to do swojego .gitconfig:
Przykładowe użycie:
Jeśli jednak masz niestabilne zmiany, musisz je schować przed rebase.
Możesz zmodyfikować alias, aby automatycznie ukrywał się, zamiast dawać ostrzeżenie. Jeśli jednak korekta nie zostanie poprawnie zastosowana, po naprawieniu konfliktów będziesz musiał ręcznie otworzyć schowek. Ręczne zapisywanie i wyskakiwanie wydaje się bardziej spójne i mniej zagmatwane.
źródło
git fixup HEAD
właśnie dla tego utworzyłem alias. Przypuszczam, że mógłbym również użyć do tego poprawki.amend = commit --amend --reuse-message=HEAD
Następnie możesz po prostu wpisaćgit amend
lubgit amend -a
i pominąć edytor dla komunikatu o zatwierdzeniu.Aby naprawić jedno zatwierdzenie:
gdzie a0b1c2d3 to zatwierdzenie, które chcesz naprawić, a 2 to liczba zatwierdzeń +1 wklejonych, które chcesz zmienić.
Uwaga: git rebase --autosquash bez -i nie działało, ale z -i działało, co jest dziwne.
źródło
--autosquash
bez-i
nadal nie działa.EDITOR=true git rebase --autosquash -i
AKTUALIZACJA: Czystszą wersję skryptu można teraz znaleźć tutaj: https://github.com/deiwin/git-dotfiles/blob/docs/bin/git-fixup .
Szukałem czegoś podobnego. Ten skrypt w Pythonie wydaje się jednak zbyt skomplikowany, dlatego opracowałem własne rozwiązanie:
Po pierwsze, moje aliasy git wyglądają tak (zapożyczone stąd ):
Teraz funkcja bash staje się całkiem prosta:
Ten kod najpierw przygotowuje wszystkie bieżące zmiany (możesz usunąć tę część, jeśli chcesz samodzielnie przygotować pliki). Następnie tworzy fixup (można również użyć squasha, jeśli tego potrzebujesz) commit. Następnie rozpoczyna interaktywne ponowne bazowanie z
--autosquash
flagą na rodzicu zatwierdzenia, które podajesz jako argument. Spowoduje to otwarcie skonfigurowanego edytora tekstu, dzięki czemu możesz sprawdzić, czy wszystko jest zgodne z oczekiwaniami, a po prostu zamknięcie edytora zakończy proces.if [[ "$1" == HEAD* ]]
Część (zapożyczone z tutaj ) jest używany, ponieważ jeśli używasz na przykład HEAD ~ 2 jak wasz commit (commit chcesz naprawić bieżących zmian z) odniesienie to HEAD zostanie przesunięty po fixup commit została stworzona i musiałbyś użyć HEAD ~ 3, aby odnieść się do tego samego zatwierdzenia.źródło
Możesz uniknąć etapu interaktywnego, używając edytora „zerowego”:
Spowoduje to użycie
/bin/true
jako edytora zamiast/usr/bin/vim
. Zawsze akceptuje wszystko, co sugeruje git, bez podpowiedzi.źródło
call(["set", "GIT_EDITOR=true", "&&", git, "rebase", "-i" ...
).To, co naprawdę przeszkadzało mi w przepływie pracy związanym z poprawkami, to fakt, że musiałem sam wymyślić, w którym zatwierdzeniu chciałem za każdym razem zmiażdżyć zmianę. Stworzyłem polecenie „git fixup”, które pomaga w tym.
To polecenie tworzy poprawki poprawek , z dodatkową magią polegającą na tym, że używa git-deps do automatycznego znalezienia odpowiedniego zatwierdzenia, więc przepływ pracy często sprowadza się do:
Działa to tylko wtedy, gdy etapowe zmiany można jednoznacznie przypisać do konkretnego zatwierdzenia w drzewie roboczym (między głównym a HEAD). Uważam, że jest tak bardzo często w przypadku typu drobnych zmian, których używam, np. Literówek w komentarzach lub nazw nowo wprowadzonych (lub zmienionych nazw) metod. Jeśli tak nie jest, wyświetli się przynajmniej lista zatwierdzeń kandydatów.
Używam tego często w moim codziennym przepływie pracy, aby szybko zintegrować małe zmiany w poprzednio zmienionych wierszach w zatwierdzeniach w mojej gałęzi roboczej. Skrypt nie jest tak piękny, jak mógłby być i jest napisany w zsh, ale już od dłuższego czasu wykonuje swoją pracę wystarczająco dobrze, kiedy nigdy nie czułem potrzeby przepisywania go:
https://github.com/Valodim/git-fixup
źródło
Korzystając z tego aliasu, można utworzyć korektę dla określonego pliku.
Jeśli wprowadziłeś jakieś zmiany,
myfile.txt
ale nie chcesz umieszczać ich w nowym zatwierdzeniu,git fixup-file myfile.txt
utworzyfixup!
dla zatwierdzenia miejsce, w którymmyfile.txt
był ostatnio modyfikowany, a następnie tak się stanierebase --autosquash
.źródło
git rebase
nie wywołano tego automatycznie.commit --fixup
irebase --autosquash
są świetne, ale nie wystarczają. Kiedy mam sekwencję zatwierdzeńA-B-C
i piszę więcej zmian w moim drzewie roboczym, które należą do jednego lub więcej istniejących zatwierdzeń, muszę ręcznie przejrzeć historię, zdecydować, które zmiany należą do których zatwierdzeń, ustawić je i utworzyćfixup!
zatwierdza. Ale git ma już dostęp do wystarczającej ilości informacji, aby móc zrobić to wszystko za mnie, więc napisałem skrypt Perla, który właśnie to robi.Za każdą porcję
git diff
fragmentu w skrypcie używa sięgit blame
do znalezienia zatwierdzenia, który ostatnio dotykał odpowiednich wierszy, i wywołujegit commit --fixup
napisanie odpowiednichfixup!
zatwierdzeń, zasadniczo robiąc to samo, co wcześniej robiłem ręcznie.Jeśli uznasz to za przydatne, nie krępuj się, aby go ulepszyć i powtórzyć, a być może pewnego dnia dostaniemy taką funkcję we
git
właściwy sposób. Bardzo chciałbym zobaczyć narzędzie, które może zrozumieć, jak należy rozwiązać konflikt scalania, gdy został wprowadzony przez interaktywną bazę danych.źródło
Napisałem małą funkcję powłoki wywoływaną
gcf
do automatycznego zatwierdzania poprawek i rebase:Na przykład możesz załatać drugie zatwierdzenie przed najnowszym za pomocą:
gcf HEAD~~
Oto funkcja . Możesz wkleić go do swojego
~/.bashrc
To używa
--autostash
do przechowywania i pobierania wszelkich niezatwierdzonych zmian, jeśli to konieczne.--autosquash
wymaga--interactive
rebase, ale unikamy interakcji, używając atrapyEDITOR
.--no-fork-point
chroni zatwierdzenia przed dyskretnym porzuceniem w rzadkich sytuacjach (gdy rozwidliłeś nową gałąź, a ktoś już zmienił bazę poprzednich zatwierdzeń).źródło
Nie znam sposobu zautomatyzowanego, ale oto rozwiązanie, które może być łatwiejsze do zrobienia przez człowieka:
źródło
git fixup
polecenia.--autosquash
Polecam https://github.com/tummychow/git-absorb :
źródło