Git 笔记本

本篇博客介绍 Git 的基本使用,争取按规范的使用 Git 使开发流程更加规范。

.git 文件结构

以下是一个 .git 文件的结构。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
.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 文件

1
2
3
4
5
├── 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 命令查看文件信息

1
git cat-file -p 0ef1525d81bad33f58a45e7a6c8018056e98bd02

如果当修改了一个历史的 commit 可能会造成悬空 object,即历史的 commit 没有 refs 指向。

1
2
3
4
5
# 查看悬空的 obj
git fsck --lost-found

# 删除不需要的 obj
git gc

Refs

存储文件内容,实际是一个指针指向对应 commit ID,一般指向最新的 commit。他有不同种类 refs/heads 表示分支,refs/tags 表示标签。

  • git reflog 查看本地更新过 HEAD 的 commit 记录。 git tag 表示一个稳定的不常更新的分支。
1
2
3
4
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 免密配置方式:

1
2
3
4
5
# 内存配置免密
git config --global credential.helper 'cache --timeout=3600'

# 硬盘配置免密 默认路径 ~/.git-credential
git config --global credential.helper "store --file /path/to/credential-file"

常用的配置指令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 修改信息
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 指定修改多长时间的对象,默认两周前
1
2
git reflog expire --expire=now --all
git gc --prune=now

gitignore

Git 会自动忽略空文件夹,因此在想要忽略某个文件夹下的全部文件,但还想保留上传该父文件夹时需要在父文件夹目录下创建 .gitignore

忽略规则相关常用命令

1
2
3
4
5
清除已经持久化文件的缓存
git rm --cached filename 

检测文件忽略规则
git check-ignore -v filename

我的 git 常用指令辞典

  • ; : 使用分号分隔多个指令可在同一行顺序执行多个 git 指令
  • &&: 使用 && 分隔多个指令可在同一行顺序执行多个 git 指令,但是如果前一个指令执行失败,后面的指令不会执行
  • git log –oneline –graph –decorate –all 查看所有分支的提交记录

初始化仓库相关

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 添加远程仓库
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

修改历史版本

1
2
3
4
5
# 修改最近一次 commit信息
commit --amend

# rebase 修改最近三个 commit
git rebase -i HEAD~3

分支相关

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 查看当前分支
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(远端)

删除

1
2
3
4
5
6
7
# 删除暂存区或分支上的文件, 但本地又需要使用, 只是不希望这个文件被版本控制
git rm --cached file_path
git commit -m 'delete remote somefile'
git push

# 放弃修改复写缓存区
git reset --hard branch

回档

1
git reset --hard 版本号

HEAD 关键字指的是当前分支最末梢最新的一个提交。也就是版本库中该分支上的最新版本。


submodule 使用

克隆一个带有 submodule 的仓库。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
git clone url
cd 进入仓库路径
# --recursive 对嵌套 submodule 也可执行
git submodules update --init --recursive

# 查看当前子模块信息
git submodule status

# 更新 submodule 到最新提交版本
git submodule update --remote

--recursive 参数用于下载子模块

1
git clone --recursive

创建克隆后,使用默认设置初始化其中的所有子模块。这是 相当于在克隆完成后立即运行 git submodule update –init –recursive 完成的。

更新 submodule 到指定 tag/commit

1
2
3
4
5
6
cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push

Git rebase

可以整合多个提交记录,注意不要合并已经 push 的记录。
merge 操作会生成一个新的节点,之前提交分开显示。 而 rebase 操作不会生成新的节点,是将两个分支融合成一个线性的操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 从当前提交位置开始,合并最近三条 commit 记录
git rebase -i HEAD~3



GNU nano 4.8                                                  /home/niku/code/git-text/test-clone/.git/rebase-merge/git-rebase-todo                                                          
pick b21522a rebase2

# 变基 54b6e35..b21522a 到 54b6e35(1 个提交)
#
# 命令:
# p, pick <提交> = 使用提交
# r, reword <提交> = 使用提交,但修改提交说明
# e, edit <提交> = 使用提交,进入 shell 以便进行提交修补
# s, squash <提交> = 使用提交,但融合到前一个提交
# f, fixup <提交> = 类似于 "squash",但丢弃提交说明日志

修改 s 参数表示将下面的 commit 合并到上面的版本

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

解决方法:

1
git config --global core.autocrlf true

这样在你提交时自动地把回车 CRLF 转换成换行 LF,而在检出代码时把换行 LF 转换成回车 CRLF

多主机一个分支

多主机公用一个仓库是可能会遇到这个问题,直接按照提示使用如下指令做关联即可。或者每次都这样提交 git push origin branch

1
git push --set-upstream origin main

常见问题

  • 分离 HEAD 情况下更改代码时,最好预先创建新分支。

git commit message 规范

type

说明 commit 的类型。

  • feat:新功能(feature)
  • fix:修补 bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改 bug 的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动
  • build:改变构建流程,新增依赖库、工具、构造工具的或者外部依赖的改动
  • perf:提高性能的改动
  • ci:自动化流程配置修改、与CI(持续集成服务)有关的改动
  • revert:回滚到上一个版本,执行git revert打印的message

subject

commit 内容简要描述,字数不宜过长。第一人称,动词现在时开头。

cherry pick

指从一个分支中选择一个提交,并将其应用到另一个分支。例如 merge 和 rebase 通常会将许多提交应用到另一个分支。

0%