Myślę, że głównym problemem jest to, że git (a kontrola wersji ogólnie) zmusza do myślenia w kategoriach sekwencji zmian, ale changeset lub funkcje oddziału lub cokolwiek nazwać spójna grupa powiązanych zmian ogólnie nie jest logiczna sekwencyjnie. Kolejność, w jakiej został napisany kod, jest przypadkowa i niekoniecznie związana z kolejnością, w jakiej należy ją przeczytać.
Nie mam na to rozwiązania, ale napisałem Perl script, aby pomóc zautomatyzować proces przepisywania historii. Jest podobny do skryptu Python @MikaEloranty, którego nie widziałem, kiedy go pisałem.
commit --fixup
i rebase --autosquash
są świetne, ale nie robią wystarczająco dużo. Kiedy mam sekwencję zatwierdzeń A-B-C
i piszę więcej zmian w moim drzewie roboczym, które należą do jednego lub więcej z tych istniejących zatwierdzeń, muszę ręcznie spojrzeć na historię, zdecydować, które zmiany należą do których zatwierdza, je wystawić i utworzyć zatwierdza fixup!
. Ale git ma już dostęp do wystarczającej ilości informacji, aby móc to wszystko dla mnie zrobić.
Do każdej porcji w git diff
skrypt korzysta git blame
aby znaleźć zobowiązują się, że ostatni dotknął odpowiednich linii i zwraca git commit --fixup
napisać odpowiednie fixup!
zobowiązuje zasadniczo robi to samo robię ręcznie wcześniej.
Jeśli skrypt nie może rozwiązać porcji do pojedynczego, jednoznacznego zatwierdzenia, zgłasza to jako nieudany fragment, a będziesz musiał wrócić do ręcznego podejścia do tego. Jeśli dwukrotnie zmienisz wiersz w dwóch osobnych zatwierdzeniach, skrypt rozwiąże zmianę w tym wierszu do najnowszego z tych zatwierdzeń, które nie zawsze mają poprawną rozdzielczość. IMHO w odmianie "normalnej formy" nie powinieneś zmieniać wiersza dwa razy w dwóch różnych zatwierdzeniach, każde zatwierdzenie powinno przedstawiać ostateczną wersję linii, która dotyka, aby pomóc recenzentowi (recenzentom). Jednak może się zdarzyć w gałęzi błędów, aby wymyślić przykład, aby linia foo(bar());
mogła zostać dotknięta przez zatwierdzenie A (zmiana nazwy foo
na fox
) i zatwierdzenie B (zmiana nazwy bar
na baz
).
Jeśli uznasz ten skrypt za przydatny, możesz go poprawić i powtórzyć go, a być może pewnego dnia otrzymamy taką funkcję w poprawnej wersji git
. Chciałbym zobaczyć narzędzie, które może zrozumieć, jak należy rozwiązać konflikt scalania, gdy zostanie wprowadzone przez interaktywny rebase.
Dlaczego takie dziwne wymaganie, że fixA musi zostać połączone w A? –
ponieważ powinien on być w A w pierwszej kolejności. – elmarco
Ja robię to samo; Nie jestem pewien, dlaczego ludzie myślą, że to dziwne. Jeśli próbujesz uporządkować commity w małe, logicznie pogrupowane elementy, naturalnie jest przygotowywać kilka niewydanych zatwierdzeń naraz. (Możesz nie wiedzieć, czy naprawdę skończyłeś z A, dopóki nie skończysz C). – andy