使用plumbing命令来深入理解git add和git commit的工作原理

前言: plumbing命令 和 porcelain命令

git中的命令分为plumbing命令和porcelain命令:

  • porcelain命令就是我们常用的git add,git commit等命令
  • plumbing命令可以理解为更底层的命令,实际上一个porcelain命令可以由若干个plumbing命令完成(见下文),plumbing命令可以帮助我们了解git底层的工作原理

阅读本文还需要了解.git目录的结构功能,以及git中的对象(commit对象、tree对象、blob对象等等)等概念,请自行参考其他文档。

1. git add

git add file在底层实际上完成了3个步骤:

  1. 根据文件内容计算SHA-1值
  2. 将文件内容存储到仓库的数据库中(.git/objects)
  3. 将文件内容注册到.git/index文件中

下面用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

2. git commit

commit所做的工作实际上是对当前的工作树(working tree)拍一个”快照“然后保存起来,git commit在底层实际上完成的步骤:

  1. 根据当前的工作树生成一个tree对象(tree对象记录了当前工作目录的结构,保存有对当前版本的文件的引用),将tree对象保存到.git/objects下
  2. 由上述tree对象生成一个commit对象,(可选)并指明该commit对象的parent、message等信息
  3. 移动分支到新生成的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

转载于:https://www.cnblogs.com/Yaigu/p/9747420.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]:CMake Error at plumbing_pub_sub/CMakeLists.txt:148 (add_dependencies): The dependency target "plumbing_pub_sub_generate_message_cpp" of target "demo03_pub_person" does not exist. 引用\[2\]:CMake Error at CMakeLists.txt:4 (CMAKE_MINIMUM_REQUIRED): CMake 3.0.2 or higher is required. You are running version 2.8.12.2-- Configuring incomplete, errors occurred! 引用\[3\]:1、下载:curl -O https://cmake.org/files/v3.6/cmake-3.6.0-Linux-x86_64.tar.gz 2、解压:tar -zxvf cmake-3.6.0-Linux-x86_64.tar.gz 注意:这个压缩包不是源码包,解压后直接用。 3、增加环境变量,使其成为全局变量: vim /etc/profile 在文件末尾处增加以下代码 export PATH=$PATH:/lnmp/src/cmake-3.6.0-Linux-x86_64/bin 注意:写自己刚安装cmake的bin的路径 使修改的文件生效 source /etc/profile 4、查看环境变量: echo $PATH 5、检查cmake版本: cmake --version 问题: CMake Error at plumbing_pub_sub/CMakeLists.txt:137 (add_executable): Cannot find source file: 回答: 根据引用\[1\]中的错误信息,CMake在执行add_dependencies时报错,提示目标"plumbing_pub_sub_generate_message_cpp"不存在。这可能是由于CMakeLists.txt文件中的依赖关系设置有误导致的。另外,引用\[2\]中的错误信息显示你正在使用的CMake版本过低,需要使用CMake 3.0.2或更高版本。你可以根据引用\[3\]中的步骤下载并安装最新版本的CMake,并将其添加到全局环境变量中。这样可以解决CMake版本不兼容的问题。至于CMake Error at plumbing_pub_sub/CMakeLists.txt:137 (add_executable): Cannot find source file:的具体原因,需要查看CMakeLists.txt文件中的代码,确认是否正确指定了源文件的路径。 #### 引用[.reference_title] - *1* [ROS通信部分编译错误](https://blog.csdn.net/m0_44999129/article/details/123158488)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [CMake安装或CMake Error at CMakeLists](https://blog.csdn.net/banyu0052/article/details/101946043)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值