Git 提效操作

作为程序员 Git 操作肯定不能少,笔者通过对Pro Git Book的通读总结了一部分对日常工作中可能忽视但是很好用的 Git 操作,希望能对你有所帮助。

git config 配置相关

Git 自带 git config 的工具来帮助控制 Git 的外观和行为。配置有三个级别分别是:

  1. 系统配置文件 –system
  2. 用户配置文件 –global
  3. 项目配置文件 –local

每个级别覆盖上一级配置,使用–list 查看 Git 此时能找到的所有配置

$ git config --list

通过–list 和–show-origin 查看所有配置及所在文件:

$ git config --list --show-origin

设置用户名和邮箱或者其他配置:

1
2
$ git config --global user.name "Your Name"
$ git config --global user.email yourname@example.com

git log 查看提交历史

git log 会按时间先后顺序列出所有提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。

查看差异

-p 或者–patch 查看提交的差异,也可以限制查看数量:-2,如下:

1
git log -p -2

–stat 查看被修改的文件

定制记录格式

–pretty=format 可以支持设置常用的格式占位符及其代表的意义,其中%h 表示提交的简写哈希值,%an 表示作者名字,%cd 表示提交日期,%s 表示提交说明,%cr 表示提交距今日期。

当然还可以为要展示的内容设置颜色,下面是本人配置的 git log 展示方式

1
git log --pretty=format:'%Cred%h%Creset - %Cblue%an%Creset : %C(yellow)%d%Creset %s %Cgreen(%cd)%Creset'

添加到全局 global 设置中:

1
git config --global alias.lg "log --pretty=format:'%Cred%h%Creset - %C(yellow)%d%Creset %s %Cgreen(%cd)%Creset'"

这样以后使用 git lg 就能用自定义的方式输出提交历史信息了

过滤查看 commit 信息

在大型项目的开发中,往往会有很多参与者,生成的 commit 信息中也会涵盖了很多因为 merge 分支而引入的 commit 信息影响对 commit 历史的查看,我们可以使用--no-merges进行过滤

1
2
3
git log --no-merges
// or
git lg --no-merges

选择查看 commit 信息

git log 提供了很多选项供我们对历史记录进行选择性查看,-n 查看最近几次提交,–author 查看提交者,–since 和–until 查看指定时间前后的提交

1
git log --author="Jun" --since="2023-2-15" --until="2023-3-1" -5

上述命令指的是查看提交者 Jun 在 2023-2-15 到 2023-3-1 号期间的最近 5 条提交记录。

撤销操作

修改上一条 commit

在 git 的任何阶段,都有可能需要撤销操作,我们可以通过 –amend 命令来重新提交。

–amend 可以直接理解成用新的一个提交来替换上一次提交,且上一次提交不会存有记录污染我们的仓库。使用此命令时也可以同步修改 commit 的信息。

1
2
3
git commit -m "feat: try"
git add .
git commit --amend

git restore 撤销操作

1
2
3
4
5
6
7
8
$ git add .
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: src/services/service/types.ts

在执行完git add .操作后,会将文件加入暂存区,运行 git status 命令会告诉我们状态,且会提示如何移除暂存区,也就是git restore --staged <file>命令。此外git restore <file>命令能够撤销在工作目录中的改动。

git tag 标签操作

查看标签

git tag支持查看标签列表,可带上可选(-l 或者–list)选项。

创建标签

Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated)。

使用-a创建附注标签,否则创建轻量标签。如:$ git tag -a v1.0 -m "new version 1.0"

在提交记录上补打标签:$ git tag -a v1.1 <提交校验和>

推送标签

推动标签到远程仓库和推送分支一样,运行git push origin <tagname>,如果想要一次性推送很多,直接使用–tags:git push origin --tags

删除标签

本地: git tag -d <tagname>
远程:git push origin --delete <tagname>

标签版本查看

使用 git checkout 命令查看标签所指向的版本,如果进行更改且提交,此变更不属于任何分支,可以根据标签创建分支:git checkout -b new-branch v1.0.0

git branch 分支管理

跟踪分支

命令 git checkout -b <branch> <remote>/<branch> 能够在本地创建一个跟踪远程仓库对应分支的本地分支。或者使用–track 快捷方式:git checkout --track <remote>/<branch>

日常中更多的是用git checkout <branch>创建本地没有,但是远程仓库有的分支。

如果想要本地分支和远程分支设置为不同名字可以用以下命令: git checkout -b <newBranch> <remote>/<branch>

在当前分支使用-u 修改跟踪的上游分支git branch -u <remote>/<branch>

查看

如果想要查看设置的所有跟踪分支,可以使用 git branch 的 -vv 选项,这会将所有的本地分支列出来并且包含更多的信息。

删除远程分支

git push origin –delete serverfix

合并

合并分支

rebase 和 merge 是我们 git 操作中常见的对分支进行合并的命令,它们的最终目的都是一致的,但是提交历史的展示将会不同。rebase 变基是将一系列提交按照原有次序依次应用到另一分支上,merge 合并则是将最终结果进行合并。

因为变基可以会导致其他合作者拉取同步时的问题,所以需要遵循变基只针对本地,提交推送到远程仓库后就不允许变基。

合并部分提交

多人协作的项目中,通常会有多个人对相同功能同时开发,这种合作模式势必会引起分支的相互依赖问题,如果需要将当前的开发分支中的部分 commit 提交合并到另一个分支上,cherry-pick 就派上用场了。

cherry-pick 有两种方式,一种是直接列出要合并的 commitId,另一种是用 first..last 的形式传入区间(不包括第一项,包括最后项):

1
2
3
4
// 合并id1和id2两条记录
git cherry-pick id1 id2
// 合并id3,id4和id5三条记录
git cherry-pick id2..id5

如果合并过程有冲突,会导致 cherry-pick 的暂停,等待用户解决冲突后执行 git cherry-pick –continue 即可。如果冲突过多或者其他因素导致不想完成此次合并,可以执行 git cherry-pick –abort 退回到原来的样子。

撤销合并

开发过程中难免会有合并出问题需要撤销的情况,Git 也为我们提供了很好的方式解决这类问题。git reset 命令用于将 HEAD 复位到指定位置,如:

1
git reset <options><commitId>

options 可选值有:

  • –hard: 删除工作区未提交的改动,暂存区和工作区都还原到之前版本,删除所有信息提交
  • –mixed: 默认值,暂存区还原到之前版本,工作区内容不变
  • –soft: 回退到某个版本

如果 reset 方法不能满足需求的话,可以考虑使用 git revert 进行撤销。git revert 本质上是一个逆向的 git cherry-pick 操作,会在提交历史中产生新的提交记录。

1
2
3
git revert -n commitId
git revert --no-edit commitId
git revert -n commitId1..commitId2

因为 git revert 是用一次新的 commit 去回滚之前的 commit,所以日后如果还要合并老分支的话,这部分代码将不会出现;git reset 是在分支上删除一些 commit,后续要合并老分支,这部分回滚的代码还会出现。

git revert 是将 HEAD 往前移,reset 是将 HEAD 往后,在推送远程仓库时,revert 一般可以直接操作,reset 可能需要添加-f 选项。

修改提交

修改最后一次提交

如果提交还没推送,我们需要修改提交信息或提交内容,可以使用:

1
$ git commit --amend

tips: –no-edit 选项可以在不对 commit 信息进行修改的时候修改提交

流程:

  • 运行上述命令
  • 在提供最后一次的提交信息的编辑器中对提交信息进行修改
  • 保存并退出编辑器,生成新提交。

下面有几个场景:

  1. 场景 1:只修改 commit 信息
1
git commit --amend -m "new commit"
  1. 场景 2:新提交文件,不修改 commit 信息
1
2
git add .
git commit --amend --no-edit
  1. 场景 3:多提交的文件需要删除
1
2
git rm --cached <file>
git commit --amend --no-edit

修改多个提交

除了修改最近一次的提交信息,git 也提供了 git rebase -i 的命令对多次提交的 commit 进行修改,git rebase -i HEAD~n 其中 n 代表最近几次提交。当执行此命令后,最近的 n 次提交将会以文本编辑器的形式倒序展示(最早的最先展示),且终端会有指引告诉各种选择以及其代表的意思。

假设现在需要对三个 commit 提交进行调整,需要完善第一次提交的 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
29
30
31
32
33
34
pick d19801d feat: new feat 1
pick cb6b02d feat: new feat 2
pick 9580869 feat: new feat 2

# Rebase efb8934..9580869 onto efb8934 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# create a merge commit using the original merge commit's
# message (or the oneline, if no original merge commit was
# specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
# to this position in the new commits. The <ref> is
# updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

使用关键词 reword 和 squash 达到我们的目的:

1
2
3
reword d19801d feat: new feat 1
pick cb6b02d feat: new feat 2
squash 9580869 feat: new feat 2

保存退出文本编辑器,则会依次变基每条记录,DONE!

参考