X

曜彤.手记

随记,关于互联网技术、产品与创业

吉 ICP 备10004938号

《Pro Git - 2nd Edition》读书笔记(二)


书接上回。

七、Git 工具

  1. (Page:200)选择修订版本
git log --abbrev-commit --pretty=oneline  # 以缩略形式查看提交记录;
git show <commit-id>  # 查看某个 <commit-id> 对应的提交详情;
git show <branch>  # 查看 <branch> 分支最近一次提交的详情;
git reflog  # 查看历史上 HEAD 所指向的提交,每一次 HEAD 发生变化时都会被记录;
git show <branch>@{n}  # 查看 <branch> 分支在第 n 次前的提交;
git log --left-right <branch-A>...<branch-B>  # 查看 <branch-A> 与 <branch-B> 包含,但又不被两者同时包含的提交;

  1. (Page:208)交互式暂存
git add -i  # 以“交互模式”来暂存变更;
git add -p/--patch  # 部分暂存;
  1. (Page:212)储藏与清理
git stash
git stash list
git stash pop [--index]
git stash apply stash@{n} [--index]
git stash drop stash@{n}
git stash -u
git stash --keep-index  # 不储藏已暂存的变更;
git stash --patch  # 交互式地提示哪些改动想要储藏;
git stash branch <branch>  # 以最近一次的的储藏记录创建一个新的分支;
git clean -d -f  # 移除所有未被追踪的文件;
git clean -d -n  # 预测将被移除的文件(dry-run);
git clean -i
  1. (Page:217)GPG 签署工作:

(略)

  1. (Page:222)搜索
git grep -n <keyword>  # 查找工作目录中文件包含关键字 <keyword> 的行,并输出行号;
git grep --count <keyword>  # 输出搜索的统计性信息;
git grep -p <keyword>  # 搜索并输出匹配的所在函数(方法);
git grep [options] <keyword> <branch/tag>
git log -S <keyword> --oneline  # 查找变更了关键字 <keyword> 的提交;
git log -L :<funcname>:<file>  # 查看 <file> 文件中 <funcname> 的每一次变更(仅适用于函数);
  1. (Page:225)重写历史
git commit --amend  # 修改最后一次提交(会直接带走暂存区的改动);
git rebase -i HEAD~{n}  # 修改最后 n 次提交(压缩、拆分、修改、移除等);
git filter-branch --tree-filter '<command>' HEAD --all  # 在所有分支的检出项目的每一个提交后运行指定的命令,然后重新提交结果;
  1. (Page:231)重置揭密
git cat-file -p HEAD  # 查看 HEAD 快照的信息;
git ls-tree -r HEAD  # 查看 HEAD 快照的目录列表,及文件的 SHA-1 校验和;
git ls-files -s  # 显示当前索引区的状态;
git reset --soft HEAD~
git reset --mixed HEAD~  # 默认情况(撤销提交,并同时取消暂存);
git reset --hard HEAD~  # 更进一步,同时清理工作区的变更;
git reset HEAD <file>  # 将索引中特定文件的内容恢复为 HEAD;
git reset <commit-id> <file>  # 从对应某次提交中恢复某个文件(默认是 --mixed);

  1. (Page:251)高级合并
git ls-files -u  # 显示未合并文件的 Git blob 对象信息;
git merge-file -p <common-file> <their-file> <our-file>  # 合并三方文件;
git config --global merge.conflictstyle diff3  # 合并冲突时显示 base 版本的内容;
git checkout --conflict=diff3 <file>  # 重新检出文件,并使用 diff3 的冲突标记;
git log --left-right --merge -p HEAD...MERGE_HEAD  # 显示冲突文件的区别;
git checkout --ours(--theirs) .
git merge -Xours(-Xtheirs) <branch>  # 合并时直接选择一边;
git revert HEAD~1  # 还原上一个提交;
git revert <start-commit>..<end-commit>
  1. (Page:269)Rerere(Reuse Recorded Resolution):允许你让 Git 记住解决一个块冲突的方法,这样在下一次看到相同冲突时,Git 可以为你自动地解决它。如果做了很多次重新合并,或者想要一个特性分支始终与你的 master 分支保持最新但却不想要一大堆合并,或者经常变基,打开 rerere 功能可以帮助你的生活变得更美好。
git config --global rerere.enabled true  # 启用 Rerere;
  1. (Page:275)使用 Git 调试
# 查找第一个出现问题的提交;
git bisect start
git bisect bad  # 标记当前为“坏”提交;
git bisect good <commit-id>  # 标记已知的“好”提交的所在位置;
# ...(重复多次,进行定位)
git bisect reset  # 重置 HEAD,完成查找;
# 使用自动化脚本查找失败的提交;
git bisect start <bad-commit> <good-commit>  # 指定查找范围;
git bisect run <script>  # 运行脚本(正常返回 0,否则非 0)使用二分法查找;
# 展示文件中每一行最后一次修改的提交;
git blame -C -L 1,2 <file>
  1. (Page:278)子模块:可以将一个 Git 仓库作为另一个 Git 仓库的子目录,同时还保持两者提交的独立。
git submodule add <upstream>  # 添加子模块;
git clone --recursive <upstream>  # 自动初始化并更新仓库中的子模块;
git submodule update --remote <submodule-name> # 让 Git 自动进入子模块并抓取更新(默认为 master 分支);
git diff --submodule  # 查看子模块的更新差异;
git submodule update --remote --merge(--rebase)  # 让 Git 自动进入子模块,并直接合并上游变更到本地(非游离状态);
git push --recurse-submodules=check  # 在推送主仓库变更时,检查子模块改动是否已经被推送,若否则终止推送;
git rev-parse HEAD  # 获得 HEAD 对应的提交 ID;
git submodule foreach <command>  # 在每一个子模块中执行命令;
  1. (Page:297)打包:通过“打包文件”的方式将一个仓库的完整构建信息传统给他人使用。
# 创建一个当前仓库的打包文件,并打包引用 HEAD,以及 <branch> 分支;
git bundle create <bundle-name> HEAD <branch>
# 打包一部分变更;
git bundle create <bundle-name> <branch> <commit-range>
# 检查是否是一个合法的 Git 包,是否拥有共同的祖先来导入;
git bundle verify <bundle-name> 
# 查看可导入的分支有哪些;
git bundle list-heads <bundle-name>  
# 基于打包文件克隆一个项目;
git clone <bundle-name> <repo-name> 
# 从打包文件中导入变更记录到 <import-branch>;
git fetch <bundle-name> <branch>:<import-branch>
  1. (Page:301)替换:用其他对象假装替换数据库中的 Git 对象,在连接不同仓库中的历史变更时很有用
git replace <old-commit> <new-commit>
  1. (Page:309)凭证存储
# 设置凭证存储方式(cache、store、osxkeychain 等等);
git config --global credential.helper cache --timeout <seconds>
git config --global credential.helper store --file <path>

八、自定义 Git

  1. (Page:315)得到当前版本的 Git 支持选项列表
man git-config

常用配置项

  1. (Page:325)Git 属性:基于路径的设置项(.gitattributes / .git/info/attributes)。可以对项目中的文件或目录单独定义不同的合并策略,让 Git 知道怎样比较非文本文件,或者让 Git 在提交或检出前过滤内容等。
# .gitattributes
*.pbxproj binary
  1. (Page:328)Git 过滤器:可以用来实现文件提交或检出时的关键字替换(比如“提交时移除敏感信息”)。一个过滤器由 “clean”(文件被暂存时触发)和 “smudge”(文件被检出时触发)两个子过滤器组成。
# .gitattributes
*.c filter=indent
git config --global filter.indent.clean indent
git config --global filter.indent.smudge cat
  1. (Page:333)Git 钩子:钩子都被存储在 Git 目录下的 hooks 子目录中。也即绝大部分项目中的 “.git/hooks”(移除示例文件后缀的 “.sample” 即可启用)。

九、Git 与其他系统

(略)

十、Git 内部原理

  1. (Page:404)Git 从本质上来讲是一个“内容寻址文件系统”,并在此之上提供了一个版本控制系统的用户界面。其内部的底层命令被称为 “Plumbing 命令”,而上层的用户友好命令被称为 “Porcelain 命令”。
  2. (Page:405)在 “.git” 文件夹中,“objects” 目录存储所有数据内容;“refs” 目录存储指向数据(分支)的提交对象的指针;HEAD 文件指示目前被检出的分支;“index” 文件保存暂存区信息。
  3. (Page:405)Git 的核心部分是一个简单的“键值对数据库”。你可以向该数据库插入任意类型的内容,它会返回一个键值(将待存储的数据外加一个头部信息一起做 SHA-1 校验运算而来),通过该键值可以在任意时刻再次检索该内容。
# 将 stdin 的数据保存于 .git 目录的 objects 文件夹内,并返回相应的键值(SHA-1);
echo "Hello, world!" | git hash-object -w --stdin
# 通过键值取回文件内容;
git cat-file -p <sha1-hash>
  1. (Page:407)树对象(Tree Object):能解决文件名保存的问题,也允许我们将多个文件组织到一起。一个树对象包含了一条或多条树对象记录,每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型和文件名信息
# 显示 master 分支上最新的提交所指向的树对象;
git cat-file -p master^{tree}
# 为某个资源的某个版本创建暂存区;
git update-index --add --cacheinfo <file-mode> <sha1-hash> <file>
# 将暂存区内容写入一个树对象(会返回对应的树对象 ID);
git write-tree
# 查看数据对象/树对象内容;
git cat-file -p <sha1-hash>
  1. (Page:410)提交对象
# 创建一个提交对象(基于一个树对象 ID 与可选的父提交对象 ID);
echo 'Commit Message.' | git commit-tree <tree-sha1-hash>
  1. (Page:413)Git 以“对象类型”作为开头来构造一个头部信息,如 “blob \ commit \ tree”。接着 Git 会添加一个空格,随后是数据内容的长度,最后是一个空字节(“\0”)。Git 会将上述头部信息和原始数据拼接起来,并计算出这条新内容的 SHA-1 校验和。
  2. (Page:415)Git 引用:SHA-1 字符串的“别名”。
# 更新一个引用的值;
git update-ref <ref-path> <ref-value>
# 查看或设置“符号引用”;
git symbolic-ref HEAD <ref-path>
  1. (Page:417)标签引用:类似于一个“提交对象”。它包含一个标签创建者信息、一个日期、一段注释信息,以及一个指针。主要的区别在于,标签对象通常指向一个提交对象,而不是一个树对象
# 创建轻量标签(一个标签引用,指向一个 SHA-1);
git update-ref refs/tags/<tag-name> <commit-sha1-hash>
  1. (Page:418)远程引用(refs/remotes):记录远程版本库的分支和状态。

  1. (Page:420)Git 会使用 Zlib 来压缩“对象数据库”中的对象资源。Git 最初向磁盘中存储对象时所使用的格式被称为“松散”对象格式(即每个版本都有对应的完整数据对象文件)。但是,Git 会时不时地将多个这些对象打包成一个称为“包文件”的二进制文件,以节省空间和提高效率。当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。
# 打包对象。会生成 “.idx” 结尾的包索引文件与 “.pack” 结尾的包文件;
git gc
# 查看已打包内容;
git verify-pack -v <idx-file>
  1. (Page:422)引用规格
git push origin <local-ref>:refs/head/<remote-ref>
git push origin :<ref>  # 删除引用(把 <src> 留空);
git push origin --delete <branch>  # 同上,自 Git v1.7 之后;
[remote "origin"]
  url = git@github.com:Becavalier/SHDB.git
  fetch = +refs/heads/*:refs/remotes/origin/*
  push = refs/heads/*:refs/heads/qa/*
  1. (Page:425)传输协议:(略)
  2. (Page:430)维护与数据恢复:
git gc --auto
# 检查数据库的完整性,找出所有没有被其他对象指向的对象(可用于找回丢失的引用);
git fsck --full
# 查看 HEAD 的变化记录;
git reflog
# 立即清理无用的变化记录(高危);
git prune --expire now
  1. (Page:437)环境变量:(略)


这是文章底线,下面是评论
  暂无评论,欢迎勾搭 :)