Яке призначення git-mv?


287

З того, що я розумію, Git на насправді не потрібно відстежувати файл перейменувати / перемістити / копіювати операції, так що реальна мета мерзотник мв ? Сторінка людини не є спеціально описовою ...

Це застаріло? Це внутрішня команда, не призначена для використання звичайними користувачами?

Відповіді:


390
git mv oldname newname

це лише скорочення для:

mv oldname newname
git add newname
git rm oldname

тобто він оновлює індекс як для старих, так і для нових шляхів автоматично.


38
Також у нього вбудовано кілька
гарантій

6
Спасибі @CharlesBailey - Чи git тоді вважає файли newNameFile та oldNameFile різними? Якщо так, що станеться, якщо ми хочемо їх об'єднати? Скажімо, ми розгалужуємо проект мурашника на гілці A і створюємо відділення B, а потім створюємо проекти для B. Назви файлів однакові, але ставляться за різними шляхами, оскільки структура проекту змінювалася. Скажімо, обидві гілки певний час росли паралельно. В якийсь момент, якщо ми хочемо об'єднати проекти, як Git дізнається, що той самий файл просто перейменований у його шлях? (Якщо «мерзотник мв» == «мерзотника оних + мерзотник гт»)
Rose

2
@SergeyOrshanskiy Якщо автоматичне виявлення піде не так mv oldname newname; git add newname; git rm oldname, воно також піде не так git mv oldname newname(див. Цю відповідь ).
Ajedi32

5
Зауважте, що git mvце дещо відрізняється від того mv oldname newname; git add newname; git rm oldname, що якщо ви внесли зміни до файлу перед git mvтим, як змінити його, ці зміни не відбуватимуться, доки не буде створено git addновий файл.
Ajedi32

2
git mv робить щось інше, оскільки він обробляє зміни у регістрі імен файлів (foo.txt до Foo.txt), тоді як ці команди виконуються окремо не (на OSX)
greg.kindel

66

Від офіційного GitFaq :

У Git є команда перейменування git mv, але це лише зручність. Ефект не відрізняється від видалення файлу та додавання іншого з іншим ім'ям і тим самим вмістом


8
Отже, ви втрачаєте історію файлів? Я припускав, що перейменування збереже стару історію для цього каталогу ...
Буде Ханкок

17
Ну так і ні. Прочитайте вище офіційне посилання GitFaq про перейменування, а потім прочитайте довгий електронний лист Лінуса Торвальда про те, чому йому не подобається поняття файлів відстеження інструментів SCM: permalink.gmane.org/gmane.comp.version-control.git/ 217
Адам Нофсінгер

3
@WillHancock Я вже трохи більше використав git і можу відповісти вам більш чітко: залежно від вашого git-клієнта та його параметрів, ви зможете простежити файл за перейменуванням, якщо файл змінився всередині досить мало, щоб він вважав це перейменувати. Якщо ви змінили файл занадто сильно і перейменовували його, хоча git не виявить його - в певному сенсі він говорить "ні, ви також можете вважати, що зовсім інший файл!"
Адам Нофсінгер

7
@AdamNofsinger це посилання мертве. Ось дзеркало: web.archive.org/web/20150209075907/http://…
Карл Уолш

2
Чи є офіційна довідка (тобто більш гідна, ніж відповідь на поширені запитання), яка визначає еквівалентність git mvта ручний підхід? Це не очевидно з git help mv.
тво

40

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 ... Тепер історія повертається до початкового a замість початкового b , що неправильно. Тож, коли ми зробили два кроки одночасно, Гіт заплутався і не відстежив зміни належним чином. До речі, у моїх експериментах те саме сталося, коли я видаляв / створював файли замість використання git mv. Приступайте обережно; вас попередили ...


5
+1 для детального пояснення. Я шукав проблеми, які можуть трапитися в історії журналів, якщо файли переміщуються в git, ваша відповідь була дуже цікава. Дякую! Btw, чи знаєте ви інші підводні камені, яких нам слід уникати під час переміщення файлів у git? (або будь-яку посилання, на яку ви могли вказувати .... не дуже пощастило гуглінг для цього)
pabrantes

1
Ну, мої приклади песимістичні. Коли файли порожні, правильніше інтерпретувати зміни набагато складніше. Я гадаю, що якщо ви просто доручаєтесь після кожного набору перейменованих назв, ви повинні бути добре.
оса

27

Як говорить @Charles, git mvце стенограма.

Справжнє питання тут - "Інші системи управління версіями (наприклад, Subversion і Perforce) спеціально розглядають перейменування файлів. Чому Git не працює?"

Лінус пояснює на http://permalink.gmane.org/gmane.comp.version-control.git/217 з характерним тактом:

Будь ласка, зупиніть це лайно "відслідковувати файли". Git відстежує саме те , що має значення, а саме "колекції файлів". Ніщо інше не має значення, і навіть думка, що це актуально, лише обмежує ваш світогляд. Зауважте, як поняття CVS "анотація" завжди неминуче закінчується обмеженням того, як люди його використовують. Я думаю, що це абсолютно марний шматок, і я описав щось, що, на мою думку, є мільйоном разів кориснішим, і все випало саме тому , що я не обмежую своє мислення неправильною моделлю світу.


9

Є ще одне використання, яке я git mvне згадував вище.

Оскільки я виявив git add -p(режим патчу git add; див. 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працювати як завжди.


5

Існує нішевий випадок, коли 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.