之前的项目一直在使用SVN管理项目代码,协同开发的场景较少,SVN也用着也还过得去。切到新项目后,都改为了Git管理项目库。
刚从Svn切过来的时候感觉不适应,搞不懂分支,本地库,fork仓的概念,也不知道如何更好的使用Git的特性来进行多个需求和问题的并行开发。经常会遇到各种问题。现在就把一些自己理解的概念和使用场景记录下。
Git在使用时大致是有3个层级:本地仓库,远程个人fork仓库,远程origin仓库。
在这里可能很多人没有个人fork仓,直接是提交代码至origin上的分支来进行提交代码。没关系,这两者不冲突,只是使用了不同的管理方式。
所以在提交代码时,也就有以下两种路径方式:
(1)修改代码->commit到本地:xxx分支->push到origin:yyy分支->提mr合入至origin:master;
(2)修改代码->commit到本地:xxx分支->push到远程个人fork仓:yyy分支->提mr合入至origin:master;
按照我个人使用理解,公司内的项目,可以直接使用第一种方式,省略fork的步骤。因为不对外公开源码,即使基于origin创建多个分支,导致origin分支众多,也没有太大关系。但是开源项目就不允许这么做,否则会导致origin仓库分支太杂太乱,不易于管理,只有被管理员和其它commiter认可的人才有资格操作origin仓的分支。
新项目的人以前都是搞开源项目的,因此使用时都会把origin仓fork到个人仓,也就是上面(2)的方式。
下面记录下自己在用fork仓时,主要侧重写一些使用场景的理解,命令的基本使用方法:
1.git clone ssh://xxx.xxx.com:2222/xxx.git(针对的是远程仓库)
用来下载远程仓库,可以下载origin也可以下载个人fork仓,在当前目录形成git本地仓库及该目录的本地仓master分支。
2.git remote(针对的是远程仓库)
当使用git clone下载代码后,本地仓库上显示clone下来的远程仓库名称默认为origin。
我在开发过程中,先会用git clone把自己的fork仓down下来。然后再使用git remote命令把master仓也关联到这个本地仓库。这样可以灵活的pull和push到这两个仓库中。
git remote -v //查看远程仓库详情
git remote remove test //删除远程仓库
git remote rename {oldname} {newname} //重命名
git remote add {仓库名} git地址 //关联远程仓库到本地仓库,名称可以自定义
3.git fetch(针对的是远程仓库的具体分支)
git fetch origin master:tmp //从名为origin远程仓库,下载master分支代码到本地仓库的tmp分支
如果对origin进行了fork,使用remote命令关联到本地仓库,并且名称为zhangsan。那可以继续使用fetch命令下载zhangsan的分支代码到本地仓库。例如:
git fetch zhangsan master:fork_tmp //从名为zhangsan 远程仓库,下载master分支代码到本地仓库的fork_tmp分支
4.git reset --hard {tag} //强制回退代码至tag标签(针对的是本地仓库的当前checkout的分支)
5.git rebase {目标分支} //变基操作,将{目标分支}的commit log强行同步给当前checkout的分支。主要是为了解决当前分支commit log和准备pull代码的远端仓库log不一致的问题,log不一致则会导致冲突问题。
git使用时遇到困扰我多次的一个问题
在这里重点记录下这个问题,自己遇到了三次,每次都花了很大的力气去解决。现在把问题解决的规避方案和根本原因记录下。
问题出现时的仓库情况:
本地仓库关联的远程分支有两个,一个是master仓库(名称为origin),一个是fork了master的个人仓库(名称为zhangsan)。
本地仓库checkout的是master。本地代码已经修改完毕。zhangsan的代码和master的代码已经同步至一样。
所做的操作:
(1)commit代码到本地仓库分支,push代码至zhangsan:bugxxx分支;
(2)在zhangsan仓库的页面上,将bugxxx的代码提mr至master;
(3)管理员将代码合入master。
到现在为止,所有都是正常的。然后我发现代码没有修改完全,需要继续修改代码,然后再mr至master。
这时候我按照以前svn的思路,我认为可以直接从master仓库pull代码到本地仓库,因为不管别人有没有合入的东西,至少我跟origin:master的代码是一致的,我pull代码下来,应该是没有问题的。
但实际上,我pull代码下来的时候,已经变成了冲突,需要merge处理代码。但此时我无论如何merge,一直没有达到我预期的效果:本地仓库和master仓库一致。除非reset回退、rebase新的master本地仓库或者重新clone代码下来。
这到底是为什么呢?
其实问题就出在上面第三步中,第三步管理员其实没有直接同意我的mr,而是close我的mr。管理员在自己本地仓库pull了zhangsan:bugxxx分支的代码,再push到了master。所以我本地仓库代码虽然和master代码是一致的,但是commit id是不同的。因此我将master的代码pull到本地仓库的时候就提醒了代码冲突。
如何规避:
解决问题的办法就是先将本地修改的代码stash一把(如果有的话),然后将origin:master分支fetch至local_master,然后将当前开发分支rebase至local_master。这样commit log就一致了,再unstash代码下来。千万不能reset回退或者clone代码下来,因为reset会导致你本地修改代码丢失,重新clone会导致stash数据丢失。
根本解决方法:
其实造成这个问题的根本原因还是对Git的不了解,不知道如何使用它完成多特性开发。
我所有的操作都是在local:master上完成的,我本地只用了这一个分支来开发,完成提交、同步等的操作,不仅工作是串行的,而且容易就会造成commit log不一致的问题。
正确的做法是local:master只用来pull代码。如果遇到要开发特性的情况,则直接git checkout -b {新分支}。在新分支上开发完毕,提交代码。此时再切回local:master,pull代码也不会报错,因为一直与origin:master的commit log是同步的。
网友评论