Ответ 1
git mv oldname newname
просто сокращается для:
mv oldname newname
git add newname
git rm oldname
то есть. он автоматически обновляет индекс как для старых, так и для новых путей.
Из того, что я понимаю, Git действительно не нужно отслеживать операции переименования/перемещения/копирования файлов, так что реальная цель git mv? Страница руководства не является особенно описательной...
Это устарело? Является ли это внутренней командой, не предназначенной для обычного пользователя?
git mv oldname newname
просто сокращается для:
mv oldname newname
git add newname
git rm oldname
то есть. он автоматически обновляет индекс как для старых, так и для новых путей.
Git имеет команду переименования
git mv
, но это просто удобство. Эффект неотличим от удаления файла и добавления другого с разными имя и тот же контент
Git просто пытается угадать для вас то, что вы пытаетесь сделать. Он делает все возможное, чтобы сохранить непрерывную историю. Конечно, это не идеально. Таким образом, git mv
позволяет вам быть явным с вашим намерением и избегать некоторых ошибок.
Рассмотрим этот пример. Начиная с пустого репо,
git init
echo "First" >a
echo "Second" >b
git add *
git commit -m "initial commit"
mv a c
mv b a
git status
Результат:
# 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")
Ошибка автоопределения:( Или это?
$ 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
а затем
$ 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
Теперь попробуйте вместо этого (не забудьте удалить папку .git
при экспериментировании):
git init
echo "First" >a
echo "Second" >b
git add *
git commit -m "initial commit"
git mv a c
git status
До сих пор так хорошо:
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: a -> c
git mv b a
git status
Теперь никто не идеален:
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a
# deleted: b
# new file: c
#
Действительно? Но, конечно...
git add *
git commit -m "change"
git log c
git log --follow c
... и результат будет таким же, как и выше: только --follow
показывает полную историю.
Теперь будьте осторожны с переименованием, поскольку любая опция может создавать странные эффекты. Пример:
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
Контрастируйте его с помощью:
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
Результат:
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... Теперь история возвращается к начальному вместо initial b, что неверно. Поэтому, когда мы делали два ходов за раз, Git запутался и не отслеживал изменения должным образом. Кстати, в моих экспериментах это случилось, когда я удалял/создавал файлы вместо использования git mv
. Продолжайте осторожно; вы были предупреждены...
Как говорит @Charles, git mv
является сокращением.
Реальный вопрос здесь: "Другие системы контроля версий (например, Subversion и Perforce) рассматривают переименование файлов специально. Почему Git?"
Линус объясняет в http://permalink.gmane.org/gmane.comp.version-control.git/217 с характерным тактом:
Пожалуйста, остановите это "треки". Git отслеживает точно, что важно, а именно "сборники файлов". Ничто другое не имеет значения, и даже мышление, что это актуально, ограничивает ваше мировоззрение. Обратите внимание, как понятие CVS "аннотировать" всегда неизбежно ограничивает ограничение использования людьми Это. Я думаю, что это абсолютно бесполезный кусок дерьма, и я описал то, что я думаю, в миллион раз полезнее, и все это выпало точно, потому что я не ограничиваю свое мышление неправильной моделью мир.
Там другое использование у меня для git mv
, не упомянутое выше.
С открытием git add -p
(git добавить режим исправления, см. http://git-scm.com/docs/git-add), мне нравится использовать его для просмотра изменений, когда я добавляю их в индекс. Таким образом, мой рабочий процесс становится (1) работать над кодом, (2) просматривать и добавлять в индекс, (3) совершать.
Как подходит git mv
? Если вы перемещаете файл напрямую, используя git rm
и git add
, все изменения добавляются в индекс, а использование git diff для просмотра изменений менее просто (перед фиксацией). Однако использование git mv
добавляет новый путь к индексу, но не изменения, внесенные в файл, что позволяет git diff
и git add -p
работать как обычно.
Есть нишевый случай, когда git mv
остается очень полезным: когда вы хотите изменить регистр имени файла в файловой системе без учета регистра. Как APFS (mac), так и NTFS (windows) по умолчанию нечувствительны к регистру (но сохраняют регистр).
greg.kindel упоминает об этом в комментарии к ответу CB Bailey.
Предположим, вы работаете на Mac и имеете файл Mytest.txt
управляемый git. Вы хотите изменить имя файла на MyTest.txt
.
Вы можете попробовать:
$ mv Mytest.txt MyTest.txt
overwrite MyTest.txt? (y/n [n]) y
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
О, Боже. Git не признает каких-либо изменений в файле.
Вы можете обойти это, переименовав файл полностью, а затем переименовав его обратно:
$ mv Mytest.txt temp.txt
$ git rm Mytest.txt
rm 'Mytest.txt'
$ mv temp.txt MyTest.txt
$ git add MyTest.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: Mytest.txt -> MyTest.txt
Ура!
Или вы можете избавить себя от всего этого, используя git mv
:
$ git mv Mytest.txt MyTest.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: Mytest.txt -> MyTest.txt