4.1分支管理
git checkout -b dev #创建分支,并切换到新建分支。 相当于: git branch <branch name> #创建分支 git checkout dev #切换分支 git branch #查看分支,当前分支前面会标一个*号。 git merge <branch> #合并分支,合并指定分支到当前分支。 $ git merge dev Updating d17efd8..fec145a Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+) 注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。 git branch -d <branch name> #删除分支 因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。 4.2分支冲突
如果在2个分支上都对一个文件的相同位置进行修改,那么当2个分支合并时,会产生冲突。 例如: master分支,feature1分支都对readme.txt的同一位置进行修改。 在master分支上合并feature1分支。 $ git merge feature1 Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result. 我们可以直接查看readme.txt的内容: Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1 ### Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容。 作出合适的修改后,提交。 用带参数的git log也可以看到分支的合并情况: $ git log --graph --pretty=oneline --abbrev-commit --graph #可以看到分支合并图。 --pretty=online #用一行来表示 --abbrev-commit #缩写commit_id 然后,就可以删除feature1分支。 $ git branch -d feature1 Deleted branch feature1 (was 75a857c). 重要注释: 一. 分支合并部分楼主只提到master先合并dev时对冲突进行手动修改然后提交。其中有几个问题不清楚实际测试了一下才知道。 1)出现冲突时,在master修改冲突并commit之前无法切换到dev分支。 2)master修改冲突并提交之后切换到dev,发现dev内容保持原来不变(合并之前dev分支)。 3)此时在dev下再次合并master无冲突,直接替换成master修改冲突并提交之后的内容。 dev先合并master的情况相同。 二. 3)很重要,在实际开发中会经常用到,这样可以保持冲突后的一致性。 三. 我理解的冲突的情况。一般来说,只要没merge过,两个分支对同一个文件的任何位置的修改都会出现分支的冲突。 例如,我们从master建立一个新分支dev, (1)dev修改而master不修改,则是最一般和最理想的情况,没有冲突。 (2)dev修改,master也修改(在master分支上的修改,或者另外分支合并造成修改),这里的修改指对同一个文件的修改,这样才会产生逻辑的冲突,都会产生分支冲突。 实验跟楼主在楼下总结的“实际项目中master是主线,每个开发小组都有自己的分支,比如dev-1, dev-2,每个组都要干两件事: 1)把自己的dev-N往master merge:自己的修改提交到master, 2)把master往自己的dev-N merge:获得别人的修改。”相吻合。 4.3分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。 (!!因为在fast forward模式中,直接将master指针指向合并的分支指针,逻辑图上看,2个分支就是一条线,意味着分支信息丢掉。) 如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。 (!!逻辑图上,会显示出分别的分支,这在实际开发中经常用到。) --no-ff方式的git merge: $ git merge --no-ff -m "merge with no-ff" dev 我亲自做了2中方式的对比。可以从分支历史图上看出。 git log --graph 分支策略 在实际开发中,我们应该按照几个基本原则进行分支管理: 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活; 那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本; 你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。 合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。 4.4Bug分支
软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。 修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除。 那么在下面的情况下呢? 我们在dev分支上,任务正在进行中没有完成,这时要在master分支上修改一个bug。 Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作。 $ git stash #存储现场 $ git checkout master #切换到master分支,建立新分支,修改,合并,删除。 .. .. .. $ git checkout dev #切换到dev分支 $ git stash list #查看保存的工作现场,栈结构 恢复有2种, (1) $ git stash apply #恢复,但是恢复后stash内容不删除 $ git stash drop #删除stash相应内容 (2) $ git stash pop #恢复的同时,也将stash相应内容删除 你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令: $ git stash apply stash@{0} 当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。 重要注释: 一. 在处理完bug,回到工作的分支后,因为master分支修改了bug,在工作分支还有存在这那个bug,即和原来一样。 二.由于这样,再合并的时候可能会出现分支冲突,按照之前的方法处理就可以。 4.5Feature分支
软件开发中,总有无穷无尽的新的功能要不断添加进来。 添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。 如果在feature分支进行中,发现不需要feature的功能,就需要删除。 $ git branch -D feature-vulcan #删除未合并过的分支 使用-d参数会有提示,无法删除。 开发一个新feature,最好新建一个分支; 如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除。 4.6多人协作
$ git remote #查看远程库的信息 $ git remote -v #详细信息 推送分支 $ git push origin master #推送master分支 $ git push origin dev #推送dev分支 * master分支是主分支,因此要时刻与远程同步; * dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步; * bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug; * feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。 抓取分支 可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆。 $ git clone git@github.com:michaelliao/learngit.git 不过,只能看到master分支。 $ git branch #查看分支 如果需要dev分支, $ git checkout -b dev origin/dev 修改之后可以推送, $ git push origin dev 如果你在推送之前,有人已经推送了自己的修改。这时会有冲突。 需要将最新的提交抓取下来,然后与本地合并,解决冲突,再推送。 $ git pull 第一次会失败,原因是没有指定本地dev分支与远程origin/dev分支的链接。根据提示,建立连接。 $ git branch --set-upstream dev origin/dev #具体格式可能不同,按照git push里的提示做 解决冲突之后,push。 因此,多人协作的工作模式通常是这样: 首先,可以试图用git push origin branch-name推送自己的修改; 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并; 如果合并有冲突,则解决冲突,并在本地提交; 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功! 如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name。 这就是多人协作的工作模式,一旦熟悉了,就非常简单。
在Git里,这个分支叫主分支,即master分支。一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上。Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变。假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并。合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支。