To-Dogit object.git 目录结构详细解释一些关键概念和文件的作用什么是hooks?钩子的工作原理钩子目录中的每个 sample 文件如何使用这些钩子提交(Commit)流程合并(Merge)流程补丁应用(Apply Patch)流程推送(Push)流程变基(Rebase)流程发送邮件(Send Email)流程服务器端的钩子接收推送(Receive Push)完整流程图Git 三个分区常用git命令GitHub 工作流 (Fork+PR)参考链接
Gitlab runner
GitHub action
Gogs https://gogs.io/
shameless@192 learngit % git init提示:使用 'master' 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中提示:配置使用初始分支名,并消除这条警告,请执行:提示:提示: git config --global init.defaultBranch <名称>提示:提示:除了 'master' 之外,通常选定的名字有 'main'、'trunk' 和 'development'。提示:可以通过以下命令重命名刚创建的分支:提示:提示: git branch -m <name>已初始化空的 Git 仓库于 /Users/shameless/github/learngit/.git/shameless@192 learngit % ls -altotal 0drwxr-xr-x 3 shameless staff 96 7 12 22:55 .drwxr-xr-x 5 shameless staff 160 7 12 22:47 ..drwxr-xr-x 9 shameless staff 288 7 12 22:55 .gitshameless@192 learngit % echo '222' > b.txtshameless@192 learngit % echo '111' > a.txtshameless@192 learngit % git add *.txt
shameless@192 learngit % tree .git/objects.git/objects├── 58│ └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c├── c2│ └── 00906efd24ec5e783bee7f23b5d7c941b0c12c├── info└── pack
shameless@192 learngit % git cat-file -t 58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6cblobshameless@192 learngit % git cat-file -p 58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c111shameless@192 learngit % git cat-file -t c200906efd24ec5e783bee7f23b5d7c941b0c12cblobshameless@192 learngit % git cat-file -p c200906efd24ec5e783bee7f23b5d7c941b0c12c222x
shameless@192 learngit % git commit -m '[+] init'[master(根提交) ceff1c5] [+] init 2 files changed, 2 insertions(+) create mode 100644 a.txt create mode 100644 b.txtshameless@192 learngit % tree .git/objects.git/objects├── 4c│ └── aaa1a9ae0b274fba9e3675f9ef071616e5b209├── 58│ └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c├── c2│ └── 00906efd24ec5e783bee7f23b5d7c941b0c12c├── ce│ └── ff1c55f0c91a6f70fc6e1a1880cc859e53e70e├── info└── pack
7 directories, 4 files
shameless@192 learngit % git cat-file -t ceff1c55f0c91a6f70fc6e1a1880cc859e53e70ecommit
shameless@192 learngit % git cat-file -p ceff1c55f0c91a6f70fc6e1a1880cc859e53e70etree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209author acshameless <[email protected]> 1720799819 +0800committer acshameless <[email protected]> 1720799819 +0800
[+] init
shameless@192 learngit % git cat-file -t 4caaa1a9ae0b274fba9e3675f9ef071616e5b209treeshameless@192 learngit % git cat-file -p 4caaa1a9ae0b274fba9e3675f9ef071616e5b209100644 blob 58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c a.txt100644 blob c200906efd24ec5e783bee7f23b5d7c941b0c12c b.txtx
shameless@192 learngit % cat .git/refs/heads/masterceff1c55f0c91a6f70fc6e1a1880cc859e53e70eshameless@192 learngit % git cat-file -t ceff1c55f0c91a6f70fc6e1a1880cc859e53e70ecommitshameless@192 learngit % git cat-file -p ceff1c55f0c91a6f70fc6e1a1880cc859e53e70etree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209author acshameless <[email protected]> 1720799819 +0800committer acshameless <[email protected]> 1720799819 +0800
[+] initblob
文件内容
tree
目录结构、文件权限、文件名
commit
上一个 commit 对应快照、作者、提交信息
Refs
HEAD、Branch、Tag
shameless@192 learngit % tree .git.git├── HEAD├── config├── description├── hooks│ ├── applypatch-msg.sample│ ├── commit-msg.sample│ ├── fsmonitor-watchman.sample│ ├── post-update.sample│ ├── pre-applypatch.sample│ ├── pre-commit.sample│ ├── pre-merge-commit.sample│ ├── pre-push.sample│ ├── pre-rebase.sample│ ├── pre-receive.sample│ ├── prepare-commit-msg.sample│ ├── push-to-checkout.sample│ ├── sendemail-validate.sample│ └── update.sample├── info│ └── exclude├── objects│ ├── info│ └── pack└── refs ├── heads └── tags
9 directories, 18 files
在你初始化了一个新的 Git 仓库后,目录结构 .git 文件夹包含了一些关键的文件和子目录,它们共同构成了一个 Git 仓库的核心。让我们详细解释一下其中每个文件和目录的作用:
HEAD:
这个文件包含了当前被检出的分支的引用。默认情况下,它指向 refs/heads/master,也就是 master 分支。
shameless@192 learngit % cat .git/HEADref: refs/heads/masterconfig:
这个文件包含了仓库的配置选项。可以在这里设置用户信息、别名、钩子等。你也可以用 git config 命令来修改这个文件。
shameless@192 learngit % cat .git/config[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = truedescription:
这个文件通常用于描述仓库的内容。这在 GitWeb 这样的 Git 浏览工具中会被用到。
shameless@192 learngit % cat .git/descriptionUnnamed repository; edit this file 'description' to name the repository.hooks:
这个目录包含了一些示例钩子脚本(以 .sample 结尾)。你可以根据需要自定义这些钩子脚本,以便在不同的 Git 操作(如提交、推送等)发生时执行特定的操作。
info:
这个目录通常包含一些不需要版本控制的信息文件。exclude 文件是在全局 .gitignore 文件之外的额外忽略文件列表。
shameless@192 learngit % cat .git/info/exclude# git ls-files --others --exclude-from=.git/info/exclude# Lines that start with '#' are comments.# For a project mostly in C, the following would be a good set of# exclude patterns (uncomment them if you want to use them):# *.[oa]# *~objects:
这个目录用于存储所有的数据对象,包括提交对象、树对象和文件对象。Git 使用哈希值(SHA-1)作为对象的唯一标识符。
info 和 pack 子目录分别用于存储对象的额外信息和打包对象。
shameless@192 learngit % ls -al .git/objects/infototal 0drwxr-xr-x 2 shameless staff 64 7 12 22:55 .drwxr-xr-x 4 shameless staff 128 7 12 22:55 ..shameless@192 learngit % ls -al .git/objects/packtotal 0drwxr-xr-x 2 shameless staff 64 7 12 22:55 .drwxr-xr-x 4 shameless staff 128 7 12 22:55 ..refs:
这个目录包含了指向提交对象的引用(即分支和标签)。
heads 子目录包含了本地分支。
tags 子目录包含了标签。
xxxxxxxxxxshameless@192 learngit % ls -al .git/refs/headstotal 0drwxr-xr-x 2 shameless staff 64 7 12 22:55 .drwxr-xr-x 4 shameless staff 128 7 12 22:55 ..shameless@192 learngit % ls -al .git/refs/tagstotal 0drwxr-xr-x 2 shameless staff 64 7 12 22:55 .drwxr-xr-x 4 shameless staff 128 7 12 22:55 ..HEAD 文件:
这是一个非常重要的文件,它决定了当前检出的分支或提交。文件内容通常是 ref: refs/heads/master,表示当前检出的分支是 master。
config 文件:
这个文件是 Git 仓库的配置文件,可以配置很多选项,比如用户信息、文件过滤、外部工具等。配置文件的格式是 INI 格式,分为不同的部分(section),每个部分包含不同的配置项。
钩子(hooks):
Git 钩子是一些脚本,在特定的 Git 操作发生时被触发。常见的钩子包括 pre-commit(提交前),post-commit(提交后),pre-push(推送前)等。你可以自定义这些钩子来执行一些自动化操作,比如代码风格检查、测试等。
objects 目录:
这个目录是 Git 的核心数据存储。每个对象(提交、树、文件)都存储在这里,文件名是对象的哈希值(SHA-1)。info 子目录包含一些额外的信息文件,pack 子目录用于存储打包的对象文件。
refs 目录:
这个目录包含了所有的引用。heads 子目录包含所有的本地分支,每个文件的内容是一个提交对象的哈希值。tags 子目录包含所有的标签,每个文件的内容也是一个提交对象的哈希值。
通过这些文件和目录,Git 能够高效地管理版本控制工作。希望这些解释对你理解 Git 的内部结构有所帮助!
Git 钩子(hooks)是一种机制,允许你在特定的 Git 操作发生时自动执行自定义脚本。钩子可以帮助自动化各种工作流,比如代码检查、测试、部署等。
Git 钩子有两种类型:
客户端钩子:这些钩子在客户端仓库中运行,通常用于检查代码质量或执行其他本地操作。
服务器端钩子:这些钩子在服务器端仓库中运行,通常用于执行访问控制或其他服务器端操作。
当你执行一个 Git 操作(如提交、推送等)时,Git 会检查相应的钩子文件是否存在。如果存在且是可执行的,Git 会在执行该操作前或后调用这个钩子脚本。
钩子脚本可以是任何可执行文件,比如 Shell 脚本、Python 脚本等。钩子文件的命名必须与 Git 预定义的钩子名称一致,并且需要去掉 .sample 后缀。
这些钩子可以帮助你在不同的 Git 操作过程中自动执行各种任务,实现代码质量控制、自动化部署、权限管理等功能。希望这些使用场景能帮助你更好地理解和应用 Git 钩子。
以下是 .git/hooks 目录中每个示例钩子(.sample 文件)的详细解释:
applypatch-msg.sample:
在 git am 应用补丁前触发。主要用于修改或验证补丁的提交消息。
使用场景:在使用 git am 应用补丁时,确保提交消息符合团队的格式规范。例如,你可以检查提交消息是否包含特定的关键字或遵循特定的格式。
示例:确保提交消息以 JIRA 任务号开头。
commit-msg.sample:
在 git commit 创建提交对象前触发。可以用于验证或修改提交消息。
使用场景:在提交代码时,验证提交消息是否符合规范,或者自动添加一些信息。例如,确保提交消息的长度不超过 50 个字符,并且以动词开头。
示例:添加一个脚本检查提交消息是否符合 Conventional Commits 规范。(强烈建议读一遍)
fsmonitor-watchman.sample:
用于与 Watchman 集成以提高文件系统监视性能。主要用于性能优化。
使用场景:在大型项目中,通过集成 Watchman 提高文件系统监视性能,减少 Git 操作的等待时间。
示例:在包含大量文件的仓库中,使用 Watchman 监视文件变化,提高 git status 的速度。
post-update.sample:
在 git push 更新服务器端仓库后触发。常用于通知其他系统更新或触发部署脚本。
使用场景:在服务器端更新仓库后,通知相关系统或触发后续操作。例如,通知 CI/CD 系统触发构建和部署。
示例:在推送到远程仓库后,触发 Jenkins 构建任务。
pre-applypatch.sample:
在 git am 应用补丁前触发。可以用于检查补丁的有效性或执行其他验证。
使用场景:在应用补丁前,检查补丁的有效性或执行代码风格检查。例如,确保补丁中的代码符合团队的代码风格规范。
示例:在应用补丁前运行 lint 工具,检查代码风格问题。
pre-commit.sample:
在 git commit 创建提交对象前触发。常用于代码风格检查、运行测试等。
使用场景:在提交代码前,进行代码检查、测试等操作。例如,运行单元测试,确保代码没有引入新的错误。
示例:在提交代码前,运行 eslint 和 jest,确保代码风格和单元测试通过。
pre-merge-commit.sample:
在 git merge 提交前触发。可以用于验证合并是否符合预期。
使用场景:在合并提交前,检查合并是否符合预期。例如,确保合并不会引入冲突或破坏现有功能。
示例:在合并前运行集成测试,确保合并不会引入新的错误。
pre-push.sample:
在 git push 推送到远程仓库前触发。可以用于检查推送内容或执行其他验证。
使用场景:在推送到远程仓库前,进行代码检查或验证。例如,确保推送的代码已经通过所有测试。
示例:在推送前运行 pre-push 钩子,检查所有单元测试和集成测试是否通过。
pre-rebase.sample:
在 git rebase 开始前触发。可以用于检查 rebase 是否安全。
使用场景:在开始 rebase 操作前,检查 rebase 是否安全。例如,确保当前分支没有未解决的冲突。
示例:在 rebase 前,检查当前分支是否有未提交的更改,防止数据丢失。
pre-receive.sample:
在服务器端接收到推送数据前触发。常用于访问控制和验证推送内容。
使用场景:在服务器端接收到推送数据前,进行访问控制和验证。例如,确保推送的代码符合公司的代码质量标准。
示例:在接收推送前,运行代码质量检查工具,拒绝不符合标准的推送。
prepare-commit-msg.sample:
在 git commit 创建提交消息前触发。可以用于预填充提交消息模板或修改提交消息。
使用场景:在创建提交消息前,预填充提交消息模板或添加额外信息。例如,自动在提交消息中添加当前分支名称。
示例:在创建提交消息前,自动添加 JIRA 任务号作为提交消息的前缀。
push-to-checkout.sample:
在服务器端 git push 更新工作目录后触发。主要用于部署环境。
使用场景:在服务器端仓库更新工作目录后,触发自动化部署或其他操作。例如,在推送后自动部署新版本的应用。
示例:在推送到服务器后,自动执行 git checkout 和 docker-compose up,部署新版本。
sendemail-validate.sample:
在 git send-email 发送邮件前触发。可以用于验证邮件内容或收件人。
使用场景:在发送邮件前,验证邮件内容和收件人。例如,确保发送的邮件没有敏感信息。
示例:在发送邮件前,检查邮件内容是否包含敏感信息,并验证收件人列表。
update.sample:
在服务器端 git push 更新引用(如分支、标签)前触发。用于验证推送的引用更新。
使用场景:在服务器端更新引用(如分支、标签)前,进行验证。例如,确保只有特定用户可以更新 master 分支。
示例:在更新分支前,检查用户权限,防止未经授权的推送。
要使用这些钩子,你需要将相应的 .sample 文件重命名并去掉 .sample 后缀,然后根据需要编辑脚本内容。例如:
xxxxxxxxxxmv .git/hooks/pre-commit.sample .git/hooks/pre-commit然后编辑 pre-commit 文件,添加你的自定义逻辑。确保该文件是可执行的:
xxxxxxxxxxchmod +x .git/hooks/pre-commit这样,当你执行 git commit 时,Git 会在提交前自动调用 pre-commit 钩子。
希望这些解释能帮助你更好地理解和使用 Git 钩子!
好的,理解不同 Git 钩子的触发时机和顺序对于有效使用它们非常重要。下面我将提供一个流程图,展示主要钩子在不同 Git 操作中的触发顺序。
理解不同 Git 钩子的触发时机和顺序对于有效使用它们非常重要。下面我将提供一个流程图,展示主要钩子在不同 Git 操作中的触发顺序。
当然,可以为每个钩子的触发时机补充对应的 Git 命令操作。这样你就能更清楚地知道在执行哪些命令时,哪些钩子会被触发。
pre-commit:
触发时机:在提交创建前。
对应命令:git commit
prepare-commit-msg:
触发时机:在编辑提交消息前。
对应命令:git commit
commit-msg:
触发时机:在提交消息编辑完成后。
对应命令:git commit
post-commit:
触发时机:在提交完成后。
对应命令:git commit
xxxxxxxxxxgit commit|pre-commit|prepare-commit-msg|commit-msg|post-commit
pre-merge-commit:
触发时机:在合并提交创建前。
对应命令:git merge
post-merge:
触发时机:在合并完成后。
对应命令:git merge
xxxxxxxxxxgit merge|pre-merge-commit|post-merge
pre-applypatch:
触发时机:在 git am 应用补丁前。
对应命令:git am
applypatch-msg:
触发时机:在编辑补丁的提交消息前。
对应命令:git am
post-applypatch:
触发时机:在补丁应用完成后。
对应命令:git am
xxxxxxxxxxgit am|pre-applypatch|applypatch-msg|post-applypatch
pre-push:
触发时机:在推送到远程仓库前。
对应命令:git push
pre-receive(远程仓库):
触发时机:在接收到推送数据前。
对应命令:git push
update(远程仓库):
触发时机:在更新引用(分支、标签)前。
对应命令:git push
post-receive(远程仓库):
触发时机:在推送数据处理完成后。
对应命令:git push
post-update(远程仓库):
触发时机:在更新引用完成后。
对应命令:git push
xxxxxxxxxxgit push|pre-push|Push to remote|pre-receive (remote)|update (remote)|post-receive (remote)|post-update (remote)
pre-rebase:
触发时机:在开始 rebase 操作前。
对应命令:git rebase
post-rewrite:
触发时机:在 rebase 操作完成后。
对应命令:git rebase
xxxxxxxxxxgit rebase|pre-rebase|post-rewrite
sendemail-validate:
触发时机:在发送邮件前。
对应命令:git send-email
xxxxxxxxxxgit send-email|sendemail-validate
pre-receive:
触发时机:在接收到推送数据前。
对应命令:git push
update:
触发时机:在更新引用(分支、标签)前。
对应命令:git push
post-receive:
触发时机:在推送数据处理完成后。
对应命令:git push
post-update:
触发时机:在更新引用完成后。
对应命令:git push
xxxxxxxxxxgit push|pre-receive (remote)|update (remote)|post-receive (remote)|post-update (remote)
通过这个详细的对应表,你可以更清楚地知道在执行哪些 Git 命令时,哪些钩子会被触发,从而更好地设计和使用这些钩子来满足你的需求。
xxxxxxxxxxCommit:pre-commit|prepare-commit-msg|commit-msg|post-commitMerge:pre-merge-commit|post-mergeApply Patch:pre-applypatch|applypatch-msg|post-applypatchPush:pre-push|Push to remote|pre-receive (remote)|update (remote)|post-receive (remote)|post-update (remote)Rebase:pre-rebase|post-rewriteSend Email:sendemail-validateReceive Push (Server-Side):pre-receive|update|post-receive|post-update
通过这个流程图,你可以更清晰地了解每个钩子在不同操作中的触发顺序和时机。希望这能帮助你更好地理解和使用 Git 钩子。
工作目录
索引 index
git repo
x
shameless@192 learngit % echo '333' > c.txtshameless@192 learngit % git status位于分支 master未跟踪的文件: (使用 "git add <文件>..." 以包含要提交的内容) c.txt
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)shameless@192 learngit % git add c.txtshameless@192 learngit % git status位于分支 master要提交的变更: (使用 "git restore --staged <文件>..." 以取消暂存) 新文件: c.txt
shameless@192 learngit % git add c.txtshameless@192 learngit % git status位于分支 master要提交的变更: (使用 "git restore --staged <文件>..." 以取消暂存) 新文件: c.txt
shameless@192 learngit % git commit -m "[2nd] +c.txt"[master b6c9172] [2nd] +c.txt 1 file changed, 1 insertion(+) create mode 100644 c.txtshameless@192 learngit % git status位于分支 master无文件要提交,干净的工作区
git命令配置 user.name 和 user.email
xxxxxxxxxxgit config --global user.name "acshameless"git config --global user.email "[email protected]"
[optional]--local 只对某个仓库有效--global 当前用户所有仓库有效--system 对系统所有登陆的用户有效显示已有配置信息
xxxxxxxxxxgit config --list --localgit config --list --globalgit config --list --system
--local 优先级高于 --globalgit cat-file
xxxxxxxxxx# 查看哈希字符串的类型git cat-file -t c620ffb
# 查看哈希字符串的内容git cat-file -p c620ffb
# 查看哈希字符串的大小git cat-file -s c620ffb修改commit message
xxxxxxxxxx# 最近一次git commit --amend
# 变基操作,合并连续 or 非连续的commit, commit 整理git rebase -i文件比较
xxxxxxxxxx# 暂存区 与 版本库git diffgit diff --cached
# 工作区 与 暂存区git diff git diff -- <filename>恢复
xxxxxxxxxx# 工作区文件状态 恢复为 暂存区文件状态git checkout -- <filename>git diff <filename>
# 暂存区文件状态 恢复为 HEAD文件状态# 暂存区已有文件 恢复至 工作区git reset HEADgit reset HEAD -- <filename>git diff --cached
# 工作区 和 暂存区 文件 恢复为 某个commit# 将 已经commit 的内容,恢复至暂存区git reset --soft <hash-value>
# 工作区 和 暂存区 文件 恢复为 某个commit# tracked 的 modified 全部清空# untracked 保留git reset --hard <hash-value> 临时任务
git add .git stashgit checkout <tmp-branch>...git checkout <work-branch>git stash pop
## worktree 新git worktree add ../path-to-file <branch-name>git worktree listcd ../path-to-file....cd git worktree remove ../path-to-file备份(几乎用不到),支持多点备份s1,s2,s3
xxxxxxxxxx# 本地备份git clone --bare /User/shameless/git-projects-s0/.git ya.gitgit clone --bare file:///User/shameless/git-projects-s0/.git zhineng.git
git remote add zhineng file:///User/shameless/git-projects-s1/zhineng.git
# 远端备份git remote add <remote-name> remote-address
分支信息
xxxxxxxxxx# 链接网络git remote show origin合并分支
xxxxxxxxxxgit pull || git fetch# 合并不相干的分支 git merge --allow-unrelated-histories <branch-name>删除分支
xxxxxxxxxx# 本地1git branch -d <branchname>git branch -D <branchname>
# 本地2git remote prunegit fetch --prune
# 远端git push origin --delete <branch-name>压缩
xxxxxxxxxx
gi# .git/objects/pack/xxxxx.idx 索引文件# .git/objects/pack/xxxxx.pack 压缩文件
git verify-pack -v <索引文件 || 压缩文件>
git remote show 解压
xxxxxxxxxx# 将 pack 文件 copy 出git仓库
git unpack-objects < /path/to/packfile垃圾清理
xxxxxxxxxxgit gc
git prune
# stackoverflow 搜一下查看索引区文件
xxxxxxxxxxgit ls-filesgit ls-files -s增加标签
xxxxxxxxxx# lightweight # .git/refs/tagsgit tag <tag-name> [commit-hash]
# annotated# .git/refs/tags# .git/objects# tag message# tag author and dategit tag -a <tag-name> -m <message> [commit-hash]
# history commit taggit tag <tag-name> <commit-hash>删除标签
xxxxxxxxxx# list taggit tag
git tag -d <tag-name>git 维护
xxxxxxxxxx# 取top20的大文件git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -20 | awk '{print$1}')"
# 取大于500k的大文件git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | awk '{if($3>500000)print $1}')"xxxxxxxxxxgit filter-branch --tree-filter 'rm -f password.txt' HEAD
git
xxxxxxxxxxgit blamegit bisectgit log --oneline --graph
x
# 1. fork + prForkgit clone <repo>
# 2. my-feat branchgit checkout -b my-feat
git diff
git add/commit
# 3. update before pushgit checkout mastergit pull origin mastergit checkout my-featgit rebase master
# 4. push & prgit push -f origin my-feat
New pull request
# 5. clean & updategit checkout mastergit branch -D my-featgit pull origin master
图解Git https://marklodato.github.io/visual-git-guide/index-zh-cn.html
Git基本原理介绍 https://space.bilibili.com/364122352/channel/collectiondetail?sid=290009
极客时间玩转Git三剑客
LearnGitBranching Game https://github.com/pcottle/learnGitBranching
Oh my git game https://github.com/git-learning-game/oh-my-git
有关 git 的学习资料 https://github.com/xirong/my-git