据我所知,Git并不真正需要跟踪文件重命名/移动/复制操作,那么真正的目的是什么呢 git mv?手册页没有特别的描述性……
它过时了吗?它是一个内部命令,而不是供普通用户使用的吗?
据我所知,Git并不真正需要跟踪文件重命名/移动/复制操作,那么真正的目的是什么呢 git mv?手册页没有特别的描述性……
它过时了吗?它是一个内部命令,而不是供普通用户使用的吗?
当前回答
正如@Charles所说,git mv是一个简写。
这里真正的问题是“其他版本控制系统(例如。Subversion和Perforce)专门处理文件重命名。为什么Git不呢?”
Linus在http://permalink.gmane.org/gmane.comp.version-control.git/217上用他特有的机智解释道:
Please stop this "track files" crap. Git tracks exactly what matters, namely "collections of files". Nothing else is relevant, and even thinking that it is relevant only limits your world-view. Notice how the notion of CVS "annotate" always inevitably ends up limiting how people use it. I think it's a totally useless piece of crap, and I've described something that I think is a million times more useful, and it all fell out exactly because I'm not limiting my thinking to the wrong model of the world.
其他回答
也许git mv在这些答案发布后发生了变化,所以我会简单更新一下。在我看来,git mv不能准确地描述为:
# not accurate: #
mv oldname newname
git add newname
git rm oldname
我经常使用git mv有两个原因,在之前的回答中没有描述:
移动大型目录结构,其中我混合了跟踪和未跟踪文件的内容。被跟踪和未跟踪的文件都将移动,并保持其跟踪/未跟踪状态 移动较大的文件和目录,我一直认为git mv将减少存储库DB历史大小。这是因为移动/重命名文件是索引/引用增量。我还没有证实这个假设,但它似乎是合乎逻辑的。
在一个特殊的情况下,git mv仍然非常有用:当您想在不区分大小写的文件系统上更改文件名的大小写时。默认情况下,APFS (mac)和NTFS (windows)都是不区分大小写的(但保留大小写)。
格雷格。金德尔在对CB Bailey的回答的评论中提到了这一点。
假设你在mac上工作,git管理着一个文件Mytest.txt。您需要将文件名更改为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
git mv oldname newname
是:
mv oldname newname
git add newname
git rm oldname
也就是说,它会自动更新旧路径和新路径的索引。
来自官方的GitFaq:
Git有一个重命名命令Git mv,但这只是为了方便。的影响 是难以区分的删除文件和添加另一个不同的 名称和内容相同
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
...结果与上面相同:only——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变得混乱,无法正确跟踪更改。顺便说一下,在我的实验中,当我删除/创建文件而不是使用git mv时,也发生了同样的情况。小心地进行;我警告过你……