Apa tujuan dari git-mv?

287

Dari apa yang saya mengerti, Git tidak benar-benar perlu melacak operasi rename / move / copy file , jadi apa tujuan sebenarnya dari git mv ? Halaman manual tidak secara khusus deskriptif ...

Apakah sudah usang? Apakah ini perintah internal, tidak dimaksudkan untuk digunakan oleh pengguna biasa?

Mauricio Scheffer
sumber

Jawaban:

390
git mv oldname newname

hanya singkatan untuk:

mv oldname newname
git add newname
git rm oldname

yaitu memperbarui indeks untuk jalur lama dan baru secara otomatis.

CB Bailey
sumber
38
Juga memiliki beberapa pengaman di
dalamnya
6
Terima kasih @CharlesBailey - Apakah git menganggap file newNameFile dan oldNameFile berbeda? Jika ya, apa yang terjadi jika kita ingin menggabungkannya? Katakanlah kita bercabang proyek semut di cabang A dan membuat Cabang B kemudian memotong proyek di B. Nama file adalah sama tetapi memakai jalur yang berbeda saat struktur proyek berubah. Katakanlah kedua cabang tumbuh untuk beberapa waktu secara paralel. Pada titik tertentu, jika kita ingin menggabungkan proyek, bagaimana git tahu bahwa itu file yang sama dengan hanya mengganti namanya path? (jika "git mv" == "git add + git rm")
Rose
2
@SergeyOrshanskiy Jika deteksi otomatis salah mv oldname newname; git add newname; git rm oldname, itu juga salah untuk git mv oldname newname(lihat jawaban ini ).
Ajedi32
5
Catatan yang git mvsedikit berbeda dari mv oldname newname; git add newname; git rm oldname, dalam hal itu jika Anda membuat perubahan pada file sebelum git mvitu, perubahan itu tidak akan dipentaskan sampai Anda git addfile baru.
Ajedi32
2
git mv sedang melakukan sesuatu yang berbeda, karena menangani perubahan dalam nama file (foo.txt ke Foo.txt) sementara perintah-perintah itu dijalankan secara individual tidak (pada OSX)
greg.kindel
66

Dari GitFaq resmi :

Git memiliki perintah ganti nama git mv, tapi itu hanya kenyamanan. Efeknya tidak bisa dibedakan dari menghapus file dan menambahkan yang lain dengan nama yang berbeda dan konten yang sama

Adam Nofsinger
sumber
8
Jadi, apakah Anda kehilangan riwayat file? Saya kira mengubah nama akan menyimpan sejarah lama untuk direktori itu ...
Will Hancock
17
Ya dan tidak. Baca tautan resmi GitFaq di atas tentang penggantian nama, dan kemudian baca email panjang Linus Torvalds tentang mengapa ia tidak menyukai gagasan tentang file pelacakan alat SCM: permalink.gmane.org/gmane.comp.version-control.git/ 217
Adam Nofsinger
3
@ WillHancock Saya telah menggunakan git sedikit lebih banyak sekarang, dan dapat menjawab Anda dengan lebih pasti: tergantung pada klien git Anda dan opsinya, Anda akan dapat melacak file melewati nama ganti jika file tersebut diubah secara internal cukup kecil sehingga dianggap sebagai ganti nama. Jika Anda mengubah file terlalu banyak DAN mengganti nama file itu, git tidak akan mendeteksinya - dalam arti itu mengatakan "tidak, Anda mungkin juga menganggap file yang sama sekali berbeda!"
Adam Nofsinger
7
@AdamNofsinger tautan itu sudah mati. Ini cerminnya: web.archive.org/web/20150209075907/http://…
Carl Walsh
2
Apakah ada referensi resmi (yaitu lebih layak dorong bahwa FAQ) yang menyatakan kesetaraan antara git mvdan pendekatan manual? Tidak jelas dari git help mv.
tvo
40

Git hanya mencoba menebak untuk Anda apa yang Anda coba lakukan. Itu membuat setiap upaya untuk melestarikan sejarah yang tak terputus. Tentu saja itu tidak sempurna. Begitugit mv memungkinkan Anda untuk eksplisit dengan niat Anda dan menghindari beberapa kesalahan.

Pertimbangkan contoh ini. Dimulai dengan repo kosong,

git init
echo "First" >a
echo "Second" >b
git add *
git commit -m "initial commit"
mv a c
mv b a
git status

Hasil:

# 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")

Deteksi otomatis gagal :( Atau berhasil?

$ 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

lalu

$ 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

Sekarang coba sebagai gantinya (jangan lupa untuk menghapus .gitfolder saat bereksperimen):

git init
echo "First" >a
echo "Second" >b
git add *
git commit -m "initial commit"
git mv a c
git status

Sejauh ini baik:

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


git mv b a
git status

Sekarang, tidak ada yang sempurna:

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a
#   deleted:    b
#   new file:   c
#

Betulkah? Tapi tentu saja...

git add *
git commit -m "change"
git log c
git log --follow c

... dan hasilnya sama seperti di atas: hanya --followmenampilkan riwayat lengkap.


Sekarang, berhati-hatilah dengan penggantian nama, karena opsi mana pun masih dapat menghasilkan efek aneh . Contoh:

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

Bandingkan dengan:

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

Hasil:

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 ... Sekarang histori akan kembali ke inisial alih - alih inisial b , yang salah. Jadi ketika kami melakukan dua gerakan sekaligus, Git menjadi bingung dan tidak melacak perubahan dengan benar. Ngomong-ngomong, dalam percobaan saya hal yang sama terjadi ketika saya menghapus / membuat file alih-alih menggunakan git mv. Lanjutkan dengan hati-hati; Anda sudah diperingatkan ...

osa
sumber
5
+1 untuk penjelasan terperinci. Saya telah mencari masalah yang mungkin terjadi dalam riwayat log jika file dipindahkan di git, jawaban Anda sangat menarik. Terima kasih! Btw, apakah Anda tahu ada jebakan lain yang harus kita hindari saat memindahkan file di git? (atau referensi apa pun yang bisa Anda tunjukkan ke .... googling tidak terlalu beruntung untuk itu)
pabrantes
1
Contoh saya pesimistis. Ketika file kosong, jauh lebih sulit untuk menafsirkan perubahan dengan benar. Saya membayangkan bahwa jika Anda hanya melakukan setelah setiap set nama, Anda harus baik-baik saja.
osa
27

Seperti yang dikatakan @Charles, git mv adalah singkatan.

Pertanyaan sebenarnya di sini adalah "Sistem kontrol versi lain (mis. Subversion dan Perforce) memperlakukan nama file secara khusus. Mengapa tidak Git?"

Linus menjelaskan di http://permalink.gmane.org/gmane.comp.version-control.git/217 dengan kebijaksanaan khas:

Tolong hentikan omong kosong "lacak file" ini. Git melacak dengan tepat apa yang penting, yaitu "koleksi file". Tidak ada hal lain yang relevan, dan bahkan berpikir itu relevan hanya membatasi pandangan dunia Anda. Perhatikan bagaimana gagasan CVS "memberi keterangan" selalu tak terhindarkan akhirnya membatasi cara orang menggunakannya. Saya pikir itu adalah omong kosong yang sama sekali tidak berguna, dan saya telah menggambarkan sesuatu yang saya pikir sejuta kali lebih bermanfaat, dan semuanya jatuh tepat karena saya tidak membatasi pemikiran saya pada model dunia yang salah.

Kolonel Panic
sumber
9

Ada kegunaan lain yang saya miliki git mv tidak disebutkan di atas.

Sejak ditemukan git add -p(mode tambalan git add; lihat http://git-scm.com/docs/git-add ), saya suka menggunakannya untuk meninjau perubahan saat saya menambahkannya ke indeks. Dengan demikian alur kerja saya menjadi (1) bekerja pada kode, (2) meninjau dan menambah indeks, (3) komit.

Bagaimana cara git mvcocok? Jika memindahkan file secara langsung kemudian menggunakan git rmdan git add, semua perubahan ditambahkan ke indeks, dan menggunakan git diff untuk melihat perubahan tidak mudah (sebelum melakukan). Menggunakan git mv, bagaimanapun, menambahkan jalan baru ke indeks tapi tidak berubah dibuat untuk file, sehingga memungkinkan git diffdan git add -pbekerja seperti biasa.

dhardy
sumber
5

Ada kasus khusus di mana git mv tetap sangat berguna: ketika Anda ingin mengubah casing nama file pada sistem file case-insensitive. Baik APFS (mac) dan NTFS (windows), secara default, case-insensitive (tetapi case-preserving).

greg.kindel menyebutkan ini dalam komentar atas jawaban CB Bailey.

Misalkan Anda bekerja pada mac dan memiliki file yang Mytest.txtdikelola oleh git. Anda ingin mengubah nama file menjadi MyTest.txt.

Kamu bisa mencoba:

$ 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

Oh sayang. Git tidak mengakui bahwa ada perubahan pada file tersebut.

Anda dapat mengatasinya dengan mengubah nama file sepenuhnya kemudian mengubah nama kembali:

$ 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

Hore!

Atau Anda bisa menyelamatkan diri dari semua gangguan dengan menggunakan 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
duncan
sumber