目录

Git 基本操作

通过一顿操作来熟悉 Git 是不二法门。

创建仓库

请自行准备好 git 环境。

创建服务器裸仓库

  • git init: 将当前的目录转换成一个 git 仓库
  • git init <directory>: 在指定目录创建一个空的 git 仓库
  • git init --bare <project-name>.git: 裸库往往被创建用于作为大家一起工作的共享库,每一个人都可以往里面 push 自己的本地修改。服务器上 bare 创建的仓库,主要用来连接,同步,协调。记录每个人本地仓库的记录,而不存放项目源代码。而每个开发人员自己电脑上分别有个小仓库,存放源代码及自己的改动
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 登录远程服务器
$ ssh <user>@<host>

// 进入操作目录
$ cd /path/to/repository

// 创建祼仓库
$ git init --bare <project-name>.git

// 退出远程服务器,进入本地终端
$ git init <directory>
$ touch README.md
$ git add README.md
$ git commit -m "Initial commit"
$ git remote add origin <user>@<host>:/path/to/repository/<project-name>.git
$ git push -u origin master

// 其它成员克隆仓库
$ git clone <user>@<host>:/path/to/repository/<project-name>.git

创建本地仓库

初始化本地仓库

1
2
3
4
5
6
7
// 创建本地仓库
$ mkdir example
$ cd example
$ git init
$ touch README.md
$ git add README.md
$ git commit -m "Initial commit"

关联远程仓库

关联多个仓库需要给不同的远程仓库起一个别名,请自行在 gitee 和 github 上创建空仓库。

1
2
3
4
5
$ git remote add gitee git@gitee.com:user/project.git
$ git push -u gitee master
$ git remote add github https://github.com/user/project.git
$ git push -u github master

分支跟踪远程分支

1
2
// 设置让本地某个分支跟踪远程的某个分支
$ git branch --set-upstream-to=origin/<branch> <branch>

克隆远程仓库

1
2
3
$ git clone <user>@<host>:/path/to/repository/<project>.git
$ git clone https://gitee.com/user/<project>.git

基本操作

初始化仓库

1
2
3
$ cd ~/Desktop && mkdir example && cd example
$ git init
Initialized empty Git repository in /Users/majinyun/Desktop/example/.git/

忽略文件

GitHub 官方提供的 忽略文件模版

.gitignore 文件格式:

  • 所有空行或者以注释符号 # 开头的行都会被 git 忽略
  • 可以使用标准的 glob 模式匹配
  • 匹配模式最后跟反斜杠 / 说明要忽略的是目录
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号 ! 取反

添加文件

空目录是不能提交到仓库中的,至少要保证目录中有一个文件。

 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
// 创建一个 README.md 文件
$ touch README.md

// 查看仓库状态
$ git status
On branch master

No commits yet

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)

// 如果这个阶段你发现文件创建错误了(本不应该放置在此目录中或不需要此文件或者其它任何原因),直接删除掉即可,否则继续以下操作
$ rm -f README.md

// 添加 README.md 文件到暂存区
$ git add README.md

// 查看仓库状态
$ git status
On branch master

No commits yet

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

    new file:   README.md

// 如果这个阶段你发现此文件不应该被添加到暂存区,请不要粗暴的 rm 掉,而是使用 git rm 命令干掉它
$ git rm --cached README.md

仓库状态

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

提交文件

 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
// 将暂存区的文件提交到仓库,正常情况下会如下面的操作一样,显示文件已经被加入到版本库中,但也有不正常的情况
$ git commit -m "Add README.md"
[master (root-commit) a384a2b] Add README.md
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

// 这个就是提交时的不正常情况,什么意思呢?第一种说法的意思是需要你配置一下仓库的用户名称和邮箱地址,这个小意思,我们直接来个全局配置和局部配置就搞定了。第二种说法的意思是你在完成上面的操作之后,可以修复用于此提交的标识,说白了就是你提交到仓库后还可以进行编辑提交记录的注释信息(就是就对万一将本次提交记录的注释信息写错的情况),它会弹出你所配置的编辑器让你修改提交记录的注释信息,很遗憾这个只修改最后一个提交记录的注释信息,那么问题来了,怎么修改前 N 次的的某个提交记录的注释信息呢,这里暂时先不探究,这个涉及到 rebase 操作,足以让我再折腾一篇来专门说这种情况
$ git commit -m "Add README.md"
[master (root-commit) a384a2b] Add README.md
 Committer: user <user@user.com>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

// 配置用户和邮箱交提交到仓库,将用户和邮箱换成你自己的,这个时间代码已经被提交到仓库
$ git config user.name "yourname"
$ git config user.email "yourname@email.com"

// 查看仓库状态
$ git status
On branch master
nothing to commit, working tree clean

修改最后一次提交日志信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ vim README.md
[1]: https://symfony.com
$ git add README.md
$ git commit -m "Add symfony link"
[master 98a19c3] Add symfony link
 1 file changed, 1 insertion(+)
$ git commit --amend
Add symfony website link # 编辑此信息

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Dec 30 19:22:08 2018 +0800
#
# On branch master
# Changes to be committed:
#  modified:   README.md
#
[master abe0281] Add symfony website link
 Date: Sun Dec 30 19:22:08 2018 +0800
 1 file changed, 1 insertion(+)

修改最后一次提交记录时的用户信息

1
2
3
4
5
$ git commit --amend --author="peter <peter@dot.org>"
[master facc111] Add symfony website link
 Author: peter <peter@dot.org>
 Date: Sun Dec 30 19:22:08 2018 +0800
 1 file changed, 1 insertion(+)

撤销对文件内容的更改

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ vim README.md
[1]: https://symfony.com
[2]: https://symfony.com/projects
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout -- README.md

提交文件变更到仓库

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ vim README.md
[1]: https://symfony.com
[2]: https://symfony.com/projects
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git add README.md
$ git commit -m "Add projects link"
[master 7d8fcb9] Add projects link
 1 file changed, 1 insertion(+)

回滚仓库到某个提交

1
2
3
4
5
6
7
8
9
$ git log --oneline
7d8fcb9 (HEAD -> master) Add projects link
facc111 Add symfony website link
a384a2b Add README.md
$ git reset --hard facc111
HEAD is now at facc111 Add symfony website link
$ git log --oneline
facc111 (HEAD -> master) Add symfony website link
a384a2b Add README.md

撤销工作区和暂存区

  • --soft:当前分支重置到指定 commit 记录位置,索引和工作树不变
  • --mixed:当前分支重置到指定 commit 记录位置,索引被更新,工作树不变
  • --hard:当前分支重置到指定 commit 记录位置,索引和工作树都更新
 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
$ touch index.{html,js,css}
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    index.css
    index.html
    index.js

nothing added to commit but untracked files present (use "git add" to track)
$ $ git add .
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   index.css
    new file:   index.html
    new file:   index.js

// 只撤销暂存区
$ git reset HEAD

// 全部撤销
$ git reset --hard HEAD
HEAD is now at facc111 Add symfony website lin

查看已暂存和未暂存的更新

 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
$ vim README.md
[1]: https://symfony.com
[2]: https://symfony.com/projects
$ git add README.md
$ vim README.md
[1]: https://symfony.com
[2]: https://symfony.com/projects
[3]: https://symfony.com/doc/current/reference/requirements.html

// 比较工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容
$ git diff
diff --git a/README.md b/README.md
index 56737ed..4a93303 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
 [1]: https://symfony.com
 [2]: https://symfony.com/projects
+[3]: https://symfony.com/doc/current/reference/requirements.html

// 查看已经暂存起来的文件和上次提交时的快照之间的差异
$ git diff --cached
diff --git a/README.md b/README.md
index 55c6709..56737ed 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 [1]: https://symfony.com
+[2]: https://symfony.com/projects

或者

// 查看已经暂存起来的文件和上次提交时的快照之间的差异
$ git diff --staged
diff --git a/README.md b/README.md
index 55c6709..56737ed 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 [1]: https://symfony.com
+[2]: https://symfony.com/projects

// 跳过使用暂存区域,git 会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md

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

    modified:   README.md
$ git commit -am "Add projects and requirements link"
[master 7778db8] Add projects and requirements link
 1 file changed, 2 insertions(+)
$ git status
On branch master
nothing to commit, working tree clean

移除文件

https://inotes.oss-cn-beijing.aliyuncs.com/git/201901/git-remove-file.webp

 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
45
46
47
48
49
50
51
52
53
// 误删了文件,期望不产生提交记录就把文件干掉(此文件从来没提交到仓库中),通过以下的操作就可以看到此文件恢复到之前创建时的状态,此时你可以考虑删除或者做其它更改
$ touch index.html && git add index.html && rm index.html
remove index.html? y
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   index.html

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    index.html
$ git checkout -- index.html
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

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

    index.html

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

// 把文件从暂存区域移除,但仍然希望保留在当前工作区
$ git add index.html
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   index.html
$ git rm --cached index.html
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

  index.html

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

// 将未加入暂存区的文件全部清理掉,即将工作区的变更全部清理掉,需要谨慎操作
$ git clean -df
Removing index.html

移动或者重命名文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ touch index.php
$ git add index.php
$ git commit -m "Add index.php"
[master da3c74c] Add index.php
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.php
$ git mv index.php index.html
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  renamed:    index.php -> index.html

差异比较

 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 diff master develop
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index e69de29..0000000
diff --git a/README.md b/README.md
index f6f24a8..c0cd272 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,3 @@
 [3]: https://symfony.com/doc/current/reference/requirements.html
 [4]: https://symfony.com/doc/current/setup.html
 [5]: http://semver.org
-[6]: https://symfony.com/doc/current/contributing/community/releases.html

// 比较两个提交记录的所有差异
$ git diff fe3b3cf 688088f
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index e69de29..0000000
diff --git a/README.md b/README.md
index f6f24a8..c0cd272 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,3 @@
 [3]: https://symfony.com/doc/current/reference/requirements.html
 [4]: https://symfony.com/doc/current/setup.html
 [5]: http://semver.org
-[6]: https://symfony.com/doc/current/contributing/community/releases.html

// 比较两个提交中的某个文件的差异
$ git diff fe3b3cf 688088f -- README.md
diff --git a/README.md b/README.md
index f6f24a8..c0cd272 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,3 @@
 [3]: https://symfony.com/doc/current/reference/requirements.html
 [4]: https://symfony.com/doc/current/setup.html
 [5]: http://semver.org
-[6]: https://symfony.com/doc/current/contributing/community/releases.html

储藏

当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。git stash 就是解决这种问题的。

储藏任务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 假设目前工作进行了一段时间后,仓库的目前的状态
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.css
  modified:   index.html
  modified:   index.js

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

  modified:   index.html

// 此时由于紧急的任务或者 bug 需要解决,暂时将之前做的任务暂存起来
$ git stash
Saved working directory and index state WIP on master: fe3b3cf Integrating submission logs

// 获取一个干净的工作目录
$ git status
On branch master
nothing to commit, working tree clean

查看储藏任务列表

1
2
3
$ git stash list
stash@{0}: WIP on master: fe3b3cf Integrating submission logs
stash@{1}: WIP on master: fe3b3cf Integrating submission logs

应用最近的储藏

 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
45
46
47
48
49
50
51
52
53
54
55
56
57
// apply 选项并不会删除储藏
$ git stash apply
$ git stash apply stash@{0}
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   README.md

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

// 此时应用储藏时与之前储藏时的文件状态不一致
$ git stash apply stash@{1}
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   index.css
  modified:   index.html # 看这个文件之前储藏时的状态
  modified:   index.js

// 带上一个 --index 的选项来告诉命令重新应用被暂存的变更
$ git stash apply stash@{0} --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.css
  modified:   index.html
  modified:   index.js

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

  modified:   index.html # 文件暂存状态恢复了

// 应用储藏后立即删除储藏
$ git stash pop --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.css
  modified:   index.html
  modified:   index.js

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

  modified:   index.html

Dropped refs/stash@{0} (5c5c3fe5374020b5d4a1b0d5303b0cb932227134)

删除储藏

1
2
$ git stash drop stash@{0}
Dropped stash@{0} (e2ffa6a2b49d31703266cf6668f2b51f94e9d62f)

取消储藏

 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
// 在某些情况下,你可能想应用储藏的修改,在进行了一些其他的修改后,又要取消之前所应用储藏的修改
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")
$ git stash
Saved working directory and index state WIP on master: fe3b3cf Integrating submission logs
$ git stash list
stash@{0}: WIP on master: fe3b3cf Integrating submission logs
$ git stash apply stash@{0} --index
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   index.html

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

// 取消应用的储藏,没有指定默认为最近一次储藏
$ git stash show -p stash@{0} | git apply -R
$ git stash show -p | git apply -R

从储藏中创建分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ git stash branch testchanges
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.css
  modified:   index.html
  modified:   index.js

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

  modified:   index.html

Dropped refs/stash@{0} (9d514109f5cf6c23c75297af595189d5af839693)