Próbuję teraz dość mocnego manewru scalania git. Problem, który napotykam, polega na tym, że wprowadziłem pewne zmiany w kodzie w mojej gałęzi, ale mój kolega przeniósł ten kod do nowego pliku w swojej gałęzi. Więc kiedy to zrobiłem git merge my_branch his_branch
, git nie zauważył, że kod w nowym pliku był taki sam jak stary, więc nie ma tam żadnych moich zmian.
Jaki jest najłatwiejszy sposób ponownego zastosowania zmian w kodzie w nowych plikach. Nie będę miał zbyt wielu problemów ze stwierdzeniem, które zmiany wymagają ponownego zastosowania (mogę po prostu użyć git log --stat
). Ale o ile wiem, nie ma sposobu, aby git ponownie zastosował zmiany w nowych plikach. Najłatwiejszą rzeczą, jaką teraz widzę, jest ręczne ponowne zastosowanie zmian, co nie wygląda na dobry pomysł.
Wiem, że git rozpoznaje bloby, a nie pliki, więc z pewnością musi istnieć sposób, aby to powiedzieć „zastosuj tę dokładną zmianę kodu z tego zatwierdzenia, z wyjątkiem tego, gdzie to było, ale gdzie jest teraz w nowym pliku”.
--rename-threshold
opcja dostosowania wymaganego podobieństwa.Odpowiedzi:
Miałem podobny problem i rozwiązałem go, dostosowując moją pracę do docelowej organizacji plików.
Powiedzmy, że zmodyfikowałeś
original.txt
swoją gałąź (local
gałąź), ale na gałęzi głównej,original.txt
została skopiowana do innej, powiedzmycopy.txt
. Ta kopia została wykonana w zatwierdzeniu, które nazywamy commitCP
.Chcesz zastosować wszystkie lokalne zmiany, zatwierdzenia
A
iB
poniższe zmiany, które zostały wprowadzone woriginal.txt
nowym plikucopy.txt
.Utwórz gałąź jednorazowego użytku
move
w punkcie początkowym zmian za pomocągit branch move X
. To znaczy, umieśćmove
gałąź w zatwierdzeniuX
, tym przed zatwierdzeniami, które chcesz scalić; najprawdopodobniej jest to zatwierdzenie, z którego wyszedłeś, aby wprowadzić zmiany. Jak napisał poniżej użytkownik @digory doo , możeszgit merge-base master local
znaleźćX
.W tej gałęzi wydaj następujące polecenie zmiany nazwy:
Spowoduje to zmianę nazwy pliku. Zauważ, że
copy.txt
w tym momencie jeszcze nie istniał w twoim drzewie.Zatwierdź swoją zmianę (nazywamy to zatwierdzenie
MV
).Możesz teraz oprzeć swoją pracę na
move
:Powinno to działać bez problemu, a zmiany zostaną zastosowane
copy.txt
w lokalnym oddziale.Teraz niekoniecznie chcesz lub musisz mieć zatwierdzenie
MV
w historii swojej głównej gałęzi, ponieważ operacja przenoszenia może prowadzić do konfliktu z operacją kopiowania przy zatwierdzaniuCP
w głównej gałęzi.Musisz tylko ponownie ustawić bazę swojej pracy, odrzucając operację przenoszenia w następujący sposób:
... gdzie
CP
jest zatwierdzenie, gdziecopy.txt
zostało wprowadzone w innej gałęzi. Ten rebases wszystkie zmiany nacopy.txt
na szczycieCP
popełnić. Teraz twojalocal
gałąź jest dokładnie taka, jakbyś zawsze modyfikowała,copy.txt
a nieoriginal.txt
, i możesz kontynuować scalanie z innymi.Ważne jest, aby zmiany zostały zastosowane
CP
lub w innycopy.txt
sposób nie istniałyby, a zmiany zostałyby zastosowane ponownieoriginal.txt
.Mam nadzieję, że to jest jasne. Ta odpowiedź jest spóźniona, ale może być przydatna dla kogoś innego.
źródło
patch
(co wiąże się również z potencjalnie dużym nakładem pracy), dlatego pomyślałem, że może być interesujące, aby to pokazać. Zwróć też uwagę, że napisanie odpowiedzi zajęło mi więcej czasu niż wprowadzenie zmian w moim przypadku. Na którym etapie poleciłbyś użycie scalania? i dlaczego? Jedyną różnicą, jaką widzę, jest to, że przez ponowne bazowanie wykonuję tymczasowe zatwierdzenie, które jest później odrzucane (zatwierdzenieMV
), co nie jest możliwe w przypadku tylko scaleń.Zawsze możesz użyć
git diff
(lubgit format-patch
), aby wygenerować łatkę, a następnie ręcznie edytować nazwy plików w łatce i zastosować ją za pomocągit apply
(lubgit am
).Krótko mówiąc, jedynym sposobem, w jaki będzie działać automatycznie, jest to, że wykrywanie zmiany nazwy git może ustalić, że stare i nowe pliki to to samo - co wygląda na to, że tak naprawdę nie są w twoim przypadku, tylko ich fragment. To prawda, że git używa obiektów blob, a nie plików, ale obiekt blob to po prostu zawartość całego pliku, bez dołączonej nazwy pliku i metadanych. Więc jeśli masz fragment kodu przeniesiony między dwoma plikami, nie są one w rzeczywistości tym samym obiektem blob - reszta zawartości obiektu BLOB jest inna, tylko wspólny fragment.
źródło
git format-patch
pracę dla zatwierdzenia. Jeśli to zrobięgit format-patch SHA1
, wygeneruje całą masę plików łatek dla całej historii. Ale myślę, żegit show SHA1 > diff.patch
zadziała równie dobrze.-1
opcji. Normalnym trybem działania dla formatu-patch jest zakres wersji, na przykładorigin/master..master
tak, aby można było łatwo przygotować serię poprawek.git apply
igit am
są zbyt wybredni, ponieważ chcą mieć te same numery linii. Ale obecnie odnoszę sukcesy zpatch
poleceniem UNIX .Oto rozwiązanie scalania polegające na napotkaniu konfliktu scalania przy zmianie nazwy i edycji oraz rozwiązaniu go za pomocą narzędzia Mergetool rozpoznającego prawidłowe 3 pliki źródłowe scalania.
Jeśli scalanie nie powiedzie się z powodu „usuniętego pliku”, o którym zdajesz sobie sprawę, że została zmieniona nazwa i została poddana edycji:
Przejście:
Utwórz plik.txt:
Utwórz oddział, w którym będziesz edytować później:
Utwórz zmianę nazwy i edytuj na wzorcu:
Zamień na gałąź i tam też edytuj:
Spróbuj połączyć wzorzec:
Zauważ, że konflikt jest trudny do rozwiązania - i że nazwy plików zostały zmienione. Przerwij, naśladuj zmianę nazwy:
Spróbuj ponownie scalić:
Świetny! Scalanie powoduje `` normalny '' konflikt, który można rozwiązać za pomocą narzędzia Mergetool:
źródło
B.txt -> C.txt
iA.txt -> B.txt
ze git mv i git nie mógł automatycznie dopasować konflikty scalania poprawnie (był już konflikty scalania między stareB.txt
i noweB.txt
). Korzystając z tej metody, konflikty scalania są teraz między poprawnymi plikami.Moje szybkie rozwiązanie tego problemu (w moim przypadku nie był to pojedynczy plik, ale cała struktura katalogów) to:
git commit -m "moved to original location for merging"
git merge his_branch
(tym razem bez konfliktów!)git commit -m "moved back to final location after merge"
W historii będziesz mieć dwa dodatkowe zatwierdzenia.
Ale ponieważ git ścieżek ruchomy z plików
git blame
,git log
etc będzie nadal działać na tych plikach, ponieważ zobowiązuje które poruszały pliki ich nie zmieni. Więc nie widzę żadnej wady tej metody i jest to bardzo proste do zrozumienia.źródło