在平时开发中你会呈现下面几种状况么?
- 刚提交了一个commit,发现没改对,改完再提交一个相同的commit message
- 不想呈现上面提交多个相同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
“节点”
commit SHA1
- 远端(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
的作用:
tig
另一个东西是tig
(git倒过来)
下面是在react
工程根目录下履行tig --all
的作用:
VSCode
、Fork
或Sourcetree
假如不习惯指令行,能够运用GUI Git东西,假如VSCode的Git Graph
、Fork和Sourcetree。下面是用Fork
检查react
工程的作用:
这儿不推重指令或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
# reset到b节点
git reset --hard HEAD^1
# 检查前史,c节点”没了“
git hist
git show 785152a
咱们发现c节点依然存在,只是在git 前史中看不到
假如我没有记住这个SHA1怎么办?
git fsck --lost-found
或许
git hist --reflog
在Fork
中能够
笨办法:保存commit SHA1
已然只需知道SHA1就能够恢复,那么在做一些“危险”操作时能够截个git hist
的图,以备不时之需。
绝技:git reflog
git记载一切你对库房的操作。能够经过git reflog指令检查操作前史。而且能够回退到任意时刻点。
上面的例子中git reset --hard HEAD^1
之后,能够经过git reflog
检查操作前史:
找到commit: c
,然后git reset --hard HEAD@{1}
就能够恢复到该处:
用Interactive rebase
收拾commit
节点
扔掉“过期”的节点
前提:咱们在自己的分支独立开发,未兼并到其他分支。
咱们在开发的进程中经常会呈现对某部分代码的重复修正,终究发现,之前提交的commit现已没有存在的意义了。这个时分咱们就能够在rebase的时分,将不再需求的节点“扔掉”。
假定咱们有三个commit:
提交的内容如上图所示。其中终究一个提交修正了console.log
的内容。
提交console.log(42)
现已没有意义,能够丢掉。后边会讲到怎么用Interactive rebase丢掉这种commit节点。
指令行Interactive rebase
在指令行中咱们也能够进行Interactive rebase:
git rebase -i HEAD^3
默认状况下git会用vi作为修正器进行Interactive rebase的修正:
假如你是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文件:
然后运转git rebase -i
后,就会自动翻开VS Code进行rebase操作:
具体操作可参阅:Interactive rebase editor from the GitLens extension
运用Fork进行Interactive Rebase
在需求收拾的一切节点前面的commit上点击鼠标右键,然后挑选Interactive Rebase → Rebase Interactively '<branch name>' to Here...
:
点击最下面咱们要删掉的commit前的选项,然后挑选drop
:
rebase之后的commit,(处理遇到的抵触)
能够看出来,console.log(42)
被删去了:
从头排序
准则:
- 非“正交”节点坚持时刻上的先后次序。不然调整次序很或许会发生抵触
- “正交”节点之间能够调整先后次序。因为这类节点之间不会发生抵触
下面是对同一个index.js的修正,调整次序必然发生抵触。但是你依然能够这么做。只需你知道每次处理抵触时,应该选用哪些代码就行。在实践作业中,多人合作时最好防止这种状况。假如无法防止,最好几个人一同确认怎么处理抵触。
下面调整的的是创立package.json文件,这个commit与其他三个commit是“正交”的,所以调整它不会发生抵触。
调整的结果如图:
小结: 运用Fork的Interactive Rebase功用能够便利地调整commit节点。上面只介绍了删去无用commit和调整次序。 除此之外还能够:
- Edit:从头修正commit message和文件
- Reword:从头修正commit message
- Squash:将当时commit与前一个commit兼并,并保留commit message
- Fixup:将当时commit与前一个commit兼并,并抛弃当时commit message
git rebase
注意事项
及时rebase
咱们在dev分支开发时master分支也在不断更新。当多人开发,且各自dev分支和master都积累了较多commits,此刻提交Merge Request,就会呈现许多Merge线。下图是一个实在项目的Merge线:
主张在master有更新时,及时将dev rebase master:
收拾dev上的commits:
dev2也做相同的操作,rebase master,注意这儿push到origin需求force push
此刻再提Merge Request
能够看到,终究的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
在Mac上,能够经过按ctrl+cmd+space
翻开emoji输入框。能够经过顶部菜单的Edit→表情与符号翻开:
commit message是分为两部分:brief简要信息和detail详细信息, 其中detail信息能够分为多行(一些系统支持markdown格式)。主张在详细信息中提交本次提交中比较关键的修正:
在指令行是经过两个-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…