文章目录
前言
Git 是一款优秀的分布式版本控制工具,对于大型项目的多人开发场景,Git 能够基于粗粒度功能 branch 或更细力度的 commitId 来进行版本控制。总而言之,学好 Git,老板再也不用担心代码被覆盖呢!给我一个 commitId,我可以撬动地球。
Git 分区
Git 主要分为 3 大区:
- 工作区(Working Directory):用户肉眼可以看到的界面
- 暂存区(stage 或 index):文件更改后暂存的区域
- 版本库(本地仓库 repository):git commit 存放数据的区域
Git 流程规范
分支的创建
分支的创建规范可以严格参考 git flow 分支规则:
- 对于新功能开发,一般地,以 feature 开头,后接具体的功能名称,例如:feature/add_login。
- 对于非紧急 bug 修复,以 fix 开头,后接具体修复内容,例如:fix/token_check。
- 对于紧急的线上 bug 修复,以 hotfix 开头,例如:hotfix/NPE。
- 对于发布的正式版本分支,以 release 开头;这种前缀开头的分支在项目开发中,只有 leader 才能进行操作,这个分支就是生产环境的分支,上述的分支都需要 merge 到这个 release 分支。
项目的分支规范
一般地,一个项目会分为三个类型分支:master 生产分支、pre 预发分支、dev 开发分支;如果细粒度来讲的话,再加一个 feature 功能开发分支。上述提到的各个分支间的区别:
- 首先,master 与 pre 分支的环境都是生产环境,唯一有些不同的是预发环境有可能没有多节点的负载均衡,预发代码量是大于等于 master 的代码量的。
- 然后 dev 和 feature 同是基于测试环境(数据库实例,中间件实例等),同样地,feature 代码量是大于等于 dev 分支代码量的。
- 当一个功能在 feature 测试通过后,merge 到 dev 分支,如果 feature 测试没问题,同环境的 dev 分支测试大概率也是没问题的。
- 那么 dev 分支再 merge 到 pre 预发分支,这个时候很可能出现问题,大概率是环境的不同造成的;一旦预发分支测试通过,这个时候就说明可以发布生产。
开发中需要注意的点
不要随意在 master 上直接开车提交代码,一旦出问题,可能就是直接丢饭碗了,这个老实地讲,很重要!!!
每次提交代码的时候,先 git pull 下,避免无必要的冲突。
不要妄想去改变或者合并别人的代码,除非你知道别人提交上来的新代码的意图;发生冲突了最好让功能 owner 自己去合并。
提交代码的时候,最后写清楚每次提交的注释(即 commit msg),这个对于后期的 code review 或回退尤为重要。
Git 的棘手场景分析
笔者在面试中,很喜欢提以下几个场景的 Git 操作;但是能够真正意义上回答上来的,却是少之又少!大部分回答都是,只能基于 IDE 进行简单的 pull、push 或 merge 操作;其实基于 IDE 也未尝不可,但是对于复杂的场景,很多同学可能不会用或根本没有去深入研究;那么笔者今天就几个典型场景以 Git 命令的形式展开分析一下。
拉取最新主干代码,进行功能迭代或 bug 修复
1. 首先切换到主干:
git checkout master
2. 然后拉取最新代码:
git pull
3. 基于 master 创建本地分支 xxx:
git checkout -b feature/xxx
4. 将本地分支 xxx push 到远程 Git 库:
git push --set-upstream origin feature/xxx
如何重命名远程分支
例如远程分支为:feature/xxx。
1. 首先切换到该远程分支对应的本地分支:
git checkout feature/xxx
2. 拉取下最新代码:
git pull
3. 进行重命名:
git blame -m feature/xxx feature/login
4. 将 feature/login 推动远程 Git 库:
git push --set-upstream origin feature/login
5. 删除老旧远程分支:
git push origin --delete feature/xxx
功能开发一半,临时修复线上紧急 bug
这个时候,新功能开发代码可能还没完成,我们需要把当前的工作进度保存下,等修复 bug 后再转过头来继续开发。
1. 保存当前的工作进度,并附上注释:
git stash save "add login func"
2. 获取 stash list:
git stash list
3. 修复完 bug 后,还原之前的工作进度:
git stash pop stash@{index}
如何挑拣别人的 commit
对于同一功能的不同分支,可能其他开发对该功能进行 bugfix,这个时候我们也想用在自己的分支 fix 这个 bug,注意不要脑残贴代码呢,敲黑板!!!
1. 获取其他开发者修复的 commitId:
git log 或 git reflog
2. 挑拣别人的 commitId 到自己的分支:
git cherry-pick commitId
如何回退版本
对于某一错误操作致使项目无法正常运行,我们需要对某一点进行还原,有点类似电脑操作系统的备份点或还原点;这个操作会使 git 指针往后退,所以在 push 的时候需要强制 push 才能成功!
1. 获取还原点,还原点选择很重要,需要选择正确版本的最新:
commitId
2. 回退版本:
git reset commitId
3. 查看 reset 后的代码更改项:
git status
4. 忽略更改项,直接强制 push:
git checkout .
git push -f
如何撤销某一个 commit
撤销操作和回退操作唯一不同的是,撤销的操作指针是往前的,回退的操作指针是往后的;撤销相当于相互抵消,等于白干!
1. 获取需要撤销的 commitId。
2. 进行撤销:
git revert commitId
如何合并分支
当功能分支测试完成,一切就绪后,需要同步下 master 分支,避免不必要的冲突;这个时候有两个选择:
git merge origin/master
git merge --no-ff origin/master
两者有什么区别呢?
-ff
默认情况是快进式(即 fast-forward),当合并两个分支时,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,叫做“快进”(fast-forward);这种情况如果删除分支,则会丢失 merge 分支信息。
--no-ff
关闭 fast-forward 模式,在提交的时候,会创建一个 merge 的 commit 信息,然后合并与 master 分支 merge 的不同行为,向后看,其实最终都会将代码合并到 master 分支,而区别仅仅只是分支上的简洁清晰的问题,然后,向前看,也就是我们使用 reset 的时候,就会发现,不同的行为就带来了不同的影响。
--squash
把一些不必要 commit 进行压缩,比如说,你的 feature 在开发的时候写的 commit 很乱,那么我们合并的时候不希望把这些历史 commit 带过来,于是使用 --squash
进行合并,此时文件已经同合并后一样了,但不移动 HEAD,不提交。需要进行一次额外的 commit 来“总结”一下,然后完成最终的合并。
这里笔者强烈推荐用 --on-ff
模式,这样合并上来的分支 commit 一目了然,便于后期的版本更迭。
创作不易,莫要白嫖,您的关注及点赞是对于我创作的最大动力与源泉。