Jak zrobić różnicę git na przeniesionym / zmienionym pliku?

128

Przeniosłem plik za pomocą git mv. Teraz chciałbym zrobić różnicę na nowym pliku, aby porównać go ze starym plikiem (ze starą, już nieistniejącą nazwą).

Jak mam to zrobic?

dr jerry
źródło
4
Wkrótce (git 2.9, czerwiec 2016) wystarczy prosty git diff -- yourRenamedFile. Zobacz moją odpowiedź poniżej
VonC

Odpowiedzi:

145

Musisz użyć -M, aby umożliwić gitowi automatyczne wykrycie przeniesionego pliku podczas porównywania. Używanie tak, git diffjak wspomniano knittl, nie działa dla mnie.

Po prostu: git diff -Mpowinien to zrobić.

Dokumentacja tego przełącznika to:

-M[<n>], --find-renames[=<n>]
       Detect renames. If n is specified, it is a threshold on the similarity index 
       (i.e. amount of addition/deletions compared to the file’s size). For example, 
       -M90% means git should consider a delete/add pair to be a rename if more than
       90% of the file hasn’t changed.
Zitrax
źródło
7
Ratownik! Moje różnice git są teraz o wiele lepsze. 1) Czy korzystanie z tej opcji jest zawsze bezpieczne? 2) Czy mogę dodać tę opcję jako domyślne zachowanie do mojego ~/.gitconfig?
kevinarpe
5
Zwróć uwagę, że wykrywanie zmiany nazwy działa tylko wtedy, gdy w kolekcji plików przetwarzanych przez git diff. Uruchomienie git diff -Mna jednym pliku (o zmienionej nazwie) nie zgłasza zmiany nazwy.
Leon
1
U mnie to nie działa, ale git log --follow -- file_after_move.txtdziała dobrze. Pokazuje całą historię, także przed przeprowadzką. Jakieś pomysły? Biegnę git version 2.11.0.windows.1.
bouvierr
1
-CMożliwość wykrywania kopii jest użyteczne i podobne. Użyłem go -Mdo przeglądania pliku różnicowego, w którym refaktoryzowałem jeden plik na dwa (bez nazwy pasującej do oryginału).
cp.engr
85

Oprócz tego, co napisał knittl , zawsze możesz użyć:

git diff HEAD:./oldfilename newfilename

gdzie HEAD:./oldfilenameoznacza starą nazwę pliku w ostatnim zatwierdzeniu (w HEAD), względem bieżącego katalogu.

Jeśli nie masz wystarczająco nowego gita, musisz zamiast tego użyć:

git diff HEAD:path/to/oldfilename newfilename
Jakub Narębski
źródło
8
Dzięki za to. Możesz także określić konkretne zatwierdzenie zamiast głowy, np.git diff 39fa7c77e85c51d43ea0cf30d33aec8721812e9e:./oldfilename newfilename
Chris Bloom,
8
Jeśli nie jest jasne, możesz również podać nazwy oddziałów lub inne odniesienia, takie jak:git diff branch:old/filen.name newfilename
jricher
Pierwsza forma u mnie działa, jeśli cddo katalogu nie dodajesz --przed commit:pathparą. Git wydaje się być bardzo wybredny w kwestii składni.
dhardy
1
@dhardy <commit-ish>:<pathname>Składnia to identyfikator obiektu, coś Git-ish; po tym, jak --Git oczekuje tylko nazw plików.
Jakub Narębski
18

Dzięki git 2.9 (czerwiec 2016) nie będziesz już musiał dodawać -M. git diffużywa -Mdomyślnie.

Zobacz zatwierdzenie 5404c11 , zatwierdzenie 9501d19 , zatwierdzenie a9276a6 , zatwierdzenie f07fc9e , zatwierdzenie 62df1e6 (25 lutego 2016) autorstwa Matthieu Moy ( moy) .
(Scalone przez Junio ​​C Hamano - gitster- w zatwierdzeniu 5d2a30d , 03 kwietnia 2016)

diff: aktywuj diff.renamesdomyślnie

Wykrywanie zmiany nazwy to bardzo wygodna funkcja, a nowi użytkownicy nie powinni musieć kopać w dokumentacji, aby z niej skorzystać.

Potencjalne zastrzeżenia co do aktywacji wykrywania zmian nazwy są takie, że czasami kończy się niepowodzeniem, a czasami jest powolne. Jednak wykrywanie zmiany nazwy jest już domyślnie aktywowane w kilku przypadkach, takich jak „ git status” i „ git merge”, więc aktywacja diff.renamesnie zmienia zasadniczo sytuacji. Gdy wykrywanie zmiany nazwy nie powiedzie się, teraz kończy się niepowodzeniem między znakami „ git diff” i „ git status”.

To ustawienie nie ma wpływu na polecenia dotyczące instalacji wodociągowych, dlatego nie ma to wpływu na dobrze napisane skrypty.

Nowe testy tej funkcji są tutaj .

VonC
źródło
1

git diff -Maktywuje wykrywanie zmiany nazwy, jak powiedzieli inni (i jak zauważył @VonC, jest domyślnie aktywowany od git 2.9). Ale jeśli masz duży zestaw zmian, wykrywanie niedokładnych zmian nazwy może nadal zostać wyłączone. Git wyświetli ostrzeżenie podobne do poniższego, które łatwo przeoczyć pośród przeglądanych różnic:

warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 450 and retry the command.

W takim przypadku ustaw opcję konfiguracyjną tak, jak sugeruje na przykład git

git config diff.renamelimit 450

i ponownie uruchom polecenie diff.

mindriot
źródło
0

Z jakiegoś powodu użycie HEAD:./oldfilename(lub ścieżki absolutnej) nie zadziałało dla mnie, ale zadziałało HEAD:oldfilename(dzięki cmn):

git diff HEAD:oldfilename newfilename
git diff 2a80f45:oldfilename f65f3b3:newfilename

HTH

Oli Studholme
źródło
Może twój dupek jest za stary, by go zrozumieć HEAD:./oldfilename?
Jakub Narębski
-4

po prostu uruchom git diffbez żadnych argumentów lub git diff -- newfilename. git jest wystarczająco inteligentny, aby porównać właściwe pliki / treści (tj. oryginalną zawartość przed zmianą nazwy ze zmienioną treścią po zmianie nazwy)

knittl
źródło
2
W większości przypadków git nie jest wystarczająco inteligentny. Po prostu git mvsprawdzenie pojedynczego pliku, a następnie porównanie stanu pomostowego z inną identyczną gałęzią spowoduje powstanie różnicy „wszystko zostało usunięte i odtworzone”, chyba że -Mzostanie użyta.
Reinderien