

使用 git 底层命令创建提交
source link: https://blog.lilydjwg.me/2015/2/8/create-git-commits-with-plumbing-commands.79611.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用 git 底层命令创建提交
本文来自依云's Blog,转载请注明。
通常,创建 git 提交使用的是 git add、git commit 这些高层命令。这些命令有个特点:它们都需要工作区的存在,并且很可能会改变工作区里的文件。
如果没有工作区,或者工作区不能用的时候怎么办呢?比如想在服务器上的纯(旧称:祼)版本库里的钩子脚本里创建提交,在版本库被更新时自动生成点东西什么的。一个简单的解决方案是再克隆一份,然后在那边弄好了再 push 过来。但那样的话,你得区分一次 push 是不是由你的脚本自身触发的了。这当然是可行的,但是,不觉得直接操作纯版本库更有意思吗 O(∩_∩)O~
或者,如果你的工作区里有一个文件叫「test」,另一个文件叫「Test」,而你当前能使用的文件系统和/或操作系统是不区分文件名大小写的,这样可能就没有办法通过工作区做想要的改动了。
我之前也曾用 pygit2 来直接创建提交。那个还是比较基础的,还是需要工作区。这次让我向大家介绍一下我的新玩法,深入 git 底层,围观一下一个提交的诞生历程~~(其实是早就玩过了的,只是一直没有分享出来而已 >_<
首先,克隆一个版本库来玩儿。直接在已有的版本库里玩太危险了,万一不小心玩坏了就囧了(虽然也不是多大的问题,毕竟我有备份的嘛=w=
git clone --bare ~/.vim dotvim
读者想要一起玩的话,可以从网络克隆我的 vim 配置版本库,如
git clone --bare git:
//github
.com
/lilydjwg/dotvim
dotvim
进去 dotvim 目录里 ls 一下,可以看到,只剩下以前在 .git 目录里会见到的文件了呢:
>>>
ls
branches config description HEAD hooks index info objects packed-refs refs
要创建的提交是在 master 分支上。我们先使用 ls-tree 命令看看这个分支上有哪些文件。ls-tree 其实是列出 tree 对象用的,加上 -r 参数就会递归地把 tree 对象里的 tree 对象给列出来,就像 -R 之于 ls 命令一样。
不过你给它提交(commit)对象也可以的啦。它会自动取这个提交所指向的 tree 对象:
git
ls
-tree -r master
git
ls
-tree -r
'master^{tree}'
嗯,分支名实际上是指向这个分支上的最后一个对象的符号引用。
我要把 vimrc 文件里的注释行全删掉。要想修改一个文件,就得先找到要修改的文件,而不像添加文件那样直接加进去就可以了。让我们把要修改的 vimrc 文件的 hash 值找出来:
old_vimrc=$(git
ls
-tree -r master |
awk
'$4 == "vimrc" { print $3 }'
)
当然这里是不必用 -r 的啦。写在这里方便嘛,下一次想改 plugin 目录下的东西可以直接改路径就可以了,不用担心要改其它可能会忘记的东西。
然后拿 cat-file 命令看看这个 blob 对象。cat-file 命令我用得挺多的,因为经常会想看看另一个分支、或者另一个提交里某个文件长什么样子。
git
cat
-
file
-p $old_vimrc
其实这里可以直接指定要显示的对象的,比如master:vimrc
就是 master 对应的提交上的 vimrc 文件。如果使用 zsh 的话,冒号后边的路径部分也是可以补全的哦。这里为了阐述原理,就做「分解动作」了。
得到了文件内容,就可以修改了。修改完毕,使用 hash-object 命令将文件存入 git 对象数据库里。这一句命令相当于修改好文件之后再做 git add 操作。hash-object 会返回对象的 hash 值。我们得把它记下来。
new_vimrc=$(git
cat
-
file
-p $old_vimrc |
sed
'/^"/d'
| git
hash
-object -w --stdin --path vimrc)
不管之前有没有,先删一下 index,也就是所谓的「staging area」。已经添加但是还未提交的目录树就存在这个文件里边了。
rm
-f index
然后,创建我们需要的 index。得使用 ls-tree 命令列出所有文件的信息,然后把我们修改过的信息加到末尾,会自动覆盖之前已有的项。如果删除这个列表里的某些项的话,就相当于是删除了那些文件。如果添加原本不存在的项,就是添加文件了。
{git
ls
-tree -r master;
echo
-e
"100644 blob $new_vimrc\tvimrc"
;} | git update-index --add --index-info
index 已经准备好了。我们把目录树写到 git 对象数据库里吧:
new_master_tree=$(git write-tree)
我们得到了一个新的 tree 对象的 hash 值。当然因为目录树是树状的,以上命令实际上会写入多个 tree 对象。我们只要有根 tree 对象的 hash 值就可以了。
该创建提交对象了:
commit=$(git commit-tree -p master -m
'在没有工作区的情况下创建的提交'
$new_master_tree)
提交对象创建好还不够。那只是一个提交对象而已,我们还没有更新分支的信息呢。我们把这个提交作为新的 master 分支的头:
git update-ref refs
/heads/master
"$commit"
大功告成!
可以使用git show
和git log
看看成果了哦~
当然,如果想要钩子脚本里使用的话,记得在修改前加锁哦。
参考资料。
Recommend
-
14
linux下创建可引导的U盘系统,使用dd命令进行Linux的ghost
-
14
10.1 Git 内部原理 - 底层命令与上层命令 无论是从之前的章节直接跳到本章,还是读完了其余章节一直到这——你都将在本章见识到 Git 的内部工作原理和实现方式。 我们认为学习这部分内容对于理解 Git 的用途和强大至关重要。不过也有人认为这些内容对...
-
7
Git常用低频底层命令 原创 编辑 ...
-
10
使用SVN命令快速创建trunk、tags和branches目录 众所周知,在SVN仓库中,branches、tr...
-
3
使用 pygit2 创建提交 本文来自依云's Blog,转载请注明。
-
4
怎样在 Linux 终端下使用 dd 命令创建一个临场 USB 驱动器 | Linux 中国深 Linux 用户可能更喜欢使用 dd 命令在 Linux 终端中创建临场 USB,这会更快速便捷。来源:
-
5
4月25日起,开发者向App Store提交的应用必须使用Xcode 13创建 2022年03月16日08:07 IT之家 我有话说(0人参与) 收藏...
-
11
当用户使用的不是企业证书解决方案,或者由于某种原因不想通过 CA 购买证书,如用于测试等场景,则需要创建自签名证书。 可以通过 Linux 的 OpenSSL 命令行工具生成自签名证书,实现加密解密, 甚至还可以当做 CA 来用,创建以及吊销证书。使用 OpenSSL...
-
8
用 git log 命令显示在特定日期的提交记录 作者:Agil Antony 2022-11-06 20:40:24 git log 命令是 Git 中一个很重要的查看提交记录的工具,它也是人们喜欢使用 Git 的原因之一。
-
5
在花费数小时修复 bug 或更新特性之后,我们开发人员最不愿意做的事情往往是仔细说明 Git 提交的内容。最新的 Visual Studio 预览版可以帮到您。使用新的生成 Git 提交消息特性来帮助您描述变更集。然后,您可以用“why”进行更改来细化消息并提交。
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK