Git基础使用(一)

417 阅读6分钟

今日份的分享将会介绍Git本地的基本操作,涉及:创建或克隆操作、修改文件、提交到暂存区、提交修改至版本库,以及查看仓库的变更历史。接下来的操作使用的系统环境为Ubuntu 20.04Windows上的操作也是一样的,只需要修改下涉及的文件或目录路径即可。

1 获取版本库

在本地建立Git项目主要有两种方法:一个是在本地初始化Git项目,另一个是从服务器上克隆Git项目。

1.1 本地初始Git项目

在本地初始Git项目也很方便,首先,定位到需要创建项目的文件夹,然后在此目录下执行如下命令:

git init

这句命令会在当前目录中创建.git子目录,这个子目录中包含了构成Git版本控制仓库骨架的必需的文件。但是,这时候并没有追踪此目录中的任何文件。

如果你选择的这个子目录是非空目录,并且想使用Git把这个文件夹已有的文件管理起来,可使用如下命令:

git add *
git commit -m "初始化Git仓库"

这里简单描述这两条命令的含义,后面的章节内容会详细介绍。

  • git add *将当前工作区中所有的文件添加到暂存区
  • git commit -m "初始化Git仓库"将暂存区的数据提交的本地Git仓库,并附上提交信息

1.2 克隆服务器上的Git项目

在笔者参与的项目中,大多数是先在GitLab或者GitHub中创建项目,然后克隆到本地。克隆这个过程需要使用的命令是git clone [url],例如:

git clone https://gitee.com/jiaoxn/git_learn_note_202102.git

这条命令将会创建一个名为git_learn_note_202102的子目录,并在其中初始化.git目录,然后将拉去远程仓库(url指定的)的最新版本的所有数据到本地。

如果想克隆到其他名字的目录中,可在后面指定目录的名称,例如:

git clone https://gitee.com/jiaoxn/git_learn_note_202102.git my_learn_note

这将会把服务器上的Git项目克隆至my_learn_note,这里需要注意的是,如果这个目录不为空,Git将会提示警告。

细心的朋友可能注意到上述命令中均使用https协议,Git还会支持其他的协议,比如:SSH,这将会在后续的笔记中详细介绍。接下来,让我们熟悉下项目过程中常用的Git本地操作命令吧。

2 修改本地的文件

还记得昨天的笔记中提到的,Git中的文件有3种状态,分别是已修改、已暂存和已提交。这里,把文件的状态再丰富一下。

Git工作目录中的文件首先可以分为已追踪(tracked)未追踪(untracked)两种状态。已追踪表示该文件存在与上一次提交的快照中,又可细分为已修改已暂存已提交。未追踪表示当前工作目录中出去已追踪的其余的所有的问题,这些文件没有包含在上一次提交的快照中。那么如何查看当前工作目录中文件的状态呢?

2.1 查看文件状态

查看文件状态可使用git status命令,在本地创建的Git项目中执行会得到:

$ git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)

上述输出首先说明了:

  • 当前所处的分支为master
  • 当前是个空项目,没有任何提交
  • 当前项目中不存在未追踪的文件,也没有存在处于修改或暂存状态的已追踪的文件处

在刚刚克隆的Git项目中,执行该命令会得到:

$ git status
位于分支 master
您的分支与上游分支 'origin/master' 一致。

无文件要提交,干净的工作区

2.2 追踪新文件

在本地初始化的目录中添加一个名为helloworld.txt的文件,然后在执行会出现什么情况呢?

$ sudo echo 'Hello, world!' > helloworld.txt
$ git status
On branch master

No commits yet

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

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

可以看到,前两行输出没有变化,但这次输出提示我们有一个文件处于未追踪状态,并将其添加“未追踪的文件”(Untracked files)列表下面,同时,也很友好地提示我们如何将追踪当前文件。

根据提示,使用命令git add <文件>追踪helloworld.txt这个文件,然后再执行git status命令,这时的输出又是什么呢?

$ git add helloworld.txt
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   helloworld.txt

这是我们可以看到,当前文件已处于追踪状态了,并且以添加到暂存区,等带下一次的提交。这里的列表Changes to be commited(等待提交的更改)列出了当前暂存区的文件。

2.3 暂存已修改的文件

如果这时再对处于暂存状态的helloworld.txt文件做修改,然后执行git status命令,又会得到什么样的输出呢?

$ sudo echo "我爱你,中国" > helloworld.txt
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   helloworld.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:   helloworld.txt

这时的输出中出现了Changed not staged for commit(已更改但会添加到暂存区)列表,并且helloworld.txt文件也出现在这个列表中,这表明,helloworld.txt被修改但是没有添加到暂存区。

我们在上一步中不是把这个文件添加到暂存区了,怎么又会出现的这个提示呢?要解释这个问题,需要改变一下对于git add这个命令的看法。git add命令是“添加修改的内容到下一次提交中,而不是把文件添加到这个项目中”;将文件添加加到暂存区时,保存的是执行git add这个命令时该文件的状态。如果此时执行git commit命令提交,提交的内容包含的是上一次执行git add时的文件内容(Hello, world!),不会包含现有工作区中的该文件修改的内容(“我爱你,中国”)。这样是不是更好理解的呢?

我们先使用命令git add helloworld.txt将该文件再次提交到暂存区。

2.4 简化显示的状态信息

在项目中,经常会遇到多个文件处于未暂存或未提交状态,这时的git status输出无疑时很冗长的。Git提供了简化的状态输出的命令:git status -sgit status --short

$ git status -s
A  bb.txt
AM helloworld.txt
?? aa.txt

怎么理解这个输出呢?

  • 输出内容中包含了未追踪的文件和未暂存或未提交的已追踪的文件
  • 文件名称左边有两列,最左边的列表示是否已暂存,右边的列表示是否已修改但未暂存
  • ??表示未追踪,A表示已暂存的文件,M表示已修改的文件

留个简单的思考题,为了得到上述的输出,我做了哪些操作呢?

2.5 忽略文件

很多时候,我们并不想把一些文件或目录添(例如:node_modules)加到Git的追踪目录中,这种情况可以通过在工作区中创建.gitignore文件来解决,.gitignore文件示例:

dist/
.DS_Store
node_modules/
/coverage
*.log

.gitignore文件中每行都会匹配特定的规则来告诉Git忽略哪些文件,常用的匹配规则模式有:

  • 空行或者#开头的行将被.gitignore文件忽略
  • 支持标准的glob模式
  • 以斜杠('/')开头的模式可用于禁止递归匹配
  • 以斜杠('/')结尾的模式表示目录
  • 以感叹号('!')开头的模式表示取反

上面提到的glob模式类似与shell所使用的简化版的正则表达式,具体来讲:

  • *匹配零个或多个字符,可以使用**匹配嵌套的目录,比如/a/**/z可以匹配/a/z,也可以匹配/a/b/c/z
  • [abc]匹配括号内任意单个字符
  • ?匹配任意单个字符
  • 方括号中用短划线连接的两个字符(例如:[0-9])表示匹配这个两个字符之间的任意单个字符(示例将会匹配0到9中任意的数字)

我们来尝试这解释下.gitignore文件的示例:

  1. dist/表示忽略dist文件下的所有文件
  2. /coverage表示忽略当前目录下的coverage,而不会忽略子目录下coverage
  3. *.log表示忽略后缀名为.log的文件

2.6 查看已暂存和未暂存的变更内容

前几小节介绍的git status可以帮助我们了解每个文件的状态,但是,并不能帮助我们了解不同状态文件之间的哪些内容发生了变化,可使用git diff命令来达到此目的。这里我们先了解如何使用git diff,详细的内容将会在后续介绍

  • 对比工作区与暂存区的变更内容:
$ git diff
diff --git a/helloworld.txt b/helloworld.txt
index af5626b..3341d9a 100644
--- a/helloworld.txt
+++ b/helloworld.txt
@@ -1 +1 @@
-Hello, world!
+<E6><88><91><E7><88><B1><E4><BD><A0><EF><BC><8C><E4><B8><AD><E5>BD>
  • 对比暂存区与版本库的变更内容:
$ git diff --staged
diff --git a/bb.txt b/bb.txt
index daebebf..e61ef7b 100644
--- a/bb.txt
+++ b/bb.txt
@@ -1 +1 @@
-ShiXX
+aa

需要注意的是,git diff不会对比当前工作区与版本库上一次提交的快照之间的差异,而是与暂存区的内容做的对比,如果把工作区所有的修改内容添加到暂存区,执行git diff将不会得到任何差异

2.7 提交变更

可通过git commit命令将暂存区的内容提交到版本库,这里需要注意的是,已修改但是没有添加到暂存区的内容不会提交到版本库。

如果执行git commit命令,将会打开昨天分享的笔记中设置的编辑器,然后输入提交的内容,保存,退出。编辑器中会有一些默认的注释的文本信息,在编写提交信息时,可以删除这些注释,也可以不删除,因为,退出编辑器时Git会自动删除这些注释并对比差异,把剩余的信息记录到对应的提交中

也可以执行git commit -m '<提交描述信息>'来简化上述步骤

$ git commit -m '测试'
[master 0fa7c98] 测试1
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 aa.txt

在输出信息中,说明了一些与提交相关的信息,如:提交到哪个分支,提交的SHA1校验和是多少(这里输出的是校验和的缩写)、提交的描述信息、有几个文件修改以及增加和删除多少行

2.8 跳过暂存区

既然可以通过-m选项简化提交操作,有没有方法跳过“添加到暂存区”这个步骤,直接将修改的文件提交呢?Git中提供了-a选项来实现。

$ git commit -a -m '<描述信息>'

2.9 移除文件

在``Git`项目中移除文件分为2中情况:

  • 在工作区中移除文件,并提交

这种情况,可以首先在工作区删除文件,然后执行命令git rm将文件的移除状态添加到暂存区,然后使用命令git commit提交修改

  • 保留工作区中的文件,从暂存区中删除文件

这种情况,可以通过命令git rm --cached <文件名>来实现,例如:

$ git rm --cached README

其中,文件名可以通过glob模式来匹配

2.10 移动文件

Git中可通过git mv命令来移动文件或者重命名文件,例如:

$ git mv aa.txt cc.txt

上述命令把aa.txt重命名未cc.txt,这时使用git status命令来查看,就会发现Git实现了重命名这个动作。

$ git mv aa.txt cc.txt
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    aa.txt -> cc.txt

这条命令相当于执行了以下3条命令:

$ mv aa.txt cc.txt
$ git rm aa.txt
$ git add cc.txt