这是我参与「第三届青训营 -后端场」笔记创作活动的的第 3 篇笔记。
本篇介绍 Git 的基本使用,争取按规范的使用 Git 使开发流程更加规范。
.git 文件结构
以下是一个 .git 文件的结构。
.git
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ ├── heads
│ │ └── main
│ └── remotes
│ └── origin
│ ├── HEAD
│ └── main
├── modules
│ └── themes
│ └── FixIt
│ ├── branches
│ ├── config
│ ├── description
│ ├── HEAD
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── fsmonitor-watchman.sample
│ │ ├── post-update.sample
│ ├── index
│ ├── info
│ │ └── exclude
│ ├── logs
│ │ ├── HEAD
│ │ └── refs
│ │ ├── heads
│ │ │ └── master
│ │ └── remotes
│ │ └── origin
│ │ └── HEAD
│ ├── objects
│ │ ├── info
│ │ └── pack
│ │ ├── pack-3f2759e5d239cc34913467329d51643b48f3e651.idx
│ │ └── pack-3f2759e5d239cc34913467329d51643b48f3e651.pack
│ ├── packed-refs
│ └── refs
│ ├── heads
│ │ └── master
│ ├── remotes
│ │ └── origin
│ │ └── HEAD
│ └── tags
├── objects
│ ├── 0e
│ │ └── f1525d81bad33f58a45e7a6c8018056e98bd02
│ ├── 12
│ │ └── 4aa45213eb54a6b7c7d5b715b88837086ee27f
│ ├── 1e
│ │ └── 14dfb2d0fa8c159232825937cb68013f268154
│ ├── 33
│ │ └── 5c6256c5ce8569a84743471d92376488b8595e
│ ├── 3c
│ │ └── 8f38a136aa07edbd81c8aa92562b1b16139b36
│ ├── info
│ └── pack
│ ├── pack-4b3a92177530dc3b688096fe7081564903e6e4bb.idx
│ └── pack-4b3a92177530dc3b688096fe7081564903e6e4bb.pack
├── packed-refs
└── refs
├── heads
│ └── main
├── remotes
│ └── origin
│ ├── HEAD
│ └── main
└── tags
- HEAD 存储当前指向的分支
- config git 配置信息
- hooks 配置 hook
- object 存储一些文件信息 (如git add 后会生成暂存区文件)
- refs 存储分支信息
object 文件
├── objects
│ ├── 0e
│ │ └── f1525d81bad33f58a45e7a6c8018056e98bd02
│ ├── 12
│ │ └── 4aa45213eb54a6b7c7d5b715b88837086ee27f
object 有三种类型: commit, tree, blob 和一个 tag 的 object 类型。
- blob 存储文件内容(git add 后产生)
- tree 存储文件目录信息
- commit 存储文件提交信息,对应唯一的版本代码
获取当前版本代码:会根据 commit 中的 tree ID 寻找 tree 信息,通过 tree 存储信息获取对应目录树信息,再从 tree 中找到 blob ID 获取文件内容。
如文件头 0e 加上后面的 f1525d81bad33f58a45e7a6c8018056e98bd02 为文件的 object id。
该文件进行了加密,但可以使用 git 命令查看文件信息
git cat-file -p 0ef1525d81bad33f58a45e7a6c8018056e98bd02
如果当修改了一个历史的 commit 可能会造成悬空 object,即历史的 commit 没有 refs 指向。
# 查看悬空的 obj
git fsck --lost-found
# 删除不需要的 obj
git gc
Refs
存储文件内容,实际是一个指针指向对应 commit ID,一般指向最新的 commit。他有不同种类 refs/heads 表示分支,refs/tags 表示标签。
git tag 表示一个稳定的不常更新的分支。
git tag v0.0.1
# 添加附注标签 Annotation Tag
git tag -a v0.0.2 -m "bla bla bla"
refs/tags 文件中存储了 object 信息和标签信息,包括那个用户打了标签。
git 配置
git 配置分为三个级别从高到低为 --system, --global, --local。每个级别的配置可能重复,低级别会覆盖高级别配置。
--system系统配置存储在/etc/gitconfig--global全局配置存储在~/.gitconfig--local本地配置存储在.git/config
http 和 ssh 远端区别
- http 远端走 http 的认证方式(token)
- ssh 走 ssh 的认证方式(公钥私钥)出于安全推荐使用 ed25519 加密
go 开发依赖库很多时经常会 pull 一些远端仓库,因此有时验证是十分麻烦的。
http 免密配置方式:
# 内存配置免密
git config --global credential.helper 'cache --timeout=3600'
# 硬盘配置免密 默认路径 ~/.git-credential
git config --global credential.helper "store --file /path/to/credential-file"
常用的配置指令
# 修改信息
git config --global user.name "xxx"
git config --global user.email "xxx"
# Instead of 配置(替换 git 传输方式,比如下面把 ssh 替换为 https 传输)
git config --global url.git@github.com:.insteadOf https://github.com/
# git 自定义命令别名(下面把 commit --amend --no-edit 命令替换为 cin)
git config --global alias.cin "commit --amend --no-edit"
##---远端配置---##
# 查看远端
git remote -v
# 设置 fetch 和 push 不同的远端(下面我单独设置了 push 远端)
git remote set--url --add --push origin git@github.com:my_repo/git.git
git gc
删除一些不需要的 object 与打包 object 减少仓库体积。
使用该指令需要进行一些前置操作才可执行。
- reflog 用于记录操作日志,防止误操作。
- git gc prune=now 指定修改多长时间的对象,默认两周前
git reflog expire --expire=now --all
git gc --prune=now
gitignore
Git 会自动忽略空文件夹,因此在想要忽略某个文件夹下的全部文件,但还想保留上传该父文件夹时需要在父文件夹目录下创建 .gitignore。
忽略规则相关常用命令
清除已经持久化文件的缓存
git rm --cached filename
检测文件忽略规则
git check-ignore -v filename
我的 git 常用指令辞典
初始化仓库相关
# 添加远程仓库
git remote add origin xxxx
# 查看本地配置文件
git config --global -l
#修改信息
git config --global user.name "xxx"
git config --global user.email "xxx"
# 提交
git push origin +分支名称
# 设置代理,端口自定义,我用的 clash 默认端口 7890
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy https://127.0.0.1:7890
# 取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy
修改历史版本
# 修改最近一次 commit信息
commit --amend
# rebase 修改最近三个 commit
git rebase -i HEAD~3
分支相关
# 查看当前分支
git branch
# -a 查看所有分支
git branch -a
# 删除分支,注意需要切换到其他分支再删除
git branch -d 分支名
# 切换分支
git checkout 分支名
# 从当前所在分支下创建并进入 dev 分支
git checkout -b dev
# push 该分支
git push origin dev
# 更新远端分支到本地(不合并)
git fetch origin dev
# 合并远端分支
git merge origin/dev
git pull = git fetch + git merge
# 远端新建分支
git push origin nikuliu:nikuliu
删除
# 删除暂存区或分支上的文件, 但本地又需要使用, 只是不希望这个文件被版本控制
git rm --cached file_path
git commit -m 'delete remote somefile'
git push
# 放弃修改复写缓存区
git reset --hard branch
回档
git reset --hard 版本号
HEAD 关键字指的是当前分支最末梢最新的一个提交。也就是版本库中该分支上的最新版本。
submodule 使用
克隆一个带有 submodule 的仓库。
git clone url
cd 进入仓库路径
git submodules update --init --recursive
--recursive 参数用于下载子模块
git clone --recursive
创建克隆后,使用默认设置初始化其中的所有子模块。这是 相当于在克隆完成后立即运行 git submodule update --init --recursive 完成的。
Git 使用中常见问题
换行符问题 LF/CRLF
在 windows 下使用 Git 一定会碰到的一个问题,在我们用 git add . 命令时会提示 warning: LF will be replaced by CRLF。
CR(CarriageReturn),LF(LineFeed),CR/LF 是不同操作系统上使用的换行符,具体如下:
Windows 平台: 使用回车 CR 和换行 LF 两个字符来结束一行,即回车+换行 \r\n;
Mac 和 Linux平台:只使用换行 LF 一个字符来结束一行,即 \n;
解决方法:
git config --global core.autocrlf true
这样在你提交时自动地把回车 CRLF 转换成换行 LF,而在检出代码时把换行 LF 转换成回车 CRLF。
多主机一个分支
多主机公用一个仓库是可能会遇到这个问题,直接按照提示使用如下指令做关联即可。或者每次都这样提交 git push origin branch 。
git push --set-upstream origin main