翻了半天命令,没发现有这个功能,是否有其他折衷的办法可以搞定?
例如:这个哈希存放在 .git 下面的某个文件内。又或者,没有 submit 的 这个 commit, 根本就没有这个 hash 值?? 我觉得肯定有...
顺便呼叫下 @chunzi 帮忙解答,还得感谢你,你翻译的 Progit 对于我之前学习 git 帮助很大。
顺便呼叫下楼下几位:
@Saito, @HuangYuHei, @HungYuHei, @happypeter, @knwang
Git 一共有 4 种 SHA1. tag, commit, tree, blob. 每一种 SHA1 其实也代表了 Git 内部的一个基本对象。
稍微解释一下就知道了。
mkdir helloworld
cd helloworld
git init
echo hello world > readme.md
git add .
git commit -am"add readme.md"
答案很简单。
git add .
在这里操作中会添加一个 blob 对象,代表 readme 文件本身。这也是为什么你需要在 add 过一个对象之后,撤销需要执行 rm 与 cache 相关命令的原因。
而文件的内容则如下所示。
helloworld git:master ❯ git ls-files -s readme.md
100644 3b18e512dba79e4c8300dd08aeb37f8e728b8dad 0 readme.md
helloworld git:master ❯ git show 3b18e512dba79
hello world
当执行下面这句的时候:
git commit -am"add readme.md"
这一步中将创建两个对象,一个是当前 work tree 的映射 tree 对象,还有一个就是 commit 对象。
tree 对象是可以包含另外的 tree 以及 blob 的。
helloworld git:master ❯ git show 7394b8cc9ca
tree 7394b8cc9ca
readme.md
helloworld git:master ❯ git cat-file -p 7394b8cc9ca
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad readme.md
上面是一个 tree 对象的具体内容。tree 里面实际上就是描述了当前 tree 的内容以及 blob 的引用。
同理 commit 也可以用相同的方式查看:
helloworld git:master ❯ git show 84073a0
commit 84073a0bffd4c80598dbc4941a5f84d78cc2adcd
Author: Saito <[email protected]>
Date: Fri Sep 14 01:12:07 2012 +0800
add readme
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/readme.md
@@ -0,0 +1 @@
+hello world
helloworld git:master ❯ git cat-file -p 84073a0
tree 7394b8cc9ca916312a79ce8078c34b49b1617718
author Saito <[email protected]> 1347556327 +0800
committer Saito <[email protected]> 1347556327 +0800
add readme
可以看到,commit 里面实际上保存的实际上是一个 tree 的 SHA1 以及 commit 的 author commiter 以及最终的 commit message.
最后我们给当前状态打一个 1.0 版本的 tag.
helloworld git:master ❯ git tag 1.0 -m"create a tag"
再来看看 tag 的 SHA1 内容。
helloworld git:master ❯ git show 1518c0a02530b3
tag 1.0
Tagger: Saito <[email protected]>
Date: Fri Sep 14 01:24:39 2012 +0800
create a tag
commit 84073a0bffd4c80598dbc4941a5f84d78cc2adcd
Author: Saito <[email protected]>
Date: Fri Sep 14 01:12:07 2012 +0800
add readme
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/readme.md
@@ -0,0 +1 @@
+hello world
helloworld git:master ❯ git cat-file -p 1518c0a02530b3
object 84073a0bffd4c80598dbc4941a5f84d78cc2adcd
type commit
tag 1.0
tagger Saito <[email protected]> Fri Sep 14 01:24:39 2012 +0800
create a tag
可以看到,tag 里面主要存储的是 commit 的 SHA1 值,tag name 以及 tagger, 还有,如果有 -m 参数的话会有 tag message.
因为 branch 不在这套体制内。是体制外的。
跟基本对象相关的东西都存在 .git/objects
里面。
而 branch 是在同级的 .git/refs
目录里面的。而 refs 目录里面,每条 ref 记录,实际上 也是只 记录了一个 commit SHA1 而已。
四种对象创建完毕.. 回头再来看,什么时候会有什么 SHA1 已经很清楚的。
回到最初的问题。有没有办法能拿到 tree SHA1. 答案是没有。
没 commit 当然也不能拿到 commit SHA1.
当然也不是 tag. 所以不能拿 tag SHA1.
YES!. 你可以拿到当前修改过并且已经被 add 过的 blob 的 SHA1 git ls-files -s readme.md
.
就是这样。
谢谢,你写的太棒,太详细了!!!
不过有一点貌似不对,也是之所以我有这个问题的缘故,引用 Progit 中的一段话:
You can create your own tree. Git normally creates a tree by taking the state of your staging area or index and writing a tree object from it. So, to create a tree object, you first have to set up an index by staging some files. To create an index with a single entry — the first version of your text.txt file — you can use the plumbing command update-index.
你把建立树对象的这个步骤延后到提交 commit 之后,但是应该是 add 之后,这个树对象已经存在了。只不过不是以 objects 下 可见的形式存在的。但是 git 有办法获取他的 sha1 (这里指的是那个入口), 否则,git diff --cached, 就没办法工作了。我觉得一定有一个 sha1, 也许就在那个 .git/index 文件内。
我理解错了,哈哈~~ 我又细细看了下,貌似就是你说的那样~~
再说下之前的需求,以前 git diff 总是以 `单文件' 的形式,打开代码比较工具,常常是打开一堆 TAB, 一点都不直观,我要这个 SHA1, 最初,我是希望通过 git archive 的方式,打包成 tar, 然后直接比较 tar 文档的目录结构,一目了然。不过后来发现,获取 index 以及 获取当前目录下的文件 (所有被索引文件以及除去所有被 ignore 文件这两步不太好搞), 所以,最后我干脆用拷贝到临时目录的形式来实现了。所以这个需求也就解决了。
不行,无效的 SHA1
可能是我的需求太怪了吧。我希望比较一个项目内任意两个 SHA1 或者 分支,或者 INDEX, 不是使用 单个文件逐个打开' 的方式, 而是首先以目录结构的方式, 显示所有文件的改动, 然后我再查看我感兴趣的
文本内容`, 这样一目了然。
我上一张图解释下:
喜欢 GUI 类的 tool Mac 下可以试试 Tower,diff 应该给你改动的文件列表 http://www.git-tower.com/index.html 其他 的系统应该也有些 GUI tool
还有,把 index commit 了不就有 SHA1 了,比较完在 reset 不就行了