git 原理与操作

· 1314 words · 3 minute read

.git 的内部目录结构 🔗

Git 是一个内容寻址(content-addressable)文件系统, 在此之上提供了一个版本控制系统。

$ ls -F1
config
description
HEAD
hooks/
info/
objects/
refs/

HEAD 文件指向目前被检出的分支。.git/objects 目录存储数据内容。 refs 目录存储指向数据(分支、远程仓库和标签等)的提交对象的指针。index 文件保存暂存区信息。

上层命令 与 底层命令 🔗

checkout、branch、remote 等 git 子命令为上层命令。

底层命令得以让你窥探 Git 内部的工作机制,也有助于说明 Git 是如何完成工作的。 例如 底层命令 git hash-object 可将任意数据保存于 .git/objects 目录(即 对象数据库),并返回指向该数据对象的唯一的键 如何向 Git 中存入内容,以及如何将它们取出?
echo 'test content' | git hash-object -w --stdin
git cat-file -p 查看对象文件。

对象 🔗

Blob数据对象。 tree目录对象。commit 版本对象。以单独文件的形式保存在.git/objects目录

删除工作目录下的文件,可以用 git 从对象文件中恢复回来。 git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt

文件的每个版本所对应的 SHA-1 不好记。 blob 对象里没有没有存文件名(类似 inode 里没有存文件名), 引入 tree 对象了。


tree 目录对象解决多个文件组织,存文件名的问题。

git cat-file -p master^{tree} master 分支上最新的提交所指向的树对象。


commit 对象。跟踪项目的不同快照。

echo 'first commit' | git commit-tree d8329f git cat-file -p fdf4fc3

git 引用 🔗

Git 分支的本质:一个指向某一系列提交之首的指针或引用。
find .git/refs -type f -type f 指定只查找普通文件(files)。

.git/refs 目录下。
.git/refs/heads 包含了本地分支的引用。每个文件的内容是相应分支的最新提交的哈希值。
.git/refs/tags 包含了标签的引用。每个文件的内容是相应标签所指向的提交的哈希值。
.git/refs/remotes 包含了远程分支的引用。每个文件的内容是相应远程分支的最新提交的哈希值。

git update-ref refs/heads/test cac0ca

image

包文件 🔗

一个大文件,只修改了一行,存在两个 blob 对象文件里很占用空间。“包文件(packfile)”的二进制文件 git gc



work dir, index/staging area, repository 🔗

work dir (touch a.txt) -- git add a.txt --> index/staging area(blob 文件) --git commit -m "aa" --> repository.

undo the changes, rewrite history with confidence 🔗

git revert

git reset --soft HEAD~1 git reflog

git cherry-pick commit-id git log -g

diff & patch, merge, 3 way merge, rebase(只操作本地的 commit,远程其他人依赖的 commit 不要操作)。

删除 commit 🔗

git reset 🔗

git reset --soft 仅移动 HEAD, git reset --mixed 移动 HEAD,更改 index 暂存区, git reset --hard 移动 HEAD,更改 index 暂存区,更改工作目录。

git log git reset --hard commit_id git push origin HEAD --force // 误删除后的恢复 git relog git reset --hard hash_id

git revert 🔗

git cheri-pick git reflog

git rebase 🔗

这个视频很清楚。https://www.youtube.com/watch?v=CRlGDDprdOQ 两个用处: 分支合并,基于的 commitid 变基分支。 合并 local commit 记录,需要 rebase 的所有 commits 历史还没有被 push 过。

合并 commit 🔗

有些对 git 的提交记录有要求,需要合并 commit git merge --squash xx_branch 接着需要 git commit -m "merge info"

整合来自不同分支的修改主要有两种方法:merge 以及 rebase。

git pull 与 git pull -rebase 的区别 🔗

fetch 之后的 merge 和 rebase 操作不同。
git pull == git fetch + git merge FETCH_HEAD git pull -rebase == git fetch + git rebase FETCH_HEAD

git internals 内部 🔗

执行 git commit 时发生了什么? 每次 commit 时存储了什么? git init 时发生了什么?

object: blob, tree, commit。

分支 branch。

working directory, staging area, repository。

可能会遇到的问题 🔗

git cat-file -p objectName -> Fatal error : Not a valid object name 🔗

.git/objects/ff/e531e3643e95e811da231410f14c76e12a68be objectName=ffe531e3643e95e811da231410f14c76e12a68be

🔗