总览(2.19.1)

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
44
$ git

usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]

这些是各种场合常见的 Git 命令:

开始一个工作区(参见:git help tutorial)
clone 克隆一个仓库到一个新目录
init 创建一个空的 Git 仓库或重新初始化一个已存在的仓库

在当前变更上工作(参见:git help everyday)
add 添加文件内容至索引
mv 移动或重命名一个文件、目录或符号链接
reset 重置当前 HEAD 到指定状态
rm 从工作区和索引中删除文件

检查历史和状态(参见:git help revisions)
bisect 通过二分查找定位引入 bug 的提交
grep 输出和模式匹配的行
log 显示提交日志
show 显示各种类型的对象
status 显示工作区状态

扩展、标记和调校您的历史记录
branch 列出、创建或删除分支
checkout 切换分支或恢复工作区文件
commit 记录变更到仓库
diff 显示提交之间、提交和工作区之间等的差异
merge 合并两个或更多开发历史
rebase 在另一个分支上重新应用提交
tag 创建、列出、删除或校验一个 GPG 签名的标签对象

协同(参见:git help workflows)
fetch 从另外一个仓库下载对象和引用
pull 获取并整合另外的仓库或一个本地分支
push 更新远程引用和相关的对象

命令 'git help -a''git help -g' 显示可用的子命令和一些概念帮助。
查看 'git help <命令>''git help <概念>' 以获取给定子命令或概念的
帮助。

安装与配置

安装

1
$ brew install 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
$ git config

用法:git config [<选项>]

配置文件位置
--global 使用全局配置文件
--system 使用系统级配置文件
--local 使用仓库级配置文件
-f, --file <文件> 使用指定的配置文件
--blob <数据对象 ID> 从给定的数据对象读取配置

操作
--get 获取值:name [value-regex]
--get-all 获得所有的值:key [value-regex]
--get-regexp 根据正则表达式获得值:name-regex [value-regex]
--get-urlmatch 获得 URL 取值:section[.var] URL
--replace-all 替换所有匹配的变量:name value [value_regex]
--add 添加一个新的变量:name value
--unset 删除一个变量:name [value-regex]
--unset-all 删除所有匹配项:name [value-regex]
--rename-section 重命名小节:old-name new-name
--remove-section 删除一个小节:name
-l, --list 列出所有
-e, --edit 打开一个编辑器
--get-color 获得配置的颜色:配置 [默认]
--get-colorbool 获得颜色设置:配置 [stdout-is-tty]

类型
-t, --type <> 取值为该类型
--bool 值是 "true""false"
--int 值是十进制数
--bool-or-int 值是 --bool or --int
--path 值是一个路径(文件或目录名)
--expiry-date 值是一个到期日期

其它
-z, --null 终止值是 NUL 字节
--name-only 只显示变量名
--includes 查询时参照 include 指令递归查找
--show-origin 显示配置的来源(文件、标准输入、数据对象,或命令行)
--default <取值> 使用 --get 参数,当缺少设置时使用默认值
1
2
$ git config --global user.name "xxx"
$ git config --global user.email "xxx@xxx"

创建版本库

初始化

选择合适的位置并创建一个空目录

1
2
3
4
5
$ mkdir gittest
$ cd gittest
$ git init

已初始化空的 Git 仓库于 /Users/tonghao/gittest/.git/

添加文件

1
2
$ touch test.txt
$ vi test.txt

第一次编辑文本内容为:

I love you

将此文件添加到git仓库有两步:

1
2
3
4
5
6
7
8
$ git add test.txt
$ git commit -m "first commit"

# -m后面为本次提交的简要说明

[master(根提交) 6b774c9] first commit
1 file changed, 1 insertion(+)
create mode 100644 test.txt

commit可以一次提交很多文件,所以可以多次add不同的文件

版本更新与回退

版本更新

继续修改文件为:

I love you
I love you tons

git status命令可以让我们时刻掌握仓库当前的状态

1
2
3
4
5
6
7
8
9
10
$ git status

位于分支 master
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)

修改: test.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a"

上面的命令输出告诉我们,test.txt被修改过了,但还没有准备提交的修改

可以使用git diff查看修改内容

1
2
3
4
5
6
7
8
9
$ git diff

diff --git a/test.txt b/test.txt
index 4499f50..ee42064 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
I love you
+I love you tons

先执行git add提交到暂存区

1
2
3
4
5
6
7
8
$ git add test.txt
$ git status

位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)

修改: test.txt

执行git commit把暂存区的所有修改提交到分支

1
2
3
4
5
$ git commit -m "second commit"
$ git status

位于分支 master
无文件要提交,干净的工作区

版本回退

再次修改test.txt并提交

I love you
I love you tons
I love you three thousand

可以使用git log命令查看历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ git log

commit c9d8c3067028da10687fa9809365e065c2f4de6a (HEAD -> master)
Author: tfcx-th <tonghao_xjtu@qq.com>
Date: Tue May 28 15:21:35 2019 +0800

third commit

commit 85930502644c8259efba527546620749e7783ee8
Author: tfcx-th <tonghao_xjtu@qq.com>
Date: Tue May 28 15:19:09 2019 +0800

second commit

commit 6b774c9cd5a5e7889f498300e5aebdcd2d933dff
Author: tfcx-th <tonghao_xjtu@qq.com>
Date: Tue May 28 14:47:31 2019 +0800

first commit

或者加上--pretty=oneline

1
2
3
4
5
$ git log --pretty=oneline

c9d8c3067028da10687fa9809365e065c2f4de6a (HEAD -> master) third commit
85930502644c8259efba527546620749e7783ee8 second commit
6b774c9cd5a5e7889f498300e5aebdcd2d933dff first commit

将test.txt回退版本,可以使用git reset命令;在git中,HEAD指向当前版本,上一个版本是HEAD^,上上个版本是HEAD^^,上100个版本可以写成HEAD-100

1
2
3
$ git reset --hard HEAD^

HEAD 现在位于 8593050 second commit

查看文件内容

I love you
I love you tons

回退以后想要回到原来的版本依然可以使用git reset,只需要一部分commmit id即可

1
2
3
git reset --hard c9d8c

HEAD 现在位于 c9d8c30 third commit

I love you
I love you tons
I love you three thousand

可以用git reflog查看命令历史

1
2
3
4
5
6
7
$ git reflog

c9d8c30 (HEAD -> master) HEAD@{0}: reset: moving to c9d8c
8593050 HEAD@{1}: reset: moving to HEAD^
c9d8c30 (HEAD -> master) HEAD@{2}: commit: third commit
8593050 HEAD@{3}: commit: second commit
6b774c9 HEAD@{4}: commit (initial): first commit

撤销修改

假设将test.txt作如下修改

I love you
I love you tons
I love you three thousand
asdasdasdasdasdasdasdasdasd
dasdasd

如果在提交之前想撤销这次修改,可以使用git checkout -- <file>把文件在工作区的修改全部撤销

1
$ git checkout -- test.txt

可以看到,test.txt变回原状态

I love you
I love you tons
I love you three thousand

如果文件已经添加到暂存区后,又作了修改,撤销修改就回到添加到暂存区后的状态

总之,git checkout -- <file>就是让文件回到最近一次git commit或git add时的状态

对于已经git add到暂存区但并没有commit的文件,可以使用git reset HEAD <file>把暂存区的修改撤销掉,重新放回工作区,然后再撤销工作区的修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git status

位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)

修改: test.txt

$ git reset HEAD test.txt

$ git status

位于分支 master
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)

修改: test.txt

删除文件

在git中,删除是一个修改操作

测试一下常见的rm指令,首先提交一个del_test.txt文件,使用rm命令

1
2
3
4
5
6
7
8
9
10
11
$ rm del_test.txt
$ git status

位于分支 master
尚未暂存以备提交的变更:
(使用 "git add/rm <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)

删除: del_test.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a"

此时只删除了工作区的文件,而没有删除版本库中的文件

如果要从版本库中删除该文件,可以使用命令git rm删掉,并且git commit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git rm del_test.txt

rm 'del_test.txt'

$ git status

位于分支 master
要提交的变更:
(使用 "git reset HEAD <文件>..." 以取消暂存)

删除: del_test.txt

$ git commit -m "delete test"

[master 726f4c1] delete test
1 file changed, 1 deletion(-)
delete mode 100644 del_test.txt

如果是误删除,可以使用git checkout -- <file>撤销修改

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以撤销

GitHub远程仓库

本地的git仓库可以关联远程的GitHub。在GitHub上先创建一个repository,
在本地的git仓库输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git remote add origin https://github.com/tfcx-th/gittest.git
$ git push -u origin master

枚举对象: 15, 完成.
对象计数中: 100% (15/15), 完成.
使用 4 个线程进行压缩
压缩对象中: 100% (8/8), 完成.
写入对象中: 100% (15/15), 1.13 KiB | 1.13 MiB/s, 完成.
总共 15 (差异 1),复用 0 (差异 0)
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/tfcx-th/gittest.git
* [new branch] master -> master
分支 'master' 设置为跟踪来自 'origin' 的远程分支 'master'

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程

由于远程库是空的,第一次推送master分支时要加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令

如果远程仓库中本身有文件,git push后会出现如下情况

1
2
3
4
5
6
7
8
9
$ git push -u origin master

To https://github.com/tfcx-th/gittest.git
! [rejected] master -> master (fetch first)
error: 推送一些引用到 'https://github.com/tfcx-th/gittest.git' 失败
提示:更新被拒绝,因为远程仓库包含您本地尚不存在的提交。这通常是因为另外
提示:一个仓库已向该引用进行了推送。再次推送前,您可能需要先整合远程变更
提示:(如 'git pull ...')。
提示:详见 'git push --help' 中的 'Note about fast-forwards' 小节。

此时需要先git pull,但会有如下问题

1
2
3
4
5
6
7
8
9
10
11
12
$ git pull origin master

warning: 没有共同的提交
remote: Enumerating objects: 3, done.
Merge branch 'master' of https://github.com/tfcx-th/gittest
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
展开对象中: 100% (3/3), 完成.
来自 https://github.com/tfcx-th/gittest
* branch master -> FETCH_HEAD
* [新分支] master -> origin/master
fatal: 拒绝合并无关的历史

可以这样解决这个问题

1
2
3
4
5
6
7
8
9
10
11
$ git pull origin master --allow-unrelated-histories

# vi界面
Merge branch 'master' of https://github.com/tfcx-th/gittest

来自 https://github.com/tfcx-th/gittest
* branch master -> FETCH_HEAD
Merge made by the 'recursive' strategy.
README.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 README.md

之后就可以顺利git push