在平时开发中你会呈现下面几种状况么?

Fearless Git Committing
  1. 刚提交了一个commit,发现没改对,改完再提交一个相同的commit message
  2. 不想呈现上面提交多个相同commit message的状况,就一向不提交,直到完全开发完毕才全体提交一个commit

前者的问题自然是commit前史很乱,他人看commit message并不知道两次相同commit message的提交有什么区别,必须看diff。 后者的问题是,其他人完全不知道你的开发进度;没有push到远端的代码,就跟没有保存的文档相同,万一硬盘挂了就BBQ了。(我经历过3次硬盘挂掉,包含一个没买多久的SSD…)

本文首要介绍几个概念和一些实践经验,并不会十分详细地介绍各种Git指令和具体操作。详细操作能够在网上自行查找。 期望经过本文给那些对初学Git、对Git有那么一丝害怕的同学以自傲、东西和方法。期望读完本文之后,你在git commit的时分更挥洒自如。

文章分为两部分

  • 经过git log掌控大局状况,经过fsck和reflog知道怎么自救
  • 经过rebase调整commits,让提交前史更合理、美观、便利后续操作

名词约好

  • commits“节点”
Fearless Git Committing
  • commit SHA1
Fearless Git Committing
  • 远端(remote)

这儿是指经过git remote add repo 增加的库房

  • commit正交

这是我自己创造的一个词。多个commit正交是指这几个commit的内容互不相干。

全景图:检查提交前史

我习惯开着Fork,随时掌握库房提交前史的当时状态。有提交会自动刷新。

git log

git log是最基本的检查提交前史的指令。但其实它有许多可选参数。这儿不做介绍。你只需将下面这个git别名加到你的.gitconfig文件中即可:

[alias]
  hist = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an %cn%C(reset)%C(bold yellow)%d%C(reset)' --all

下面是在react工程根目录下履行git hist的作用:

Fearless Git Committing

tig

另一个东西是tig(git倒过来) 下面是在react工程根目录下履行tig --all的作用:

Fearless Git Committing

VSCodeForkSourcetree

假如不习惯指令行,能够运用GUI Git东西,假如VSCode的Git Graph、Fork和Sourcetree。下面是用Fork检查react工程的作用:

Fearless Git Committing
Fearless Git Committing

这儿不推重指令或GUI,哪个便利用哪个,互不排斥。

  • 比方在开发机上,指令行显然更便利快捷一些;
  • 本地开发GUI更便利一些;
  • GUI界面供给大部分Porcelain指令;指令行能够运用许多底层Plumbing指令(拜见)

救生圈:先学会自救方法

Fearless的前提是遇到问题知道怎么补救。

查找"丢失"commit

# 在一个空目录初始化一个库房
git init
# commit3个空节点
git commit --allow-empty -m 'a'
git commit --allow-empty -m 'b'
git commit --allow-empty -m 'c'

记住c的SHA1位785152a

Fearless Git Committing
# reset到b节点
git reset --hard HEAD^1
# 检查前史,c节点”没了“
git hist
Fearless Git Committing
git show 785152a

咱们发现c节点依然存在,只是在git 前史中看不到

Fearless Git Committing

假如我没有记住这个SHA1怎么办?

git fsck --lost-found

Fearless Git Committing

或许

git hist --reflog
Fearless Git Committing

Fork中能够

Fearless Git Committing

笨办法:保存commit SHA1

已然只需知道SHA1就能够恢复,那么在做一些“危险”操作时能够截个git hist的图,以备不时之需。

绝技:git reflog

git记载一切你对库房的操作。能够经过git reflog指令检查操作前史。而且能够回退到任意时刻点。

上面的例子中git reset --hard HEAD^1之后,能够经过git reflog检查操作前史:

Fearless Git Committing

找到commit: c,然后git reset --hard HEAD@{1}就能够恢复到该处:

Fearless Git Committing

Interactive rebase收拾commit节点

扔掉“过期”的节点

前提:咱们在自己的分支独立开发,未兼并到其他分支。

咱们在开发的进程中经常会呈现对某部分代码的重复修正,终究发现,之前提交的commit现已没有存在的意义了。这个时分咱们就能够在rebase的时分,将不再需求的节点“扔掉”。

假定咱们有三个commit:

Fearless Git Committing

提交的内容如上图所示。其中终究一个提交修正了console.log的内容。


Fearless Git Committing

Fearless Git Committing

提交console.log(42)现已没有意义,能够丢掉。后边会讲到怎么用Interactive rebase丢掉这种commit节点。

指令行Interactive rebase

在指令行中咱们也能够进行Interactive rebase: git rebase -i HEAD^3

默认状况下git会用vi作为修正器进行Interactive rebase的修正:

Fearless Git Committing

假如你是vim党,这个操作是十分便利的。

用VS Code插件Gitlens进行Interactive rebase

VS Code中的GitLens也有类似的功用。首要需求设置git的editor为VS Code:

git config --global core.editor "code --wait"
# git config --global core.editor "vim"

或修正.gitconfig文件:

Fearless Git Committing

然后运转git rebase -i后,就会自动翻开VS Code进行rebase操作:

Fearless Git Committing

具体操作可参阅:Interactive rebase editor from the GitLens extension

运用Fork进行Interactive Rebase

在需求收拾的一切节点前面的commit上点击鼠标右键,然后挑选Interactive Rebase → Rebase Interactively '<branch name>' to Here...

Fearless Git Committing
Fearless Git Committing

点击最下面咱们要删掉的commit前的选项,然后挑选drop:

Fearless Git Committing

rebase之后的commit,(处理遇到的抵触) 能够看出来,console.log(42)被删去了:

Fearless Git Committing

从头排序

准则:

  • 非“正交”节点坚持时刻上的先后次序。不然调整次序很或许会发生抵触
  • “正交”节点之间能够调整先后次序。因为这类节点之间不会发生抵触

下面是对同一个index.js的修正,调整次序必然发生抵触。但是你依然能够这么做。只需你知道每次处理抵触时,应该选用哪些代码就行。在实践作业中,多人合作时最好防止这种状况。假如无法防止,最好几个人一同确认怎么处理抵触。

Fearless Git Committing

下面调整的的是创立package.json文件,这个commit与其他三个commit是“正交”的,所以调整它不会发生抵触。

Fearless Git Committing

调整的结果如图:

Fearless Git Committing

小结: 运用Fork的Interactive Rebase功用能够便利地调整commit节点。上面只介绍了删去无用commit和调整次序。 除此之外还能够:

Fearless Git Committing
  • Edit:从头修正commit message和文件
  • Reword:从头修正commit message
  • Squash:将当时commit与前一个commit兼并,并保留commit message
  • Fixup:将当时commit与前一个commit兼并,并抛弃当时commit message

git rebase注意事项

及时rebase

Fearless Git Committing

咱们在dev分支开发时master分支也在不断更新。当多人开发,且各自dev分支和master都积累了较多commits,此刻提交Merge Request,就会呈现许多Merge线。下图是一个实在项目的Merge线:

Fearless Git Committing

主张在master有更新时,及时将dev rebase master:

Fearless Git Committing

收拾dev上的commits:

Fearless Git Committing
Fearless Git Committing

dev2也做相同的操作,rebase master,注意这儿push到origin需求force push

Fearless Git Committing
Fearless Git Committing

此刻再提Merge Request

Fearless Git Committing

能够看到,终究的commit前史很简练。 适时rebase master能够及时发现、处理抵触。将终究Merge呈现的大量抵触涣散在每次rebase中处理。 降低了终究集中处理抵触或许带来的犯错的或许性。

更好的commit message

(2023/01/18 更新)

在commit message最前面增加一个提交类型的emoji,能够一望而知提交类型。而且在提交前史中快速过滤不关心的提交类型:

  • init: 初始化工程
  • feat: ✨ 新功用
  • WIP: Working in progress
  • fix: 修正bug
  • refactor:♻️ 重构代码
  • ignore: 修正.gitignore文件
  • chore: 日常(非代码)
  • log: 增加日志
  • prune: 删去代码、文件、目录
  • style: 修正款式
  • config: 修正装备
  • doc: 写注释、文档
  • tag: 打tag
Fearless Git Committing

在Mac上,能够经过按ctrl+cmd+space翻开emoji输入框。能够经过顶部菜单的Edit→表情与符号翻开:

Fearless Git Committing

commit message是分为两部分:brief简要信息和detail详细信息, 其中detail信息能够分为多行(一些系统支持markdown格式)。主张在详细信息中提交本次提交中比较关键的修正:

Fearless Git Committing

在指令行是经过两个-m参数实现的:

git commit -m "brief" -m "detail"

谨慎git push -f

假如rebase的分支从来没有push到远端。此刻你能够为所欲为地调整commit节点。 一旦现已push到远端,那么你push -f时,其他在这个分支的开发者的对应分支,依然指向就得commit。 这就容易呈现各种难以追查的问题。假如你不得不push -f。确保只有你一个人在这个分支上作业。或许,告诉一切checkout过这个分支的人,从头checkout。

提交相互正交的commit

上面咱们也看到了,正交的commit调整起来不会发生抵触。所以咱们在多人协作时,

  • 每个人需求修正的文件之间尽或许没有堆叠,防止抵触。
  • 但总有一些公共文件我们都或许修正。此刻能够将文件再细分为多个文件,然后在进口文件一致import。 终究或许发生抵触的文件就只有进口文件。处理抵触更便利些。
  • 正交的多个commit独自提交,并确保提交的commit相对独立,以便利cherry-pick后能够正常作业 :比方,当重构代码时,你又不得不保护一个线上版本。正确安排线上版本的commit和文件拆分,能够在需求时,将commit便利地cherry-pick到重构分支。

终究

本文粗浅地介绍了日常开发中commit相关的一些实践心得。期望对我们有帮助。

链接

  • www.atlassian.com/git/tutoria…