1.前言
Git的本地使用仅仅服务于个人,若想多人合作,还是得通过网络和远程仓库来共享和同步。这时就面临着如何获取代码,如何更新代码,如何解决冲突和如何上传代码等问题。只要了解了这些,便可以在工作中舒服地使用Git了。
2.从远端获取
作为一名开发者,最常遇到的情况便是中途参与一个项目,那么获取已经完成的代码,在此基础上开发是必修课。
2.1.下载到本地
远程仓库是存在服务器上的,需通过网络地址去访问。而git clone
便可以通过网址下载仓库的代码,支持的协议有:http/https,ssh,git,file,ftp/ftps,rsync。
由于下载的内容在本地会用文件夹存储,目录名默认与远程仓库的一致。若想修改,可以在git clone
的命令最后添加目录名作为参数。
当代码下载完毕后,Git会给网址取个别名方便用户使用,专业的称呼为主机名,默认是origin,可通过git remote
查看。若想知道远程仓库的网址,后加-v
即可。若想修改主机名,在git clone
时,在网址前添加-o <主机名>
,或者git remote rename <原主机名> <新主机名>
便可改变。
默认分支是master,但开发通常是基于develop或feature分支,具体在之后的Gitflow工作流中会详细讲解。这时得切换分支,那如何知道有哪些分支呢?git branch
可以查看分支,后加-r
只显示远程分支,而-a
显示本地和远程的分支。更强大的是git remote show <主机名>
,不仅显示远程分支,还显示网址、HEAD以及本地分支与远程分支的映射关系。
2.2.更新到本地
Git不会主动从远程仓库上更新代码,当觉得远端有新的内容时,可通过git fetch
取回本地。但是,存放在<主机名>/<分支名>
下,对于开发的分支没有影响,所以不改变工作区文件。
3.同步工作区
上一篇中提到过工作区的文件由本地分支和版本来决定。为了改变工作区从而改变IDE或Explorer中看到的内容,需要将正在使用的本地分支与映射的远程分支(已更新)进行合并,而且合并的过程中可能会出现冲突,这些都需要解决。
3.1.merge
git merge
是比较常用的合并命令,默认使用Fast-forward方式,即当不存在冲突时,将两个分支的提交(commit)按时间先后排序并依次合并,同时删除合并分支的提交信息。当用git log --graph
或gitk
查看记录时,不会感觉有合并的操作,除了所有的指针都跑到一起(HEAD、<所在分支指针>、<合并指针>),如下图右半部分(忽略了指针)。在团队合作时,这样不能直观地看出人员的操作,通常用git merge --no-ff
命令代替,禁用Fast-forward方式,保留所有的操作信息,如下图左半部分。
3.2.rebase
git rebase
的目的也是为了合并,不过原理不同。它是将所在分支的所有提交转为补丁(patch)移到.git/rebase
目录下暂存,再将指针指向合并分支的末尾,并应用那些补丁。当用git log --graph
或gitk
查看记录时,也不会感觉有合并的操作。
3.3.conflict
若是仅仅看上面的内容,似乎差异体现在合并后提交信息的展示顺序上。其实当发现冲突(conflict)时,处理的方式上会有明显的不同。首先解释一下什么是冲突?当合并时发现不同的分支修改了相同的位置,Git不知道谁是正确的,所以需用户自己选择,解决冲突。
- merge会执行完合并操作,在工作区文件中用
<<<<<<<
、=======
和>>>>>>>
标记出冲突的地方。开发人员解决后,再执行一次提交变化的操作,表示修改错误即可。这次提交将出现在提交记录中,并成为最新的版本。 - rebase则是出现冲突就暂停操作,等开发人员解决了,通过命令
git add
添加变化和git rebase --continue
继续操作,任何时候都可以git rebase --abort
来终止操作,回到rebase前的状态。好处是,记录不会多出解决冲突的提交;坏处是,冲突多时得重复处理。 -
git fetch
和git merge
可以用git pull
代替,而git fetch
和git rebase
可以用git pull --rebase
代替。
4.推送到远端
代码同步好了,自然就应该开始工作了。可是团队合作时如何让其他人接收到你的更新呢?首先,须将远程仓库作为中转站,更新的代码都推送上去,别人主动从远程仓库下载更新。
4.1.正常推送
假设不会在远程仓库那冲突的话,只需要按照git push <主机名> <本地分支名>:<远程分支名>
输入命令即可。由于本地分支默认映射的是固定主机的固定远程分支,即origin上的同名分支,所以简写git push
。
需注意的是,若写了本地分支而与之映射的分支在远端没有,则会在远端新建同名分支;若省略本地分支而写了远程分支,则会删除此远程分支。当想改变分支的映射关系,只需某次推送时,在主机名前加-u
就可以设置此主机为默认主机。
4.2.推送前更新
若别人在你之前推送了代码,且包含你修改的文件,那么在推送时就会冲突。为了避免这种情况的发生,规范的做法是先更新本地需提交的分支,合并有差异的地方(参照同步工作区),再进行推送。当然,若你觉得远程仓库上代码是可以忽略掉的,在主机名前加--force
即可覆盖远程仓库上的同名文件。
5.总结
到此已经可以使用Git完成一个操作流程,比如向GitHub上提交自己的开源项目。但是这些仍然不足以让你在较大规模的公司中游刃有余,还需要懂得如何合理地利用分支、标签实现功能的并行开发,如何通过Gerrit结合Git实现CodeReview等。