0%

Git笔记

Git是目前世界上最先进的分布式版本控制系统,版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。

创建一个版本库并进行初始化,Git自动为我们创建了唯一一个master分支。提交更改,实际上就是把暂存区的所有内容提交到当前分支。

创建版本库

1
2
3
4
5
6
7
8
9
#创建repository
$ mkdir Git #在工作区生成文件夹
$ cd Git
$ pwd
/home/houmin/Git

#初始化repository
$ git init #把这个目录变成git可以管理的仓库,初始化后在当前目录下会出现.git文件
Initialized empty Git repository in /home/houmin/Git/.git/

把文件添加到版本库

在Git目录下编写README

1
2
Git is a version control system.
Git is free software.

1
2
3
4
5
6
7
8
#把文件添加到仓库
$ git add README

#把文件提交到仓库
$ git commit -m "wrote a README file"
[master (root-commit) 426ef38] wrote a README file
1 file changed, 2 insertions(+)
create mode 100644 README

查看版本状态

将README修改成

1
2
Git is a distributed version control system.
Git is free software.

使用git status命令
1
2
3
4
5
6
7
8
9
houmin@cosmos:~/Git$ 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

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

如果想要查看具体修改了什么,可以使用git diff命令
1
2
3
4
5
6
7
8
9
houmin@cosmos:~/Git$ git diff README
diff --git a/README b/README
index 380bce1..a5ea0a2 100644
--- a/README
+++ b/README
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is distributed a version control system.
Git is free software

关于git diff
1
2
git diff    #是工作区(work dict)和暂存区(stage)的比较
git diff --cached #是暂存区(stage)和分支(master)的比较

查看快照记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
houmin@cosmos:~/Git$ git log
commit 4a9cf61afe93d8b59894d8daf5f7c951be4a6936
Author: SimpCosm <weihoumin@gmail.com>
Date: Sat Mar 4 09:37:48 2017 +0800

add GPL

commit d4dd11712513cd30b029a41f66e48b173af5c910
Author: SimpCosm <weihoumin@gmail.com>
Date: Sat Mar 4 09:34:41 2017 +0800

add distributed

commit 426ef38f6f0791079ea54a7fff88015578697a3c
Author: SimpCosm <weihoumin@gmail.com>
Date: Fri Mar 3 20:39:38 2017 +0800

wrote a README file

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

1
2
3
4
houmin@cosmos:~/Git$ git log --pretty=oneline
4a9cf61afe93d8b59894d8daf5f7c951be4a6936 add GPL
d4dd11712513cd30b029a41f66e48b173af5c910 add distributed
426ef38f6f0791079ea54a7fff88015578697a3c wrote a README file

版本回退

首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交4a9cf6…be4a6936,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

现在,我们要把当前版本“append GPL”回退到上一个版本“add distributed”,就可以使用git reset命令:

1
2
houmin@cosmos:~/Git$ git reset --hard HEAD^
HEAD is now at d4dd117 add distributed

Git提供了一个命令git reflog用来记录你的每一次命令:

1
2
3
4
5
houmin@cosmos:~/Git$ git reflog
d4dd117 HEAD@{0}: reset: moving to HEAD^
4a9cf61 HEAD@{1}: commit: add GPL
d4dd117 HEAD@{2}: commit: add distributed
426ef38 HEAD@{3}: commit (initial): wrote a README file

撤销工作区的修改

修改README为

1
2
3
Git is distributed a version control system.
Git is free software
My Boss is stupid

这个时候查看状态
1
2
3
4
5
6
7
8
9
houmin@cosmos:~/Git$ 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

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

可以使用git checkout -- <file>丢弃工作区的修改
1
houmin@cosmos:~/Git$ git checkout -- README

撤销暂存区的修改

如果我将上面那个add到暂存区,那么用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:

1
2
3
4
5
6
7
8
9
10
11
12
houmin@cosmos:~/Git$ git reset HEAD README
Unstaged changes after reset:
M README
houmin@cosmos:~/Git$ 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

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

然后这个时候再使用git checkout -- <file>即可撤销工作区的修改。

删除文件

假设现在版本库里面有LICENCE这个文件,命令行下删除

1
2
3
4
5
6
houmin@cosmos:~/Git$ git status
On branch master
nothing to commit, working directory clean
houmin@cosmos:~/Git$ ls
LICENCE README
houmin@cosmos:~/Git$ rm LICENCE

查看状态
1
2
3
4
5
6
7
8
9
houmin@cosmos:~/Git$ git status
On branch master
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: LICENCE

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

现在有两种选择

  • 确实是要从版本库里面删除LICENCE
    1
    2
    3
    4
    5
    6
    houmin@cosmos:~/Git$ git rm LICENCE
    rm 'LICENCE'
    houmin@cosmos:~/Git$ git commit -m "rm LICENCE"
    [master 35d660e] rm LICENCE
    1 file changed, 1 deletion(-)
    delete mode 100644 LICENCE
  • 撤销删除
    1
    $ git checkout -- LICENCE

分支管理

创建分支

git初始化的时候默认创建master分支。HEAD严格来说不指向提交,而是指向master,master才是指向提交的。当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上。

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
houmin@cosmos:~/Git$ git branch dev     #创建分支dev
houmin@cosmos:~/Git$ git checkout dev #切换到分支dev
Switched to branch 'dev'
houmin@cosmos:~/Git$ git branch #查看分支
* dev
master
houmin@cosmos:~/Git$ ls
README
houmin@cosmos:~/Git$ vim BRANCH #在分支dev上添加BRANCH文件
houmin@cosmos:~/Git$ git status
On branch dev
Untracked files:
(use "git add <file>..." to include in what will be committed)

BRANCH

nothing added to commit but untracked files present (use "git add" to track)
houmin@cosmos:~/Git$ git add BRANCH
houmin@cosmos:~/Git$ git commit -m "add BRANCE at branch dev"
[dev 02cb6cb] add BRANCE at branch dev
1 file changed, 1 insertion(+)
create mode 100644 BRANCH
houmin@cosmos:~/Git$ ls
BRANCH README
houmin@cosmos:~/Git$ git checkout master #切换到master分支
Switched to branch 'master'
houmin@cosmos:~/Git$ ls
README

合并分支

我们可以使用git merge合并指定分支到当前分支。

1
2
3
4
5
6
houmin@cosmos:~/Git$ git merge dev
Updating 35d660e..02cb6cb
Fast-forward
BRANCH | 1 +
1 file changed, 1 insertion(+)
create mode 100644 BRANCH

这里采用的是Fast-forward的合并方式,就是直接把master指向dev的当前提交。

删除分支

git branch -d dev可以 删除分支

1
2
3
4
5
6
7
8
9
houmin@cosmos:~/Git$ git branch
dev
* master
houmin@cosmos:~/Git$ git branch -d dev
Deleted branch dev (was 02cb6cb).
houmin@cosmos:~/Git$ git b
bisect blame branch bundle
houmin@cosmos:~/Git$ git branch
* master

远程仓库

创建SSH Key

在github上面创建Git仓库

添加远程仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 在本地仓库文件夹下添加远程仓库
houmin@cosmos:~/Git$ git remote add origin git@github.com:SimpCosm/Git.git
# 添加后,远程库的名字就是origin,这是Git默认的叫法

# 下一步,把本地仓库的所有内容推送到远程仓库
houmin@cosmos:~/Git$ git push -u origin master
Counting objects: 16, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (16/16), 1.43 KiB | 0 bytes/s, done.
Total 16 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To git@github.com:SimpCosm/Git.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.

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

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

推送成功后,可以立刻在GitHub页面中看到远程库的内容已经和本地一模一样。

learning git
从现在起只要在本地做了提交,就可以通过命令

1
$ git push origin master

把master分支的最新修改提交到远程仓库。

从远程仓库克隆

现在我们在github上面有一个musicbox仓库,我们可以通过git clone把它克隆到本地。

1
2
3
4
5
6
7
8
9
10
houmin@cosmos:~$ git clone git@github.com:SimpCosm/musicbox.git
Cloning into 'musicbox'...
remote: Counting objects: 349, done.
remote: Total 349 (delta 0), reused 0 (delta 0), pack-reused 349
Receiving objects: 100% (349/349), 69.87 KiB | 84.00 KiB/s, done.
Resolving deltas: 100% (222/222), done.
Checking connectivity... done.
houmin@cosmos:~$ cd musicbox/
houmin@cosmos:~/musicbox$ ls
flavor.json LICENSE.txt NEMbox README.md setup.py

管理标签

创建标签

1
2
3
houmin@cosmos:~/Git$ git tag v0.1       # 创建标签
houmin@cosmos:~/Git$ git tag # 查看标签
v0.1

默认标签是打在最新提交的commit上的,也可以使用git tag <tag-name> <commit-id>来给之前的commit添加标签。
在使用git tag查看标签的时候,不是按时间顺序输出的,而是按字母顺序。可以用git show <tag-name>查看标签信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
houmin@cosmos:~/Git$ git show v0.1
commit 674a26838d4654340e9f587bb701c5588e853ea3
Author: SimpCosm <weihoumin@gmail.com>
Date: Sat Mar 4 11:15:33 2017 +0800

add SLAVE at branch slave

diff --git a/SLAVE b/SLAVE
new file mode 100644
index 0000000..24083a9
--- /dev/null
+++ b/SLAVE
@@ -0,0 +1 @@
+we are now at branch slave

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字,并且可以在git show输出看到说明文字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
houmin@cosmos:~/Git$ git show v0.01
tag v0.01
Tagger: SimpCosm <weihoumin@gmail.com>
Date: Sat Mar 4 11:29:04 2017 +0800

version 0.01 released

commit 426ef38f6f0791079ea54a7fff88015578697a3c
Author: SimpCosm <weihoumin@gmail.com>
Date: Fri Mar 3 20:39:38 2017 +0800

wrote a README file

diff --git a/README b/README
new file mode 100644
index 0000000..380bce1
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+Git is a version control system.
+Git is free software

操作标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
houmin@cosmos:~/Git$ git tag
v0.01
v0.1
houmin@cosmos:~/Git$ git tag -d v0.01 # 删除标签
Deleted tag 'v0.01' (was 252fcd1)
houmin@cosmos:~/Git$ git push origin v0.1 # 推送本地标签到远程仓库
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:SimpCosm/Git.git
* [new tag] v0.1 -> v0.1
houmin@cosmos:~/Git$ git tag -d v0.1 # 如果想要删除远程仓库的标签,先得删除本地标签
Deleted tag 'v0.1' (was 674a268)
houmin@cosmos:~/Git$ git push origin :refs/tags/v0.1 # 然后使用`git push origin :refs/tags/<tag-name>`删除远程标签
To git@github.com:SimpCosm/Git.git
- [deleted] v0.1

常见git命令补充

git pull

git pull命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并。

1
2
3
4
5
6
7
8
$ git pull <远程主机名> <远程分支名>:<本地分支名>
# 比如,取回origin主机的next分支,与本地的master分支合并,需要写成下面这样。
$ git pull origin next:master
# 如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
$ git pull origin next
# 上面命令表示,取回origin/next分支,再与当前分支合并。实质上,这等同于先做git fetch,再做git merge。
$ git fetch origin
$ git merge origin/next

在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动”追踪”origin/master分支。

Git也允许手动建立追踪关系。

1
2
3
4
5
6
7
8
git branch --set-upstream master origin/next
# 上面命令指定master分支追踪origin/next分支。
# 如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名。
$ git pull origin
#上面命令表示,本地的当前分支自动与对应的origin主机”追踪分支”(remote-tracking branch)进行合并。

# 如果当前分支只有一个追踪分支,连远程主机名都可以省略。
$ git pull

Reference