主要内容:【历史穿梭】、【改变历史】、【Git 克隆】
历史穿梭
查看条件个数:
git rev-list HEAD | wc -l
版本表示法:git rev-parse
git rev-parse
pick out and massage parameters for other git commands.
--git-dir
可以显示 Git 版本库的位置--show-cdup
当前工作区目录的深度--parseopt
可以用于被 Git 无关应用用于解析命令行参数
# 显示分支,tag
git rev-parse --symbolic --branches
git rev-parse --symbolic --branches
# 显示定义的所有引用
git rev-parse --symbolic --glob=refs/*
# 显示多个表达式的 SHA1 哈希值:
git rev-parse master refs/heads/master
6652a0dce6a5067732c00ef0a220810a7230655e
6652a0dce6a5067732c00ef0a220810a7230655e
^后面的数字代表该提交的第几个父提交,~<n>就相当于连续<n>个符号^
git rev-parse A~3 A^^^
e80aa7481beda65ae00e35afc4bc4b171f9b0ebf
e80aa7481beda65ae00e35afc4bc4b171f9b0ebf
# 暂存区里的文件和HEAD中的文件相同
git rev-parse :gitg.png HEAD:gitg.png
fc58966ccc1e5af24c2c9746196550241bc01c50
fc58966ccc1e5af24c2c9746196550241bc01c50
# 在提交日志中查找字串的方式显示提交
git rev-parse :/"Commit A"
81993234fc12a325d303eccea20f6fd629412712
版本范围表示法:git rev-list
git rev-list
可以帮助研究 Git 的各种版本范围语法。
# 从开始到 tag:A 的所有历史提交
git rev-list --oneline A
# 每个 tag 历史提交的并集
git rev-list --oneline D F
# ^ 排除这个版本及其历史版本
git rev-list --oneline ^G D
# ^G D 等价于 G..D
git rev-list --oneline G..D
# 含 ^ 的参数顺序不重要,..
# ^B C 相当于 B..C
# C ^B 相当于 B..C
# C..B 相当于 ^C B
浏览日志:git
--graph
参数调用 git log
可以显示字符界面的提交关系图。
git config --global alias.glog "log --graph"
--oneline
单行显示-<n>
显示最近的条日志 -p
显示变动--stat
显示变动摘要
查看、分析某一个提交:
git show D --stat
tag D
...
git cat-file -p D^0
差异比较:git diff
- 比较里程碑 B 和里程碑 A,用命令:git diff B A
- 比较工作区和里程碑 A,用命令:git diff A
- 比较暂存区和里程碑 A,用命令:git diff -cached A
- 比较工作区和暂存区,用命令:git diff
- 比较暂存区和 HEAD,用命令:git diff -cached
- 比较工作区和 HEAD,用命令:git diff HEAD
显示不同版本下的文件差异:
git diff <commit1> <commit2> -- <paths>
非 Git 目录/文件的差异比较,可在版本库之外使用:
git diff <path1> <path2>
--word-diff
差异逐 词 比较,而非缺省的逐 行 比较
文件追溯:git blame
逐行显示文件,在每一行的行首显示此行最早是在什么版本引入的,由谁引入。
只想查看某几行,使用 -L n,m 参数:
git blame -L 6,+5 README
二分查找:git bisect
定位问题代码。
改变历史
作为分布式版本控制系统,一旦版本库被多人共享,改变历史就可能是无法完成的任务。
悔棋
git commit –amend
单步悔棋,修补式提交。
检出文件到前一版:
git checkout HEAD^ -- src/hello.h
多步悔棋
git reset --soft HEAD^^
回到未来
拣选指令 git cherry-pick
从众多的提交中挑选出一个提交应用在当前的工作分支中。
该命令需要提供一个提交 ID 作为参数,操作过程相当于将该提交导出为补丁文件,然后在当前 HEAD 上重放形成无论内容还是提交说明都一致的提交。
操作例子:A B C D E F
6 次提交。
例子 1.1:出掉 D
:
# 将 HEAD 指针切换到 C
git checkout C
# 拣选将 E 提交在当前 HEAD 上
git cherry-pick E
# 拣选操作将 F 提交在当前 HEAD 上
git cherry-pick master
# 将 master 分支指向新的提交 ID(f677821)上
git checkout master
git reset --hard HEAD@{1}
例子 1.2:D 融入 C:
git checkout D
# 将 C 和 D 融合
git reset --soft HEAD^^
# 提交说明重用C提交的提交说明
git commit -C C
git cherry-pick E
git cherry-pick F
git rebase 对提交执行变基操作,即可以实现将指定范围的提交“嫁接”到另外一个提交之上。
git rebase --onto <newbase> <since> <till>
变基操作的过程:
- 首先执行 git checkout
,如果 till 不是一个分支,则变基操作是在 detached HEAD 分离头指针 状态的,当变基结束后,对 master 分支执行重置以实现把变基结果记录在分支中。 - 将
.. 所标识的提交范围写到一个临时文件中。( .. 是指包括 的所有历史提交排除 以及 的历史提交后形成的版本范围) - 当前分支强制重置(git reset –hard)到
。 - 从保存在临时文件中的提交列表中,一个一个将提交按照顺序重新提交到重置之后的分支上。
- 如果遇到提交已经在分支中包含,跳过该提交。
- 如果在提交过程遇到冲突,变基过程暂停。用户解决冲突后,执行 git rebase –continue 继续变基操作。或者执行 git rebase –skip 跳过此提交。或者执行 git rebase –abort 就此终止变基操作切换到变基前的分支上。
例子 2.1:出掉 D
:
git rebase --onto C D F
# or
git rebase --onto C E^ F
例子 2.2:D 融入 C:
git checkout D
# C和D融合
git reset --soft HEAD^^
git add .
# 复用 C 的提交信息
git commit -C C
# 记住这个提交 ID,可以用 tag 的方法
git tag newbase
git rebase --onto newbase E^ master
-i
交互式变基方法。
例子 3.1:出掉 D
:
git rebase -i D^
# d, drop = remove commit
# 提交 D 标示修改为 d
例子 3.2:D 融入 C:
git rebase -i C^
# 提交 D 标示修改为 s
丢弃历史
重点内容第一次 Get
历史有的时候会成为负担。只保留最近的 100 次提交,抛弃之前的历史提交。那么应该如何操作呢?
例:清除 tag A 之前的提交历史:
# 查看里程碑A指向的目录树
git cat-file -p A^{tree}
# 使用git commit-tree命令直接从该目录树创建提交
echo "Commit from tree of tag A." | git commit-tree A^{tree}
8f7f94ba6a9d94ecc1c223aa4b311670599e1f86
# 命令git commit-tree的输出是一个提交的SHA1哈希值。
# 会发现这个提交没有历史提交,可以称之为孤儿提交。
git log 8f7f94ba6a9d94ecc1c223aa4b311670599e1f86
# 将master分支从里程碑到最新的提交全部迁移到刚刚生成的孤儿提交上。
git rebase --onto 8f7f94ba6a9d94ecc1c223aa4b311670599e1f86 A master
反转提交
git revert HEAD
Git 克隆
鸡蛋不装在一个篮子里
1. git clone <repository> <directory>
2. git clone --bare <repository> <directory.git>
3. git clone --mirror <repository> <directory.git>
一般约定俗成裸版本库的目录名以 .git
为后缀。
用法 3 区别于用法 2 之处在于用法 3 克隆出来的裸版本对上游版本库进行了注册,这样可以在裸版本库中使用 git fetch 命令和上游版本库进行持续同步。
克隆生成裸版本库
git clone --bare /path/to/my/workspace/demo /path/to/repos/demo.git
demo.git 目录就是版本库目录,不含工作区。
git --git-dir=/path/to/repos/demo.git config core.bare
true
# 向其 push
git push /path/to/repos/demo.git
创建生成裸版本库
git init --bare /path/to/repos/demo-init.git