git 常用命令 一文中介绍了 git 的一些基本命令, 在 Git 中 4 个阶段的撤销更改 中则介绍了 git 四个阶段的”后悔药”, 这篇文章则汇集了几个不太常用但非常有用的命令。

只克隆某个分支

有时我们想克隆的一个仓库有超多个分支,或者克隆的时候想克隆的不是默认分支,那么这时 候我们可以自己指定克隆某一个分支:

1
git clone -b WantBranch  远程git仓库地址

还可以克隆指定深度,减少克隆的量:

1
git clone --depth=1  远程git仓库地址

把二者合到一起:

1
git clone -b WantBranch --depth=1 远程git仓库地址

则是只克隆远程仓库中 WantBranch 这个分支的最近一次深度提交。

在 git 中创建空分支

有时候因为要重构代码或者要新建一个完全与当前分支无关的分支(比如gh-pages分支), 我们就需要创建一个完全空分支,从头开始,那么就需要用到下面的这个命令了:

1
git checkout --orphan gh-pages

我们就创建了一个”孤立”的空分支,并且默认继承当前分支的全部内容,如果不需要,可以 使用 git rm -rf . 删除,之后再重新提交。

注意,如果我们没有进行任何提交,那么这个分支将不存在,只有我们向这个分支提交(commit) 了内容之后,才能通过 git branch 看到这个分支。

修改 commit 时间

The author is the person who originally wrote the work, whereas the committer is > the person who last applied the work. ― Pro Git book

git 其实中有两个作者,作者提交者 ,相应的也会有两个日期。作者 指的是实际作出修改的人,提交者 指的是最后将此工作成果提交到仓库的人。所以, 当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目时,你就是作者, 而那个核心成员就是提交者[1]

如果我们想指定提交(commit)时间或者希望修改上次甚至是以前的 commit 的时间,那么就 需要 git 中的 --date 命令了:

1
2
3
4
5
# 只修改上次 commit 的作者时间(AUTHOR_DATE). 
# 注意, 修改后 hash 值会发生改变.
git commit --amend --date="YYYY-MM-DDThh:mm:ss±hh:mm" -C 28f2d7b81e037aa4fcdf45f6353cb7c2aa10e336
# 同时修改 COMMITTER_DATE 和 AUTHOR_DATE.
GIT_COMMITTER_DATE="YYYY-MM-DDThh:mm:ss±hh:mm" git commit --amend --date="YYYY-MM-DDThh:mm:ss±hh:mm" -C HEAD~2

也可以通过设置环境变量来实现修改:

1
2
export GIT_AUTHOR_DATE="YYYY-MM-DDThh:mm:ss±hh:mm"
export GIT_COMMITTER_DATE="YYYY-MM-DDThh:mm:ss±hh:mm"

之后再进行 commit . 注意之后及时取消这两个环境变量:

1
2
unset GIT_AUTHOR_DATE
unset GIT_COMMITTER_DATE

变基

1
2
3
4
# 多主题分支变基
git rebase -onto
# 交互式变基
git rebase -interactive

变基会修整历史,然后将分支历史并入主线,可以理解成美化过的历史,而合并则可以不修 改历史,让分支历史依然独立存在,可以看作原始的历史。

永远不要对已经推到主干分支服务器或者团队其他成员的提交进行变基,我们选择变基 还是合并的范围应该在自己当前工作范围内。’

从 git commit 中永久删除某些文件

有时我们会错误的提交一些文件(比如账号密码密钥等),希望从 commit 历史中完全删掉 这些文件,就像他们从来没有出现过一样,通过下面的命令可以实现这一点:

1
2
3
4
5
6
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch DeleteDir/ -r' --prune-empty --tag-name-filter cat -- --all
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
git push --force --verbose --dry-run
git push --force

其中,DeleteDir 是我们希望完全删除的文件(目录),-r 是递归删除,git push --force --verbose --dry-run 是只在本地提交,并没有提交到远程。

注意:所有受到影响的 commit 的 ID 都会被重写,

删除在本地有但在远程库中已经不存在的分支

有时有些分支在远程库已经不存在了(你之前从远程库拉取过,可能之后被其他人删除了), 这时候我们可以删除本地库中这些相比较远程库中已经不存在的分支:

1
2
## 可以先使用 git remote show origin,查看远程分支
git remote prune origin

删除远程分支、tag

另外一种反过来的情况是,有些分支已经提交到远程,但是我们想把它同时地从本地和远程 进行删除,当然,可以分别利用git的web删除远程分支,但如果是tag之类的呢?这时候还是 命令行更方便

1
2
3
4
# 删除分支
git branch -r -d origin/branch-name
# 推送到远程
git push origin :branch-name

对于删除远程的标签tag,只需把branch换成tag即可:

1
2
3
4
# 删除本地标签:
git tag -d 标签名
# 删除远程标签:
git push origin :refs/tags/标签名

参考