Contents

Git

Git

一、git基本使用

1、commit

[root@node01 project]# git add 1.txt
[root@node01 project]# git commit -m "create new 1.txt"
[master (root-commit) 3e8ce87] create new 1.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 1.txt

2、diff文件

[root@node01 project]# git diff 1.txt
diff --git a/1.txt b/1.txt
index e69de29..21d56a0 100644
--- a/1.txt
+++ b/1.txt
@@ -0,0 +1 @@
+1111111111111111

3、版本回退

在进行版本回退时,使用HEAD代表当前版本,HEAD^ 代表上一个版本,HEAD^^代表上上个版本,还可以使用HEAD~10代表前10个版本

[root@node01 project]# git reset --hard HEAD^
HEAD is now at fdf9d68 add new 1111
[root@node01 project]# 
[root@node01 project]# cat 1.txt 
1111111111111111
[root@node01 project]# 

也可以使用如下命令格式:

[root@node01 project] git reset --hard <commit_id>

[root@node01 project]# git reflog 1.txt
fdf9d68 HEAD@{0}: reset: moving to HEAD^
996cc77 HEAD@{1}: commit: add new 222
fdf9d68 HEAD@{2}: commit: add new 1111
3e8ce87 HEAD@{3}: commit (initial): create new 1.txt
[root@node01 project]# 
[root@node01 project]# git reset --hard 996cc77

4、撤销更改

1)对于尚未添加到暂存区的修改,可直接通过编辑原文件或者使用git checkout -- <file>的方式进行撤销

[root@node01 project]# git checkout -- 1.txt
[root@node01 project]# git status 
# On branch master
nothing to commit, working directory clean

2)对于已经添加到暂存区,但还没有git commit的修改,可使用git reset HEAD <file>的方式撤销

[root@node01 project]# vim 1.txt 

[root@node01 project]# git add 1.txt
[root@node01 project]# git status 
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   1.txt
#
[root@node01 project]# git reset HEAD 1.txt
Unstaged changes after reset:
M	1.txt

[root@node01 project]# git status 
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   1.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

[root@node01 project]# git checkout -- 1.txt
[root@node01 project]# git status 
# On branch master
nothing to commit, working directory clean
[root@node01 project]# cat 1.txt 
1111111111111111
22222222222222222
3333333333333

3)对于已经添加到暂存区,并已经提交的修改可通过git reset –hard <commit_id>的方式进行撤销

[root@node01 project]# vim 1.txt 

[root@node01 project]# git add 1.txt
[root@node01 project]# git commit -m "add new 44444444"
[master 240af53] add new 44444444
 1 file changed, 1 insertion(+)
 
[root@node01 project]# git reflog 1.txt
240af53 HEAD@{0}: commit: add new 44444444
5424335 HEAD@{1}: commit: add new 333333
996cc77 HEAD@{2}: reset: moving to 996cc77
3e8ce87 HEAD@{3}: reset: moving to 3e8ce87
996cc77 HEAD@{4}: reset: moving to 996cc77
fdf9d68 HEAD@{5}: reset: moving to HEAD^
996cc77 HEAD@{6}: commit: add new 222
fdf9d68 HEAD@{7}: commit: add new 1111
3e8ce87 HEAD@{8}: commit (initial): create new 1.txt
[root@node01 project]# 
[root@node01 project]# 
[root@node01 project]# git reset --hard 5424335
HEAD is now at 5424335 add new 333333

二、git配置

1、配置基本信息

[root@localhost srv]# git config --global user.name 'sugar'
[root@localhost srv]# git config --global user.email 't@local.com'
[root@localhost srv]# git config --global color.ui true      #配置显示的颜色,方便看到更改的信息
[root@localhost srv]# git config --global core.ignorecase false     # 配置大小写敏感,git默认大小写不敏感
 

2、gitconfig配置文件

[user]
        name = sugar
        email = t@local.com
#       signingkey = DCE96Cxxxxxxxxxxxxxxxxxxxxxxxx
#[commit]
#        gpgsign = true

# ~/github/ 目录下的项目使用~/github/.gitconfig下的gitconfig配置文件
[includeIf "gitdir:~/github/"]
  path = ~/github/.gitconfig

[includeIf "gitdir:~/my-prod/"]
  path = ~/my-prod/.gitconfig

[init]
        defaultBranch = main 
[color]
        ui = true
[alias]
        lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
[alias]
        # status
        st  = status
        ss = status --short --branch

        # stash
        sh  = stash
        shp = stash pop
        shl = stash list
        shs = stash save
        sha = stash apply
        std = stash drop

        # branch
        br  = branch
        bra = branch -a
        brm = branch -m
        co  = checkout
        cob = checkout -b
        sw  = switch
        swc = switch -c
        
        # remote
        ra  = remote add
        rao = remote add origin
        ru  = remote set-url
        ruo = remote set-url origin
        rv = remote -v

        # fetch
        fe  = fetch
        fep = fetch -p
        fo  = fetch origin
        fop = fetch origin -p

        # merge
        mr  = merge
        mnc = merge --no-commit
        # msq = merge --squash

        # commit
        cm = commit -m

        # config user and mail
        user = config user.name
        mail = config user.email


[url "git@github.com:username"]
        insteadOf = https://github.com/username

# 强制https转ssh协议
[url "ssh://git@local.com/"]
        insteadOf = https://local.com/

[core]
        excludesfile = ~/.gitignore_global
        autocrlf = input
        quotepath = false
        ignorecase = false
        editor = vim

#       sshCommand = ssh -i ~/.ssh/id_rsa -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no

[i18n "commit"]
        encoding = utf-8
[i18n]
        logoutputencoding = utf-8

[http "https://github.com"]
        proxy = socks5://127.0.0.1:8888

[http]
        proxy = http://127.0.0.1:8889
[https]
        proxy = http://127.0.0.1:8889

3、windows上终端打开出现乱码

cmd配置

git config --global core.quotepath false 
git config --global gui.encoding utf-8
git config --global i18n.commit.encoding utf-8 
git config --global i18n.logoutputencoding utf-8 
# bash 环境下
export LESSCHARSET=utf-8
# cmd环境下:
set LESSCHARSET=utf-8

powershell配置

git config --global core.quotepath false
git config --global gui.encoding utf-8
git config --global i18n.commit.encoding utf-8
git config --global i18n.logoutputencoding utf-8
$env:LESSCHARSET='utf-8'

git bash

sugar@sugar MINGW64 /e/Desktop/company/github (master)
$ cat /etc/bash.bashrc
alias ls='ls -F --color --show-control-chars'
NOW_DIR="E:\Desktop"
cd ${NOW_DIR}
export LESSCHARSET=utf-8

三、分支管理

git版本库所有的操作都是运行在分支上,git仓库创建时会建立默认的分支,名称为master;所有的操作都在master分支上进行 在对版本库中的文件进行操作时,可以创建不同的分支,不同的操作运行在不同的分支上,不同分支上的操作不会相互干扰,操作进行完成后,可以合并不同分支上的操作

1、创建分支

[root@node01 project]# git checkout -b game
Switched to a new branch 'game'
[root@node01 project]# 
[root@node01 project]# git branch 
  dev
* game
  master

1)远程chekout到本地

[root@node01 project]# git checkout origin/develop -b develop

2)删除分支

# 删除本地分支
[root@node01 project]# git branch -d release-1.1.0

# 强制删除
[root@node01 project]# git branch -D release-1.1.0

# 删除远程分支
[root@node01 project]# git push origin --delete  release-1.1.0
或者
[root@node01 project]# git push origin :release-1.1.0

3)根据hash值进行checkout

git checkout  d21a8c517ca3xxxxxxxxxxxxxxxxxxxxxxxxxxx

4)分支合并

切换到准备合并后的分支,合并其他分支到当前分支

[root@node01 project]# git merge dev 
Updating bb6fb7a..d83dae8
Fast-forward
 1.txt | 2 ++
 1 file changed, 2 insertions(+)

四、tag管理

打标签,用于仓库某个提交打上标签,以表示其特殊性。比较有代表性的是人们会使用这个功能来标记发布结点( v1.0v2.0 等等)

1、查看本地已有标签

[root@localhost github_web]# git tag
4.101.0
4.103.0
4.103.1

列出所有标签 -l或者--list,指定某些提交信息-l "v4.4*"

2、创建tag

Git 支持两种标签:

  • 轻量标签(lightweight)

  • 附注标签(annotated)。

轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。

而附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。 通常会建议创建附注标签,这样你可以拥有以上所有信息。但是如果你只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。

附属标签:
git tag -a v1.4 -m "my version 1.4"

查看详细信息

git show v1.4

输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。

轻量标签:

另一种给提交打标签的方式是使用轻量标签。 轻量标签本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。 创建轻量标签,不需要使用 -a-s-m 选项,只需要提供标签名字:

$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4

这时,如果在标签上运行 git show,你不会看到额外的标签信息。 命令只会显示出提交信息:

$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <t@local.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number
后期打标签
git tag -a v1.2 9fceb02
共享标签

默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样——你可以运行 git push origin <tagname>

$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.5 -> v1.5

如果想要一次性推送很多标签,也可以使用带有 --tags 选项的 git push 命令。 这将会把所有不在远程仓库服务器上的标签全部传送到那里。

$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.4 -> v1.4
 * [new tag]         v1.4-lw -> v1.4-lw

3、删除标签

要删除掉你本地仓库上的标签,可以使用命令 git tag -d <tagname>。 例如,可以使用以下命令删除一个轻量标签:

$ git tag -d v1.4-lw
Deleted tag 'v1.4-lw' (was e7d5add)

注意上述命令并不会从任何远程仓库中移除这个标签,你必须用 git push <remote> :refs/tags/<tagname> 来更新你的远程仓库:

方法一git push <remote> :refs/tags/<tagname>

$ git push origin :refs/tags/v1.4-lw
To /git@github.com:username/project.git
 - [deleted]         v1.4-lw

上面这种操作的含义是,将冒号前面的空值推送到远程标签名,从而高效地删除它。

方法二:直接删除远程标签

$ git push origin --delete <tagname>

4、检出标签

检出标签为一个分支,格式为git checkout -b branch_name tag_name

git checkout -b version2 v2.0.0

5、.git 目录

 ├── HEAD    
    ├── branches
    ├── config
    ├── description
    ├── hooks
    │ ├── pre-commit.sample
    │ ├── pre-push.sample
    │ └── ...
    ├── info
    │ └── exclude
    ├── objects
    │ ├── info
    │ └── pack
    └── refs
     ├── heads
     └── tags
  • config (配置)该文件包含你的仓库配置,比如远程的 url ,你的邮箱和用户名等。每次你在控制台使用 git config… 都会对这里产生影响。
  • description(描述)供 gitweb ( github 的一种前身) 使用,显示仓库的描述。
  • hooks (钩子)这是一个有趣的特性。 Git 提供了一套脚本,可以在每个有意义的 Git 阶段自动运行。这些被称为钩子的脚本可以在提交 (commit)、变基 (rebase)、拉取 ( pull ) 操作的前后运行。脚本命预示着它的执行时机。如我们可以编写 pre-push 的作为钩子,进行推送代码前的检查。
  • info (信息)你可以将不想被 git 管理的文件记录到 .gitignore 文件中。排除文件的意思是不想共享这个文件。例如你不想共享你的 IDE 自定义配置,将其添加到 .gitignore 文件中即可。

五、cherry-pick

参考:https://www.ruanyifeng.com/blog/2020/04/git-cherry-pick.html

对于多分支的代码库,将代码从一个分支转移到另一个分支是常见需求。

这时分两种情况。一种情况是,你需要另一个分支的所有代码变动,那么就采用合并(git merge)。另一种情况是,你只需要部分代码变动(某几个提交),这时可以采用 Cherry pick。

1、基本语法

git cherry-pick命令的作用,就是将指定的提交(commit)应用于其他分支。

$ git cherry-pick <commitHash>

上面命令就会将指定的提交commitHash,应用于当前分支。这会在当前分支产生一个新的提交,当然它们的哈希值会不一样。

举例来说,代码仓库有masterfeature两个分支。

 a - b - c - d   Master
      \
        e - f - g Feature

现在将提交f应用到master分支。

# 切换到 master 分支
$ git checkout master

# Cherry pick 操作
$ git cherry-pick f

上面的操作完成以后,代码库就变成了下面的样子。

 a - b - c - d - f   Master
      \
        e - f - g Feature

从上面可以看到,master分支的末尾增加了一个提交f

git cherry-pick命令的参数,不一定是提交的哈希值,分支名也是可以的,表示转移该分支的最新提交。

$ git cherry-pick feature

上面代码表示将feature分支的最近一次提交,转移到当前分支。

操作示例:

[sugar@centos-7 git-test]$ git log -1
commit dcf3a215fd6ba3288ad21584d2112bdab5a713b4
Author: sugar <cccc@gmail.com>
Date:   Sun Sep 12 14:29:26 2021 +0800

    feat: v1 version 1s add
[sugar@centos-7 git-test]$ git checkout master
Switched to branch 'master'
[sugar@centos-7 git-test]$ git log
commit 31da420cc2d2ae6094f88e368a72f0353541d89f
Author: sugar <cccc@gmail.com>
Date:   Sun Sep 12 14:25:43 2021 +0800

    feat: 第一此增加
[sugar@centos-7 git-test]$ git cherry-pick dcf3a215fd6ba3288ad21584d2112bdab5a713b4
[master fa78bb0] feat: v1 version 1s add
 1 file changed, 2 insertions(+), 1 deletion(-)
[sugar@centos-7 git-test]$ ls
cccc.txt
[sugar@centos-7 git-test]$ git log -1
commit fa78bb090d3221ba2ff9cae59efa1f8691677115
Author: sugar <cccc@gmail.com>
Date:   Sun Sep 12 14:29:26 2021 +0800

    feat: v1 version 1s add

2、转移多个commit

Cherry pick 支持一次转移多个提交

[sugar@centos-7 git-test]$ git cherry-pick <HashA> <HashB>

连续提交多个commit

# 提交A到B的commit,但不包含A;提交A必须早于提交B,否则命令将失败,但不会报错。
[sugar@centos-7 git-test]$ git cherry-pick A..B 

# 提交A到B的commit,包含A
[sugar@centos-7 git-test]$ git cherry-pick A^..B 

3、参数

git cherry-pick命令的常用配置项如下。

(1)-e--edit

打开外部编辑器,编辑提交信息。

(2)-n--no-commit

只更新工作区和暂存区,不产生新的提交。

(3)-x

在提交信息的末尾追加一行(cherry picked from commit ...),方便以后查到这个提交是如何产生的。

(4)-s--signoff

在提交信息的末尾追加一行操作者的签名,表示是谁进行了这个操作。

(5)-m parent-number--mainline parent-number

如果原始提交是一个合并节点,来自于两个分支的合并,那么 Cherry pick 默认将失败,因为它不知道应该采用哪个分支的代码变动。

-m配置项告诉 Git,应该采用哪个分支的变动。它的参数parent-number是一个从1开始的整数,代表原始提交的父分支编号。

$ git cherry-pick -m 1 <commitHash>

上面命令表示,Cherry pick 采用提交commitHash来自编号1的父分支的变动。

一般来说,1号父分支是接受变动的分支(the branch being merged into),2号父分支是作为变动来源的分支(the branch being merged from)。

4、代码冲突

如果操作过程中发生代码冲突,Cherry pick 会停下来,让用户决定如何继续操作。

1)--contine

用户解决代码冲突后,第一步将修改的文件重新加入暂存区(git add .),第二步使用下面的命令,让 Cherry pick 过程继续执行。

$ git cherry-pick --continue

2)--abort

发生代码冲突后,放弃合并,回到操作前的样子。

3)--quit

发生代码冲突后,退出 Cherry pick,但是不回到操作前的样子。

5、转移到另外一个仓库

Cherry pick 也支持转移另一个代码库的提交,方法是先将该库加为远程仓库。

# 添加一个远程仓库
$ git remote add target git://gitUrl

# 将远程仓库的代码抓取到本地
$ git fetch target

# 检查一下要从远程仓库转移的提交,获取它的哈希值
$ git log target/master

# 使用git cherry-pick命令转移提交
$ git cherry-pick <commitHash>

六、合并commit

在使用 Git 作为版本控制的时候,我们可能会由于各种各样的原因提交了许多临时的 commit,而这些 commit 拼接起来才是完整的任务。那么我们为了避免太多的 commit 而造成版本控制的混乱,通常我们推荐将这些 commit 合并成一个。

1、查看提交历史

$ git log
commit 3ca6ec340edc66df13423f36f52919dfa3......

commit 1b4056686d1b494a5c86757f9eaed844......

commit 53f244ac8730d33b353bee3b24210b07......

commit 3a4226b4a0b6fa68783b07f1cee7b688.......

2、git rebase

想要合并1-3条,有两个方法

1)从HEAD版本开始往过去数3个版本

$ git rebase -i HEAD~3

2)指名要合并的版本之前的版本号

$ git rebase -i 3a4226b

请注意3a4226b这个版本是不参与合并的,只是把它当做一个坐标

3、选择要合并的提交

p是保留,s是合并

1)执行了rebase命令之后,会弹出一个窗口,头几行如下:

pick 3ca6ec3   '注释**********'

pick 1b40566   '注释*********'

pick 53f244a   '注释**********'

2)将pick改为squash或者s,之后保存并关闭文本编辑窗口即可。改完之后文本内容如下:

pick 3ca6ec3   '注释**********'

s 1b40566   '注释*********'

s 53f244a   '注释**********'

3)然后保存退出,Git会压缩提交历史,如果有冲突,需要修改,修改的时候要注意,保留最新的历史,不然我们的修改就丢弃了。修改以后要记得敲下面的命令:

pick 3ca6ec3   '注释**********'

s 1b40566   '注释*********'

s 53f244a   '注释**********'

4)冲突解决

然后保存退出,Git会压缩提交历史,如果有冲突,需要修改,修改的时候要注意,保留最新的历史

git add .  

# 继续合并
git rebase --continue 

# 放弃合并
git rebase --abort  

如果没有冲突,或者冲突已经解决,则会出现如下的编辑窗口:

# This is a combination of 4 commits.  
#The first commit’s message is:  
注释......
# The 2nd commit’s message is:  
注释......
# The 3rd commit’s message is:  
注释......
# Please enter the commit message for your changes. Lines starting # with ‘#’ will be ignored, and an empty message aborts the commit.

5)检查

git log查看 commit 历史信息,查询commit的信息

七、Git Hook

Git Hook 也分为两个端: 客户端和服务端。

客户端的 Git Hook 就是工作在我们本地机器的,服务端的 Git Hook 则是工作在我们提交到远程的服务器仓库中。

客户端 Git Hook:

  • pre-commit: 执行git commit命令时触发,常用于检查代码风格
  • prepare-commit-msg: 触发于 commit message 编辑器呼起前 ,default commit message创建后,常用于生成默认的标准化的提交说明
  • commit-msg: 开发者编写完并确认commit message后触发,常用于校验提交说明是否标准
  • post-commit: 整个git commit完成后触发,常用于邮件通知、提醒
  • applypatch-msg: 执行git am命令时触发,常用于检查命令提取出来的提交信息是否符合特定格式
  • pre-applypatch: git am提取出补丁并应用于当前分支后,准备提交前触发,常用于执行测试用例或检查缓冲区代码
  • post-applypatch: git am提交后触发,常用于通知、或补丁邮件回复(此钩子不能停止git am过程)
  • pre-rebase: 执行git rebase命令时触发
  • post-rewrite: 执行会替换commit的命令时触发,比如git rebase或git commit –amend
  • post-checkout: 执行git checkout命令成功后触发,可用于生成特定文档,处理大二进制文件等
  • post-merge: 成功完成一次 merge行为后触发
  • pre-push: 执行git push命令时触发,可用于执行测试用例
  • pre-auto-gc: 执行垃圾回收前触发

服务端 Git Hook:

  • pre-receive: 当服务端收到一个 push 操作请求时触发,可用于检测 push 的内容
  • update: update 脚本和 pre-receive 脚本十分类似,不同之处在于它会为每一个准备更新的分支各运行一次。 假如推送者同时向多个分支推送内容,pre-receive 只运行一次,相比之下 update 则会为每一个被推送的分支各运行一次。
  • post-receive: post-receive 挂钩在整个过程完结以后运行,可以用来更新其他系统服务或者通知用户。它的用途包括给某个邮件列表发信,通知持续集成(continous integration)的服务器,或者更新问题追踪系统(ticket-tracking system) —— 甚至可以通过分析提交信息来决定某个问题(ticket)是否应该被开启,修改或者关闭。
使用git hook

Git Hook 本身自带有脚本,会存放在仓库 .git/hooks 文件夹中,目录一般是这样的:

- YourGitRepo
  |- .git
     |- hooks
        |- hooks--commit-msg.sample
        |- hooks--post-update.sample
        ...

注意如果是 sample 文件,要去掉 .sample 后缀,变成前面 Git Hook 分类 中提到对应的操作来作为文件名。

比如我要做的校验 commit 的提交信息,那么使用的 Git Hook 脚本名应该为 commit-msg.

hooks--commit-msg.sample 里的内容为:

#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message.  The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit.  The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".

# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

# This example catches duplicate Signed-off-by lines.

test "" = "$(grep '^Signed-off-by: ' "$1" |
	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
	echo >&2 Duplicate Signed-off-by lines.
	exit 1
}

上面说明里有一些基本说明, 这里获得的 $1 参数,其实是存放 commit msg 内容的文件路径,为 .git/COMMIT_EDITMSG.

利用命令:

msg=$(cat $1)

就能取到 commit 的信息,稍作修改,就能达到我说的,校验团队 commit 信息的规范的目的了。

Git Hook 不生效

如果遇到不起作用的,可能脚本没有打开执行权限,导致没办法执行。我就是这样的情况。

cd 到 .git/hooks 目录下,执行 chmod 777 命令即可,如:

chmod 777 commit-msg

八、Git GC

清理不必要的文件并优化本地存储库

参考链接:Git - 管理 | Administration - git gc - 开发者手册 - 云+社区 - 腾讯云 (tencent.com)

Git的底层并没有采用 CVS、SVN 底层所采用的那套增量式文件系统,而是采用一套自行维护的存储文件系统。当文件变动发生提交时,该文件系统存储的不是文件的差异信息,而是文件快照,即整个文件内容,并保存指向快照的索引。这种做法,提高 Git 分支的使用效率;但也容易导致代码仓库中内容重复程度过高,从而仓库体积过大。当遇到这种情况时,或者需要将仓库推送到远程主机时,就需要Git中的gc(garbage collect)功能,也就是垃圾回收功能。

大体来说,当运行 “git gc” 命令时,Git会收集所有松散对象并将它们存入 packfile,合并这些 packfile 进一个大的 packfile,然后将不被任何 commit 引用并且已存在一段时间 (数月) 的对象删除。 此外,Git还会将所有引用 (references) 并入一个单独文件。

就细节而言,Git做了这几件事:

  • pack_refs 过程
  • reflog expire 过程
  • repack 过程
  • prune 过程
  • rerere 过程

概要:

git gc [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force]

描述:

在当前存储库中运行许多内务处理任务,例如压缩文件修订(以减少磁盘空间并提高性能)并移除可能由之前git add调用创建的不可达对象。

鼓励用户在每个存储库中定期运行此任务,以保持良好的磁盘空间利用率和良好的操作性能。

一些git命令可能会自动运行git gc; --auto详细信息请参阅下面的标志。如果您知道自己在做什么,并且所有您想要的都是永久禁用此行为而无需进一步考虑,请执行以下操作:

$ git config --global gc.auto 0

选项:

  • –aggressive

通常git gc运行速度很快,同时提供良好的磁盘空间利用率和性能 此选项将导致git gc更积极地优化存储库,但花费更多时间。这种优化的效果是持久的,所以这个选项只需要偶尔使用; 每隔几百个变更集左右。

  • –auto

使用此选项,git gc检查是否需要进行任何清洁工作; 如果没有,它会退出而不执行任何工作。一些git命令git gc --auto在执行可能会产生许多松散对象的操作之后运行。

如果存储库中的松散对象太多或包装太多,则需要进行内务处理。如果松散对象的数量超过了gc.auto配置变量的值,则所有松散对象都将使用组合到一个包中git repack -d -l。将值设置gc.auto为0将禁用自动填充松散物体。

如果包装数量超过了价值gc.autoPackLimit,那么现有包装(标有.keep文件的包装除外)将通过使用-A选项合并到一个包装中git repack。设置gc.autoPackLimit为0将禁用自动合并包装。

  • –prune=

修剪比日期更旧的松散对象(默认为2周前,可由配置变量覆盖gc.pruneExpire)。–prune =不管年龄大小,都修剪松散的物体,并且如果另一个进程同时写入存储库,则会增加腐败风险; 请参阅下面的“注意事项”。–prune默认打开。

  • –no-prune

不要修剪任何松动的物体。

  • –quiet

取消所有进度报告。

  • –force

git gc即使可能有另一个git gc实例在此存储库上运行,也强制运行。

注意:

git gc尽量不要删除在存储库中任何位置引用的对象。特别是,它不仅会保存当前一组分支和标记所引用的对象,还会保留由索引引用的对象,远程跟踪分支,git filter-branchrefs / original /中保存的引用或reflogs(可引用分支中的提交后来修改或倒带)。如果您希望某些对象被删除而不是,请检查所有这些位置,并决定在您的情况下删除这些引用是否有意义。

另一方面,当git gc与另一个进程同时运行时,可能会删除另一个进程正在使用但尚未创建引用的对象。这可能会导致其他进程失败或者可能会损坏存储库,如果其他进程稍后添加对已删除对象的引用。Git有两个功能可以显着缓解这个问题:

  1. --prune保留修改时间比日期更新的任何对象以及可从其访问的所有对象。

  2. 将对象添加到数据库的大多数操作都会更新对象的修改时间(如果该对象已存在,以便应用#1)。

然而,这些功能并不能提供完整的解决方案,因此,同时运行命令的用户必须忍受一些腐败风险(实践中似乎很低),除非他们关闭自动垃圾收集git config gc.auto 0

九、Git gpg签名

# 查看gpg密钥
[root@local ~]# gpg --list-key
/root/.gnupg/pubring.kbx
------------------------
pub   rsa4096 2021-08-23 [SC]
      C40EA42A60xxxxxxxxxxxxxxxxxx
uid           [ 绝对 ] cccc (local) <t@local.com>
sub   rsa4096 2021-08-23 [E]

pub   rsa4096 2021-08-23 [SC]
      3CB22116355xxxxxxxxxxxxxxxxxx
uid           [ 绝对 ] tom (github) <t@local.cc>
sub   rsa4096 2021-08-23 [E]

配置使用gpg签名

# git 配置使用gpg签名
git config --global user.signingkey <gpg-key-id>

# 提交是否强制 GPG,带上--global 是作用全局,局部的去除--global
[root@sugar2 ~]# git config --global commit.gpgsign true


# commit 提交设置GPG签名,如果没有设置强制,则需要加上-S
[root@sugar2 ~]# git commit -S -m “commit message"

# 在github上签名的提交将显示包含“ Verified”

问题:

[root@sugar ssl]# git commit -m "init repo"
error: gpg 数据签名失败
fatal: 写提交对象失败

参考链接:https://zhuanlan.zhihu.com/p/97984430

解决办法:export GPG_TTY=$(tty)

在环境变量里增加一项GPG_TTY