本文是对Git速查手册(第二版)的更新,补充了一些近期使用或者收集的一些命令。
下载与安装
Git
下载地址:https://git-scm.com/downloads,安装请参考页面说明。
建议使用版本
v1.8
及以上。
配置
Git
配置分为三个级别:
--system
:系统级,位于/etc/gitconfig
;--global
:用户级,位于~/.gitconfig
;--local
:仓库级,位于[repo]/.git/config
,为默认级别且优先级最高;
用户信息
删除global
用户信息,防止不同Git
服务之间冲突:
1 | $ git config --global --unset user.name |
配置用户名:
1 | $ git config --local user.name "username" |
克隆协议
一般Git
服务默认都支持SSH
和HTTPS
,SSH
支持的原生Git
协议速度最快,HTTPS
除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令。
SSH
检查本机SSH
公钥,若存在,则将id_rsa.pub
添加到Git
服务的SSH keys
:
1 | $ ls ~/.ssh |
若不存在,则生成:
- 单个
Git
服务1
$ ssh-keygen -t rsa -C "your_email@youremail.com"
- 多个
Git
服务1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19$ ssh-keygen -t rsa -C "your_email@youremail.com" -f "git1_id_rsa"
$ ssh-keygen -t rsa -C "your_email@youremail.com" -f "git2_id_rsa"
$ cp git1_id_rsa* ~/.ssh/
$ cp git2_id_rsa* ~/.ssh/
# 创建配置文件
$ vi ~/.ssh/config
# git1
Host git1.com
HostName git1.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/git1_id_rsa
# git2
Host git2.com
HostName git2.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/git2_id_rsa
配置完成后,将对应的id_rsa.pub
添加到Git
服务的SSH keys
,再次检查ssh连接情况;若不生效,则重启后再尝试:
1 | $ ssh -T git@github.com |
若出现上述信息,则表示设置成功。
克隆:
1 | $ git clone git@git.server:test.git |
HTTPS
关闭ssl
校验:
1 | $ git config --global http.sslverify false |
克隆:
1 | $ git clone https://git.server/test.git |
协议切换
查看当前协议:
1 | $ git remote -v |
从https
切换至ssh
:
1 | git remote set-url origin git@domain:username/ProjectName.git |
从ssh
切换至https
:
1 | git remote set-url origin https://domain/username/ProjectName.git |
自定义配置
超时时间
1 | $ git config --global credential.helper 'cache --timeout=3600' |
保存用户凭证
1 | $ git config --global credential.helper store |
执行后,下次操作输入的用户名和密码会被保存,后续不必手动输入用户名和密码。若同时使用不同的Git
服务,则不推荐使用。
多Git服务
若同时使用不同的Git
服务,可以根据目录配置用户信息(需要使用v2.13.0
及以上版本):
首先修改用户目录下的
.gitconfig
,通过includeIf
配置不同目录的配置文件:1
2
3
4
5
6
7
8- [user]
- name = weijie.yuan
- email = weijie.yuan@gitlab.com
+ [includeIf "gitdir:~/github/"]
+ path = .gitconfig-github
+ [includeIf "gitdir:~/gitlab/"]
+ path = .gitconfig-gitlab根据配置的
path
,分别创建.gitconfig-github
文件和.gitconfig-gitlab
文件:1
2
3
4
5
6
7
8
9$ vi .gitconfig-github
[user]
name = weijie.yuan
email = weijie.yuan@github.com
$ vi .gitconfig-gitlab
[user]
name = weijie.yuan
email = weijie.yuan@gitlab.comincludeIf
配置有如下规则:家目录下的
.gitconfig
,includeIf
后面的path
最后需要/
结尾;家目录下的
.gitconfig
,原有的user
部分需要删除;家目录下的
.gitconfig
,includeIf
中配置的各个目录,不能是包含关系;
文本编辑器
Linux
or MacOS
:
1 | $ git config --global core.editor vim |
Windows
:
1 | > git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin" |
文本比较合并工具
查看支持的工具集合(推荐使用meld
):
1 | $ git difftool --tool-help |
Linux
or MacOS
:
1 | $ git config --global diff.tool meld |
Windows
:
1 | > git config --global diff.tool meld |
显示颜色
1 | $ git config --global color.ui.true |
操作别名
示例,将checkout
设置为别名co
:
1 | $ git config --global alias checkout co |
查看所有配置
1 | $ git config --local --list |
基础操作
工作流
工作区就是你的本地仓库目录,不过其中的.git
目录不属于工作区,而是版本库,里面存了很多东西,其中最重要的就是称为stage
(或者叫index
)的暂存区,还有Git
为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
查看状态:
1 | $ git status |
添加修改到暂存区:
1 | $ git add <filename> |
提交修改到版本库:
1 | $ git commit -m "commit message" |
commit message
的填写可以参考写好 Git Commit 信息的 7 个建议。
现在来解释一下前面的添加和提交操作:
git add
:把文件修改添加到暂存区;git commit
:把暂存区的所有内容提交到当前分支,即版本库;
版本历史记录
查看当前仓库所有文件的版本历史记录:
1 | $ git log |
查看每个文件的版本历史记录:
1 | $ git log <filename> |
查看包含指定关键字的版本历史记录:
1 | $ git log --grep="keywords" |
查看指定时间段的版本历史记录,如下示例时间段为2020.9.23
全天:
1 | $ git log --after="2020-9-23 00:00:00" --before="2020-9-23 23:59:59" |
暂存
当你需要切换分支时,若当前工作区还有些修改没有完成、又不适合提交的,操作切换分支是会提示出错的,这时就需要将这些修改暂存起来:
1 | $ git stash save "message" |
查看:
1 | $ git stash list |
恢复:
1 | $ git stash pop [--index] [stash@{num}] |
--index
表示不仅恢复工作区,还会恢复暂存区;num
是你要恢复的操作的序列号,默认恢复最新进度。
删除进度:
1 | $ git stash drop [stash@{num}] # 删除指定进度 |
撤销与回退
查看当前仓库状态:
1 | $ git status |
查看文件更改:
1 | $ git difftool <filename> |
查看提交历史:
1 | $ git log |
撤销工作区Tracked files
的修改:
1 | $ git checkout -- <filename> |
撤销工作区Untracked files
的修改:
- n:查看将会删除的文件,防止误删;
- f:
Untracked
的文件; - d:
Untracked
的目录; - x:包含
gitignore
的Untracked
文件和目录一并删掉,慎用!;
1 | git clean -nfd |
只回退暂存区(git add
),不删除工作空间代码:
1 | $ git reset HEAD <filename> # 无filename则默认回退全部 |
回退版本区(git commit
)和暂存区(git add
),不删除工作空间代码:
1 | $ git reset --mixed HEAD^ # --mixed为默认参数 |
回退版本区(git commit
),但是不回退暂存区(git add
),不删除工作空间代码:
1 | $ git reset --soft HEAD^ |
回退版本区(git commit
)和暂存区(git add
),并删除工作空间代码(不包括Untracked files
),执行后直接恢复到指定<commit-id>
状态:
1 | $ git reset --hard <commit-id> |
HEAD
表示当前版本,HEAD^
表示上个版本,HEAD^^
表示上上个版本,上100个版本可以表示为HEAD~100
以此类推。
回退版本后,若需要返回原来的版本,会发现找不到未来的commit id
,则需要查看操作命令历史进行查找:
1 | $ git reflog |
从版本库删除文件:
1 | $ git rm <filename> |
若你的代码已经push
到线上,则推荐使用下面这个命令回滚:
1 | $ git revert <commit-id> |
revert
是用一次新的commit
来回滚之前的commit
,更安全;reset
则是直接删除指定的commit
,若直接push
会导致冲突。
使用帮助
查看帮助:
1 | $ git --help |
仓库管理
推送本地修改到远程仓库
1 | $ git push -u origin <feature-branch-name> |
-u
选项可以将本地分支与远程分支关联,下次git pull
操作时可以不带参数.具体参见这里。
添加本地仓库到远程
1 | $ cd repo |
origin
就是一个名字,是git
为你默认创建的指向这个远程代码库的标签。
获取远程仓库
1 | $ git clone git@github.com:USERNAME/repo.git |
查看远程仓库
1 | $ git remote -v |
关联远程仓库
1 | $ git remote add upstream git@github.com:USERNAME/repo.git |
同步远程仓库的更新
1 | $ git remote -v |
仓库引用(子仓库)
Git
包含submodule
和subtree
两种引用方式,官方推荐使用subtree替代submodule
:
submodule
添加子模块
1 | $ git submodule add git@github.com:USERNAME/repo.git <submodule-path> |
执行成功后,暂存区会有两个修改:.gitmodules
和命令中<submodule-path>
指定的路径。
提交更新:
1 | $ git commit |
使用子模块
克隆使用了子模块的项目后,默认其子模块目录为空,需要在项目根目录执行如下命令单独下载:
1 | $ git submodule update --init --recursive |
更新子模块
子模块仓库更新后,使用子模块的项目必须手动更新才能同步最新的提交:
1 | $ cd <submodule-path> |
完成后返回项目根目录,可以看到子模块有待提交的更新,执行提交即可:
1 | $ git add . |
删除子模块
删除子模块目录及源码:
1 | $ rm -rf <submodule-path> |
删除项目根目录下.gitmodules
文件中待删除的子模块相关条目:
1 | $ vi .gitmodules |
删除版本库下的子模块目录,每个子模块对应一个目录,只删除对应的子模块目录即可:
1 | rm -rf .git/module/<submodule-path> |
删除子模块缓存:
1 | git rm --cached <submodule-path> |
提交更新:
1 | $ git add . |
subtree
1 | # 第一次初始化 |
清理仓库
清理本地无效的远程追踪分支
1 | $ git pull # 拉取更新 |
清理无用的分支和标签
1 | $ git branch -d <branch-name> |
清理大文件
查看仓库占用空间:
1
2$ git count-objects -v
$ du -sh .git寻找大文件
ID
:1
$ git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10
输出的第一列是文件
ID
,第二列表示文件(blob
)或目录(tree
),第三列是文件大小,此处筛选了最大的10条。根据文件
ID
映射文件名:1
$ git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}')"
根据文件名,从所有提交中删除文件:
1
$ git filter-branch --force --index-filter 'git rm -rf --cached --ignore-unmatch [FileName]' --prune-empty --tag-name-filter cat -- --all
删除缓存下来的
ref
和git
操作记录:1
2$ git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
$ git reflog expire --expire=now --all清理
.git
目录并推送到远程:1
2$ git gc --prune=now
$ git push -f --all在执行
push
操作时,git
会自动执行一次gc
操作,不过只有loose object
达到一定数量后才会真正调用,建议手动执行。重新查看仓库占用空间,发现较清理前变小很多:
1
2$ git count-objects -v
$ du -sh .git
清理大型二进制文件
由于Git
在存储二进制文件时效率不高,所以需要借助第三方组件。
分支管理
查看分支
查看所有分支:
1 | $ git branch -a |
有
*
标记的是当前分支。
查看某个<commit id>
属于哪个分支:
1 | $ git branch -a --contains <commit id> |
创建分支
在本地创建分支:
1 | $ git branch <newbranch> # 创建 |
在本地创建分支并切换:
1 | $ git checkout -b <newbranch> # 创建并切换 |
从标签创建分支:
1 | $ git branch <newbranch> <tagname> |
获取远程分支到本地并创建本地分支:
1 | $ git checkout -b <local-branch> <remote-branch> |
推送新建本地分支到远程:
1 | $ git push -u origin <remote-branch-name> |
创建空白分支
创建一个分支,该分支会包含父分支的所有文件,但不会指向任何历史提交:
1 | $ git checkout --orphan <newbranch> |
删除所有文件:
1 | $ git rm -rf . |
提交分支:
1 | $ echo '# new branch' >> README.md |
删除分支
删除本地分支:
1 | $ git branch -d <branch> |
若当前分支因为有修改未提交或其它情况不能删除,请使用
-D
选项强制删除。
清理无用的本地分支:
1 | $ git remote prune origin |
通常在
remote
上的分支被删除后,更新本地分支列表时使用。
删除远程分支(三种方法):
1 | $ git push origin --delete <remote-branch-name> |
更新分支
获取远程分支到本地已有分支:
1 | $ git branch --set-upstream <local-branch> origin/branch |
同步当前分支的所有更新,使用git pull
并不保险:
1 | # 下载最新的代码到远程跟踪分支, 即origin/<branch-name> |
同步其它分支的所有更新,本例拉取master
分支更新:
1 | $ git fetch origin master |
同步其它分支的部分更新,即同步某几次提交:
1 | # 同步提交A |
标签管理
查看标签
1 | $ git tag |
创建标签
1 | $ git tag -a <tagname> -m "tag message" # 创建标签在当前最新提交的commit上 |
若创建标签基于的
commit
被删除,标签不会被影响,依旧存在。
推送标签
推送标签到远程服务器:
1 | $ git push origin <tagname> # 推送一个本地标签 |
删除标签
1 | $ git tag -d <tagname> # 删除一个本地标签 |
进阶技巧
忽略特殊文件
当你的仓库中有一些文件,类似密码或者数据库文件不需要提交但又必须放在仓库目录下,每次git status
都会提示Untracked
,看着让人很不爽,提供两种方法解决这个问题。
本地忽略
在代码仓库目录创建一个.gitignore
文件,编写规则如下:
1 | tmp/ # 忽略tmp文件夹下所有内容 |
全局忽略
在用户目录创建一个.gitignore_global
文件,编写规则同.gitignore
,并修改~/.gitconfig
:
1 | [core] |
如果添加的忽略对象已经Tracked
,纳入了版本管理中,则需要在代码仓库中先把本地缓存删除,改变成Untracked
状态:
1 | $ git rm -r --cached . |
重写历史(慎用!)
修改历史提交(变基)
1 | $ git rebase -i [git-hash| head~n] |
其中git-hash
是你要开始进行rebase
的commit
的hash
,而head~n
则是从HEAD
向前推n
个commit
修改最近一次提交信息
1 | $ git commit --amend |
修改提交记录中的用户信息
修改最近一次提交的用户信息:
1 | $ git commit --amend --author="GIT_AUTHOR_NAME <GIT_AUTHOR_EMAIL>" |
全局修改用户信息:
1 | $ git filter-branch --commit-filter ' |