十甫寸木南
Articles10
Tags6
Categories0
Git 记录:mv

Git 记录:mv

Created By: 十甫寸木南
Last Edited: Jan 18, 2020 2:22 PM

Git mv 的定义
Git mv 的用法
Description & options
总结

其实关于 git mv 这条命令,还是在看官方文档的时候无意中看到的,当时第一反应是:mv 不是 Shell 命令吗?怎么 Git 中也有 mv 命令,而且还不止,还有 rmls-filesls-tree 这样的极具 Shell 特色的命令!

于是呢,我决定探究一番!

Git mv 的定义

学习一个新的事物,必然第一件事是先看这个东西是什么,即它的定义。

官网给的解释是这样的:“Move or rename a file, a directory, or a symlink.”
其实意思很简单,“移动或重命名一个文件或目录,或符号链接。

看到这里,我稍微有点疑惑,这个符号链接(symlink)是个什么东西呢?待我之后再去探究一番!😂

这里,应该是不影响理解 git mv 这个命令的,于是,我接着看了下去。

Git mv 的用法

看完官网对 git mv 这个命令的解释后,我没有立即看下去,而是打开了 iterm ,想要先看一下这个命令的用法。

01

于是呢,我又有疑惑出现了:git mv [<options>] <source>... <destination>source 后面的 ... 是什么意思呢?

可以一次对多个文件操作?

既然这条命令的作用是移动或重命名文件,难道说重命名文件可以一次重命名多个文件?那怎么区分哪个是重命名前的文件,哪个是重命名后的文件呢?git mv a b c d ?This is 开玩笑呢吧?

可是, Usage 中显示的 source 和 destination 明显是源和目的地的意思啊!

等等!👀

我似乎知道了!

虽然说重命名文件的话,如果一次写了多个源文件,比如 git mv a b c d 这样,根本没办法区分开源文件名和目标文件名,但是,如果是移动的话,就没问题了!比如:git mv a b c d dir/ ,这样的话完全可以只用最后一个参数来做识别;如果最后一个参数代表的是个目录,而前面又有多个参数,那么就说明这条命令此时的用法应该是移动

也就是说,git mv 这条命令其实有两种用法:

  • move ,即移动文件或目录
  • rename ,即重命名文件或目录

想到这儿,我一下子感觉豁然开朗!

既然如此的话,试一下呗!

先做好预备工作,现在暂存区里有 4 个文件,分别是:abcd

02

首先先验证一下,是不是我之前猜想的无法一次性重命名多个文件这个猜想是正确的呢?

03

错误提示:destination 'dd' is not a directory

很明显,我的猜想是对的,而且也从侧面验证了,我的猜想十有八九是对的,即: **git mv 这条命令是以最后一个参数作为一个标识符来判断当前这条命令执行的应该是 move 还是 rename 的。**

不过,写到这里,我再次产生了一个疑惑,因为我看到错误提示说的是 destination 'dd' is not a directory ,不是一个目录?为什么提示说不是一个目录?它怎么知道应该提示不是一个目录,而不是提示参数过多呢?

难道说,这条命名底层的实现机制其实是先检查参数个数,如果参数个数为 2 ,说明是重命名文件;如果参数个数 > 2 ,说明是移动文件!

可是也不对啊,即便参数个数是 2 ,也可以是移动一个文件到某一个目录下啊!

04

我明白了!

真相只有一个,**git mv 会先去检查参数个数**:

  • 参数个数 > 2 ,则说明是移动多个文件或目录到某一个指定的目录下

  • 参数个数 =2 ,则说明操作的是单个文件或目录

    操作单个文件或目录的情况下,

    • 如果是 文件 → 文件,那必然是重命名
    • 如果是文件 → 目录,那就是移动
    • 如果是 目录 → 目录,应该和 Shell 命令 mv是一致的,要看后一个目录后有没有跟 /

当然了,这些其实应该都算是 Shell mv 命令的机制吧?毕竟 Shell 下 mv 命令也是有两重作用的!

不过呢,之前看 mv 命令的时候也没有想到过这么多,就当是自己学习了!而且,我觉得这样一番探究下来,对我自己的收获也很大!

不过呢,这都是我自己的猜测,虽然我觉得应该八九不离十,但是,毕竟我没有去看这个命令的源码!待我有时间了去看一下源码,探究一下究竟是不是我猜测的这样!

到这里呢,其实我觉得对这个命令的基础部分已经猜测完毕了,但是呢,毕竟是个 Git 命令,肯定会和 Git 相关,会和工作区或者暂存区,甚至存储库有关系,要不然直接用 mv 了,为啥要多此一举前面加个 git 呢?

而且其实在前面的尝试中,我已经看到了一个现象,那就是:使用 git mv 命令后,所有的改动都会直接被 add 到暂存区中,即:⬇️

05

似乎很方便的亚子啊!😄节省了好多步骤,如果用 Shell 命令的话,似乎得 2 步才可以:

mv a aa        # 重命名文件a为aa
git add a aa   # 将 delete a 的操作和 new file 加入到暂存区

确实方便了很多啊,那么,既然这么有趣又方便,那就继续看呗!

不过,自己能猜到的已经都猜完了,接下来就继续看文档吧!😄

Description & options

再次回到官方文档,映入眼帘的是一段描述:

06

我擦,这不是和我的猜测一模一样吗?😁😁😁看到这里,还是很开心的。虽然是一个很简单的命令,但是以我目前这个菜鸟级别的水平来说,我觉得还是很欣慰的😂

OK,那既然描述和我的猜测一样,那就不去深究了,大概看一下就可以了,继续往下看参数部分吧!

参数部分呢,其实从之前用法的部分和上面官网上给的描述中都可以看出,git mv 这条命令有 4 个可用的参数选项,分别是:

  • -f | —-force
  • -k
  • -n | —-dry-run
  • -v | —-verbose

就一个一个来看吧:

-f | —-force

其实看到 force 这个单词就应该明白了,强制的意思,既然是强制,为什么要强制呢?

必然有原因造成无法直接成功执行 git mv ,那又是个什么情况呢?文件或目录已存在!造成命名冲突!

除了这个原因,我想不出什么其他的!

话不多说,来试一下就知道了:

07

果然,当要重命名的目标名已被占用,即文件 b 已存在的情况下,是无法执行成功的!来看一下当前的文件目录及 git 状态:

08

文件毫无变化!

OK,那来试一下 -f 吧,如果真的是强制更改的话,我觉得应该会直接覆盖掉 b 文件,为了验证这一点,我先给两个文件里都写点内容吧:

09

好,可以区分开这两个文件了,那就尝试一下:

10

果然直接覆盖掉了,没有问题!好,来看一下官方的解释吧:

11

强制重命名或移动一个文件,即使目标存在!

我觉得我猜得还是很准的!😊下一个,come on!

-k

-k 这个参数吧,没给 long 形式,我也猜不出啥意思😂还是来看官方给的解释吧:

12

一长串,懒得看了,直接翻译吧:

13

跳过移动或重命名可能导致错误情况的动作(除非给出 -f<后面的那句翻译有点烂😂>

理解加猜测一下呗:如果有错误情况发生,就跳过!

???那岂不是说,没有发生错误的可以继续正常执行?

那这也就说明双参数的肯定不在考虑范围内,当然,考虑也行,但是只改一个文件,出错跳过和出错退出没啥区别啊!

OK,那就试一下呗:

既然要试多参情况,容我先建个目录:

首先是上次的改动,我就留着了:

14

然后呢,建目录,目录中建文件:

15

将改动全部提交:

16

准备工作有点多哈,没关系,所有的准备都是为了更好的实验,来吧,Come on!

17

看来确实如此!

**-k 参数会在某个文件执行错误时跳过该文件,继续执行其他的文件!**

-n | —dry-run

这个有单词解释,dry-run ,原谅我英语不好,于是我查了一下,空运行的意思!

惯例,来让我先猜一下,空运行,不运行?假运行?难道是说虽然敲了回车,但是并没有执行?有病啊!😂

好吧,还是看看官网的解释吧!

18

什么也不做;仅显示将发生什么。

搜得思内!

相当于一个 precheck ,不真正地执行命令,但是会将真正执行命令时会发生的事全部打印出来,就像 log 一样。

好吧,看起来挺简单,试一下呗!(为省事期间,上次执行命令的结果我直接提交了,就不贴图了)

19

这个感觉挺简单的,我就不细解释了,直接下一个吧!

-v | —verbose

好吧,英语不好真TM吃亏,待我查一下:verbose 冗长的

什么鬼?我咋有点不明白呢?

直接看官网解释吧!

20

好吧,我还是没明白,再翻译一下:在文件移动时报告它们的名称。

???怎么报告?执行了命令之后,把执行的结果显示出来?

-n 一样显示,但是会真的执行操作?

试一下吧!

21

好吧,果然是这样!

执行操作且输出执行结果!

看到这里呢,4 个参数也就全部看完了,继续下一部分吧!

呃。。。

22

23

子模块?什么鬼哦?

原谅我的无知,我第一次听到这个概念,好吧,那就先到这里吧,后面的部分,待我研究完子模块后再加上吧!

总结

总结一下呗,毕竟我写得很啰嗦😂😂😂

  1. Usage

     usage: git mv [<options>] <source>... <destination>
     # **移动或重命名一个文件或目录,或符号链接。**
    
         -v, --verbose         be verbose  # **执行操作且输出执行结果!**
         -n, --dry-run         dry run     # **什么也不做;仅显示将发生什么。**
         -f, --force           force move/rename even if target exists
                                                                                 # **强制重命名或移动一个文件,即使目标存在!**
         -k                    skip move/rename errors
                                           # **-k 参数会在某个文件执行错误时跳过该文件,继续执行其他的文件!**
  2. git mv 这条命令其实有两种用法

    • move ,即移动文件或目录

    • rename ,即重命名文件或目录

      git mv [-v] [-f] [-n] [-k] <源> <目标> # 移动或重命名
      git mv [-v] [-f] [-n] [-k] <源> … <目标目录> # 移动

  3. 使用 git mv 命令后,所有的改动都会直接被 add 到暂存区中

  4. git mv 的原理(猜测,不要全信)

    git mv 会先去检查参数个数

    • 参数个数 > 2 ,则说明是移动多个文件或目录到某一个指定的目录下

    • 参数个数 =2 ,则说明操作的是单个文件或目录

      操作单个文件或目录的情况下,

      • 如果是 文件 → 文件,那必然是重命名
      • 如果是文件 → 目录,那就是移动
      • 如果是 目录 → 目录,应该和 Shell 命令 mv是一致的,要看后一个目录后有没有跟 /