据我所知,Git并不真正需要跟踪文件重命名/移动/复制操作,那么真正的目的是什么呢 git mv?手册页没有特别的描述性……
它过时了吗?它是一个内部命令,而不是供普通用户使用的吗?
据我所知,Git并不真正需要跟踪文件重命名/移动/复制操作,那么真正的目的是什么呢 git mv?手册页没有特别的描述性……
它过时了吗?它是一个内部命令,而不是供普通用户使用的吗?
当前回答
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照常工作。
其他回答
正如@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移动文件,更新索引以记录被替换的文件路径,以及更新任何受影响的Git子模块。与手动移动不同的是,它还会检测到git不会作为更改检测到的纯大小写重命名。
它的行为类似于(尽管不完全相同)将文件从外部移动到git,使用git rm从索引中删除旧路径,并使用git add将新路径添加到索引中。
回答的动机
这个问题有很多不错的部分答案。这个答案试图将它们组合成一个单一的有凝聚力的答案。此外,任何其他答案都没有指出的一点是,手册页实际上基本上回答了这个问题,但它可能不那么明显。
详细解释
手册页中显示了三种不同的效果:
The file, directory, or symlink is moved in the filesystem: git-mv - Move or rename a file, a directory, or a symlink The index is updated, adding the new path and removing the previous one: The index is updated after successful completion, but the change must still be committed. Moved submodules are updated to work at the new location: Moving a submodule using a gitfile (which means they were cloned with a Git version 1.7.8 or newer) will update the gitfile and core.worktree setting to make the submodule work in the new location. It also will attempt to update the submodule.<name>.path setting in the gitmodules(5) file and stage that file (unless -n is used).
正如在回答中提到的,git mv非常类似于移动文件,将新路径添加到索引中,并从索引中删除之前的路径:
mv oldname newname
git add newname
git rm oldname
然而,正如这个答案所指出的,gitmv在行为上并不完全相同。通过git mv移动文件会将新的路径添加到索引中,但不会添加文件中任何修改的内容。另一方面,使用这三个单独的命令将整个文件添加到索引中,包括任何修改过的内容。当使用修补索引的工作流,而不是在文件中添加所有更改时,这可能是相关的。
此外,正如在这个回答和这个评论中提到的,git mv有一个额外的好处,就是在不区分大小写但保留大小写的文件系统上处理只区分大小写的重命名,就像当前macOS和Windows文件系统中经常出现的情况一样。例如,在这样的系统中,git在通过mv Mytest.txt Mytest.txt移动文件后不会检测到文件名已经更改,而使用git mv Mytest.txt Mytest.txt将成功更新其名称。
来自官方的GitFaq:
Git有一个重命名命令Git mv,但这只是为了方便。的影响 是难以区分的删除文件和添加另一个不同的 名称和内容相同
在一个特殊的情况下,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