git 实践
本文主要收集有关 git 相关的优化及使用技巧。
git
git 是使用最广的分布式代码版本控制系统.
参考文档:
working
在 Git 中,working directory(工作目录)是指当前正在进行编辑和修改的文件的目录。它是与 Git 仓库中的版本控制系统相对应的文件系统中的一个目录。
当在工作目录中进行修改时,Git 会跟踪这些更改并将其标记为未暂存的更改。这意味着这些更改尚未被提交到 Git 仓库中。工作目录中的文件可以包括新创建的文件、已修改的文件和已删除的文件。
工作目录是进行开发和编辑的主要区域。可以在工作目录中添加、修改和删除文件,然后使用 Git 的各种命令来管理这些更改。当准备好将更改提交到 Git 仓库时,可以使用 git add 命令将更改暂存到暂存区,然后使用 git commit 命令将更改提交到仓库。
总结来说,工作目录是进行开发和编辑的区域,其中包含了对文件的修改。Git 会跟踪这些修改并提供一系列命令来管理和提交这些更改。
index
在 Git 中,"index" 是指暂存区(也称为索引或缓存)。暂存区是 Git 的一个重要概念,它充当了工作区和最终提交的代码库之间的中间层。
当在工作区修改了文件后,Git 并不会立即将这些修改提交到代码库中。相反,Git 要求将修改的文件添加到暂存区,然后再将暂存区的内容提交到代码库中。这个过程分为两个步骤:
-
将修改的文件添加到暂存区:使用 git add 命令将工作区的修改添加到暂存区。这样,Git 就会将这些修改纳入下一次提交的范围内。
-
将暂存区的内容提交到代码库:使用 git commit 命令将暂存区的内容提交到代码库中。这样,Git 就会创建一个新的提交,包含了暂存区的内容,并将其添加到代码库的历史记录中。
通过使用暂存区,可以对提交进行精细的控制。可以选择性地将修改的文件添加到暂存区,而不是一次性提交所有的修改。这样可以帮助构建更有意义的提交,使代码库的历史记录更加清晰和可读。
HEAD
在 Git 中,HEAD 是一个指向当前所在分支最新提交的指针。它可以被看作是当前工作树的快照,指示了当前所在分支的最新提交。
HEAD 在 Git 中有两个主要的作用:
-
标识当前所在分支的最新提交:当在 Git 中进行提交操作时,HEAD 会自动更新为最新的提交。这意味着 HEAD 始终指向当前所在分支的最新提交。
-
作为切换分支的指针:当切换分支时,HEAD 会随之移动到新分支的最新提交。这样,就可以在不同的分支之间进行切换,并查看每个分支的最新提交。
在 Git 中,HEAD 通常指向一个分支引用,例如 refs/heads/master。这表示 HEAD 当前指向 master 分支的最新提交。当在 Git 中进行提交操作时,新的提交将被添加到当前所在分支的提交历史中,并且 HEAD 将指向这个新的提交。
除了指向分支引用,HEAD 还可以指向一个具体的提交哈希值。这种情况下,处于 “分离头指针” 状态,意味着不再位于任何分支上,而是直接在某个特定的提交上工作。
总之,HEAD 在 Git 中是一个重要的指针,用于标识当前所在分支的最新提交。它允许在不同的分支之间进行切换,并且在提交操作时自动更新为最新的提交。
git auto-complete
bash auto-complete
使用 git 提供的补全脚本
1 | echo "source /usr/share/bash-completion/completions/git" >> ~/.bashrc |
powershell auto-complete
使用 choco install git-posh
1 | # Set your PowerShell execution policy |
reference
git EOL
[!TIP]
优化文件从 windows 挂进容器时,git 触发多个文件更改问题,tips-and-tricks。
1 | # .gitattributes |
git LFS
git 配置参考 LFS 和 Devcontainer
LFS 配置示例如下,将常用的 AI 模型文件作为 LFS 形式提交:
1 | # Model Format |
git rebase
links:
modify history
将遗漏的提交提交到历史中倒是第 2 个记录中
1 | # rebase 提取两个记录 |
Squash in git
通过 Interactive Rebase 实现,将第一个提交后面的提交改成 s,保存退出,按照提示操作即可。
1 | # rebase 操作后续 3 个提交记录 |
通过 merge 加 --squash 参数的方式,本地分支被完整的保留下来。
1 | git merge --squash feat/add-coin |
squash reference
git reset
参考文档:
1 | # 将文件从staged转为unstaged |
git restore
参考文档:
1 | # discard the unstaged changed file |
git remote
1 | # 添加远程 |
git with --depth
仓库过大时,使用 depth 可加快拉取代码。
1 | # --depth 1 |
git config
config
查看所有的 git 配置位置,system/global/local 配置。
1 | # 查看配置及配置所属位置 |
credential
Git 的全局配置,用于存储凭据,比如用户名和密码,这样在与远程 Git 仓库交互时就不需要每次都输入它们。
1 | git config --global credential.helper store |
http
1 | git config --global http.sslVerify false |
proxy
1 | git config --global url.https://ghproxy.com/https://github.com.insteadOf https://github.com |
git log
查看历史
查看文件夹的历史提交记录
1 | git log -- ./folder-history |
git filter-branch
–index-filer
删除所有提交有关文件夹的历史
1 | git filter-branch --force --index-filter \ |
git tag
本节总结了相关常用的 git tag 命令。
查看
1 | # 查看所有的 tag,可直接筛选结果 |
创建
1 | # 用 tag-name 创建 light tag |
同步
1 | # 推送所有本地tag到远程 |
GitLab API tag
1 | # 删除 tag |
git branch
git branch -m
远程分支重命名后,本地需要跟踪最新的分支
1 | git branch -m main master |
git commit
-s
在 Git commit 中,有时会看到 Signed-off-by 的标记。这是一个常见的实践,用于指示提交者已经阅读并同意相关的许可和贡献规范。
Signed-off-by 标记的格式通常是在提交信息的末尾添加一行,类似于:
1 | Signed-off-by: Your Name <your@email.com> |
通过在提交信息中包含 Signed-off-by 标记,提交者表明他们有权将这些更改提交到代码库,并同意遵守相关的法律和规定。这也可以用于追踪和验证提交的来源。
要配置 Signed-off-by 标记,可以按照以下步骤进行操作:
-
打开 Git 仓库所在的命令行终端或 Git GUI 工具。
-
在进行提交之前,确保已经设置了正确的用户名和邮箱地址。可以使用以下命令来设置:
1 | git config --global user.name "Your Name" |
确保将 “Your Name” 替换为真实姓名,将 “your@email.com” 替换为真实邮箱地址。
-
进行提交时,在提交信息的末尾添加 Signed-off-by 标记。可以手动添加,或者使用 Git 提供的提交模板或钩子来自动生成。例如,在命令行中使用以下命令进行提交:
1 | git commit -s -m "Your commit message" |
links:
ssh 签名
使用 ssh 配置对提交进行签名,前提是已存在 ssh 签名密钥,并注册到远程版本控制。
1 | git config commit.gpgsign true # 一般不需要全局开启,只需要在提交时指定-s即可 |
–cleanup
对提交消息进行清理
links:
git commit -m
1 | git commit -m <title> -m <content> |
git commit empty
git 空提交,用于在本地测试及保证源码不变动的情况下增加一个提交或删除相关的空提交。
增加一个空提交
Step 1. 创建一个新提交。
1 | git commit --allow-empty -m "Trigger test deployment" |
Step 2. 推动空提交到远程。
1 | git push |
删除空提交
Step 1. 查看空提交
1 | git rev-list HEAD | while read commitHash; do |
Step 2. 删除空提交
1 | git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' -f HEAD |
解释:
-
-filter-branch: 让重写分支。
-
-commit-filter: 过滤器进行提交。
-
git_commit_non_empty_tree “$@”: 包括这个参数 -commit-filter 将跳过提交离开树。 树散列不变如果没有文件被改变,因此承诺是空的。
-
-f: --force 缩写。
links:
git revert
git revert 用于回退代码版本
1 | # 将 B 到 D 都 revert |
git repo clean
安装完后,可绑定到 git 使用:
1 | # 扫描仓库当前分支的文件,文件最小为1G,类型为tar.gz,显示前1个结果 |
reference
git submodule
教程参考:
add
添加子模块,当使用远程 url 时,使用 depth 加快 clone 进行绑定。
1 | # 使用 url 绑定子模块 |
编辑项目生成的 .gitmodules 在对应的子项目模块添加 shallow = 1
,为远程同步子模块 clone 根据 --recommend-shallow 使用对应的深度同步初始化子模块。
1 | [submodule "sub1"] |
delete
删除子模块
1 | git submodule deinit [-f] <folder> |
-
.gitmoduels 子模块相关描述删除
-
.git/config 子模块相关描述删掉
-
.git/modules/path/to/submodule
-
运行 git rm --cached path/to/submodule (no trailing slash)
-
删除其余并提交子模块非 git 相关配置
update
拉取更新子模块
1 | git submodule update --init --recursive |
move
移动子模块到新目录
1 | git mv src/sub1 src/sub1_new |
git diff
输出对比差异,在某些时候可用于 patch 补丁方面。
-
diff --git a/new.txt b/new.txt:a 版本的 new.txt(变动前) 与 b 版本的 new.txt(变动后) 比较
-
index 0e9cc9b…af0a351 100644:a 版本的在 index 的对象的哈希值 b 版本在工作区的对象的哈希值 文件信息(644 表示权限)
-
— a/new.txt:变动前的文件
-
@@ -1,2 +1,3 @@:变动前的文件从第 1 行开始,连续 2 行;变动后的文件第行开始,连续 3 行存在差异 。
-
-:红色部分表示减少的部分
-
+:绿色部分表示增加的部分
1 | # 输出差异 |
git commit convention
一个好的提交 message 规则
-
从主体中分离出标题并用空行隔开
-
限制标题字符 50 以内
-
大写标题行
-
不需要结束标题行
-
在主题行中使用祈使语气
-
主体使用 72 字符换行包装
-
使用主体解释 what、why、how
[!NOTE]
另加 Github Gist Commit Message Guidelines 及示例 wiki
git commit --amend
修改上一个提交内容,包括修改提交作者
1 | git commit --amend --author="Author Name <email@address.com>" |
追加到前一个提交中,并不做任何更改
1 | git add . |