2009-07-07 41 views
228

Z tego co rozumiem, Git naprawdę nie musi śledzić plików zmienić nazwę/przenieść/kopiować operacje, więc jaki jest prawdziwy cel z git mv? Strona podręcznika nie jest specjalnie opisowa ...Jaki jest cel git-mv?

Czy jest przestarzała? Czy jest to polecenie wewnętrzne, które nie powinno być używane przez zwykłych użytkowników?

Odpowiedz

300
git mv oldname newname 

jest tylko skrótem:

mv oldname newname 
git add newname 
git rm oldname 

to znaczy automatycznie aktualizuje indeks dla starych i nowych ścieżek.

+29

Ma także kilka wbudowanych zabezpieczeń. –

+4

Dzięki @CharlesBailey - czy git uważa pliki newNameFile i oldNameFile za różne? Jeśli tak, co się stanie, jeśli chcemy je połączyć? Załóżmy, że tworzymy projekt mrówki w oddziale A i tworzymy Oddział B, a następnie tworzymy projekty na B. Nazwy plików są takie same, ale umieszczane na różnych ścieżkach w miarę zmiany struktury projektu. Powiedzmy, że obie gałęzie rosły przez jakiś czas równolegle. W którymś momencie, jeśli chcemy połączyć projekty, to czy dowiemy się, że to ten sam plik, który zmienił nazwę swojej ścieżki?(jeśli "git mv" == "git add + git rm") – Rose

+0

Zgaduję, to jest to samo z prawdopodobieństwem 99,9999%. Oczywiście, automatyczne wykrywanie może pójść źle, jeśli masz np. wiele plików o tej samej nazwie i/lub tej samej treści. – osa

59

Z official GitFaq:

Git posiada polecenie zmiany nazwy git mv, ale to jest po prostu wygoda. Efekt jest nie do odróżnienia od usunięcie pliku i dodanie drugiego z innym nazwie i tej samej treści

+6

Czy tracisz historię plików? Przypuszczam, że zmiana nazwy zachowa starą historię dla tego katalogu ... –

+14

Cóż, tak i nie. Przeczytaj oficjalny odsyłacz do GitFaq powyżej o nazwach, a następnie przeczytaj długotrwały e-mail Linusa Torvaldsa o tym, dlaczego nie podoba mu się pojęcie plików śledzenia narzędzia SCM: http://permalink.gmane.org/gmane.comp.version- control.git/217 –

+2

@WillHancock Użyłem git trochę więcej i mogę odpowiedzieć bardziej zdecydowanie: w zależności od twojego klienta git i jego opcji, będziesz mógł prześledzić plik po zmianie nazwy, jeśli plik zmienił się wewnętrznie mało na tyle, że uważa to za zmianę nazwy. Jeśli zmienisz plik za dużo I zmień jego nazwę, git go nie wykryje - w pewnym sensie mówi "nie, możesz równie dobrze wziąć pod uwagę zupełnie inny plik!" –

18

Jak mówi @Charles, git mv jest skróconym.

Prawdziwe pytanie brzmi: "Inna wersja systemów kontroli wersji (np. Subversion i Perforce) traktuje szczególnie nazwy plików." Dlaczego nie Git?

Linus wyjaśnia w http://permalink.gmane.org/gmane.comp.version-control.git/217 z charakterystycznym taktem:

Proszę zatrzymać ten "Pliki utworów" bzdura. Git utwory dokładnie co ważne, czyli "zbiory plików". Nic innego nie jest istotne, a nawet, że jest to istotne, ogranicza jedynie twój światopogląd. Zauważ, że pojęcie "adnotacji" CVS zawsze nieuchronnie kończy się ograniczeniem tego, jak ludzie używają go. Myślę, że to całkowicie bezużyteczny kawałek bzdur, i opisałem, że jest to milion razy bardziej użyteczne, i wszystko to wypadło, dokładnie, ponieważ nie ograniczam mojego myślenia do niewłaściwego modelu świat.

+0

Czy masz lustro dla tego linku? Jest teraz zepsuty. – cjm

+4

Aby uzyskać szczegółowe wyjaśnienie, wypróbuj https://web.archive.org/web/20160304045715/http://permalink.gmane.org/gmane.comp.version-control.git/217 –

25

Git stara się odgadnąć, co chcesz zrobić. Podejmuje wszelkie próby zachowania nieprzerwanej historii. Oczywiście nie jest doskonały. Tak więc git mv pozwala ci jasno wyrazić swoją intencję i uniknąć błędów.

Rozważ ten przykład. Zaczynając od pustego repo,

git init 
echo "First" >a 
echo "Second" >b 
git add * 
git commit -m "initial commit" 
mv a c 
mv b a 
git status 

Wynik:

# On branch master 
# Changes not staged for commit: 
# (use "git add/rm <file>..." to update what will be committed) 
# (use "git checkout -- <file>..." to discard changes in working directory) 
# 
# modified: a 
# deleted: b 
# 
# Untracked files: 
# (use "git add <file>..." to include in what will be committed) 
# 
# c 
no changes added to commit (use "git add" and/or "git commit -a") 

Autodetekcja udało :( Albo to zrobił?

$ git add * 
$ git commit -m "change" 
$ git log c 

commit 0c5425be1121c20cc45df04734398dfbac689c39 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:24:56 2013 -0400 

    change 

a następnie

$ git log --follow c 

Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:24:56 2013 -0400 

    change 

commit 50c2a4604a27be2a1f4b95399d5e0f96c3dbf70a 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:24:45 2013 -0400 

    initial commit 

Teraz spróbuj zamiast (pamiętaj, aby usunąć folder .git podczas eksperymentów):

git init 
echo "First" >a 
echo "Second" >b 
git add * 
git commit -m "initial commit" 
git mv a c 
git status 

tej pory tak dobrze:

# On branch master 
# Changes to be committed: 
# (use "git reset HEAD <file>..." to unstage) 
# 
# renamed: a -> c 


git mv b a 
git status 

teraz , nobo dy jest idealny:

# On branch master 
# Changes to be committed: 
# (use "git reset HEAD <file>..." to unstage) 
# 
# modified: a 
# deleted: b 
# new file: c 
# 

Naprawdę? Ale oczywiście ...

git add * 
git commit -m "change" 
git log c 
git log --follow c 

... a wynik jest taki sam jak powyżej: tylko --follow przedstawia pełną historię.


Teraz należy być ostrożnym z zmiana nazwy, jak albo opcja może nadal wywołują skutki dziwne. Przykład:

git init 
echo "First" >a 
git add a 
git commit -m "initial a" 
echo "Second" >b 
git add b 
git commit -m "initial b" 

git mv a c 
git commit -m "first move" 
git mv b a 
git commit -m "second move" 

git log --follow a 

commit 81b80f5690deec1864ebff294f875980216a059d 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:35:58 2013 -0400 

    second move 

commit f284fba9dc8455295b1abdaae9cc6ee941b66e7f 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:34:54 2013 -0400 

    initial b 

Kontrast go:

git init 
echo "First" >a 
git add a 
git commit -m "initial a" 
echo "Second" >b 
git add b 
git commit -m "initial b" 

git mv a c 
git mv b a 
git commit -m "both moves at the same time" 

git log --follow a 

Wynik:

commit 84bf29b01f32ea6b746857e0d8401654c4413ecd 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:37:13 2013 -0400 

    both moves at the same time 

commit ec0de3c5358758ffda462913f6e6294731400455 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:36:52 2013 -0400 

    initial a 

Ups ... Teraz historia wraca do parafować zamiast początkowy b, co jest złe. Kiedy więc robiliśmy dwa ruchy na raz, Git był zdezorientowany i nie śledzi prawidłowo zmian. Nawiasem mówiąc, w moich eksperymentach to samo stało się, gdy usunąłem/utworzyłem pliki zamiast używać git mv. Kontynuuj ostrożnie; zostałeś ostrzeżony ...

+3

+1. Szukałem problemów, które mogą się zdarzyć w historii logów, jeśli pliki są przenoszone w git, twoja odpowiedź była naprawdę interesująca. Dziękuję Ci! Btw, czy znasz inne pułapki, których powinniśmy unikać podczas przenoszenia plików w git? (lub jakiekolwiek odniesienie, które możesz wskazać ... niezbyt szczęśliwe googlowanie) – pabrantes

+1

Cóż, moje przykłady są pesymistyczne. Gdy pliki są puste, znacznie trudniej jest właściwie zinterpretować zmiany. Wyobrażam sobie, że jeśli po prostu zatwierdzasz po każdym zestawie nazw, powinieneś być w porządku. – osa

6

Jest jeszcze jedno użycie, które mam dla git mv, nie wymienione powyżej.

Od odkrycia git add -p (tryb poprawki git add za patrz http://git-scm.com/docs/git-add), lubię go używać, aby sprawdzić zmiany, jak dodać je do indeksu. W ten sposób mój przepływ pracy staje się (1) pracą nad kodem, (2) sprawdzaniem i dodawaniem do indeksu, (3) zatwierdzaniem.

W jaki sposób pasuje git mv? Jeśli przenosisz plik bezpośrednio, używając git rm i git add, wszystkie zmiany zostaną dodane do indeksu, a użycie zmiany git w celu wyświetlenia zmian jest mniej proste (przed zatwierdzeniem). Jednakże użycie parametru git mv powoduje dodanie nowej ścieżki do indeksu, ale nie zmian wprowadzonych do pliku, dzięki czemu git diff i git add -p działają tak jak zwykle.