保华的Rails学习笔记

如何利用github和git进行协作

牒权声明

本文首发于微信公众号:
杜具一格(baohua-xuexi)
请注意:
无需授权即可转载

如何利用Github进行协作开发(图文讲解详细步骤)
团队协作开发中,大部分都会用到版本控制软件,比如Git等。本文将通过实例,图文详细讲解在工作环境中,如何利用Git+Github进行协作开发,我们分场景讲解

情景1(主程与副程都在master开发)

将团队成员加入Collaborators
主程(A)在Github新建Repo项目,并加成员B为合作者
B把Repo项目clone回去
A修改代码,然后推代码上去commit & git push
B拉代码下来 git pull
B修改代码,然后推代码上去commit&git push
A拉代码下来git pull

1、在repo中,把成员B加入成为副程

2、我们开两个iTerm窗口,左边设为A用户,右边设为B用户,B用户从github上边把jd-test这个repo给clone下来,放入不同的目录里边,二者所在的专案目录不同(为了区分不同用户协作)

3、A用户,我们从截图看出,它当前不是在master分支,我们现在切换到master,把最新分支story5合并入master


4、此时,A用户只是在本地终端把最新代码(在story5分支)合并到master了,但是在github上边以及B用户终端,它们的master分支都不是合并后的最新代码,此时,我们需要让B用户以及github上边的代码与A用户本地终端的代码保持同步,我们在A用户终端执行git push origin master,把master分支的最新代码(合并story5后的代码)push到github

我们进入github,发现commits已增加到38个了,

而且点击commits链接进去后

发现这些代码是之前story5里边的,现在已合并入master分支了

6、这时候B用户需要从github上边拉最新master代码(合并story5后的代码),使用命令git pull origin master


此时,A用户、B用户以及github三者的代码保持一致了

7、这时候,A用户,对app/views/welcome/index.html.erb文件进行了修改(加入了一行内容),然后commit,并push到github的repo

这时候观察SourceTree,我们可以看出,B用户比起github落后了一个版本

或者B用户执行git status(数据稍有延迟),也可以看出来比github落后了一个版本

8、此时B用户把github上边的最新代码拉下来就可以了,执行命令git pull origin maste

这时候A用户、B用户以及github上边repo三者的代码又保持一致了

同样的,当B用户在本地修改代码后,需要commit并且push到github
A用户执行git pull拉最新代码下来后,A、B用户以及github三者代码就保持一致了
1、首先B用户修改并commit和push


这时候我们用SourceTree观察,发现A用户比github上的repo(origin/master)落后了一个版本


或者用git status也可以查出来(数据会有延迟,A用户push上以后,停顿一下再执行git status)

2、这时候,A用户执行git pull origin master就可以把最新代码拉下来了
执行完以后,A、B用户以及github上边的repo(origin/master)三者代码就保持一致了

情景二(出现rejected)

A修改代码,然后推代码上去 commit & git push
B修改代码,然后推代码上去 commit & git push
碰到![rejected]master->master(fetch fitst)的失败信息
B要先拉代码下来git pull进行代码自动合并
B再次git push
A拉代码下来git pull

1、A用户修改README文件


A用户修改后,进行git commit及git push

2、同时,B用户在修改app/views/welcome/index.html.erb文件

B用户进行git commit和git push,在进行git push的时候,出现错误

3、我们可以看到![rejected] master -> master(fetch first)的报错信息,之所以出现这样的rejected报错,原因是github的repo上边有A推的最新代码,B用户并没有拉最新代码下来,就又执行git push,它们接不起来
解决办法是B用户先运行git pull把最新代码拉下来,然后再运行git push推送代码,这时候,A用户需要再进行git pull操作拉最新代码下来
当B进行git pull操作的时候,跳出了一个atom的编辑框(MERGE_MSG)

4、这时我们保存这个文件就可以了

发现B用户已经拉最新代码下来了
5、这时我们用git status或者SourceTree进行检测的时候,发现B用户本地代码比github上边代码已超前了2个版本

B用户需要用git push推代码上去

6、我们再用git status或SourceTree检测下

B用户终端代码和github保持一致了
7、此时用git status或者SourceTree检测A用户代码

发现A落后两个版本(是指本地终端比github落后2个版本),所以A用户要执行git pull,把最新的代码拉下来

这时候,A用户、B用户以及github上边的repo三者的代码保持一致了

场景二总结:两个用户同时都修改代码并且push的时候,后边的用户push的时候,就会收到rejected报错信息,这时候后边的用户就要先执行git pull,然后再重新push,同时前边的用户需要运行git pull拉最新代码下来

情景三(出现rejected)

上边情景二是A和B修改不同的档案,情景三是A和B修改相同的档案(同一档案不同部位)

A修改代码,然后推代码上去commit & git push
B修改代码,然后推代码上去commit & git push
碰到![rejected]master-> master(non-fast forward)的失败信息
B要先拉代码下来git pull进行代码合并
B再次git push
A拉代码下来 git pull

1、A用户修改app/views/welcome/index.html.erb文件,并且进行commit & git push


2、同时呢,B用户也在改这个app/views/welcome/index.html.erb文件(不同部位)
B修改后然后进行commit & git push
当git push的时候出现报错信息

3、用情景2的方法,B先执行git pull拉代码,然后git push

4、此时A要执行git pull拉最新代码下来

其实与情景二是相同的解决方法

情景四(同时修改同一文件的相同部位而出现conflict)

A修改代码,然后推代码上去commit & git push
B修改代码,然后推代码上去commit & git push
碰到![rejected]master-> master(non-fast forward)的失败信息
B要先拉代码下来git pull进行代码合并
自动合并失败(Automatic merge fiailed),需要手动解决冲突,然后git commit
B再次git push
A拉代码下来 git pull

情景四与情景三不同的是,A和B同时改同一个档案的同一部位
1、A用户修改app/views/welcome/index.html.erb文件,第二行代码前后各插入一行代码


然后进行commit并git push到github

2、同时B也在修改app/views/welcome/index.html.erb这个文件,并且也是在第二行代码前后各加一行代码

B用户修改后进行commit并git push
当git push的时候,出现报错如下图(rejected):

3、这时,与情景二、三解决方法一样,要先git pull拉代码下来,然后再git push,当进行git pull的时候出现报错(conflict)

4、提示有confilct,当自动merge时出错,我们执行git status查看

提示both modified了同一个文件,即A和B用户同时修改app/views/welcome/index.html.erb这个文件
5、这时候,我们打开app/views/welcome/index.html.erb这个文件

上图中,第2行到10行,是冲突部分,即A和B同时修改的部分,用<<<<<<和 >>>>>>符号包起来,同时======符号把A用户commit的代码与B用户commit的代码分开,
其中上边是B用户commit的代码,下边是A用户commit的代码
这时候,我们要修改这个文件,决定保留A用户或者B用户commit的代码

如果保留B用户commit的代码,则第6到10行的代码直接先删除,第2行的代码也删除
如果保留A用户commit的代码,则第2到6行的代码直接先删除,第10行的代码也删除

6、我们决定保留B用户commit的代码


则修改后的代码为:

7、修改后,进行git commit并git push

8、这时候,A用户需要执行git pull把最新代码拉下来

现在,A的代码与B的代码一致了(即都更新到B用户commit的最新代码了)

情景五(切新分支做新功能)

情景五就是我们教程上边的协作方法了
在协作之前,主程A用户

在本地终端把最新分支的代码merge到master(切换到master分支,git merge 最新分支)
git push origin master,把合并后的最新master代码push到github

副程B用户

在本地需要git clone最新代码下来
cd 专案名,进入clone后的专案
cp config/database.yml.example config/database.yml
bundle install
rake db:migrate

这些步骤上边情景中已做过,我们这里不再赘述
1、B用户在master分支基础上切新分支出来


我们在BB分支上,做些改动

然后进行git commit操作

并且git push新分支到github的repo

2、这时候,B用户登录github并且打开github上边相应的repo

我们可以看到最新的BB分支已push到github
B用户现在要发出pull request,点击New pull request按钮

然后跳转到下图

base后边需要选择master,compare后边需要是副程的新分支BB
然后点击下边的Create pull request

点击后,就成功创建了一个pull request,如下图

从上图中可以看出,这个migrate#1是daniel-hua发出的,是合并一个分支BB到master,只有1个commit,现在它的状态是open(主程处理后的pull request显示状态为close)
我们往下拉,可以看到


提示没有冲突,可以进行合并,并且只有对这个repo有write权限的用户才能merge这个pull request,B用户是副程,没有这个权限,主程A才有merge权限

3、这时候主程A用户登录github,打开相应的repo,点击Pull requests,显示如下图


1 Open表示有1个pull request处于open状态(主程还没做merge处理),closed表示已处理过的pull request
点击下边的migrate,显示如下图:

在上图中,Commits 1表示这个pull request有1个commit,File changed 5表示这个pull request中有5个文件发表了改动,下边的Leave a comment中可以添加这次pull request的描述信息,显示"This branch has no conflicts with the base branch" ,表示没有冲突,"Merging can be performed automatically."表示可以进行自动合并,我们点击Merge pull request按钮,然后出现下图

点击comfirm merge,就完成了merge pull request操作了

4、此时,A用户运行git pull把最新代码拉到本地

5、这时候B用户,已完成了BB分支的开发而且被主程合并到master了,B用户首先要切换到master分支,然后从github拉master分支的最新代码下来

此时,A用户和B用户以及github的repo,三者的代码一致了

B用户可以在master重新切新分支出来,做新的功能了

因此副程B用户的任务就是:在本地master基础上切新分支出来-> 开发完后push当前分支到github -> 上github上开pull request给主程 ->主程合并后切换到master分支 -> git pull拉master最新代码下来 -> 在master上切新分支出来做新功能....

情景六:合并时有冲突

在情景五中,如果主程A在合并的时候有冲突,需要处理完冲突再合并(有冲突也不能合并)
前边的步骤与情景五类似,由于篇幅问题,我们快速做完前边步骤
切新分支CC出来


1、B修改seeds.rb文件,并且commit和git push新分支cc到github

2、B用户登录github发出pull request

从上边截图中可以看出,不能自动合并,不过这个pull request还是可以create的,我们先create这个pull request,让主程解决这个冲突并合并代码
点击下边的Create pull request,创建完成pull request
3、此时,A用户登录github并打开相应的repo
点击pull request进入到这个待合并的pull request

点击Resolve conflicts按钮,进入有冲突的文件

左边是有冲突的文件,右边是冲突明细
有右侧明细中,有冲突的代码用<<<<<<<和>>>>>>>包起来
======= 又把这部分分成了上下两半
上半部分是当前pull request中这个文件的写法
下半部分是当前master分支上这个文件的写法
如果我们保留cc分支的代码,则把23-26行的代码直接删除,同时把20行的代码也删除
点击Mark as resolved按钮

之后会跳转回当前pull request地址,显示 This branch has no conflicts with the base branch,点击 Merge pull request,然后 Confirm merge 就可以了

4、这时候,A用户git pull拉最新代码下来,B用户切换到master分支并拉最新代码下来

此时,A用户、B用户以及github上的repo三者代码都一致了

情景七(主程在github进行merge时,还想修改副程的代码)

1、副程在master分支切新分支出来,并修改文件,然后commit、git push新分支到github


2、然后去github创建一个pull request

3、此时主程A在github上边merge的时候,发现有些代码还要进一步修改,修改后再合并,先拉B用户新增的分支到本地

4、在SourceTree里边依次点击origin-dd-检出,这时候A用户终端自动(按回车)切换到dd分支了
或者在终端执行git checkout -b dd origin/dd,这样也可以在本地建立一个dd分支用于跟踪远程origin/dd分支内容

5、主程A用户在dd分支下边,修改一些文件,并且commit

6、然后切到master分支,并且合并dd分支到master

7、现在执行git push把master最新内容push到github

8、这个时候,B用户在dd分支,dd分支已开发完并且被合并到master了,首先要切到master分支,然后拉最新代码下来

这时候,A、B用户都是最新的代码了

补充说明

1、在终端运行stree直接打开SourceTree的配置方法
首先,在终端执行atom ~/.zshrc
然后,在.zshrc文件里边加入下边这行代码
alias stree='/Applications/SourceTree.app/Contents/Resources/stree'


现在,在终端输入stree就会直接打开SourceTree了
2、rejected报错
出现rejected报错一般发生在下列情形
远程github上边有更新代码,但是没有git pull拉最新代码下来,就在本地执行了git push操作
解决方法:在本地先git pull拉最新代码下来,然后再git push推本地的新改动到github
3、conflict报错
出现conflict报错一般发生在下列情形
主程与副程,都修改了一个文件的相同部位,当git pull拉代码下来并与本地代码合并时发生了冲突
解决方法:手工进入有冲突的文件,修改好以后重新push代码到github,然后另外一个协作者git pull拉最新代码下来

更多文章,请关注我的公众号: