登录/注册
六六六一啊
1186
占位
2
占位
0
浏览量
占位
粉丝
占位
关注
5.5-Git提交引用
六六六一啊
2020-12-31 11:32:44 2020-12-31
178
0

Git提交引用和引用日志

提交是 Git 的精髓所在,你无时不刻不在创建和缓存提交、查看以前的提交,或者用各种Git命令在仓库间转移你的提交。大多数的命令都对同一个提交操作,而有些会接受提交的引用作为参数。比如,你可以给 git checkout 传入一个引用来查看以前的提交,或者传入一个分支名来切换到对应的分支。

引用一次提交的各种方式

知道提交的各种引用方式之后,Git 的命令就会变得更加强大。在这章中,我们研究提交的各种引用方式,来一窥 git checkoutgit branchgit push 等命令的工作原理。

我们还会学到如何使用 Git 的引用日志查看似乎已被删除的提交。

哈希字串

引用一个提交最直接的方式是通过 SHA-1 的哈希字串,这是每个提交唯一的 ID。你可以在 git log 的输出中找到提交的哈希字串。

commit 0c708fdec272bc4446c6cabea4f0022c2b616eba
Author: Mary Johnson <mary@example.com>
Date:   Wed Jul 9 16:37:42 2014 -0500

    一些提交信息

在 Git 命令中传递时,你只需要提供足以确定那个提交的哈希子串即可。比如,你可以这样用 git show 的命令显示上面的提交:

git show 0c708f

有时,我们需要把分支、标签或者其他间接的引用转变成对应提交的哈希。git rev-parse 命令正是你需要的。下面这个命令返回 master 分支提交的哈希字串:

git rev-parse master

当你写的自定义脚本中需要将提交引用作为参数时,这个命令非常有用。你可以让 git rev-parse 帮你处理转换,而不用手动做这件事。

引用

ref 是提交的间接引用。你可以把它当做哈希字串的别名,但对用户更友好。这就是 Git 内部表示分支和标签的机制。

引用以一段普通的文本存在于 .git/refs 目录中,就是我们平时说的那个 .git。你去 .git/refs 文件夹查看仓库中的引用。你可以看到下面这样的结构,但具体的文件取决于你的仓库中有什么分支和标签,以及你的远程仓库。

.git/refs/
    heads/
        master
        some-feature
    remotes/
        origin/
            master
    tags/
        v0.9

heads目录定义了你本地仓库中的所有分支。每一个文件名和你的分支名一一对应,文件中包含一个提交的哈希字串。这个就是分支顶端的所在位置。为了验证这一点,试试在 Git 根目录运行下面这两个命令:

# 输出`refs/heads/master`文件内容
cat .git/refs/heads/master

# 查看`master`分支尾端的提交
git log -1 master

cat 命令返回的哈希字串和 git log 命令显示的哈希字串应该是一致的。

如果要改变 master 分支的位置,Git 只需要更改 refs/heads/master 的文件内容。同样地,创建新的分支也只需要将当前提交的哈希字串写入到新的文件中。这也是为什么 Git 分支比 SVN 轻量那么多的其中一个原因。

tags 目录也是以相同的方式存储,只不过其中存的是标签而不是分支。remotes 目录将你之前用 git remote 命令创建的所有远程仓库以子目录的形式一一列出。在每个文件夹中,你可以找到所有 fetch 到本地仓库的远程分支。

指定引用

当你向 Git 命令传入引用的时候,你既可以指定引用完整的名称,也可以使用缩写,然后让 Git 来寻找匹配。你应该已经对引用的缩写很熟悉了,每次你通过名称引用分支的时候都会这么做。

git show some-feature

这里的 some-feature 参数其实是分支名的缩写。Git 在使用前将它解析成 refs/heads/some-feature。你也可以在命令行中指定引用的全称,就像这样:

git show refs/heads/some-feature

这避免了引用可能产生的所有歧义。这是非常必要的,比如你同时有一个标签和分支都叫 some-feature。然而,如果使用正常的命名规范,你不应该有这样的歧义。

我们会在 refspec 一节见到更多引用名称。

打包引用目录

对于大型仓库,Git 会周期性地执行垃圾回收来移除不需要的对象,将所有引用文件压缩成单个文件来获得更好的性能。你可以使用这个命令强制垃圾回收来执行压缩:

git gc

这个命令把 refs 文件夹中所有单独的分支和标签移动到了 .git 根目录下的 packed-refs 文件中。如果你打开这个文件,你会发现提交的哈希字串和引用之间的映射关系:

00f54250cf4e549fdfcafe2cf9a2c90bc3800285 refs/heads/feature
0e25143693cfe9d5c2e83944bbaf6d3c4505eb17 refs/heads/master
bb883e4c91c870b5fed88fd36696e752fb6cf8e6 refs/tags/v0.9

另一方面,正常的 Git 功能不会受到任何影响。但如果你好奇你的 .git/refs 文件夹为什么是空的,这一节告诉你了答案。

特殊的引用

除了 refs 文件夹外,.git 根目录还有一些特殊的引用。如下所示:

  • HEAD – 当前所在的提交或分支。
  • FETCH_HEAD – 远程仓库中 fetch 到的最新一次提交。
  • ORIG_HEAD – HEAD 的备份引用,避免损坏。
  • MERGE_HEAD – 你通过 git merge 并入当前分支的引用(们)。
  • CHERRY_PICK_HEAD – 你 cherry pick 使用的引用。

这些引用由 Git 在需要时创建和更新。比如说,git pull 命令首先运行 git fetch,而 FETCH_HEAD 引用随之改变。然后,运行 git merge FETCH_HEAD 来将 fetch 到的分支最终并入仓库。当然,你也可以使用其他任何引用,因为我相信你已经对 HEAD 很熟悉了。

这些文件包含的内容取决于它们的类型和你的仓库状态。HEAD 引用可以包含符

暂无评论