Обработка переименований файлов в git

Я читал, что при переименовании файлов в 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
#

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

Ответ 1

Для 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, что приводит к тому, что вы ожидать

[email protected] /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, но вот подсказка от Линус

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

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

Ответ 2

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

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

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

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

См. Разница между "git add -A" и "git добавить" .

Ответ 3

Лучше всего попробовать это для себя.

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

~/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, является неправильным.

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

Ответ 4

вы должны 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 есть не что иное, как обертка script, которая делает именно это: удалите файл из индекса и добавьте его под другим именем

Ответ 5

Подумайте о своих файлах с точки зрения 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 deleteion", ни mobile.css не включены.

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

$ git rm iphone.css

git сообщает вам, что именно произошло: ( iphone.css удалено. Больше ничего не произошло)

затем добавьте новый файл 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.

Ответ 6

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

Что вы ошибетесь.

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

Ответ 7

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

git mv #oldfile #newfile

Шаг 2: git фиксация и добавление комментариев

git commit -m "rename oldfile to newfile"

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

git push origin #localbranch:#remotebranch

Ответ 8

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

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

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

Ответ 9

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

Ответ 10

В случаях, когда вам действительно нужно переименовывать файлы вручную, например. используя script для пакетного переименования пучка файлов, то с помощью git add -A . работал у меня.

Ответ 11

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

Обходной путь прост, но вы должны сделать это, прежде чем совершать использование Xcode:

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

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

  • сделать commit -m 'изменить имя'

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