Git学习笔记(1)-简单案例与常规操作

Git命令文档查询

直接输入git help可以查看Git的帮助信息,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
D:\zcode\test>git help
usage: git [--version] [--help] [-C <path>] [-c name=value]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
These are common Git commands used in various situations:
start a working area (see also: git help tutorial)
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one
work on the current change (see also: git help everyday)
add Add file contents to the index
mv Move or rename a file, a directory, or a symlink
reset Reset current HEAD to the specified state
rm Remove files from the working tree and from the index
examine the history and state (see also: git help revisions)
bisect Use binary search to find the commit that introduced a bug
grep Print lines matching a pattern
log Show commit logs
show Show various types of objects
status Show the working tree status
grow, mark and tweak your common history
branch List, create, or delete branches
checkout Switch branches or restore working tree files
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
merge Join two or more development histories together
rebase Reapply commits on top of another base tip
tag Create, list, delete or verify a tag object signed with GPG
collaborate (see also: git help workflows)
fetch Download objects and refs from another repository
pull Fetch from and integrate with another repository or a local branch
push Update remote refs along with associated objects
'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.

这里面基本上是Git常用的命令。

如果要查询具体的哪一条命令的用法,例如diff命令,如下所示:

1
git help diff

此时就会出现一个网页,里面详细描述了git diff命令的用法,再来看一个config的用法,如下所示:

1
git help config

这里需要注意的是,在查询某个命令如何使用时,不需要添加前面的git字符,在git的命令行中,命令的格式基本上就是git + 命令这种形式使用的,例如git diff,但是在搜索git diff这个命令如何使用时,只需要使用git help diff即可,而不是git help git diff

Git其它学习资源

这一部分列举一些Git的其他使用资料:

Pro Git

Pro Git是GitHub公司出身的人写的。

LearnGitBranching

这是一个学习Git的网站,非常适合初学者,尤其是对那些树形结构比较码也得到的人。

tryGit

在Web上一边操作一边学习Git。

版本管理

版本管理就是管理更新的历史记录。它为我们提供了一些在软件开发过程中必不可少的功能,例如记录一款软件添加或更改源代码的过程,回滚到特定阶段,恢复误删除的文件等。在Git出现以前,人们普遍采用Subversion等集中型版本管理系统,而现在Git已经成为了主流。

版本管理有两种方式,分别是集中型分散型

集中型将所有数据集中存放在服务器当中,这样就能方便管理代码。不过,如果开发者所处的环境不能连接服务器,就无法获取最新的源代码, 开发也就几乎无法进行,并且服务器如果遇到意外,代码就会损失,它的管理模式如下所示:

分散型的管理模式如下所示:

GitHub将仓库Fork给了每一个用户,这里的Fork英文意思是拿起叉吃饭,可以形象地理解为,把源代码拿过来。Fork的过程就是将GitHub的某个特定仓库复制到自己的账户下。Fork出的仓库与原仓库是两个不同的仓库,开发者可以如图所示,分散型拥有多个仓库。不过,由于本地的开发环境中就有仓库,所以开发者不必连接远程仓库就可以进行开发。图中只显示了一般的使用流程。实际上,所有仓库之间都可以进行push和pull。即便不通过GitHub,开发者A也可以直接向开发者B的仓库进行push或pull。

GitHub与Git的区别

在 Git 中,开发者将源代码存入名叫Git 仓库的资料库中并加以使用。而GitHub则是在网络上提供 Git 仓库的一项服务,从字面上也好理解,Hub的意思是节点,中心的意思,GitHub暗示了这种方式是一种分散式的代码管理思路,而GitHub上公开的软件源代码全都由Git进行管理。

GitHub的主要功能

GitHub提供的主要功能有Git仓库,Organization。

Git仓库

普通用户可以免费创建任意个Git仓库,如果要创建私有仓库,需要付费。

Organization

公司通常使用Organization账户。

Issue

Issue是将一个任务或问题分配给一个 Issue 进行追踪和管理。每一个功能更改或修改都对应一个Issue,讨论或修正都以Issue为中心,只要查看Issue就能知道和这个更改相关的一切信息。

Wiki

Wiki是对代码文档的说明。

Pull Request

Pull Request是指开发者在本地对源代码进行更改后,向GitHub中托管的Git仓库请求合并的功能。开发者可以在Pull Request上通过评论交流,例如“修正了BUG,可以合并一下吗?”以及“我试着做了这样一个新功能,可以合并一下吗?”等。通过这个功能,开发者可以轻松更改源代码,并公开更改的细节,然后向仓库提交合并请求。而且,如果请求的更改与项目的初衷相违,也可以选择拒绝合并。

GitHub的Pull Request可以查看源代码的前后差别,也可以对指定的一行代码进行评论。

Pull Request可以让特定的用户来查看,只要用@用户名这个功能即,跟微博类似。Pull Request也能够提供Wiki功能,开发者可以创建文档,Wiki的更新历史记录也能在Git中进行管理。

输入#编号这种字样,GitHub会连接到该仓库所对应的Issue编号。输入用户名/仓库名#编号则能连接一指定仓库所对应的Issue编号。

Git安装与配置

在使用Git管理代码之前,需要申请一个GitHub账户,过程略。

在本地进行代码管理时,需要安装Git的客户端,去官网(https://desktop.github.com/)下载即可。

安装后,操作系统中就会有Git Bash,这是一种命令行管理工具,如下所示:

在第一次使用Git时,需要配置一下,如下所示:

1
2
$ git config --global user.name "Firstname Lastname"
$ git config --global user.email "your_email@example.com"

运行这个命令后,会在~/.gitconfig中以如下形式输出设置文件。

1
2
3
[user]
name = Firstname Lastname
email = your_email@example.com

想更改这些信息时,可以直接编辑这个设置文件即可。这里设置的姓名和邮箱地址会用在Git的提交日志中。
在配置Git时,如果将color.ui设置为auto,则命令的输出就更有可读性。

1
$ git config --global color.ui auto

配置后就会在~./gitconfig中出现以下记录:

1
2
[color]
ui = auto

设置SSH key

GitHub上连接已有仓库时的认证,是通过使用了SSH的公开密钥认证方式进行的,现在让我们来创建公开密钥认证所需的SSH Key,并将其添加至GitHub,如下所示:

1
2
3
4
5
6
$ ssh-keygen -t rsa -C "your_email@example.com"
Generating public/private rsa key pair.
Enter file in which to save the key
(/Users/your_user_directory/.ssh/id_rsa): 按回车键
Enter passphrase (empty for no passphrase): 输入密码
Enter same passphrase again: 再次输入密码

其中your_email@example.com是创建账户时用的邮箱地址。

输入密码后就会出现以下信息:

1
2
3
4
5
6
7
8
9
Your identification has been saved in /Users/your_user_directory/.ssh/id_rsa.
Your public key has been saved in /Users/your_user_directory/.ssh/id_rsa.pub.
The key fingerprint is:
fingerprint值 your_email@example.com
The key's randomart image is:
+--[ RSA 2048]----+
| .+ + |
| = o O . |

其中id_rsa文件是私有密钥,id_rsa.pub是公开密钥。

添加公开密钥

在GitHub中添加公开密钥,今后就可以用私有密钥进行认证了。点击右上角的账户设定按钮(Settings),选择SSH and GPGKeys菜单。点击Add SSH Key之后,在Title中输入适当的密钥名称。Key部分请粘贴id_rsa.pub文件里的内容。id_rsa.pub的内容可以用如下方法查看:

1
2
$ cat ~/.ssh/id_rsa.pub
ssh-rsa 公开密钥的内容 your_email@example.com

运行结果如下所示:

1
2
3
20161111@DESKTOP-IVG4HR1 MINGW64 ~/Desktop
$ cat ~/.ssh/id_rsa.pub
ssh-rsa A...这里面有很多字符,我就略去了...j app_web@qq.com

添加成功后,创建账户时所用的邮箱就会收到一封邮件。完成成上述设计后,就可以使用手中的私人密钥与GitHub进行认证和通信了,可以试一下:

1
2
3
D:\zcode\Medicial-Statistics-4th>ssh -T git@github.com
Warning: Permanently added 'github.com,52.74.223.119' (RSA) to the list of known hosts.
Hi 20170505a! You've successfully authenticated, but GitHub does not provide shell access.

在GitHub创建了一个仓库后,在初始化仓库后会自动生成.gitignore文件,这个文件会帮用户把不需要在Git仓库中进行版本管理的文件记录在.gitignore中。

Git基本操作

在这一部分中,我们进行一些常规操作,看一下如何使用Git来保存文件或代码。

第一,先在D:\zcode中添加一个文件夹test,使用的命令是mkdir,如下所示:

1
2
3
4
D:\zcode>mkdir test
D:\zcode>cd test
D:\zcode\test>git init
Initialized empty Git repository in D:/zcode/test/.git/

解释一下命令:

  1. mkdir test:在D:\zcode下创建了一个名为test的文件夹;
  2. git init:初始化test这个目录,运行这个命令行,会在目录下创建一个.git目录(这个目录是隐藏的),这个目录记录了管理当前目录内容所需要的仓库数据,如果初始化成功,就会出现上面的提示信息。

在Git中,我们将这个test这个文件夹(有的也叫目录)内的内容称为“附属于该仓库的工作树”。文件的编辑等操作在工作树中进行,然后记录到仓库中,以此管理文件的历史快照。如果想将文件恢复到原先的状态,可以从仓库中调取之前的快照,在工作树中打开。开发者可以通过这种方式获取以往的文件。

git status命令

git status命令是用来查看Git仓库的状态,工作树和仓库在被操作的过程中,状态会不断发生变化。在Git操作过程中时常用git status命令查看当前状态,现在我们使用git status来查看一下状态,如下所示:

1
2
3
4
5
6
D:\zcode\test>git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)

结果显示,现在我们正处于master分支之下(On branch master),现在没有什么提交的内容(nothing to commit)。

现在我们在test中创建一个文件,使用README.md命名,在这个文件中输入test Github字样。

保存文件后,再输入git status,如下所示:

1
2
3
4
5
6
7
8
9
10
11
D:\zcode\test>git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)

现在可以看到,Untracked files:下显示了README.md文件,其实只要对Git的工作树或仓库进行操作,git status就会显示发生变化。

git add命令

如果要让README.md这个文件成为Git仓库的管理对象,就霜肆使用git add命令将其添加到暂存区,暂存区是提交之前的一个临时区域,如下所示:

1
2
3
4
5
6
7
8
9
10
11
D:\zcode\test>git add README.md
D:\zcode\test>git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md

可以看到,README.md文件已经显示在了Changes to be committed:中。

git commit

现在提交文件,如下所示:

1
2
3
4
D:\zcode\test>git commit -m "First commit"
[master (root-commit) 8d73594] First commit
1 file changed, 1 insertion(+)
create mode 100644 README.md

其中参数-m后面添加了"First commit"信息,这是对提交的这个文件的概述,如果不加-m这个参数,则Git会直接打开一个文本编辑器,让用户输入更加详细的说明信息,如下所示:

1
2
3
4
5
6
# 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:
# new file: "README - \345\211\257\346\234\254.md"
#

git log提交日志

使用git log可以查看提交的日志,如下所示:

1
2
3
4
5
6
D:\zcode\test>git log
commit 8d73594940e8a3a5be8a30db0fcc149019d8fb91
Author: 20170505a <app_web@qq.com>
Date: Thu Jul 4 13:07:18 2019 +0800
First commit

其中commit后面接了一串代码8d73594940e8a3a5be8a30db0fcc149019d8fb91,这是提交的哈希值。

git-log --pretty=short简化提交信息

如果只想显示提交信息的第一行,需要在git log后面添加上--pretty=short参数,如下所示:

1
2
3
4
5
D:\zcode\test>git log --pretty=short
commit 8d73594940e8a3a5be8a30db0fcc149019d8fb91
Author: 20170505a <app_web@qq.com>
First commit

git log 文件名特定文件或目录的日志

如果只针对某个特定的文件或目录,只需要在git log后面添加上文件或目录的名称即可,如下所示:

1
2
3
4
5
6
D:\zcode\test>git log README.md
commit 8d73594940e8a3a5be8a30db0fcc149019d8fb91
Author: 20170505a <app_web@qq.com>
Date: Thu Jul 4 13:07:18 2019 +0800
First commit

git log -p文件提交带来的改动

添加上-p参数可以显示文件提交带来的改动,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
D:\zcode\test>git log -p README.md
commit 8d73594940e8a3a5be8a30db0fcc149019d8fb91
Author: 20170505a <app_web@qq.com>
Date: Thu Jul 4 13:07:18 2019 +0800
First commit
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4b9bd4f
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+test Github
\ No newline at end of file

git diff更改前后的差异

git diff可以查看工作树、暂存区、最新提交之间的差别。现在举个例子,在刚才的README.md文件中删除原来的信息,再输入以下内容:

1
# Git教程

现在执行git diff命令,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
D:\zcode\test>git diff
diff --git "a/README - \345\211\257\346\234\254.md" "b/README - \345\211\257\346\234\254.md"
deleted file mode 100644
index 4b9bd4f..0000000
--- "a/README - \345\211\257\346\234\254.md"
+++ /dev/null
@@ -1 +0,0 @@
-test Github
\ No newline at end of file
diff --git a/README.md b/README.md
index 4b9bd4f..b52d3b6 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
-test Github
\ No newline at end of file
+# Git教程
+
warning: LF will be replaced by CRLF in README.md.
The file will have its original line endings in your working directory.

原来README.md中的内容是test Github,现在则是# Git教程字样。现在解释一下上面的内容:

  1. -test Github:前面有一个减号,这说明我们把原来的test Github字样删除了;
  2. +# Git教程:前面有一个加号,这说明我们现在添加了# Git教程字样。

现在使用git add命令把这个修改过后的文件加入暂存区,即输入git add README.md命令,再执行git diff命令发,如下所示:

1
2
3
4
5
6
7
8
9
10
D:\zcode\test>git diff HEAD
diff --git a/README.md b/README.md
index 4b9bd4f..b52d3b6 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
-test Github
\ No newline at end of file
+# Git教程
+

这里我们使用的参数是HEAD,即git diff HEAD,这里的HEAD是指指当前分支中最新一次提交的分支,表示的是本次提交与上次提交之间的差别。

现在使用git commit -m "Add index"命令将文件加入到暂存区,顺便再查看一下提交日志,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
D:\zcode\test>git commit -m "Add index"
[master 6b3a637] Add index
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 "README - \345\211\257\346\234\254.md"
D:\zcode\test>git log
commit 6b3a637cee900627058c4896b3330146d1ea4f58
Author: 20170505a <app_web@qq.com>
Date: Thu Jul 4 13:23:11 2019 +0800
Add index
commit 8d73594940e8a3a5be8a30db0fcc149019d8fb91
Author: 20170505a <app_web@qq.com>
Date: Thu Jul 4 13:07:18 2019 +0800
First commit

此时我们使用git push命令把这个文件提交一下,运行结果如下所示:

1
2
3
4
5
6
7
8
9
D:\zcode\test>git push
fatal: No configured push destination.
Either specify the URL from the command-line or configure a remote repository using
git remote add <name> <url>
and then push using the remote name
git push <name>

发现出错了,错误的信息大概有以下这些内容:

  1. 推送出错,没有因为配置推送的目的地。也就是说,我们虽然在本地创建了一个test目录,想把这个目录的内容推送到Github上,但是Github上有好几个仓库,不知道推送到哪个。
  2. 可以使用git remote add <name> <url>命令来配置一下。

现在我们来配置一个,在Github上创建一个新的仓库,命令为test2,其他的信息很容易设置,略过。

然后在本地的test目录内用命令行输入以下内容:

1
2
git remote add origin git@github.com:20170505a/test2.git
git push -u origin master

解释一下命令:

第一行的git remote add origin git@github.com:20170505a/test2.git:表示将GitHub上创建的20170505a/test2.git仓库当作本地仓库的远程仓库,这个命令会将这个远程仓库的名称设置为origin。

第二行的git push -u origin master:将当前目录中的内容摄像头给远程仓库origin的master分支,-u参数可以在推送的同时,将origin仓库的master分支设置为本地仓库当分支的上游(upstream),添加了这个参数扣,以后再运行git pull命令从远程仓库中获取内容时,本地仓库的这个分子可以直接从origin的master分支获取内容,而不用再添加参数。

执行了该操作后,本地仓库的master分支的内容将会被推送到GitHub的远程仓库中。

运行结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
D:\zcode\test>git remote add origin git@github.com:20170505a/test2.git
D:\zcode\test>git push -u origin master
Warning: Permanently added 'github.com,52.74.223.119' (RSA) to the list of known hosts.
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 469 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
Branch master set up to track remote branch master from origin.
To github.com:20170505a/test2.git
* [new branch] master -> master

此时,完成推送。

经过此次配置,下一次在test目录中直接修改或添加文件后,就不需要再次配置了,只需要按照常规的git addgit commitgit push命令顺序操作即可。

推送到其他分支

我们除了可以将本地仓库中的内容推送到master分支外,远程仓库也可以创建其他分支,例如我们在本地仓库中创建一个other_test的分支,并将它以同名形式push至远程仓库,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
D:\zcode\test>git checkout -b other_test
Switched to a new branch 'other_test'
D:\zcode\test>git push -u origin other_test
Warning: Permanently added 'github.com,52.74.223.119' (RSA) to the list of known hosts.
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'other_test' on GitHub by visiting:
remote: https://github.com/20170505a/test2/pull/new/other_test
remote:
Branch other_test set up to track remote branch other_test from origin.
To github.com:20170505a/test2.git
* [new branch] other_test -> other_test

此时去远程Github仓库的页面查看一下,如下所示:

点开,如下所示:

克隆仓库

在当Github上创建了一个仓库后,可以把这个仓库克隆(clone)到本地,代码命令为$ git clone git@github.com:用户名/仓库名,其中仓库名可以在GitHub上查看地,基本都是20170505a/raw_data.git这个样本,如下所示:

1
2
3
4
5
6
7
8
9
D:\zcode>git clone git@github.com:20170505a/raw_data.git
Cloning into 'raw_data'...
Warning: Permanently added 'github.com,13.229.188.59' (RSA) to the list of known hosts.
remote: Enumerating objects: 124, done.
Receiving objects: 100% (124/124), 751.58 KiB | 198.00 KiB/s, done.
Resolving deltas: 100% (42/42), done.
D:\zcode>cd raw_data

在执行了git clone命令后,会默认处于master分支之下,同时系统会自动将origin设置为该远程仓库的标识符,也就是说当前本地仓库的master分支与Github端远程仓库(origin)的master分支在内容是完全相同的。

参考资料

  1. GitHub入门与实践.[日] 大塚弘记.支鹏浩/刘斌(译).人民邮电出版社.2015-7