Fork me on GitHub
KeKe Blog

Git基本命令

   Git是一个开源的分布式版本控制系统,可以有效、高速的处理或大或小的项目版本管理。Git起初是由Linus Torvalds开发的。由于在工作中需要写大量的shell和python脚本,为了方便自己的工作和修改调整,尝试使用git在linux上对相关的脚本进行版本管理,由于之前使用更多的是svn,对git的了解相对较少,只能参考这网上的相关文档一点点的熟悉和操作,期间也试过几次大坑,导致之前的数据都没了。

   目前版本控制系统主要有两种,分别是集中式版本控制系统(如CVS和SVN)和分布式版本控制系统(如Git)。

集中式版本控制系统:有一个中央服务器,所有代码库都只保存在其中,工作时都用的自己电脑,从服务器获取,提交时最终都要汇总到中心服务器。总之,服务器挂了,所有库都完蛋了。而且必须要联网的情况下才能使用,上传速度也慢。

分布式版本控制系统:分布式版本控制系统没有中央服务器,每个人的电脑上都是一个完整的版本库,只要交换对方的修改就行,把各自的修改推送给对方。而且分布式版本控制系统也有一台充当“中央服务器”的电脑,只是用来交换修改之用。

区别:集中式需要联网,分布式不需要;集中式上传速度慢,分布式快;集中式必须要有中心节点才能干活,分布式可以不需要;集中式不需要初始化很多东西就能干活,而分布式则要拷贝整个历史记录。

  好的工具,还是需要一点一点的去学习理解的。一切知识都没有捷径的,继续要理论支持,也需要实践去验证。

1 安装和创建版本库

1.1 安装配置

Mac OS,Linux和Windows对git都支持。

git基础配置:

1
2
git config --global user.name "AllenKe"
git config --global user.email "allenouyangke@icould.com"

解释:git config命令的–global参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

1.2 创建版本库

版本库=仓库(repository),也可以理解为一个目录。

Step1:Linux创建一个目录

1
mkdir -p /export/ops/ && cd /export/ops

Step2:git init将目录变成Git可以管理的仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
git init
# 使用tree命令查看.git目录结构
[root@test ops]# tree -L 1 .git
.git
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
├── index
├── info
├── logs
├── objects
├── ORIG_HEAD
└── refs

Step3:添加文件到Git仓库里

1
2
3
4
5
6
7
8
9
# 新建README.txt文件
[root@test ops]# ll
-rw-r--r-- 1 root root 0 3月 23 16:30 README.txt
# 使用git来add和commit
git add README.txt
git commit -m "Add the README.txt"
0 files changed
create mode 100644 readme.txt

2 版本管理

2.1 版本修改查看

在README.txt中添加“This is the README.txt!”,然后使用git status查看相关的状态

1
2
3
4
5
6
7
[root@test ops]# vim README.txt
[root@test ops]# git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: README.txt

git diff查看文件的修改的内容

1
2
3
4
5
6
7
8
[root@test ops]# git diff README.txt
diff --git a/README.txt b/README.txt
index a92611d..0bc488b 100644
--- a/README.txt
+++ b/README.txt
@@ -1 +1 @@
-This is my README.tx!
+This is my README.txt!

然后git add添加进缓存区

1
2
3
4
5
6
7
[root@test ops]# git add README.txt
[root@test ops]# git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: README.txt

使用gitcommit提交到仓库

1
2
3
[root@test ops]# git commit -m "modify the README.txt"
[master 091320b] modify the README.txt
1 files changed, 1 insertions(+), 0 deletions(-)

2.2 版本回退

git log可以查看最近到最远的详细提交日志

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@test ops]# git log
commit 091320b2ab5d20a72c58e4c8e70c9c678551221c
Author: AllenKe <allenouyangke@icloud.com>
Date: Sat Mar 31 14:11:18 2018 +0800
modify the README.txt
commit 204e91dac20c40b329a3c972be3c64a41a0b9ee6
Author: AllenKe <allenouyangke@icloud.com>
Date: Thu Mar 29 22:19:34 2018 +0800
Add the s3list
......

git log --pertty=oneline简略显示最近的日志

1
2
3
4
5
6
7
8
9
[root@test ops]# git log --pretty=oneline
091320b2ab5d20a72c58e4c8e70c9c678551221c modify the README.txt
204e91dac20c40b329a3c972be3c64a41a0b9ee6 Add the s3list
3da50549f39193f3af73501f0e0b859e93148258 Add the ansible
951af1ada93b38fc089870f0a10f20d0709f17a9 add the fabfile,serlist,nginx and python
a80d7e408d41db822861b4179dd52685dd6fb240 The 2th README.txt
7749c88c5d441842b81f37d9df594df9d13a7427 The version for README.txt
3f5d17cd0d34a3dcc5a50437a93bd2248a7f0824 Add some content to README.txt
f8adb270983e759cdc6bdf4010722e347d7885d8 add the README.txt

在Git中使用HEAD^表示上一个版本,HEAD^^表示上上个版本。

git reset --hard HEAD^回退到上一个版本

git reset --hard 091320b2回退到指定版本

回退到某个版本后,若是又想恢复到新版本,先执行git reflog找到历史命令中要恢复的版本commit id,然后执行git reset --hard commit_id

2.3 工作区和缓存区

Git和其他版本控制系统不同的是拥有一个暂存区的概念

  • 工作区(Working Directory):就是在电脑中能看到的目录
  • 版本库(Repository):即工作区中的隐藏目录“.git”

GIT的版本库里存了最终能够的称为stage或者叫index的暂存区

Git会自动创建的第一个分支master和指向master的一个指针HEAD

暂存区就是存放修改后的代替叫文件,git add命令就是将要提交的所有修改放到暂存区(Stage),而git commit命令就是将暂存区的所有修改提交到分支。

2.4 管理修改

git diff HEAD -- README.txt查看工作区和版本库里面最新版本的修改信息。

每次修改文件后,若是不把修改内容add进暂存区,就无法加入到commit中。

2.5 撤销修改

git checkout -- file可以丢弃工作区的修改,有可能回到最近一次的git commit状态或是git add的状态。

1
note: git checkout file #表示创建一个file新分支

git reset HEAD file把暂存区的修改撤销(unstage),重新返回工作区

git reset命令既可以回退版本,也可以吧暂存区的修改回退到工作区。当用HEAD时,便是最新的版本。

2.6 删除文件

本地命令删除rm README.txt,然后版本库中删除命令git rm README.txt

git checkout -- README.txt若是删除后想恢复

3 远程仓库

   Github托管:注册帐号后,本地Git仓库和Git远程仓库之间的传输是通过SSH加密的。
设置如下:
Step1:创建SSH Key,Shell下或Git bash下执行——$ ssh-keygen -t rsa -C “邮件地址”,一路设置,最终在用户主目录年里面生成ssh目录,里面包含公/私钥两个文件。
Step2:登录Github,打开“Account settings”,“SSH Keys”页面,然后点击“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa_pub文件内容,然后点击“Add Key”,Key添加成功。

GitHub允许添加多个Key,以便可以在多台电脑上进行提交。

3.1 添加远程库

在Github上创建一个仓库,以便与本地仓库同步。

由于Github上的learn_android仓库是空的,需要将本地仓库与之关联。
本地仓库下执行:

1
2
# origin是远程仓库名,可以替换。
$ git remote add origin git@github.com:GitHub账号名/learn_android.git

将当前分支master推送到远程仓库。
第一次推送加-u参数,不仅为了将本地的master分支推送到远程新的master分支,还可以将本地的master分支和远程master分支关联起来,以便以后的推送和拉去中简化命令。

1
2
3
4
5
# 第一次推送
git push -u origin master
# 一般推送
git push origin master

3.2 从远程库克隆

git clone克隆一个本地库

$ git clone git@github.com:GitHub账号名/仓库名.gitSSH方式

**https://github.com/Https方式

GitHub账号名/仓库名.git\
Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快

4 分支管理

4.1 创建分支和合并分支

创建dev分支,然后切换到dev分支

1
2
3
4
5
6
7
$ git checkout -b dev
Switched to a new branch 'dev'
## 等同于
$ git branch dev
$ git checkout dev
Switched to branch 'dev'

git branch查看分支

1
2
3
[root@test ops]# git branch
* dev
master

切换回master分支

1
2
3
4
5
6
7
8
9
10
[root@test ops]# git checkout master
M README.txt
D install/nginx.py
D install/nginx.pyc
D install/python.py
D install/python.pyc
Switched to branch 'master'
[root@test ops]# git branch
dev
* master

合并dev分支到master分支

1
2
3
4
5
6
[root@test ops]# git merge dev
Updating 091320b..fb8c40b
# Fast-forward表示“快进模式”
Fast-forward
README.txt | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

合并后删除dev分支

1
2
3
4
5
[root@test ops]# git branch -d dev
Deleted branch dev (was fb8c40b).
# 再次查看,只剩下master分支了
[root@test ops]# git branch
* master

4.2 解决冲突

当Git无法自动合并分支时,必须先解决冲突。
冲突解决后,再add和commit。

git log --graph查看分支合并图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 方法1
[root@test ops]# git log --graph --pretty=oneline
* fb8c40bf5aa051449de0832426fdfd7bceaadf14 dev modify the README.txt
* 091320b2ab5d20a72c58e4c8e70c9c678551221c modify the README.txt
* 204e91dac20c40b329a3c972be3c64a41a0b9ee6 Add the s3list
* 3da50549f39193f3af73501f0e0b859e93148258 Add the ansible
* 951af1ada93b38fc089870f0a10f20d0709f17a9 add the fabfile,serlist,nginx and pyth
* a80d7e408d41db822861b4179dd52685dd6fb240 The 2th README.txt
* 7749c88c5d441842b81f37d9df594df9d13a7427 The version for README.txt
* 3f5d17cd0d34a3dcc5a50437a93bd2248a7f0824 Add some content to README.txt
* f8adb270983e759cdc6bdf4010722e347d7885d8 add the README.txt
# 方法2
[root@test ops]# git log --graph --pretty=oneline --abbrev-commit
* fb8c40b dev modify the README.txt
* 091320b modify the README.txt
* 204e91d Add the s3list
* 3da5054 Add the ansible
* 951af1a add the fabfile,serlist,nginx and python
* a80d7e4 The 2th README.txt
* 7749c88 The version for README.txt
* 3f5d17c Add some content to README.txt
* f8adb27 add the README.txt

4.3 分支管理策略

   通常,合并分支时,如果可能,Git会用“Fast forward”模式,但这种模式下,删除分支后,会丢掉分支信息,所以若是想要保留合并的历史,在merge时加上–no-ff参数就会使用普通模式进行合并,而且合并后在版本库中会有记录。

1
2
# 普通模式进行合并,需要加上--no-ff选项
git merge --no-ff -m "merge with no-ff" dev

4.4 Bug分支

若是在某个开发分支工作进行到一半,需要修复一个已有版本的bug,那么先将工作现场储藏起来,执行以下命令:

1
2
3
4
git stash
Saved working directory and index state WIP on dev: 6224937 add
merge
HEAD is now at 6224937 add merge

假设需要在master分支进行修改,则创建临时分区,执行以下命令:

1
2
3
4
5
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
$ git checkout -b issue-101
Switched to a new branch 'issue-101'

修改完成后在master分支进行修改,则创建爱你临时分支

1
2
3
4
5
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
$ git checkout -b issue-101
Switched to a new branch 'issue-101'

修改完成后在合并,然后撒谎年初临时分支,最后再切回之前的开发分支

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 checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
# 合并分支
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
# 删除临时分支
$ git branch -d issue-101
Deleted branch issue-101 (was cc17032).
# 切换会之前的开发分支
$ git checkout dev
Switched to branch 'dev'
$ git status
# On branch dev
nothing to commit (working directory clean)
# 查看stash的内容
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge

恢复之前保存的内容,并将stash的内容删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ 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} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)

git stash apply恢复
git stash drop删除

4.5 Feature分支

开发一个新feature时,最好新建一个分支,若是要丢弃一个没有被合并过的分支,执行强制删除命令:* git branch -D 分支名称*

4.6 多人协作

查看远程库的信息

1
2
3
git remote
# 或更详细信息
git remote -v

git push origin master推送本地master分支到远程库

git push origin dev推送本地dev分支到远程库

git checkout -b dev origin/dev假设要在dev分支上开发,则创建远程仓库origin的dev分支到本地

注意:git push origin dev若是失败,就先用git pull从origin/dev拉取更新,本地合并解决冲突后再推送,若git pull也失败,出现“no tracking information”提示,原因可能是没有指定本地dev分支与远程origin/dev分支的链接,那么,我们设置链接:

1
2
3
4
5
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
# 然后再执行推送
git pull

故障排查:

  • 首先,可以试图用 git push origin branch-name 推送自己的修改;
  • 如果推送失败,则因为远程分支比你的本地更新,需要先用 git pull试图合并;
  • 如果合并有冲突,则解决冲突,并在本地提交;
  • 没有冲突或者解决掉冲突后,再用git push origin branch-name 推送就能成功。

5 标签管理

5.1 创建标签

切换到打标签的分支

1
2
3
4
5
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'

打标签

1
2
# 格式:git tab name
git tag v1,0

查看所有标签

1
2
$ git tag
v1.0

在commit id是“6224937”的版本上打标签

1
2
$ git tag v0.9 6224937
# 注:标签不是按时间顺序列出,而是按字母排序的。

查看标签信息

1
2
# 格式:git show tagname
$ git show v0.9

创建带有说明的标签:-a指定标签名,-m指定说明文字

1
$ git tag -a v0.1 -m "version 0.1 released" 3628164

通过-s用私钥签名(签名采用PGP签名的)

1
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a

5.2 操作标签

标签打错了,需要删除

1
2
$ git tag -d v0.1
Deleted tag 'v0.1' (was e078af9)

推送某个标签到远程

1
2
3
4
5
# 格式:git push origin tagname
$ git push origin v1.0
# 一次性推送全部尚未推送的到远程的标签
$ git push origin --tags

标签已推送到远程,先从本地删除

1
$ git tag -d v0.9

然后从远程删除。

1
$ git push origin :refs/tags/v0.9

6 自定义Git

Git显示颜色

1
$ git config --global color.ui true

配置别名

1
2
3
4
5
6
7
8
# 配置git status的别名为st
$ git config --global alias.st status
# 配置reset HEAD的别名为unstage
$ git config --global alias.unstage 'reset HEAD'
# 配置一个git last,让其显示最后一次提交信息
$ git config --global alias.last 'log -1'

配置又颜色格式等信息的log

1
2
3
$ git config --global alias.lg "log --color --graph --
pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)
%C(bold blue)<%an>%Creset' --abbrev-commit"

7 参考资料

Git教程

Git基本命令使用

-------------本文结束 感谢您的阅读-------------