git-mv 的目的是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1094269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 06:42:09  来源:igfitidea点击:

What's the purpose of git-mv?

git

提问by Mauricio Scheffer

From what I understand, Git doesn't really need to track filerename/move/copy operations, so what's the real purpose of git mv? The man page isn't specially descriptive...

据我了解,Git 并不真正需要跟踪文件重命名/移动/复制操作,那么git mv的真正目的是什么?手册页没有特别的描述性......

Is it obsolete? Is it an internal command, not meant to be used by regular users?

它过时了吗?它是一个内部命令,不打算由普通用户使用吗?

回答by CB Bailey

git mv oldname newname

is just shorthand for:

只是简写:

mv oldname newname
git add newname
git rm oldname

i.e. it updates the index for both old and new paths automatically.

即它自动更新旧路径和新路径的索引。

回答by Adam Nofsinger

From the official GitFaq:

来自官方 GitFaq

Git has a rename command git mv, but that is just a convenience. The effect is indistinguishable from removing the file and adding another with different name and the same content

Git 有一个重命名命令git mv,但这只是为了方便。效果与删除文件并添加另一个名称不同但内容相同的文件没有区别

回答by osa

Git is just trying to guess for you what you are trying to do. It is making every attempt to preserve unbroken history. Of course, it is not perfect. So git mvallows you to be explicit with your intention and to avoid some errors.

Git 只是想为您猜测您要做什么。它正在尽一切努力保存完整的历史。当然,它并不完美。因此git mv,您可以明确表达自己的意图并避免一些错误。

Consider this example. Starting with an empty repo,

考虑这个例子。从一个空的回购开始,

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

Result:

结果:

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

Autodetection failed:( Or did it?

自动检测失败:( 或者是吗?

$ 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

and then

进而

$ 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

Now try instead (remember to delete the .gitfolder when experimenting):

现在尝试(记住.git在实验时删除文件夹):

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

So far so good:

到现在为止还挺好:

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


git mv b a
git status

Now, nobody is perfect:

现在,没有人是完美的:

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

Really? But of course...

真的吗?但是当然...

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

...and the result is the same as above: only --followshows the full history.

...结果和上面一样:只--follow显示完整的历史记录。



Now, be careful with renaming, as either option can still produce weird effects. Example:

现在,重命名时要小心,因为任一个选项仍然会产生奇怪的效果。例子:

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

Contrast it with:

对比一下:

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

Result:

结果:

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... Now the history is going back to initial ainstead of initial b, which is wrong. So when we did two moves at a time, Git became confused and did not track the changes properly. By the way, in my experiments the same happened when I deleted/created files instead of using git mv. Proceed with care; you've been warned...

Ups... 现在历史回到初始 a而不是初始 b,这是错误的。所以当我们一次做两个动作时,Git 变得混乱并且没有正确跟踪变化。顺便说一下,在我的实验中,当我删除/创建文件而不是使用git mv. 谨慎行事;你被警告了...

回答by Colonel Panic

As @Charles says, git mvis a shorthand.

正如@Charles 所说,git mv是速记。

The real question here is "Other version control systems (eg. Subversion and Perforce) treat file renames specially. Why doesn't Git?"

这里真正的问题是“其他版本控制系统(例如 Subversion 和 Perforce)特别对待文件重命名。为什么 Git 不这样?”

Linus explains at http://permalink.gmane.org/gmane.comp.version-control.git/217with characteristic tact:

Linus 在http://permalink.gmane.org/gmane.comp.version-control.git/217 上以特有的机智解释道:

Please stop this "track files" crap. Git tracks exactlywhat matters, namely "collections of files". Nothing else is relevant, and even thinkingthat 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 exactlybecause I'm not limiting my thinking to the wrong model of the world.

请停止这种“跟踪文件”废话。Git准确跟踪重要的内容,即“文件集合”。闲来无事是相关的,甚至是 思维,这是相关的限制了你的世界观。请注意 CVS“注释”的概念如何总是不可避免地限制人们使用它的方式。我认为这是一个完全无用的一块垃圾,我已经描述的东西,我觉得是一百万次更加有用,而这一切都掉了出来 正是因为我不限制我的思维世界的错误的模型。

回答by dhardy

There's another use I have for git mvnot mentioned above.

还有一个我git mv上面没有提到的用途。

Since discovering git add -p(git add's patch mode; see http://git-scm.com/docs/git-add), I like to use it to review changes as I add them to the index. Thus my workflow becomes (1) work on code, (2) review and add to index, (3) commit.

自从发现git add -p(git add 的补丁模式;请参阅http://git-scm.com/docs/git-add)后,我喜欢在将更改添加到索引时使用它来查看更改。因此,我的工作流程变成了 (1) 处理代码,(2) 并添加到索引,(3) 提交。

How does git mvfit in? If moving a file directly then using git rmand git add, all changes get added to the index, and using git diff to view changes is less easy (before committing). Using git mv, however, adds the new path to the index but not changes made to the file, thus allowing git diffand git add -pto work as usual.

怎么git mv融入?如果直接移动文件然后使用git rmand git add,所有更改都会添加到索引中,并且使用 git diff 查看更改不太容易(在提交之前)。git mv但是,使用会将新路径添加到索引,但不会对文件进行更改,从而允许git diffgit add -p照常工作。

回答by duncan

There's a niche case where git mvremains very useful: when you want to change the casing of a file name on a case-insensitive file system. Both APFS (mac) and NTFS (windows) are, by default, case-insensitive (but case-preserving).

有一种特殊情况git mv仍然非常有用:当您想在不区分大小写的文件系统上更改文件名的大小写时。默认情况下,APFS (mac) 和 NTFS (windows) 都不区分大小写(但保留大小写)。

greg.kindel mentions this in a comment on CB Bailey's answer.

greg.kindel 在对 CB Bailey 的回答的评论中提到了这一点。

Suppose you are working on a mac and have a file Mytest.txtmanaged by git. You want to change the file name to MyTest.txt.

假设您在 Mac 上工作并且有一个Mytest.txt由 git 管理的文件。您想将文件名更改为MyTest.txt.

You could try:

你可以试试:

$ 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 dear. Git doesn't acknowledge there's been any change to the file.

哦亲爱的。Git 不承认文件有任何更改。

You couldwork around this with by renaming the file completely then renaming it back:

可以通过完全重命名文件然后将其重命名来解决此问题:

$ 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

Hurray!

欢呼!

Or you could save yourself all that bother by using git mv:

或者,您可以使用以下方法省去所有麻烦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