大厂真实项目中规范的Git开发流程和回退
fork开发模式
因为项目都是多人开发,所以一般都是采用的fork
模式进行开发,也就是程序员们先把修改提交到自己fork
的仓库,然后在这个仓库的某个分支上进行项目的仓库分支的merge request
,一般是向develop
分支发起合并。
首先我们会对主仓库进行fork,有一个个人版本的仓库,还有一个项目的仓库。在本地进行git的配置,一般会把两个远程仓库都配上(origin repo + your repo),至于为什么会这么做,我们后面再说。
下文用origin
来代表项目仓库,yourrepo
来代表你fork
的仓库。因为涉及到内部信息和系统,所以不会有截图,全文都是文字和具体命令。
使用分支管理开发
通常,企业内部会有一个需求单系统,需求在这个系统上发布,在实现需求的时候会将某个分支绑定上,这样就可以很容易追踪一个需求到底是如何实现的,进行了哪些修改。并且能够自动绑定分支的提交信息和流转状态等等。
作为一个程序员,我们的视角应该是这样的。
- 接到一个需求
- 打算进行开发
git checkout develop
回到develop
分支,这应该是我们开发时每一次需求的根分支,要保持这个分支和远程仓库的同步。git pull origin master
拉取一下最新的代码,pull
命令就是fetch
和merge
的组合命令。fetch
用来获取远端仓库该分支最新的修改,merge
用来和你的本地分支进行合并,这样就能保持decelop
的干净状态、和远端项目永远是同步的。一般来说master
分支是比较稳定的最新代码,这样只之后提交发生冲突的概率比较低。如果你们的项目是c端的频繁发布的产品,那么git pull origin release
可能更符合你们的情况。git checkout -b branchname
,基于这个干净的develop
分支代码和记录,生成一个新的分支,在这个分支上进行开发。- 将分支与需求进行绑定。
- 进行开发和单元测试,测试无误之后准备提交代码。
git add filenames
,这里把工作目录下的文件添加到暂存区,禁止使用git add .
提交全量git commit -m "msg"
,这里提交到本地仓库,也就是在branchname
这个分支上进行了某些修改,本地已经有记录了,但是还没有同步到远程代码仓库。commit
信息有特定的规范,一般像下面一样,以行为类型开头,括号包裹模块,附上简单信息,description
中附加详细信息或测试结果。feat (project): 1.添加xx表 2.添加xx功能
。git fetch origin
,再次获取最新的代码仓库信息。git rebase -i origin/develop
,这里向最新的仓库develop
分支进行基准,合并到origin/develop
分支上,补全缺失的历史记录,注意,rebase
操作的本质上,把你本地分支branchname
的修改应用到develop
分支上,它会找到这两个分支最近的一次公共祖先,然后把a
对于develop
缺失的历史记录打一系列的补丁,再在分支前方生成一个新的点,让这次提交是develop
的最新提交,从而让develop
提交记录是一条线。注意:rebase
是会更改历史sha-1
值的,因为更改了a
分支的历史提交记录。git push yourrepo develop
,进行提交。如果需要多次提交的话,之后需要-f
或者--force-with-lease
这种比较安全的强制提交。因为rebase
会修改记录,所以想多次提交必须强制执行,这也是分支管理开发最不方便的一点。- 发起
merge-request
,这里会比较你更改的这些文件和原仓库对应文件的区别,一般不会有问题。偶尔如果你和同事一起修改了某一个文件,会产生冲突,这时候你需要处理冲突,重复上述add commit push
的操作就ok了。 - 更改需求状态,完成需求。
一条分支走到底
上面那一种使用分支管理进行开发是比较规范的开发过程,但是诟病有两个。
- 同一时刻只能进行一个功能的开发,如果需要切换到其他功能的开发,需要
git stash
,然后完成之后再git stash pop
重新开发。当然stash
也不是万能的,如果需要你先commit
提交某些修改,再进行新功能的开发,往往就不是很方便。 - 一个分支进行
rebase + push
之后,想要再次提交就必须强制执行,这是比较危险的操作,如果想要安全执行的话又需要创建新分支add + commit + rebase + push
,对于需求单和程序员都不够友好。
所以在某些时候,使用单分支进行开发能解决一部分问题,即一条分支走到底,多个功能复用一个分支进行开发,甚至所有功能都在这个分支上进行开发。
这样会比较简单,上述内容的git pull + add + commit + push + merge request
就是开发过程的全流程了。
远程开发同步问题
现在开发机环境和本地通常是隔离的,也就是说我们必须在本地IDE连接上开发机,才能拥有开发机的网络和测试环境。
这时候我们就有两套代码,一套是在本地IDE供我们编辑和修改的,一套是在开发机上测试执行的,我一般是这么同步的。
- 开启
auto upload
功能,每次进行修改自动推到远端开发机上。 - 在开发机上推代码,维护开发机的
git
、代码和分支永远是干净的。 - 在开发机上推完代码之后,本地的
git
环境就会有很多已修改的文件,这时候我们再把远端开发机的.git
仓库download
过来。 - 完成一个需求开发之后,本地和远端开发机的文件以及
git
状态应该是一致的,分支无需一致,因为本地不用推代码。
Git回退
因为git
将从开始工作到提交到远程仓库存储
分成了四部分,即我们都知道的工作区、暂存区、本地仓库和远程仓库,所以回退应该也有四种,分别是
- 取消工作目录的修改
- 取消暂存区的修改
- 取消本地仓库的修改
- 取消远程仓库的修改
取消工作区: git checkout filename
,会把文件的状态回滚到最近一次提交,和ide
提供的git rollback
功能是一样的,一般是我们不想要某个文件的修改时使用。
取消暂存区: 有时候我们修改了很多文件,有一些文件不应该是这次提交,但是不小心git add
了,这时候我们应该通过git reset filename
进行重置,让这个文件从暂存区移除,reset
命令有三种模式,--soft
、--hard
和--mixed
,默认是--mixed
三者的区别如下
mixed
:只有暂存区变化,也就是add
之后,我们使用git reset filename
,不会改变文件的修改,但是会把它从我们的暂存区移出去。soft
:回溯到某个节点,不会影响工作区和暂存区。比如我们commit
了三次,然后git reset --soft commit1id
,这个时候本地仓库分支就回退到了commit1
的时候,但是本地工作区代码还是commit3
时的代码。hard
:和soft
相反,会影响工作区,git reset --hard commit1id
,这个时候本地仓库分支就回退到了commit1
的时候,但是本地工作区代码也变成了commit1
时的代码。
取消本地仓库
某些时候我们可能编写了一些不合时宜的代码,里面有bug或者不需要,但是这些代码以及被commit
到了本地仓库,这时候我们对它们回滚就需要用到git reset
和git revert
这两个方法。
上面已经说过了reset
,就是把HEAD
指针移到之前的某个修改,并且可以选择保存工作区代码或者丢弃。
另一个选择是revert
,这个命令和reset
来说刚好相反,它是生成一个新的commit
节点,这个节点的内容就是撤销某一次提交,历史commit
记录会被保存,撤销的这一次commit
记录也会保存,刚好和reset
相反。
git revert HEAD
用来回退一次版本,git revert HEAD^
回到上上一次。
取消远程
其实就是在取消本地仓库的基础上push
一下推到远端,如果是reset
取消,那么需要-f
,因为修改了分支历史;但是如果是revert
,则直接推就可以,并没有修改分支历史,而是多了一个撤销某一次提交的记录。
推荐阅读
转载自:https://juejin.cn/post/7356043872622198836