git使用文档

一、创建版本库

1、本地仓库

1、创建文件夹,使用该文件夹作为仓库根目录

1
2
3
4
$ mkdir repo #创建文件夹,名字为repo
$ cd repo #进入repo目录
$ pwd
/home/power/root

2、通过git init 命令来初始化仓库

1
2
$ git init
Initialized empty Git repository in /home/power/root

2、远程仓库

1)查看远程仓库信息

1
2
3
4
# 查看关联的远程仓库的名称
git remote
# 查看关联的远程仓库的详细信息
git remote -v
  1. 添加远程仓库的关键

远程仓库的名称一般默认为 origin ,当然,你可以设置为其他的名称。

通过 git clone 下载项目到本地时,项目文件夹中的 .git 目录就是版本库目录。

.git 目录中的 config 文件中有远程仓库的关联配置。

1
2
# git_url 为你的远程仓库的 url,可采用 http 协议或 ssh(git) 协议
git remote add origin <url>

3)删除远程仓库的关联

1
git remote remove <name>

4)修改远程仓库的关键

方式一:

1
git remote set-url origin <newurl>

方式二: 先删除再添加

1
2
3
4
5
# 删除关联的远程仓库
git remote remove <name>

# 添加新的远程仓库关联
git remote add <name> <url>

方式三:直接修改.git目录下的config配置文件

二、提交文件

1、在 /home/power/root 下创建 test.txt 文件,并输入一些文字

1
2
3
4
5
6
7
8
$ touch test.txt	# 创建test.txt文件
$ vi test.txt # 编辑test.txt文件,进入新窗口,按 i 进入插入模式,输入文本后按 ESC -> :wq
$ cat test.txt # 查看test.txt内容
this is a new file # 这里test.txt内部的文字,直接在控制台输出
$ pwd
/home/power/root
$ ls -a
.git test.txt

2、使用 git add <filename | . > 文件添加到本地仓库

1
$ git add test.txt

完成,没有任何的输出。

git add filename :将指定的文件添加到仓库

git add .. (点)用来代替当前文件及其子文件添加到仓库。

3、使用 git commit -m <message> 告诉 git 将使用 git add 命令添加的内容提交到仓库

1
2
$ git commit -m "添加了新文件"
[master ...]

-m 参数用于为本次提交添加评论,可以根据自己的情况添加更有意义的评论内容。

注:

git add 可以使用多次,多次提交仅需要使用一次 git commit 就可完成提交

三、版本回退

1、快照、版本

在 git 中,一次 commit 被称为一个快照(版本),下面让我们多次修改文件并提交。

版本1:添加了新文件

1
this is a new file

版本2:修改了文件

1
this is a update file

版本3:再次修改了文件

1
this is a file with update

2、查看提交记录

使用 git log 命令可以查看我们每次提交的ID、日期、提交人和评论。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git log
commit ba26d28a0473efc9f4077aa4605057dd6c9248f2 (HEAD -> master) # ID
Author: unknown <zhoutaotao@bojoy.net> #提交人
Date: Fri May 10 10:30:32 2019 +0800 # 提交时间

再次修改了文件 #提交时添加的评论

commit 22844da5053b6516b3e8a52d0972f23b6ad53254
Author: unknown <zhoutaotao@bojoy.net>
Date: Fri May 10 10:30:01 2019 +0800

修改了文件

commit d4adfa45270384a698c8aea37425a73234218ba6
Author: unknown <zhoutaotao@bojoy.net>
Date: Fri May 10 10:21:56 2019 +0800

添加了新文件

如果git log 命令执行后发现输出的内容过多,那么,我们可以通过添加 --pretty=oneline 来使得输出一行显示

1
2
3
4
$ git log --pretty=oneline
ba26d28a0473efc9f4077aa4605057dd6c9248f2 (HEAD -> master) 再次修改了文件
22844da5053b6516b3e8a52d0972f23b6ad53254 修改了文件
d4adfa45270384a698c8aea37425a73234218ba6 添加了新文件

3、回退版本

在 git 中,用 HEAD 表示当前版本,也就是最新提交的ID为“ba26d28…”,上一个版本就是 HEAD^,上上个版本就是 HEAD^^,如果我们要会退到前100个版本,我们可以使用 HEAD~100。这种方式也进适用于最近的几个版本之间回退。

git reset命令用来回退版本。

1
2
3
4
$ git reset --hard HEAD^
HEAD is now at 22844da 修改了文件
$ cat test.txt
this is a update file # 发现文件已经会退到第二版

如果我们回退版本时发现自己回退错了版本,那怎么办?先让 git log命令看看日志变化

1
2
3
$ git log --pretty=oneline
22844da5053b6516b3e8a52d0972f23b6ad53254 (HEAD -> master) 修改了文件
d4adfa45270384a698c8aea37425a73234218ba6 添加了新文件

从日志中可以发现,第三版提交的记录居然不存在了,我们想要回到第三版怎么办?

git reset --hard <id> 可以帮助我们会退到第三版,前提是我们并没有关闭当前的命令行,可以从控制台的日志中找到第三版的ID。

1
2
3
4
$ git reset --hard ba26d28
HEAD is now at ba26d28 再次修改了文件
$ cat test.txt
this is a file with update #第三版的文件内容又回来了

但是通过刚才的命令我们发现,第三版的ID是一长串内容,而我们只写了前几位,这样真的可以?答案是可以的。git 会通过给定的前几位去查找ID,如果查找的ID唯一,就正常执行命令。否则命令错误。

但是,如果我们关闭了当前控制台窗口,没办法在窗口中找到提交记录的ID怎么办?

总是会有办法的,我们可以使用 git reflog 查询到 git 指针的所有操作记录

1
2
3
4
5
6
$ git reflog
ba26d28 (HEAD -> master) HEAD@{0}: reset: moving to ba26d28
22844da HEAD@{1}: reset: moving to HEAD^
ba26d28 (HEAD -> master) HEAD@{2}: commit: 再次修改了文件
22844da HEAD@{3}: commit: 修改了文件
d4adfa4 HEAD@{4}: commit (initial): 添加了新文件

这样,我们就可以找到指定的版本号了。

4、查看当前文件状态

git status可以查看当前工作区文件的状态。

1
2
3
4
5
6
7
8
9
$ 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: test.txt

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

5、文件与版本库对比

git diff <id> -- <filename>可以查看指定文件与版本库之间的差异

1
2
3
4
5
6
7
8
$ git diff d4adfa4 -- test.txt
diff --git a/test.txt b/test.txt
index 3b2aed8..d2a9c10 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-this is a new file
+this is a file with update

6、撤销修改

git checkout -- <file>可以将指定文件回退到最近一次 git addgit commit状态

1
2
3
4
$ git checkout -- test.txt
$ git status
On branch master
nothing to commit, working tree clean

如果我们已经通过 git add 将文件添加到缓存区,但还没有执行 git commit 命令,我们可以使用 git reset HEAD <file> 将缓存区的内容撤销掉,重新放入工作区。再次通过 git checkout -- <file> 将文件回退。

7、删除文件

git rm <file> 用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容

四、分支管理

1、创建分支

首先,我们创建dev分支,然后切换到dev分支:

1
2
$ git checkout -b dev
Switched to a new branch 'dev'

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

1
2
3
$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后,用git branch命令查看当前分支:

1
2
3
$ git branch
* dev
master

git branch命令会列出所有分支,当前分支前面会标一个*号。

我们可以在当前分支上工作,工作完成后通过 git commit进行提交

2、合并分支

现在,我们把dev分支的工作成果合并到master分支上:

1
2
3
4
5
$ git merge dev
Updating d46f35e..b17d20e
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)

git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

用带参数的git log也可以看到分支的合并情况:

1
2
3
4
5
6
$ git log --graph --pretty=oneline --abbrev-commit
* cf810e4 (HEAD -> master) conflict fixed
|\
| * 14096d0 (feature1) AND simple
* | 5dc6824 & simple
|/

3、删除分支

合并完成后,就可以放心地删除dev分支了:

1
2
$ git branch -d dev
Deleted branch dev (was b17d20e).

删除后,查看branch,就只剩下master分支了:

1
2
$ git branch
* master

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

注:如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除。

4、分支管理策略

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

下面我们实战一下--no-ff方式的git merge

首先,仍然创建并切换dev分支:

1
2
$ git checkout -b dev
Switched to a new branch 'dev'

修改readme.txt文件,并提交一个新的commit:

1
2
3
4
$ git add readme.txt 
$ git commit -m "add merge"
[dev f52c633] add merge
1 file changed, 1 insertion(+)

现在,我们切换回master

1
2
$ git checkout master
Switched to branch 'master'

准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward

1
2
3
4
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

合并后,我们用git log看看分支历史:

1
2
3
4
5
6
7
$ git log --graph --pretty=oneline --abbrev-commit
* e1e9c68 (HEAD -> master) merge with no-ff
|\
| * f52c633 (dev) add merge
|/
* cf810e4 conflict fixed
...

在实际开发中,我们应该按照几个基本原则进行分支管理:

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

5、隐藏工作细节

git stash 可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作

1
2
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge

查看隐藏的工作空间

1
2
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;

另一种方式是用git stash pop,恢复的同时把stash内容也删了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ git stash pop
On branch dev
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: hello.py

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.txt

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

你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

1
$ git stash apply stash@{0}

6、多人协作

  1. 首先用git clone <path>拉取分支
  2. 查看远程库信息git remote -v
  3. 试图用git push origin <branch-name>推送自己的修改;
  4. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  5. 如果合并有冲突,则解决冲突,并在本地提交;
  6. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

7、美化提交线

  • rebase操作可以把本地未push的分叉提交历史整理成直线;
  • rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
1
$ git rebase

8、创建远程分支

  1. 新建本地分支
1
git checkout -b dev
  1. 将本地分支推送到远程
1
git push origin dev:dev

前一个dev是本地分支的名称,后一个dev是远程分支的名称

9、删除远程分支

方式一: 直接推送一个空分支到远程分支,相当于删除远程分支

1
git push origin :dev

方式二:指定--delete参数

1
git push origin --delete dev

五、标签管理

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。

tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。

1、创建标签

  • 命令git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id;
  • 命令git tag -a <tagname> -m "blablabla..."可以指定标签信息;
  • 命令git tag可以查看所有标签。

2、操作标签

  • 命令git push origin <tagname>可以推送一个本地标签;
  • 命令git push origin --tags可以推送全部未推送过的本地标签;
  • 命令git tag -d <tagname>可以删除一个本地标签;
  • 命令git push origin :refs/tags/<tagname>可以删除一个远程标签。

六、自定义git

  • 配置邮箱:git config --global user.email <mail>
  • 配置用户名:git config --global user.name <name>
  • 配置控制台颜色:git config --global color.ui true

1、忽略特殊文件

  • 忽略某些文件时,需要编写.gitignore
  • .gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
  • git add -f <file> 强制添加文件
  • git check-ignore -v <file> 检查配置文件错误,git会提示配置文件中的那条规则把指定文件排除了。

2、配置别名

git config --global alias.别名 命令可以为命令配置别名。

--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。

3、配置文件

配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat .git/config 
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:michaelliao/learngit.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[alias]
last = log -1

别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:

1
2
3
4
5
6
7
8
9
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com

配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。

七、命令总结

命令 解释
git init 初始化仓库
git add <file> 添加文件到临时区
git add -f <file> 强制添加文件到临时区
git commit -m <msg> 提交文件到分支
git reset --hard commit_id 恢复文件到指定版本
git log --graph --pretty=oneline --abbrev-commit 单行显示提交历史信息
git reflog 查看命令历史
git status 查看工作区状态
git rm <file> 删除指定文件
git branch 查看所有分支
git branch <name> 创建分支
git checkout <name> 切换分支
git checkout -b <name> 创建 + 切换分支
git merge <name> 合并分支
git merge --no-ff -m <msg> 禁用快速合并并添加标签,分支历史看以看到分支信息
git branch -d <name> 删除分支
git branch -D <name> 强制删除分支
git stash 保存工作现场并隐藏
git stash list 查看隐藏的工作现场
git stash apply 恢复工作现场,stash内容不删除
git stash apply <stash@{0}> 恢复到指定的工作现场,stash内容不删除
git stash drop 删除工作现场
git stash pop 恢复工作现场,并删除stash内容
git stash pop <stash@{0}> 恢复到指定的工作现场,并删除stash内容
git remote -v 查看远程库信息
git push origin master 将master分支推送到远程库
git clone <path> 从远程库克隆信息
git pull <remote> <branch> 抓取远程的新提交
git checkout -b branch-name origin/branch-name 在本地床架和远程分支对应的分支,本地和远程分支的名称最好保持一致
git branch --set-upstream branch-name origin/branch-name 建立本地分支和远程分支的关联
git rebase 合并分支提交线
git tab <tagname> -m <msg> <commit-id> 新建标签,默认为 HEAD,也可以指定一个 commit-id
git tag 查看所有标签
git show <tagname> 查看标签信息
git tag -d <tagname> 删除标签
git push origin <tagname> 推送标签到远程
git push origin --tags 一次性推送所有未推送的标签到远程
git push origin :refs/tags/<tagname> 删除远程标签,需要先删除本地标签
git config --global user.email <mail> 配置全局邮箱
git config --global user.name <name> 配置全局用户名
git config --global color.ui true 显示控制台颜色
git config alias.<aliasname> <commend> 为commend配置别名为aliasname,复合命令要使用单引号包裹
git check-ignore -v <file> 检查配置文件错误