Git 是什么?
Git 是一个分布式的代码管理容器,本地和远端都保有一份相同的代码。 Git 仓库主要是由是三部分组成:本地代码,缓存区,提交历史,这几乎是所有操作的本质,但是为了文章更加简单易懂,就不围绕这块展开了,有兴趣的可以去了解下。 开门见山,我们直接来说说 Git 有哪些常见的操作。
Git 有哪些常规操作?
我们简单说说Git有哪些常规操作,能够让我们应付简单的开发需求。
克隆代码
"" type="png" w="691" src="/UploadFiles/2021-04-02/201709072128191.jpg">"" type="png" w="640" src="//img.jbzj.com/file_images/article/201709/201709072128192.jpg">
从某个角度上来说,Git维护的就是一个commitID树,分别保存着不同状态下的代码。 所以你对代码的任何修改,最终都会反映到 commit 上面去。
"" type="png" w="594" src="/UploadFiles/2021-04-02/201709072128193.jpg">
相对来说,git merge 处理冲突更直接,而git rebase 能够保证清晰的 commit 记录。 合并 commit 的时候,通常会发生冲突。 可以全局搜索特殊字符比如<<<,找到需要处理的代码位置,然后认真分析应该保留哪一部分代码。
在团队协作的时候,分支是必不可少的。那么应该如何对分支进行操作呢?
操作分支
所谓的分支其实就是一个指向 commitID 的指针,你可以去 .git/refs/heads 里去看看。
通常情况下,我们建议分支至少能够明确的标记功能名称,如果能标记用户就更好了,比如 qixiu/feature 。 "" type="png" w="376" src="/UploadFiles/2021-04-02/201709072128206.png">
可以同时看到本地分支和远端分支,配合上前文介绍的 git fetch -p 可以第一时间查看到最新的分支信息。 "" type="png" w="722" src="/UploadFiles/2021-04-02/201709072128207.jpg">
"" type="png" w="564" src="/UploadFiles/2021-04-02/201709072128208.jpg">
仔细看上图,reflog 记录了你所有的 git 命令操作,对于复原某些莫名其妙的场景或者回滚误操作有极大的帮助。 试想一个场景:你使用 git reset --hard commitID 把本地开发代码回滚到了一个之前的版本,而且还没有推到远端,怎么才能找回丢失的代码呢? 你如果使用 git log 查看提交日志,并不能找回丢弃的那些 commitID。 而 git reflog 却详细的记录了你每个操作的 commitID,可以轻易的让你复原当时的操作并且找回丢失的代码。 当然,如果你丢失的代码都没有提交记录,那么恭喜你,你的代码真的丢了。
压缩提交记录
这也是一个很实用的功能,前文提过,我们在开发中的时候尽量保持一个较高频率的代码提交,这样可以避免不小心代码丢失。但是真正合并代码的时候,我们并不希望有太多冗余的提交记录,而且 rebase 合并代码的时候,会把每个 commit 都处理一下,有时候会造成冗余的工作。 所以,压缩日志之后不经能让 commit 记录非常整洁,同时也便于使用 rebase 合并代码。
那么,如何压缩commit记录呢? "" type="png" w="499" src="/UploadFiles/2021-04-02/201709072128209.jpg">
从实际应用来说,三种日志压缩都很优秀, git reset 更简单, git rebase -i 更细腻。
git rebase,合并代码
前文简单介绍了 git rebase 和 git merge 的区别,坦率讲,他们各有优劣。 git rebase 能让你的 commit 记录非常整洁,无论是线上回滚还是 CodeReview 都更轻松;但却是一个有隐患的操作,使用时务必谨慎。 git merge 操作更安全,同时也更简单;但却会增加一些冗余的 commit 记录。
这儿简单说说 rebase 的合并流程和注意事项吧。看下图
有三个点需要注意: "" type="png" w="640" src="//img.jbzj.com/file_images/article/201709/2017090721282011.jpg">当你不断 rebase master 的时候,其实你本地的 d 都变成了 d' ,再要和远端 pay 分支保持一致,你的本地分支 commit 记录已经不堪入目了。
所以,为了安全,团队可以考虑采用 merge。
pull request,方便CodeReview
Git 不仅提供了代码托管以及代码开发的帮助,还提供了代码审核类似的功能。 当我们在功能分支开发完成之后,可以发起一个 pull request 请求,选择需要对比的两个分支
它会创建一个 pull request,制定相关人员来对代码进行 review。 通常情况下,团队应该鼓励交叉 review,涉及到公共代码的时候,一定要让相关人 review。
git hook,Git 的生命周期
这个大多数人应该都,听说过,git操作有它自身的生命周期,在不同的生命周期,我们可以做一些自动化的事情。
举两个简单的例子: ✦ pre-commit的时候我们可以做 eslint ✦ post-commit的时候,我们可以做利用 jenkins 类似的工具做持续集成
当然还有更多的声明周期,具体可以参考 Git 钩子
git submodule && git subtree,管理第三方模块
这两个命令通常用来管理公用的第三方模块。比如一些通用的底层逻辑、中间件、还有一些可能会频繁变化的通用业务组件。 当然,两者还是有区别的。 git submodule 主要用来管理一些单向更新的公共模块或底层逻辑。 git subtree 对于部分需要双向更新的可复用逻辑来说,特别适合管理。比如一些需要复用的业务组件代码。在我之前的实践中,我也曾用subtree来管理构建系统逻辑。
git alias,简化 Git 命令
我们可以通过配置 git alias 来简化需要输入的 Git 命令。 比如前文的 git subtree 需要输入很长的 Git 命令,我们可以配置 .git/config 文件来解决。
// git stpull appfe demo/xxx
// git stpush appfe demo/xxx
[alias]
stpull = !git subtree pull --prefix=$1 appfe $2 \
&& :
stpush = !git subtree pull --prefix=$1 appfe $2 \
&& git subtree split --rejoin --prefix=$1 $2 \
&& git subtree push --prefix=$1 appfe $2 \
&& :
总结说点啥?
该文首先介绍了 Git 常规操作 ✦ 包括克隆代码、操作 commit、操作分支等。其实 Git 常规操作的命令并不多,请看第一部分的简单总结。
其次介绍了 Git 开发流程 ✦ 该部分主要介绍了两种主流的开发模式:比较轻量的 基于功能分支的开发流程 *和适合复杂项目的 *GitFlow 开发流程 ,两种模式各有使用的场景,对于常规使用,前者就已经足够了。
最后介绍了一些 Git 实用技巧 ✦ 主要包括:reflog 操作,压缩日志,rebase 的注意事项,利用 pull request 做 codeReview,利用 git hook 做一些自动化工作等。
题图:pexels,CC0 授权。