Странное поведение `git mv`
В прошлом месяце я начал вносить вклад в репозиторий GitHub, разветвив соответствующий репозиторий, создав функциональную ветвь и затем отправив запрос на извлечение. Повторяя этот процесс в течение нескольких дней, я столкнулся со странной проблемой при переименовании файлов с помощью предустановленной команды Linux mv
а также с командой Git git mv
,
Проблема в том, что в зависимости от того, когда вы перемещаете / переименовываете файл с git mv
, когда ты git add
это и в какой момент вы редактируете переименованный файл, вы либо получаете:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: somethingelse -> something
Или это:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: something
deleted: somethingelse
Чтобы продемонстрировать это, я написал тест:
#!/bin/bash
# To my knowledge, this “problem” only occurs with new files in a Git repo
printf "COMMAND: mkdir -v gitrepo\n\n"
mkdir -v gitrepo
printf "\nCOMMAND: cd gitrepo\n\n"
cd gitrepo
printf "\nCOMMAND: git init\n\n"
git init
printf "\nCOMMAND: git status\n\n"
git status
printf "\nCOMMAND: touch something\n\n"
touch something
printf "\nCOMMAND: git status\n\n"
git status
printf "\nCOMMAND: git add something\n\n"
git add something
printf "\nCOMMAND: git status\n\n"
git status
printf '\nCOMMAND: git commit -m "Added something"\n\n'
git commit -m "Added something"
printf "\nCOMMAND: git status\n\n"
git status
printf "\nCOMMAND: git mv something somethingelse\n\n"
git mv something somethingelse
printf "\nCOMMAND: git status\n\n"
git status
# Type in the following on line 1: First line of code
printf "\nCOMMAND: vim somethingelse\n\n"
vim somethingelse
printf "\nCOMMAND: git status\n\n"
git status
printf "\nCOMMAND: git add somethingelse\n\n"
git add somethingelse
printf "\nCOMMAND: git status\n\n"
git status
printf '\nCOMMAND: git commit -m "Renamed something to somethingelse and edited somethingelse"\n\n'
git commit -m "Renamed something to somethingelse and edited somethingelse"
printf "\nCOMMAND: git status\n\n"
git status
printf "\nCOMMAND: git mv somethingelse something\n\n"
git mv somethingelse something
printf "\nCOMMAND: git status\n\n"
git status
# If you add something to the first line, the rename will not be detected by Git
# However, if you instead create 2 newlines and fill line 3 with new code,
# the rename gets detected for whatever reason
printf "\nCOMMAND: vim something\n\n"
vim something
printf "\nCOMMAND: git status\n\n"
git status
printf "\nCOMMAND: git add something\n\n"
git add something
printf "\nCOMMAND: git status\n\n"
git status
printf '\nCOMMAND: git commit -m "Renamed somethingelse to something and edited something"\n\n'
git commit -m "Renamed somethingelse to something and edited something"
printf "\nCOMMAND: git status\n\n"
git status
cd .. && rm -fr gitrepo && printf "\nREMOVED gitrepo folder\n"
printf "\nDONE.\n"
По некоторым причинам, это в основном влияет на "новые файлы", а не те, которые уже существуют в репозитории. Если вы клонируете мою ветвь хранилища Spoon-Knife с git clone https://github.com/christianheinrichs/Spoon-Knife.git
Например, а затем примените рабочий процесс связанного тестового сценария, вы увидите, что в большинстве случаев вы сможете переименовать файл README.md, например, в README, отредактировать его, и он все равно будет считаться переименованным вместо новый файл / удаленный сплит.
Хотя я мог воспроизвести новый файл / удаленное поведение на клонированном репо-ветке Spoon-Knife, я не совсем уверен, как я это сделал, и поверьте мне, когда скажу, что пытался это выяснить.
Так что именно здесь происходит, что я не понимаю?
См.: https://gist.github.com/christianheinrichs/e50bfdd5eec70a606fa6ce4a88c5951b
1 ответ
git
не держит флаг, говорящий "это newname
файл изначально назывался oldname
файл":
git mv oldname newname
# is exactly equivalent to :
mv oldname newname
git rm oldname
git add newname
При отображении статуса файла, git
пытается угадать, если это было rename
или delete + add
сравнивая содержимое файлов и видя, насколько они похожи.
Итак, если вы начнете с git mv
файл, а затем отредактируйте файл, в зависимости от степени изменения файла, git может или не может увидеть, что все началось с mv
,
Смотрите также ответ на этот вопрос: как Git узнает, что файл был переименован?