本文是对Git速查手册(第二版)的更新,补充了一些近期使用或者收集的一些命令。
设置Git
版本
Git
下载地址:https://git-scm.com/downloads,推荐使用v1.8
及以上版本。
查看Git
版本:
1 | $ git --version |
用户信息
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
服务,不推荐使用:
1 | $ git config --global credential.helper store |
执行后,下次操作输入的用户名和密码会被保存,后续不必手动输入用户名和密码。
配置超时时间:
1 | $ git config --global credential.helper 'cache --timeout=3600' |
根据目录配置用户信息,需要使用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
中配置的各个目录,不能是包含关系;
克隆协议
一般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 |
工具配置
配置diff
和merge
工具,可以通过git difftool --tool-help
查看支持的工具集合,推荐使用meld
。
Linux
orMacOS
:1
2$ git config --global diff.tool meld
$ git config --global merge.tool meldWindows
:1
2
3
4
5> git config --global diff.tool meld
> git config --global merge.tool meld
> git config --global difftool.bc3.path 'C:\Program Files (x86)\Meld\Meld.exe'
> git config --global mergetool.meld.path 'C:\Program Files (x86)\Meld\Meld.exe'
> git config --global difftool.meld.path 'C:\Program Files (x86)\Meld\Meld.exe'
配置编辑器:
Linux
orMacOS
:1
$ git config --global core.editor vim
Windows
:1
> git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
配置显示颜色:
1 | $ git config --global color.ui.true |
配置Git
操作别名,示例:
1 | $ git config --global alias checkout co |
上面的命令将
checkout
设置为别名co
。
查看所有配置
1 | $ git config --local --list |
工作流
工作区就是你的本地仓库文件夹,不过其中的.git
目录不属于工作区,而是版本库,里面存了很多东西,其中最重要的就是称为stage
(或者叫index
)的暂存区,还有Git
为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
现在来解释一下前面的添加和提交操作:
git add
:把文件修改添加到暂存区;git commit
:把暂存区的所有内容提交到当前分支,即版本区;
基本操作
获取远程仓库:
1 | $ git clone git@github.com:USERNAME/repo.git |
将本地的仓库添加到远程:
1 | $ cd repo |
origin
就是一个名字,是git
为你默认创建的指向这个远程代码库的标签。
添加修改到暂存区:
1 | $ git add <filename> |
提交修改到版本区:
1 | $ git commit -m "commit message" |
commit message
的填写可以参考写好 Git Commit 信息的 7 个建议。
推送修改到远程服务器:
1 | $ git push -u origin <feature-branch-name> |
-u
选项可以将本地分支与远程分支关联,下次git pull
操作时可以不带参数.具体参见这里。
查看远程仓库:
1 | $ git remote -v |
添加上游仓库:
1 | $ git remote add upstream git@github.com:USERNAME/repo.git |
fork
后同步上游仓库的更新:
1 | $ git remote -v |
代码引用在Git
上有submodule
和subtree
两种方式,推荐使用subtree方式:
1 | # 第一次初始化 |
分支
查看所有分支,有*
标记的是当前分支:
1 | $ git branch -a |
创建本地分支:
1 | $ git branch <newbranch> |
创建并切换本地分支:
1 | $ git checkout -b <newbranch> |
从标签创建分支:
1 | $ git branch <branch> <tagname> |
推送新建本地分支到远程:
1 | $ git push -u origin <remote-branch-name> |
删除本地分支:
1 | $ git branch -d <branch> |
若当前分支因为有修改未提交或其它情况不能删除,请使用
-D
选项强制删除。
删除远程分支(三种方法):
1 | $ git push origin --delete <remote-branch-name> |
清除无用的分支:
1 | $ git remote prune origin |
说明:remote上的一个分支被其他人删除后,需要更新本地的分支列表。
获取远程分支到本地已有分支:
1 | $ git branch --set-upstream <local-branch> origin/branch |
获取远程分支到本地并新建本地分支:
1 | $ git checkout -b <local-branch> <remote-branch> |
同步当前分支的所有更新,使用git pull
并不保险:
1 | # 下载最新的代码到远程跟踪分支, 即origin/<branch-name> |
同步其它分支的所有更新,本例拉取master
分支更新:
1 | $ git fetch origin master |
同步其它分支的部分更新,即同步某几次提交:
1 | # 同步提交A |
查看某个<commit id>
属于哪个分支:
1 | $ git branch -a --contains <commit id> |
标签
查看标签:
1 | $ git tag |
创建标签:
1 | $ git tag -a <tagname> -m "tag message" # 创建标签在当前最新提交的commit上 |
推送标签到远程服务器:
1 | $ git push origin <tagname> # 推送一个本地标签 |
删除标签:
1 | $ git tag -d <tagname> # 删除一个本地标签 |
撤销与回退
查看当前仓库状态:
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 stash save "message" |
查看:
1 | $ git stash list |
恢复:
1 | $ git stash pop [--index] [stash@{num}] |
--index
表示不仅恢复工作区,还会恢复暂存区;num
是你要恢复的操作的序列号,默认恢复最新进度。
删除进度:
1 | $ git stash drop [stash@{num}] # 删除指定进度 |
清理仓库
清理本地无效的远程追踪分支
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
在存储二进制文件时效率不高,所以需要借助第三方组件。
忽略特殊文件
当你的仓库中有一些文件,类似密码或者数据库文件不需要提交但又必须放在仓库目录下,每次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 filter-branch --commit-filter ' |
帮助
查看帮助:
1 | $ git --help |