Обработка переименований файлов в git - PullRequest
408 голосов
/ 15 апреля 2010

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

Однако, делая это сегодня вечером, я вернулась к git mv.

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#

Переименуйте мою таблицу стилей в Finder с iphone.css на mobile.css

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   deleted:    css/iphone.css
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   css/mobile.css

Итак, git теперь думает, что я удалил один файл CSS и добавил новый. Не то, что я хочу, давайте отменим переименование и пусть git сделает всю работу.

> $ git reset HEAD .
Unstaged changes after reset:
M   css/iphone.css
M   index.html

Вернуться туда, где я начал.

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#

Позволяет использовать git mv вместо.

> $ git mv css/iphone.css css/mobile.css
> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   renamed:    css/iphone.css -> css/mobile.css
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   index.html
#

Похоже, у нас все хорошо. Так почему же git не узнал переименование в первый раз, когда я использовал Finder?

Ответы [ 11 ]

327 голосов
/ 15 апреля 2010

Для git mv страница справочника говорит

Индекс обновляется после успешного завершения, [....]

Итак, сначала вы должны обновить индекс самостоятельно (используя git add mobile.css). Тем не менее
git status все равно покажет два разных файла

$ git status
# On branch master
warning: LF will be replaced by CRLF in index.html
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#       new file:   mobile.css
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted:    iphone.css
#

Вы можете получить другой вывод, запустив git commit --dry-run -a что приводит к тому, что вы ожидать

Tanascius@H181 /d/temp/blo (master)
$ git commit --dry-run -a
# On branch master
warning: LF will be replaced by CRLF in index.html
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#       renamed:    iphone.css -> mobile.css
#

Я не могу точно сказать, почему мы видим эти различия от git status до
git commit --dry-run -a, но вот подсказка от Linus

мерзавец действительно даже не не заботится обо всем "переименовать обнаружение" внутри, и любые ваши коммиты сделано с переименованиями полностью независимы от Затем мы используем эвристику, чтобы показать переименования.

A dry-run использует реальные механизмы переименования, а git status вероятно, нет.

72 голосов
/ 21 октября 2011

Вы должны добавить два измененных файла в индекс, прежде чем git распознает его как ход.

Единственная разница между mv old new и git mv old new в том, что git mv также добавляет файлы в индекс.

mv old new тогда git add -A тоже сработало бы.

Обратите внимание, что вы не можете просто использовать git add ., потому что это не добавляет удаления в индекс.

См. Разница между "git add -A" и "git add."

18 голосов
/ 01 апреля 2014

Лучше всего попробовать самим.

mkdir test
cd test
git init
touch aaa.txt
git add .
git commit -a -m "New file"
mv aaa.txt bbb.txt
git add .
git status
git commit --dry-run -a

Теперь git status и git commit --dry-run -a показывает два разных результата, где git status показывает bbb.txt как новый файл / aaa.txt удаляется, а команды --dry-run показывают фактическое переименование .

~/test$ git status

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   bbb.txt
#
# 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)
#
#   deleted:    aaa.txt
#


/test$ git commit --dry-run -a

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

Теперь идите и зарегистрируйтесь.

git commit -a -m "Rename"

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

Мораль истории: если вы не уверены, был ли ваш файл переименован, введите «git commit --dry-run -a». Если он показывает, что файл переименован, все готово.

10 голосов
/ 09 июля 2015

Для git 1.7.x у меня работали следующие команды:

git mv css/iphone.css css/mobile.css
git commit -m 'Rename folder.' 

Не было необходимости в git add, так как исходный файл (т.е. css / mobile.css) уже был в подтвержденных файлах ранее.

10 голосов
/ 15 апреля 2010

вам нужно git add css/mobile.css новый файл и git rm css/iphone.css, так что git знает об этом. тогда он покажет тот же результат в git status

вы можете ясно увидеть это в выводе статуса (новое имя файла):

# Untracked files:
#   (use "git add <file>..." to include in what will be committed)

и (старое имя):

# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)

я думаю, что негласно git mv - это не что иное, как скрипт-обертка, который делает именно это: удаляет файл из индекса и добавляет его под другим именем

9 голосов
/ 11 февраля 2015

Давайте подумаем о ваших файлах с точки зрения git.

Имейте в виду, git не отслеживает какие-либо метаданные о ваших файлах

В вашем хранилище есть (среди прочего)

$ cd repo
$ ls
...
iphone.css
...

и он находится под контролем git:

$ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked
file is tracked

Проверьте это с помощью:

$ touch newfile
$ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked
(no output, it is not tracked)
$ rm newfile

Когда вы выполните

$ mv iphone.css mobile.css

С точки зрения git,

  • нет iphone.css (удаляется - git предупреждает об этом -).
  • есть новый файл mobile.css .
  • Эти файлы совершенно не связаны.

Итак, git сообщает о файлах, которые ему уже известны ( iphone.css ) иновые файлы, которые он обнаруживает ( mobile.css ), но только когда файлы в индексе или HEAD git начинает проверять их содержимое.

На данный момент, ни "iphone.css delete", ни mobile.css находятся в индексе.

Добавить удаление iphone.css в индекс

$ git rm iphone.css

git точно скажет, что произошло: (* iphone.css удалено. Nбольше ничего не произошло)

затем добавьте новый файл mobile.css

$ git add mobile.css

На этот раз и удаление, и новый файл находятся в индексе.Теперь git обнаруживает тот же контекст и выставляет его как переименованный.Фактически, если файлы похожи на 50%, он обнаружит это как переименование, которое позволит вам немного изменить mobile.css , сохранив операцию как переименование.

Смотрите, это воспроизводимо приgit diff.Теперь, когда ваши файлы в индексе, вы должны использовать --cached.Немного отредактируйте mobile.css , добавьте это к индексу и увидите разницу между:

$ git diff --cached 

и

$ git diff --cached -M

-M - это "обнаружить переименования""опция для git diff.-M означает -M50% (при сходстве 50% и более git выражает его как переименование), но вы можете уменьшить его до -M20% (20%), если много редактируете mobile.css.

7 голосов
/ 27 мая 2014

Шаг 1: переименовать файл из старого файла в новый файл

git mv #oldfile #newfile

Step2: сделать коммит и добавить комментарии

git commit -m "rename oldfile to newfile"

Шаг 3: отправить это изменение на удаленный сервер

git push origin #localbranch:#remotebranch
7 голосов
/ 15 апреля 2010

Git распознает файл по содержимому, а не видит его как новый неотслеживаемый файл

Вот где ты ошибся.

Это только после , когда вы добавите файл, git распознает его по содержимому.

3 голосов
/ 15 апреля 2010

Вы не ставили результаты своего поиска. Я полагаю, что если вы переместились через Finder, а затем сделали git add css/mobile.css ; git rm css/iphone.css, git вычислил бы хэш нового файла и только потом понял, что хэши файлов совпадают (и, следовательно, это переименование).

2 голосов
/ 17 августа 2012

Для пользователей Xcode: Если вы переименуете свой файл в Xcode, вы увидите, что значок значка изменится на добавление. Если вы делаете коммит с использованием XCode, вы фактически создаете новый файл и теряете историю.

Обойти это легко, но вы должны сделать это перед тем, как совершить операцию, используя Xcode:

  1. Сделайте git Status для вашей папки. Вы должны увидеть, что внесенные изменения верны:

переименован: Project / OldName.h -> Project / NewName.h переименован: Project / OldName.m -> Project / NewName.m

  1. do commit -m 'name change'

Затем вернитесь в XCode, и вы увидите, что значок изменился с A на M, и теперь он сохранен для внесения дальнейших изменений в xcode.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...