标签:echo hang parent 格式 rect 版本 tag 详细 ref
git中的命令分为plumbing命令和porcelain命令:
git add
,git commit
等命令阅读本文还需要了解.git目录的结构功能,以及git中的对象(commit对象、tree对象、blob对象等等)等概念,请自行参考其他文档。
git add file
在底层实际上完成了3个步骤:
下面用plumbing命令完成git add
的功能:
------------------------------------------------------------
~ ? git init demo
Initialized empty Git repository in /home/lvhao/demo/.git/
------------------------------------------------------------
~ ? cd demo
------------------------------------------------------------
~/demo(master) ? echo "nihao" >> nihao.txt
------------------------------------------------------------
~/demo(master*) ? git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
nihao.txt
nothing added to commit but untracked files present (use "git add" to track)
~/demo(master*) ? git hash-object -w nihao.txt # 对应于步骤1和2,-w表示写
ba9c1ad3d3b761e84cd8f9e9a18404f6f2552fcf
这时候查看.git/objects目录:
~/demo(master*) ? tree .git/objects
.git/objects
├── ba
│ └── 9c1ad3d3b761e84cd8f9e9a18404f6f2552fcf
├── info
└── pack
3 directories, 1 file
~/demo(master*) ? git update-index --add --info-only nihao.txt # 对应于步骤3(关于两个参数请参见git help update-index)
上面的update-index
,就是更新.git/index文件,有关该文件的详细格式请参考https://stackoverflow.com/questions/4084921/what-does-the-git-index-contain-exactly。
该index文件主要包含了存在于暂存区(即index)中文件条目,可以通过git ls-files --stage
来查看该文件的主要内容:
~/demo(master*) ? git ls-files --stage
100644 ba9c1ad3d3b761e84cd8f9e9a18404f6f2552fcf 0 nihao.txt
这时候,nihao.txt已经存在于暂存区(即index),所以说上面的三个步骤相当于git add nihao.txt
:
~/demo(master*) ? git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: nihao.txt
porcelain命令:
git add file
等同于plumbing命令:
git hash-object -w file
git update-index --add --info-only file
commit所做的工作实际上是对当前的工作树(working tree)拍一个”快照“然后保存起来,git commit
在底层实际上完成的步骤:
# 继续上面的代码
~/demo(master*) ? git write-tree # 即步骤1
8e335a3e0ffa15ff97acc7f4d97e03d63612ec7a
让我们查看一下这个tree对象,可见它保存了对当前工作目录下文件/目录的引用:
~/demo(master*) ? git cat-file -p 8e335a
100644 blob ba9c1ad3d3b761e84cd8f9e9a18404f6f2552fcf nihao.txt
~/demo(master*) ? git commit-tree -m "Initial Commit" 8e335a # 即步骤2
1f1fbcf8ff46d8d2548372c38cf3f1eabf8bfbc8 # 新生成的commit的SHA-1
这时候我们查看状态,还是待commit状态,这是因为commit-tree仅仅是生成了一个新的commit对象,并不会导致HEAD及分支的移动:
~/demo(master*) ? git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: nihao.txt
为了利用当前的分支,我们需要修改分支的引用,git update-ref refs/heads/分支名 commit-hash
命令来更新分支的位置到刚刚创建的commit:
~/demo(master*) ? git update-ref refs/heads/master 1f1fbc # 即步骤3
由于.git/HEAD默认就是指向master分支,所以得到如下结果:
~/demo(master) ? git status
On branch master
nothing to commit, working tree clean
查看一下提交日志:
~/demo(master) ? git log --graph --oneline
* 1f1fbcf (HEAD -> master) Initial Commit
porcelain命令的:
git commit -m "xxx" file
等同于plumbing命令的:
git write-tree # 得到tree的hash: tree-hash
git commit-tree -m "xxx" (-p parent-hash) tree-hash # 得到commit的hash,commit-hash
git update-ref refs/heads/分支名 commit-hash
使用plumbing命令来深入理解git add和git commit的工作原理
标签:echo hang parent 格式 rect 版本 tag 详细 ref
原文地址:https://www.cnblogs.com/Yaigu/p/9747420.html