Почему "git mv" не перемещает файл? Как заставить его действовать "нормально"?

Пожалуйста, прости мое невежество здесь... Вот предыстория: я создал каталог TestScritps для организации тестовых скриптов. Я переместил три сценария из <root dir> в <root dir>/TestScripts, Я перемещал по одному и выполнял локальный коммит после каждого. Затем я подтолкнул все изменения.

Я пошел к другой машине и выполнил тянуть:

$ cd cryptopp/
$ git pull
remote: Counting objects: 25, done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 25 (delta 11), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (25/25), done.
From https://github.com/weidai11/cryptopp
   2ac9ea1..2a22a84  master     -> origin/master
Updating 2ac9ea1..2a22a84
Fast-forward
 TestScripts/cryptest-android.sh |   44 +
 TestScripts/cryptest-ios.sh     |   40 +
 TestScripts/cryptest.sh         | 5729 +++++++++++++++++++++++++++++++++++++++
 rijndael.cpp                    |    2 +-
 setenv-android.sh               |   85 +-
 5 files changed, 5870 insertions(+), 30 deletions(-)
 create mode 100755 TestScripts/cryptest-android.sh
 create mode 100755 TestScripts/cryptest-ios.sh
 create mode 100755 TestScripts/cryptest.sh

$ ls *.sh
cryptest-android.sh  cryptest.sh     setenv-android.sh   setenv-ios.sh
cryptest-ios.sh      rdrand-nasm.sh  setenv-embedded.sh

Обратите внимание, что файлы были только скопированы; они не были перемещены.

Я проверил git-mv man-страница, но ошибочное поведение не обсуждается.

У меня два вопроса. Почему git mv только копировать файлы, а не перемещать их? Как я могу сделать git mv выполнять "нормально"? Здесь "обычно" означает то, что ожидает почти каждый, кто использовал командную строку - он перемещает файл из <target location> в <destination location>,


Вот соответствующая история команд.

  994  rm -rf cryptopp/
  995  git clone https://github.com/weidai11/cryptopp
  996  cd cryptopp/
  997  mkdir TestScripts
  998  git mv cryptest.sh TestScripts/
  999  ls *.sh
 1000  git commit TestScripts/cryptest.sh -m "Organize test scripts (Issue 303)"
 1001  ls *.sh
 1002  git mv cryptest-ios.sh TestScripts/
 1003  git commit TestScripts/cryptest-ios.sh -m "Organize test scripts (Issue 303)"
 1004  ls *.sh
 1005  git commit

2 ответа

Решение

Из резюме, показанного в выводе git pullЯ вижу, что эти файлы не были удалены.

Когда вы сделали, например:

git commit TestScripts/cryptest.sh -m "Organize test scripts (Issue 303)"

Хотя Git обычно хорош в отслеживании перемещений файлов, внутренне перемещение записывается как удаление одного файла и создание нового идентичного. Вы зафиксировали новый файл, а не удаление файла из исходного местоположения, таким образом, создавая впечатление, что Git просто скопировал файл.

В будущем, как правило, не рекомендуется указывать имя файла из commit команда:

git commit -m "Organize test scripts (Issue 303)"

Ты можешь сделать git status заранее посмотреть, что будет зафиксировано, и изменить по мере необходимости.

Полная сессия может выглядеть так:

$ git mv cryptest.sh TestScripts/
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        renamed:    cryptest.sh -> TestScripts/cryptest.sh

$ git commit -m "Organize test scripts (Issue 303)"
$ git status
On branch master
nothing to commit, working directory clean
$ ls cryptest.sh
ls: cannot access cryptest.sh: No such file or directory
$ ls TestScripts/cryptest.sh
TestScripts/cryptest.sh

Чтобы исправить, сделайте:

git rm cryptes*.sh
git commit

Если вы хотите исправить свою историю, вы можете сделать:

git rebase -i HEAD^3

и измените команду для соответствующих коммитов из pick в edit, На каждой остановке выполните:

git rm <file>
git commit --amend
git rebase --continue

куда <file> текущий оригинальный файл

Обратите внимание, что это перезапишет вашу историю, поэтому это может вызвать проблемы при перемещении между машинами.


Обратите внимание, что нет необходимости удалять и повторно клонировать репозиторий Git, поэтому, если у вас возникнут проблемы в будущем, лучше попытаться исправить проблему с корнем. ( Поиск вокруг или спросите здесь, если вам нужна помощь!)

Проблема в вашем (ab) использовании git commit команда.

git mv действительно перемещает файл как следует. Скажем, у меня есть репо с одним файлом, который называется aи я хочу переместить его как b:

$ git mv a b
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    a -> b

$ ls
b <-- Only b exists here, no a

Движение теперь занесено в индекс, но не зафиксировано. Чтобы создать коммит, я делаю:

$ git commit -m "Move a as b"

Однако то, что вы сделали, было:

$ git commit b -m "Move a as b"
[master b275677] Move a as b
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b

Когда вы даете имя файла в качестве аргумента git commit он включает только файлы, перечисленные в коммите, вместо записи текущего индекса.

Внутри git не понимает, что такое ход. Он понимает, что файл был создан, а другой файл был удален. Инструменты, которые используются для отображения истории (git log например) объединить эти две части информации и отобразить файл как перемещенный. Но когда вы указали, что в коммит должен быть включен только вновь созданный файл, он не записал удаление старого файла, поэтому он не отображается как движение при извлечении с другого компьютера.

Итак, ответ на ваш вопрос: "Почему" git mv "не перемещает файл? Как заставить его работать" нормально "?" - он перемещает файл, но вы специально указали git совершать только создание нового файла, а не удаление старого. Чтобы заставить его действовать нормально, не делайте этого - вместо этого, выпустите git commit без имен файлов в качестве аргументов.

Другие вопросы по тегам