Mục đích của git-mv là gì?


287

Theo những gì tôi hiểu, Git không thực sự cần theo dõi các hoạt động đổi tên / di chuyển / sao chép tệp , vậy mục đích thực sự của git mv là gì? Trang người đàn ông không đặc biệt mô tả ...

Có phải nó đã lỗi thời? Đây có phải là một lệnh nội bộ, không có nghĩa là được sử dụng bởi người dùng thông thường?

Câu trả lời:


390
git mv oldname newname

chỉ là viết tắt cho:

mv oldname newname
git add newname
git rm oldname

tức là nó tự động cập nhật chỉ mục cho cả đường dẫn cũ và mới.


38
Ngoài ra, nó có một vài két sắt được tích hợp sẵn.
Jakub Narębski

6
Cảm ơn @CharlesBailey - Có phải git sau đó coi các tệp newNameFile và oldNameFile là khác nhau không? Nếu có, điều gì xảy ra nếu chúng ta muốn hợp nhất chúng? Giả sử chúng tôi phân nhánh một dự án ant trên nhánh A và tạo nhánh B sau đó thực hiện các dự án trên B. Tên tệp giống nhau nhưng đặt trên các đường dẫn khác nhau khi cấu trúc dự án thay đổi. Nói cả hai nhánh phát triển song song. Tại một số điểm nếu chúng ta muốn hợp nhất các dự án, làm thế nào để git biết rằng đó là cùng một tệp chỉ đổi tên đường dẫn của nó? (nếu "git mv" == "git add + git rm")
Hoa hồng

2
@SergeyOrshanskiy Nếu tự động phát hiện sai mv oldname newname; git add newname; git rm oldname, nó cũng sẽ sai git mv oldname newname(xem câu trả lời này ).
Ajedi32

5
Lưu ý rằng git mvhơi khác so với mv oldname newname; git add newname; git rm oldname, nếu bạn thực hiện thay đổi tệp trước khi nhập git mv, những thay đổi đó sẽ không được thực hiện cho đến khi bạn git addgửi tệp mới.
Ajedi32

2
git mv đang làm một cái gì đó khác nhau, vì nó xử lý các thay đổi trong trường hợp tên tệp (foo.txt thành Foo.txt) trong khi các lệnh đó chạy riêng lẻ không (trên OSX)
greg.kindel

66

Từ GitFaq chính thức :

Git có lệnh đổi tên git mv, nhưng đó chỉ là sự tiện lợi. Hiệu ứng này không thể phân biệt được với việc xóa tệp và thêm tệp khác có tên khác và cùng nội dung


8
Vì vậy, bạn mất lịch sử tập tin? Tôi đã cho rằng việc đổi tên sẽ giữ lịch sử cũ cho thư mục đó ...
Will Hancock

17
Vâng, có và không. Đọc liên kết chính thức của GitFaq ở trên về việc đổi tên và sau đó đọc e-mail dài của Linus Torvalds về lý do tại sao anh ta không thích khái niệm về tệp theo dõi công cụ SCM: permalink.gmane.org/gmane.comp.version-control.git/ 217
Adam Nofsinger

3
@WillHancock Bây giờ tôi đã sử dụng git một chút và có thể trả lời bạn dứt khoát hơn: tùy thuộc vào ứng dụng khách git của bạn và các tùy chọn của nó, bạn sẽ có thể theo dõi tệp qua đổi tên nếu tệp thay đổi trong nội bộ đủ để nó coi nó là một đổi tên. Nếu bạn thay đổi tệp quá nhiều VÀ đổi tên nó, git sẽ không phát hiện ra - theo nghĩa là nó nói "không, bạn cũng có thể coi đó là một tệp hoàn toàn khác!"
Adam Nofsinger 6/03/2015

7
@AdamNofsinger liên kết đó đã chết. Đây là một tấm gương: web.archive.org/web/20150209075907/http:// giấy
Carl Walsh

2
Có một tài liệu tham khảo chính thức (nghĩa là đáng tin cậy hơn về lực đẩy mà Câu hỏi thường gặp) nêu rõ sự tương đương giữa git mvvà cách tiếp cận thủ công không? Nó không rõ ràng từ git help mv.
tvo

40

Git chỉ đang cố gắng đoán cho bạn những gì bạn đang cố gắng làm. Nó đang làm cho mọi nỗ lực để bảo tồn lịch sử không bị phá vỡ. Tất nhiên, nó không hoàn hảo. Vì vậy, git mvcho phép bạn rõ ràng với ý định của bạn và để tránh một số lỗi.

Hãy xem xét ví dụ này. Bắt đầu với một repo trống,

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

Kết quả:

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

Tự động sửa lỗi thất bại :( Hoặc đã làm điều đó?

$ 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

và sau đó

$ 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

Bây giờ hãy thử thay thế (nhớ xóa .gitthư mục khi thử nghiệm):

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

Càng xa càng tốt:

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


git mv b a
git status

Bây giờ, không ai là hoàn hảo:

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

Có thật không? Nhưng đương nhiên là...

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

... Và kết quả cũng giống như trên: chỉ --followhiển thị toàn bộ lịch sử.


Bây giờ, hãy cẩn thận với việc đổi tên, vì một trong hai tùy chọn vẫn có thể tạo ra các hiệu ứng kỳ lạ . Thí dụ:

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

Tương phản với:

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

Kết quả:

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

Up ... Bây giờ lịch sử đang quay trở lại ban đầu a thay vì b ban đầu , đó là sai. Vì vậy, khi chúng tôi thực hiện hai động tác cùng một lúc, Git trở nên bối rối và không theo dõi các thay đổi đúng cách. Nhân tiện, trong các thí nghiệm của tôi, điều tương tự cũng xảy ra khi tôi xóa / tạo tệp thay vì sử dụng git mv. Tiến hành cẩn thận; Mày đã được cảnh báo...


5
+1 để giải thích chi tiết. Tôi đã tìm kiếm các vấn đề có thể xảy ra trong lịch sử nhật ký nếu các tệp được di chuyển trong git, câu trả lời của bạn thực sự thú vị. Cảm ơn bạn! Btw, bạn có biết bất kỳ cạm bẫy nào khác mà chúng ta nên tránh trong khi di chuyển tệp trong git không? (hoặc bất kỳ tài liệu tham khảo nào bạn có thể chỉ đến .... không may mắn cho việc này)
pabrantes

1
Vâng, ví dụ của tôi là bi quan. Khi các tệp trống, việc giải thích chính xác các thay đổi sẽ khó khăn hơn nhiều. Tôi tưởng tượng rằng nếu bạn chỉ cam kết sau mỗi lần đổi tên, bạn sẽ ổn thôi.
osa

27

Như @Charles nói, git mvlà một tốc ký.

Câu hỏi thực sự ở đây là "Các hệ thống kiểm soát phiên bản khác (ví dụ: Subversion và Perforce) xử lý việc đổi tên tệp một cách đặc biệt. Tại sao không phải là Git?"

Linus giải thích tại http://permalink.gmane.org/gmane.comp.version-control.git/217 với chiến thuật đặc trưng:

Vui lòng dừng "tập tin theo dõi" tào lao này. Git theo dõi chính xác những gì quan trọng, cụ thể là "bộ sưu tập các tập tin". Không có gì khác có liên quan, và thậm chí nghĩ rằng nó có liên quan chỉ giới hạn thế giới quan của bạn. Lưu ý rằng khái niệm CVS "chú thích" luôn luôn chắc chắn kết thúc giới hạn cách mọi người sử dụng nó. Tôi nghĩ rằng đó là một thứ nhảm nhí hoàn toàn vô dụng, và tôi đã mô tả thứ gì đó mà tôi nghĩ là hữu ích hơn gấp triệu lần, và tất cả đều rơi ra chính xác bởi vì tôi không giới hạn suy nghĩ của mình về mô hình sai lầm của thế giới.


9

Có một cách sử dụng khác mà tôi đã git mvkhông đề cập ở trên.

Kể từ khi khám phá git add -p(chế độ vá của git add; xem http://git-scm.com/docs/git-add ), tôi muốn sử dụng nó để xem xét các thay đổi khi tôi thêm chúng vào chỉ mục. Do đó, quy trình làm việc của tôi trở thành (1) làm việc với mã, (2) xem xét và thêm vào chỉ mục, (3) cam kết.

Làm thế nào để git mvphù hợp với? Nếu di chuyển tệp trực tiếp sau đó bằng cách sử dụng git rmgit add, tất cả các thay đổi sẽ được thêm vào chỉ mục và sử dụng git diff để xem các thay đổi sẽ dễ dàng hơn (trước khi cam kết). git mvTuy nhiên, sử dụng thêm đường dẫn mới vào chỉ mục nhưng không thay đổi được thực hiện cho tệp, do đó cho phép git diffgit add -phoạt động như bình thường.


5

Có một trường hợp thích hợp git mvvẫn rất hữu ích: khi bạn muốn thay đổi vỏ của tên tệp trên hệ thống tệp không phân biệt chữ hoa chữ thường. Cả APFS (mac) và NTFS (windows), theo mặc định, không phân biệt chữ hoa chữ thường (nhưng bảo quản chữ hoa).

greg.kindel đề cập đến điều này trong một bình luận về câu trả lời của CB Bailey.

Giả sử bạn đang làm việc trên máy mac và có tệp Mytest.txtđược quản lý bởi git. Bạn muốn thay đổi tên tập tin thành MyTest.txt.

Bạn có thể thử:

$ 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

Trời ơi. Git không thừa nhận có bất kỳ thay đổi nào đối với tệp.

Bạn có thể giải quyết vấn đề này bằng cách đổi tên tập tin hoàn toàn sau đó đổi tên lại:

$ 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

Tiếng hoan hô!

Hoặc bạn có thể tự cứu mình tất cả những điều phiền phức bằng cách sử dụng 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.