四、将文件添加到Git仓库

在前面的实战部分,已经体验过怎么将文件添加到本地的git仓库了。

image-20200923165017057.png

image-20200923165435138.png

工作目录(实战中的learngit文件夹)下的每一个文件都不外乎这两种状态:已跟踪未跟踪

已跟踪:已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 git 已经知道的文件。

未跟踪:除了已跟踪的文件,都是未跟踪文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态,因为 git 刚刚检出了它们, 而你尚未编辑过它们。

编辑过某些文件之后,由于自上次提交后你对它们做了修改,git 将它们标记为已修改文件。 在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复。下图为文件的状态变化周期


文件的状态变化周期

小朋友你是否有很多问号

接着往下看,看完还不懂,提上你40米长的大刀来砍我。

检查当前文件状态

这里再次使用learngit目录,在上面的实践结束后,该目录下只有一个readme.txt文件,我们使用git status命令查看一下文件处于什么状态,使用此命令,会看到类似这样的输出:

$ git status
On branch master # 说明当前所在分支 master 为默认分支名
nothing to commit, working tree clean # emmm~ 你细细拼一下这什么意思

这个输出表明自实践结束后,还未对目录里的文件进行过任何修改,也没有出现任何处于未跟踪状态的新文件,否则 git 会在这里列出来,最后,该命令还显示了当前所在分支(之后会介绍分支)。

现在,在learngit目录下,新建一个test.txt文件,文件内容为:

this is a test file

此时,使用git status命令,就能看到一个新的未被跟踪的文件:

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test.txt

nothing added to commit but untracked files present (use "git add" to track)

在状态报告中可以看到新建的 test.txt 文件出现在 Untracked files 下面。未跟踪的文件意味着 git 仓库中没有这些文件;git 不会自动将之纳入跟踪范围。现在搞懂未跟踪文件的意思了吧。

image-20200923173631258.png

如果想要将test.txt也加入git仓库,让git进行管理,就要先将test.txt加入暂存区,进行跟踪。

已经提到很多次暂存区了,那么究竟什么是暂存区?

image-20200923172728086.png

工作区、暂存区和版本库

工作区(Working Directory):

就是在电脑里能看到的目录,比如learngit文件夹就是一个工作区:

image-20200923174337765.png

版本库(Repository):

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

image-20200923174541512.png

分支和HEAD的概念我们以后再讲。

前面有讲过使用git add命令将文件加入暂存区,实际上是把要提交的文件的所有修改添加到暂存区,然后执行git commit就可以一次性把暂存区的所有修改提交到本地仓库的分支上。

暂存区(Stage或Index):

一般存放在 .git目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。暂存区可以理解为一个虚拟工作区,这个虚拟工作区会跟踪工作区的文件变化(增删改等操作)。这个工作区的位于.git 文件夹下的index文件中。

需要理解一点:当需要对工作区的修改提交到版本库前,暂存区会与工作区进行差异比较,如果工作区与暂存区的文件不一致,那么需要同步工作区的修改到暂存区,然后才可以提交到版本库。从这个意义讲,暂存区可以说是工作区和版本库的桥梁。好处自然是可以在真正提交到版本库之前做任意的操作,在需要真正提交的时候 commit 到版本库 。当执行完git commit命令时,暂存区会被清空。

实践出真知,我们来实践一下:

在之前的操作中,添加了一个新的文件test.txt,之后就没有其他操作了,现在,我们修改一下readme.txt文件,比如加上一句话:

Git is a version control system.
Git is free software.
Git has a mutable index called stage.

再用git status查看一下状态:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   readme.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test.txt

no changes added to commit (use "git add" and/or "git commit -a")

git非常清楚的告诉了我们,readme.txt被修改了,而test.txt的状态是未被跟踪的。

现在,使用git add命令,把readme.txttest.txt都添加到暂存区,使用git status再次查看一下状态:

# 将readme.txt和test.txt一次性添加到暂存区
$ git add readme.txt test.txt
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt
        new file:   test.txt

此时,暂存区的状态就变成这样了:

image-20200923183904023.png

所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

$ git commit -m 'understand how stage works'
[master 8ec32e3] understand how stage works
 2 files changed, 3 insertions(+), 1 deletion(-)
 create mode 100644 test.txt

一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:

$ git status
On branch master
nothing to commit, working tree clean

现在版本库变成了这样,暂存区就没有任何内容了:

image-20200923185023250.png

搞定收工!

image-20200923190158250.png

跟踪新文件

使用命令git add开始跟踪一个文件,这个已经讲过很多次了,就不赘述了,不过要注意的是文件名不能写错:

# 这里要写文件的全名
$ git add test.txt
# 文件名没有写全,或者写错,会出现下面的信息
$ git add test
fatal: pathspec 'test' did not match any files
$ git add test.tx
fatal: pathspec 'test.tx' did not match any files

暂存已修改的文件

暂存已修改的文件,使用的命令是:

image-20200923191152796.png

没错,还是git add,惊不惊喜意不意外?这个前面也已经提到了,就不赘述了。

git add命令是个多功能命令:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。将这个命令理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目(仓库)中”要更加合适。

这里有一个需要注意的点:同一个文件,同时出现在暂存区和非暂存区。

我们来重现一下这个问题:

首先,修改readme.txt文件,将内容改为:

Git is a version control system.
Git is free software.
Git has a mutable index called stage.
Git is so good

使用git add命令将readme.txt放入暂存区,使用git add命令查看:

$ git add readme.txt
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt

再次修改readme.txt文件:

Git is a version control system.
Git is free software.
Git has a mutable index called stage.
Git is so good
Linus is god

此时再次运行git status命令看看:

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   readme.txt

现在readme.txt文件同时出现在暂存区和非暂存区。实际上 git 只不过暂存了你最后一次运行 git add 命令时的版本。 如果你现在提交,你在git add 命令之后的修改,不会被提交到仓库中。 所以,运行了 git add 之后又进行过修改的文件,需要重新运行 git add 把最新版本重新暂存起来:

$ git add readme.txt
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt

现在把readme.txt提交到仓库吧

$ git commit -m 'update readme.txt'
[master 0086f1a] update readme.txt
 1 file changed, 3 insertions(+), 1 deletion(-)

状态简述

git status 命令的输出十分详细,显得有些繁琐。 git 有一个选项可以帮你缩短状态命令的输出,这样可以以简洁的方式查看更改。 如果你使用 git status -s 命令或 git status --short 命令,你将得到一种格式更为紧凑的输出。你可能会看到以下输出:

$ git status -s
 M helloGit.txt
MM README.md
M  test.txt
A  testC.c
?? testDoc.doc

新添加的未跟踪文件前面有 ?? 标记,新添加到暂存区中的文件前面有 A 标记,修改过的文件前面有 M 标记。输出中有两栏,左栏指明了暂存区的状态,右栏指明了工作区的状态。例如,上面的状态报告显示: helloGit.txt 文件在工作区已修改但尚未暂存,而 test.txt 文件已修改且已暂存。 README.md 文件已修改,暂存后又作了修改,因此该文件的修改中既有已暂存的部分,又有未暂存的部分

image-20200918042109655.png

是不是有点晕?没关系,我们再实践一下,重现上面的输出。

上面的输出涉及了5个文件,我们learngit目录中已经有两个了,再新建三个文件app.txtgoogle.txtali.txt,文件内容任意就行。

  1. app.txtgoogle.txt添加到暂存区中

    $ git add app.txt google.txt
    # 单独提交 app.txt文件
    $ git commit -m 'commit app.txt' app.txt
    

    再修改app.txt文件内容

  2. 修改test.txt文件,并使用git add命令将其加入暂存区

  3. 修改readme.txt文件,并使用git add命令将其加入暂存区,之后再次进行修改

  4. 使用git status -s命令查看状态

    $ git status -s
     M app.txt
    A  google.txt
    MM readme.txt
    M  test.txt
    ?? ali.txt
    

    如果步骤1中没有单独提交app.txt文件,那么输出应该是这样的:

    $ git status -s
    AM app.txt
    A  google.txt
    MM readme.txt
    M  test.txt
    ?? ali.txt
    

小结:使用git status -s查看状态,状态会以两列显示,左栏表示暂存区的状态,右栏表示工作区的状态。

完美复现了,现在将他们提交到仓库,以免忘记,影响下次实验:

$ git commit -a -m 'update file content and add app.txt google.txt'
[master b9cb70f] update file content and add app.txt google.txt
 4 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100644 app.txt
 create mode 100644 google.txt

忽略文件

一般来讲,总有不需要放入git仓库进行管理的文件,也不想看到它出现在未跟踪列表,在这种情况下,我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件的模式。 来看一个实际的 .gitignore 例子:

$ cat .gitignore # cat命令可以查看文件内容
*.[oa]  # 文件内容
*~      # 文件内容

第一行告诉 git 忽略所有以 .o.a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 git 忽略所有名字以波浪符~结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就为你的新仓库设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。

文件 .gitignore 的格式规范如下:

  • 所有空行或者以 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c); 问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(**)表示匹配任意中间目录,比如 a/**/z 可以匹配 a/za/b/za/b/c/z 等。

我们再看一个 .gitignore 文件的例子:

# 忽略所有的 .a 文件
*.a

# 跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a

# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO

# 忽略任何目录下名为 build 的文件夹
build/

# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt

# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf

在最简单的情况下,一个仓库可能只根目录下有一个 .gitignore 文件,它递归地应用到整个仓库中。 然而,子目录下也可以有额外的 .gitignore 文件。子目录中的 .gitignore 文件中的规则只作用于它所在的目录中。

Tip:GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 https://github.com/github/gitignore 找到它。

实践:在做完上一个示例之后,我们使用git status -s命令查看文件状态

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        ali.txt

nothing added to commit but untracked files present (use "git add" to track)

git 会一直提示ali.txt未被跟踪,这是不是很烦人,假如这个文件,就是个临时文件,没有价值的文件,我们不想让git管理它,那么,这个时候,我们可以新建一个.gitignore文件,将它加入git仓库进行管理。

首先,新建.gitignore文件。这里说一下,在Windows系统下,是不能直接新建以.开头的文件,除非你这么命名.gitignore.txt(这个是可行的),那么假如你新建的是.gitignore.txt文件,并添加了如下内容:

ali.txt

那看看git是怎么看待这个文件的:

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore.txt
        ali.txt

nothing added to commit but untracked files present (use "git add" to track)

没错,就是个普通文件,它并没有让git忽略掉ali.txt文件,那咋办?没错,你可能会想到手动改后缀名呗,那我们来看一下:

image-20200925133517166.png

image-20200925133740607.png

坑爹的Windows就是不让你改,想砸电脑啊有木有?那可千万别砸,大好几千呢,总有解决问题的方法的。

之前介绍过Notepad++这款软件,这个软件真的超好用,没装的装一下。打开Notepad++,新建文件(中文界面,都是各界精英肯定会),然后在文件中输入一下内容:

ali.txt

没错,就上面一行,然后Ctrl + S保存,这个时候,重点来了(敲黑板):

image-20200925135601734.png

然后去learngit这个目录下看看,有没有.gitignore文件,接下来就是见证奇迹的时刻:

image-20200925135845470.png

.gitignore诞生了,现在来看看git是怎么看待这个文件的:

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore

nothing added to commit but untracked files present (use "git add" to track)

发现没有,ali.txt文件不见了,这说明我们的.gitignore文件生效了,这个时候,我们只需要把.gitignore文件添加到暂存区,然后commit提交到git仓库就行了。当然你不暂存,不提交,都是可以的,它照样可以生效,只是不暂存不提交,你之后每次使用git status命令,都能看见它,你说烦不烦,所以还是乖乖暂存提交吧

$ git add .gitignore
$ git commit -m 'add file .gitignore '
[master f2e4019] add file .gitignore
 1 file changed, 1 insertion(+)
 create mode 100644 .gitignore
# 在查看一下文件状态 
$ git status
On branch master
nothing to commit, working tree clean

我们再来看看ali.txt是不是还在我们磁盘上:

image-20200925140745067.png

嗯,还在,说明我真的没有删它,它真的是被git给忽略掉了。OK,示例结束。

image-20200925141042753.png

这里有一个奇葩的需求:.gitignore忽略自己,经典的我忽略我自己,可还行。

image-20200918042109655.png

但是 .gitignore 作为一个仓库结构的一部分,本身就应该是存在的,如果什么都不想忽略,那么就没必要建一个文件了。真碰到这种需求,总归还是要解决的。如果把.gitignore加到.gitignore文件中,是不起作用的。

解决办法:

编辑当前项目下的./git/info/exclude文件,然后将需要忽略提交的.gitignore文件路径写入就行了,注意写入文件的路径是相对项目根目录而言的。

查看已暂存和未暂存的修改

如果你想知道某个文件具体修改了什么地方,可以用 git diff 命令。

现在我们再次修改readme.txt文件后暂存,然后编辑test.txt文件后先不暂存,运行git status命令将会看到:

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   test.txt

要查看尚未暂存的文件更新了哪些部分,不加参数直接输入 git diff

$ git diff
diff --git a/test.txt b/test.txt
index 879fceb..9e431f3 100644
--- a/test.txt
+++ b/test.txt
@@ -1,2 +1,3 @@
 this is a test file
-add some file      # 前面是-说明是删除的内容
\ No newline at end of file # 在文件末尾没有换行符,这个是编辑器和系统的问题,我没有乱说,我有图为证,后面上Linux下的图
+add some file      # 前面是+说明这是新增的内容 至于为什么先删后加,通过和Linux系统的对比,我认为是系统或者编辑器的问题,如果有知道真相的小伙伴,可以告诉我,帮我纠正一下,共同进步,后面上Linux下的图
+test git diff      # 前面是+说明这是新增的内容
\ No newline at end of file

此命令比较的是修改之后还没有暂存起来的变化内容。

想要查看已暂存文件修改了什么内容,可以用git diff --staged命令。这条命令将比对已暂存文件与最后一次提交的文件差异:

$ git diff --staged
diff --git a/readme.txt b/readme.txt
index 7cc6fe7..67386fd 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,4 +4,5 @@ Git has a mutable index called stage.
 Git is so good
 Linus is god
 add app.txt file
-add google.txt file
\ No newline at end of file
+add google.txt file
+test git diff
\ No newline at end of file

Linux系统下,同样这两个文件,同样的内容,同样的操作方式:

image-20200925145534853.png

可以看到,只是系统和编辑器不同,Windows多出了几行无关的内容(警告信息),并且出现了先删除后添加的情况,所以我猜测是系统和编辑器的不同造成的,如果不是,希望知情的小伙伴可以告诉我真正原因!

回归正题,请注意,git diff本身只显示尚未暂存的改动,而不是自上次提交以来所做的所有改动。 所以有时候你一下子暂存了所有更新过的文件,运行 git diff 后却什么也没有,就是这个原因。

像之前说的,暂存 test.txt再修改(自己随便修改一下),可以使用 git status 查看已被暂存的修改或未被暂存的修改。 如果我们的环境(终端输出)看起来如下:

$ git add test.txt
# 修改test.txt文件
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt
        modified:   test.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   test.txt

这里test.txt出现在了暂存和未暂存的两种状态,现在运行git diff看暂存前后的变化:

$ git diff
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory # 可能会出现警告信息,请忽略它
diff --git a/test.txt b/test.txt
index 117f3a6..940c7b0 100644
--- a/test.txt
+++ b/test.txt
@@ -1,3 +1,4 @@
 this is a test file
 add some file
 test git diff
+# test line

然后用git diff --cached查看已经暂存起来的变化(--stagedcached作用是一样的):

$ git diff --cached
# readme.txt
diff --git a/readme.txt b/readme.txt
index 7cc6fe7..bcb9d8f 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,4 +4,5 @@ Git has a mutable index called stage.
 Git is so good
 Linus is god
 add app.txt file
-add google.txt file
\ No newline at end of file
+add google.txt file
+test git diff
# test.txt 重点看这里 是不是没有# test line这一行内容
diff --git a/test.txt b/test.txt
index 879fceb..117f3a6 100644
--- a/test.txt
+++ b/test.txt
@@ -1,2 +1,3 @@
 this is a test file
-add some file
\ No newline at end of file
+add some file
+test git diff

这里我们先不提交,因为下面我们就要来讲提交了。

image-20200923165017057.png

然而并没有!

分析文件差异也可以使用图形化的工具或外部 diff 工具来比较差异,比如DIffMerge,其他工具,自己去找一下。

还可以使用 git difftool 命令来调用 emerge 或 vimdiff 等软件输出 diff 的分析结果。 使用 git difftool --tool-help 命令来看你的系统支持哪些 git Diff 插件。git difftool会依次输出所有文件的分析结果,如果想看某一个文件的diff结果,就加上文件全名,比如:xxx路径下的test.txt,应该写成:git difftool xxx/text.txt

提交更新

在提交之前,务必确认还有什么已修改或者新建的文件还没有git add过,否则提交的时候不会记录这些尚未暂存的变化。 这些已修改但未暂存的文件只会保留在本地磁盘。所以,每次准备提交前,先用 git status 看下,你所需要的文件是不是都已暂存起来了, 然后再运行提交命令 git commit

$ git commit

直接运行该命令,会启动你选择的文本编辑器来输入提交说明,如果不输入提交说明,就会提交失败。

编辑器会显示类似下面的文本信息(默认使用的是vim编辑器,可配置自己的编辑器):

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Changes to be committed:
#       modified:   readme.txt
#       modified:   test.txt
#
# Changes not staged for commit:
#       modified:   test.txt
#

可以看到,默认的提交消息包含最后一次运行 git status 的输出,放在注释行里,另外开头还有一个空行,供你输入提交说明。 你完全可以去掉这些注释行,不过留着也没关系,多少能帮你回想起这次提交更新的内容有哪些。

更详细的内容修改提示可以用 git commit -v 查看,这会将你所作的更改的 diff 输出呈现在编辑器中,以便让你知道本次提交具体作出哪些修改。

Tip:启动的编辑器是通过 Shell 的环境变量 EDITOR 指定的,一般为 vim 或 emacs。 当然也可以 使用 git config --global core.editor 命令设置你喜欢的编辑器。例如:git config --global core.editor vim

另外,你也可以在 git commit 命令后添加 -m 选项,将提交信息与命令放在同一行,如下所示:

$ git commit -m 'commit by xxx'
[master c8731ea] commit by xxx
 2 files changed, 4 insertions(+), 2 deletions(-)

现在已经进行了一次提交! 可以看到,提交后它会告诉你,当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和(c8731ea)是什么,以及在本次提交中,有多少文件修订过,多少行添加和删改过。

跳过使用暂存区提交更新

git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给 git commit 加上 -a 选项,git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤:

$ git status # 查看文件状态 ,可以看到test.txt未被暂存
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")
# 提交未被暂存的文件
$ git commit -a -m 'use commit -a -m  command to commit'
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory
[master d1e9096] use commit -a -m  command to commit
 1 file changed, 1 insertion(+)
# 再次查看文件状态
$ git status
On branch master
nothing to commit, working tree clean

提交之前不再需要 git add 文件了。 这是因为 -a 选项使本次提交包含了所有修改过的文件。 这很方便,但是要小心,有时这个选项会将不需要的文件添加到提交中。

移除文件

要从 git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。 可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。

如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 “Changes not staged for commit” 部分(也就是 未暂存清单)看到:

$ rm test.txt # 从硬盘中删除test.txt文件,见图
$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    test.txt

no changes added to commit (use "git add" and/or "git commit -a")
image-20200925172443275.png

然后再运行 git rm 记录此次移除文件的操作:

$ git rm test.txt # 从暂存区和硬盘中删除test.txt
rm 'test.txt'
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    test.txt
# 提交,提交之后,上面 deleted 信息就不见了
$ git commit -m 'delete test.txt'
[master a8de87f] delete test.txt
 1 file changed, 4 deletions(-)
 delete mode 100644 test.txt

提交之后,test.txt文件就不在纳入版本管理,也就是从仓库删除了。如果要删除之前修改过或已经放到暂存区的文件,则必须使用强制删除选项 -f(译注:即 force 的首字母),否则会报错。 这是一种安全特性,用于防止误删尚未添加到快照的数据,强制删除的数据不能被 git 恢复。

另外一种情况是,我们想把文件从 git 仓库中删除(或从暂存区域移除),但仍然希望保留在当前工作目录中。 换句话说,你想让文件保留在磁盘,但是并不想让 git 继续跟踪。 当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目的,使用 --cached 选项:

$ git rm --cached readme.txt
rm 'readme.txt'
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    readme.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        readme.txt
# 提交
$ git commit -m 'delete readme.txt from repository and stage'
[master cfef1ea] delete readme.txt from repository and stage
 1 file changed, 8 deletions(-)
 delete mode 100644 readme.txt
# 查看文件状态,readme.txt为未跟踪状态,并没有从本地硬盘删除
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        readme.txt

nothing added to commit but untracked files present (use "git add" to track)

git rm 命令后面可以列出文件或者目录的名字,也可以使用 glob 模式(正则表达式)。比如:

$ git rm log/\*.log

此命令删除 log/ 目录下扩展名为 .log 的所有文件。 类似的比如:

$ git rm \*~

该命令会删除所有名字以 ~ 结尾的文件。

移动文件

要在 git 中对文件改名,可以这么做:

$ git mv file_from file_to

此时查看文件状态信息

# 先修改文件名,比如:把app.txt改为application.txt
$ git mv app.txt application.txt
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    app.txt -> application.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        readme.txt
# 记得提交一下
$ git commit -m 'rename app.txt -> application.txt'

其实,运行 git mv 就相当于运行了下面三条命令:

$ mv app.txt application.txt
$ git rm app.txt
$ git add application.txt

分开操作,git 也会意识到这是一次重命名,所以不管何种方式结果都一样。 两者唯一的区别是,mv 是一条命令而非三条命令,直接用 git mv 方便得多。 不过有时候用其他工具批处理重命名的话,要记得在提交前删除旧的文件名,再添加新的文件名。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342