前言

在 2005 年的某一天,Linux 之父 Linus Torvalds 发布了他的又一个里程碑作品——Git。它的出现改变了软件开发流程,大大地提高了开发流畅度,直到现在仍十分流行,完全没有衰退的迹象。其实一般情况下,只需要掌握 git 的几个常用命令即可,但是在使用的过程中难免会遇到各种复杂的需求,这时候经常需要搜索,非常麻烦,故总结了一下自己平常会用到的 git 操作。本文根据团队实践记录 Git 入门指南和 Git 常用命令,文章中不仅记录了 Git 的搭建和使用教程,还参考了大量 Git 团队使用规范上的经验,希望大家可以结合自己团队的实际应用场景让 Git 协作优雅的落地。

Git 是目前世界上最先进的分布式版本控制系统

更新记录

2020 年 02 月 06 日 - 更新 Git 命令学习
2016 年 04 月 22 日 - 初稿

阅读原文 - https://wsgzao.github.io/post/git/

扩展阅读

Git Book - https://git-scm.com/book/zh/
git 简明指南 - http://rogerdudler.github.io/git-guide/index.zh.html
常用 Git 命令清单 - http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html
猴子都能懂的 GIT 入门 - http://backlogtool.com/git-guide/cn/
Git 教程 - http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

SVN 与 Git 的最主要的区别

SVN 是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。

Git 是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件 A,其他人也在电脑上改了文件 A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

Git 搭建和使用

Git 上手并不难,深入学习还是建议多实践,可以参考扩展阅读中廖雪峰的 Git 教程

Git 服务端

服务端搭建 Git 很简单,有更多需求不妨试试 Gogs 和 Gitlab

使用 Gogs 轻松搭建可能比 GitLab 更好用的 Git 服务平台 - https://wsgzao.github.io/post/gogs/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 安装 git
sudo apt-get install git
yum install git

# 创建一个 git 用户,用来运行 git 服务
sudo adduser git

# 创建证书使用公钥免密码登录(可选)
ssh-keygen -t rsa
vi ~/.ssh/authorized_keys

# 初始化 Git 仓库
sudo git init --bare sample.git
sudo chown -R git:git sample.git

# 禁用 shell 登录
vi /etc/passwd
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

# 在客户端上克隆远程仓库
git clone git@server:/srv/sample.git

管理公钥推荐使用 Gitosis
Gitosis - https://github.com/res0nat0r/gitosis
Gitosis 配置手记 - http://debugo.com/gitosis/

管理权限推荐使用 Gitolite
Gitolite - https://github.com/sitaramc/gitolite

Git 客户端

Git 客户端可以按个人习惯来选择,遵守团队协作中的 Git 规范标准才是更重要的

Git - https://git-scm.com/
TortoiseGit - https://tortoisegit.org/
SourceTree - https://www.sourcetreeapp.com/

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
# 以最基本的 Git 命令行为例,先下载 Git
https://git-scm.com/download/

# 配置 git 提交用户名和邮箱,定义别名方便区分
git config --global user.name "你的姓名"
git config --global user.email "you@example.com"

# 克隆仓库
git clone cap@172.28.70.243:/cap/cap.git

$ git clone cap@172.28.70.243:/cap/cap.git
Cloning into 'cap'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

# 测试推送
touch README
git add README
git commit -m "add readme"
git push origin master

Counting objects: 3, done.
Writing objects: 100% (3/3), 199 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To cap@172.28.70.243:/cap/cap.git
* [new branch] master -> master

Git 常用命令

符号约定

  • <xxx> 自定义内容
  • [xxx] 可选内容
  • [<xxx>] 自定义可选内容
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
# 初始设置
git config --global user.name "< 用户名 & gt;" # 设置用户名
git config --global user.email "< 电子邮件 & gt;" # 设置电子邮件

# 本地操作
git add [-i] # 保存更新,-i 为逐个确认。
git status # 检查更新。
git commit [-a] -m "< 更新说明 & gt;" # 提交更新,-a 为包含内容修改和增删,-m 为说明信息,也可以使用 -am。

# 远端操作
git clone <git 地址 & gt; # 克隆到本地。
git fetch # 远端抓取。
git merge # 与本地当前分支合并。
git pull [< 远端别名 & gt;] [< 远端 branch>] # 抓取并合并, 相当于第 2、3 步
git push [-f] [< 远端别名 & gt;] [< 远端 branch>] # 推送到远端,-f 为强制覆盖
git remote add < 别名 & gt; <git 地址 & gt; # 设置远端别名
git remote [-v] # 列出远端,-v 为详细信息
git remote show < 远端别名 & gt; # 查看远端信息
git remote rename < 远端别名 & gt; < 新远端别名 & gt; # 重命名远端
git remote rm < 远端别名 & gt; # 删除远端
git remote update [< 远端别名 & gt;] # 更新分支列表

# 分支相关
git branch [-r] [-a] # 列出分支,-r 远端 ,-a 全部
git branch < 分支名 & gt; # 新建分支
git branch -b < 分支名 & gt; # 新建并切换分支
git branch -d < 分支名 & gt; # 删除分支
git checkout < 分支名 & gt; # 切换到分支
git checkout -b < 本地 branch> [-t < 远端别名 & gt;/< 远端分支 & gt;] #-b 新建本地分支并切换到分支, -t 绑定远端分支
git merge < 分支名 & gt; # 合并某分支到当前分支

Git 常用命令

  • workspace: 本地的工作目录。(记作 A)
  • index:缓存区域,临时保存本地改动。(记作 B)
  • local repository: 本地仓库,只想最后一次提交 HEAD。(记作 C)
  • remote repository:远程仓库。(记作 D)

以下所有的命令的功能说明,都采用上述的标记的 A、B、C、D 的方式来阐述。

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
# 初始化 
git init // 创建
git clone /path/to/repository // 检出
git config --global user.email "you@example.com" // 配置 email
git config --global user.name "Name" // 配置用户名

# 操作
git add <file> // 文件添加,A → B
git add . // 所有文件添加,A → B

git commit -m "代码提交信息" // 文件提交,B → C
git commit --amend // 与上次 commit 合并, *B → C

git push origin master // 推送至 master 分支, C → D
git pull // 更新本地仓库至最新改动, D → A
git fetch // 抓取远程仓库更新, D → C

git log // 查看提交记录
git status // 查看修改状态
git diff// 查看详细修改内容
git show// 显示某次提交的内容

# 撤销操作
git reset <file>// 某个文件索引会回滚到最后一次提交, C → B
git reset// 索引会回滚到最后一次提交, C → B
git reset --hard // 索引会回滚到最后一次提交, C → B → A

git checkout // 从 index 复制到 workspace, B → A
git checkout -- files // 文件从 index 复制到 workspace, B → A
git checkout HEAD -- files // 文件从 < span class="built_in">local repository 复制到 workspace, C → A

# 分支相关
git checkout -b branch_name // 创建名叫“branch_name” 的分支,并切换过去
git checkout master // 切换回主分支
git branch -d branch_name // 删除名叫“branch_name” 的分支
git push origin branch_name // 推送分支到远端仓库
git merge branch_name // 合并分支 branch_name 到当前分支(如 master)
git rebase // 衍合,线性化的自动, D → A

# 冲突处理
git diff // 对比 workspace 与 index
git diff HEAD // 对于 workspace 与最后一次 commit
git diff <source_branch> <target_branch> // 对比差异
git add <filename> // 修改完冲突,需要 add 以标记合并成功

# 其他
gitk // 开灯图形化 git
git config color.ui true // 彩色的 git 输出
git config format.pretty oneline // 显示历史记录时,每个提交的信息只显示一行
git add -i // 交互式添加文件到暂存区

git 命令一览

Git 简明指南

命令 解析
git init 初始化本地 git 仓库(创建新仓库)
git config –global user.name “xxx” 配置用户名
git config –global user.email “xxx@xxx.com 配置邮件
git config –global color.ui true git status 等命令自动着色
git config –global –unset http.proxy remove proxy configuration on git
git clone git+ssh://git@192.168.53.168/VT.git clone 远程仓库
git status 查看当前版本状态(是否修改)
git add xyz 添加 xyz 文件至 index
git add . 增加当前子目录下所有更改过的文件至 index
git commit -m ‘xxx’ 提交
git commit –amend -m ‘xxx’ 合并上一次提交(用于反复修改)
git commit -am ‘xxx’ 将 add 和 commit 合为一步
git rm xxx 删除 index 中的文件
git rm -r * 递归删除
git log 显示提交日志
git log -1 显示 1 行日志 -n 为 n 行
git log –stat 显示提交日志及相关变动文件
git show dfb02e6xxxx 显示某个提交的详细内容
git show dfb02 可只用 commitid 的前几位
git show HEAD 显示 HEAD 提交日志
git show HEAD^ 显示 HEAD 的父(上一个版本)的提交日志 为上两个版本 5 为上 5 个版本
git tag 显示已存在的 tag
git tag -a v2.0 -m ‘xxx’ 增加 v2.0 的 tag
git show v2.0 显示 v2.0 的日志及详细内容
git log v2.0 显示 v2.0 的日志
git diff 显示所有未添加至 index 的变更
git diff –cached 显示所有已添加 index 但还未 commit 的变更
git diff HEAD^ 比较与上一个版本的差异
git diff HEAD — ./lib 比较与 HEAD 版本 lib 目录的差异
git diff origin/master..master 比较远程分支 master 上有本地分支 master 上没有的
git diff origin/master..master –stat 只显示差异的文件,不显示具体内容
git remote add origin git+ssh://git@192.168.53.168/VT.git 增加远程定义(用于 push/pull/fetch)
git branch 显示本地分支
git branch –contains 50089 显示包含提交 50089 的分支
git branch -a 显示所有分支
git branch -r 显示所有原创分支
git branch –merged 显示所有已合并到当前分支的分支
git branch –no-merged 显示所有未合并到当前分支的分支
git branch -m master master_copy 本地分支改名
git checkout -b master_copy 从当前分支创建新分支 master_copy 并检出
git checkout -b master master_copy 上面的完整版
git checkout features/performance 检出已存在的 features/performance 分支
git checkout –track hotfixes/BJVEP933 检出远程分支 hotfixes/BJVEP933 并创建本地跟踪分支
git checkout v2.0 检出版本 v2.0
git checkout -b devel origin/develop 从远程分支 develop 创建新本地分支 devel 并检出
git checkout — README 检出 head 版本的 README 文件(可用于修改错误回退)
git merge origin/master 合并远程 master 分支至当前分支
git cherry-pick ff44785404a8e 合并提交 ff44785404a8e 的修改
git push origin master 将当前分支 push 到远程 master 分支
git push origin :hotfixes/BJVEP933 删除远程仓库的 hotfixes/BJVEP933 分支
git push –tags 把所有 tag 推送到远程仓库
git fetch 获取所有远程分支(不更新本地分支,另需 merge)
git fetch –prune 获取所有原创分支并清除服务器上已删掉的分支
git pull origin master 获取远程分支 master 并 merge 到当前分支
git mv README README2 重命名文件 README 为 README2
git reset –hard HEAD 将当前版本重置为 HEAD(通常用于 merge 失败回退)
git branch -d hotfixes/BJVEP933 删除分支 hotfixes/BJVEP933(本分支修改已合并到其他分支)
git branch -D hotfixes/BJVEP933 强制删除分支 hotfixes/BJVEP933
git ls-files 列出 git index 包含的文件
git show-branch 图示当前分支历史
git show-branch –all 图示所有分支历史
git whatchanged 显示提交历史对应的文件修改
git revert dfb02e6e4f2f7b573337763e5c0013802e392818 撤销提交 dfb02e6e4f2f7b573337763e5c0013802e392818
git ls-tree HEAD 内部命令:显示某个 git 对象
git rev-parse v2.0 内部命令:显示某个 ref 对于的 SHA1 HASH
git reflog 显示所有提交,包括孤立节点
git show master@{yesterday} 显示 master 分支昨天的状态
git log –pretty=format:’%h %s’ –graph 图示提交日志
git stash 暂存当前修改,将所有至为 HEAD 状态
git stash list 查看所有暂存
git stash show -p stash@{0} 参考第一次暂存
git stash apply stash@{0} 应用第一次暂存
git grep “delete from” 文件中搜索文本 “delete from”

.gitignore

Some common .gitignore configurations

https://gist.github.com/octocat/9257657

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
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so

# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Logs and databases #
######################
*.log
*.sql
*.sqlite

# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

如何提交 PR

引用 kubeasz 的帮助文件为例

为项目 kubeasz 提交 pull request

首先请核对下本地 git config 配置的用户名和邮箱与你 github 上的注册用户和邮箱一致,否则即使 pull request 被接受,贡献者列表中也看不到自己的名字,设置命令:

1
2
$ git config --global user.email "you@example.com"
$ git config --global user.name "Your Name"
  1. 登陆 github,在本项目页面点击 fork 到自己仓库
  2. clone 自己的仓库到本地:git clone https://github.com/xxx/kubeasz.git
  3. 在 master 分支添加原始仓库为上游分支:git remote add upstream https://github.com/easzlab/kubeasz.git
  4. 在本地新建开发分支:git checkout -b dev
  5. 在开发分支修改代码并提交:git add ., git commit -am ‘xx 变更说明’
  6. 切换至 master 分支,同步原始仓库:git checkout master, git pull upstream master
  7. 切换至 dev 分支,合并本地 master 分支(已经和原始仓库同步),可能需要解冲突:git checkout dev, git merge master
  8. 提交本地 dev 分支到自己的远程 dev 仓库:git push origin dev
  9. 在 github 自己仓库页面,点击 Compare & pull request 给原始仓库发 pull request 请求
    a. 等待原作者回复(接受 / 拒绝)

Git 使用规范

Git 使用规范流程 - http://www.ruanyifeng.com/blog/2015/08/git-use-process.html
团队中的 Git 实践 - https://ourai.ws/posts/working-with-git-in-team/
构家网 git 团队协作使用规范 v2 - http://wenku.baidu.com/view/e1430d1b7f1922791788e81e

Git 使用规范提醒

  • 使用 Git 过程中,必须通过创建分支进行开发,坚决禁止在主干分支上直接开发。review 的同事有责任检查其他同事是否遵循分支规范。
  • 在 Git 中,默认是不会提交空目录的,如果想提交某个空目录到版本库中,需要在该目录下新建一个 .gitignore 的空白文件,就可以提交了
  • 把外部文件纳入到自己的 Git 分支来的时候一定要记得是先比对,确认所有修改都是自己修改的,然后再纳入。不然,容易出现代码回溯
  • 多人协作时,不要各自在自己的 Git 分支开发,然后发文件合并。正确的方法应该是开一个远程分支,然后一起在远程分支里协作。不然,容易出现代码回溯(即别人的代码被覆盖的情况)
  • 每个人提交代码是一定要 git diff 看提交的东西是不是都是自己修改的。如果有不是自己修改的内容,很可能就是代码回溯
  • review 代码的时候如果看到有被删除掉的代码,一定要确实是否是写代码的同事自己删除的。如果不是,很可能就是代码回溯

Git 练习

如果线下环境做 git 练习不便,可以选择开源中国的在线 Git 命令学习

git exercises: navigate a repository

git 练习答案

开源中国在线 Git 命令学习

参考文章

珍藏多年的 Git 问题和操作清单

Git 大全

git - 简明指南

猴子都能懂的 GIT 入门

想要学好 Git,应该掌握哪些基础知识?

文章目录
  1. 1. 前言
  2. 2. 更新记录
  3. 3. SVN 与 Git 的最主要的区别
  4. 4. Git 搭建和使用
    1. 4.1. Git 服务端
    2. 4.2. Git 客户端
  5. 5. Git 常用命令
  6. 6. git 命令一览
  7. 7. .gitignore
  8. 8. 如何提交 PR
  9. 9. Git 使用规范
  10. 10. Git 练习
  11. 11. 参考文章