本文为个人整理笔记,参考与廖雪峰老师的官方GIT教程:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

在之前的GIT入门介绍中,我们了解了本地一些GIT操作的命令和原理,在这一节将一起学习一下GIT远程管理和版本管理的相关内容。


远程仓库

如果要在github上管理我们的代码,并在本地进行修改提交就需要了解git 远程仓库的相关内容。github是git官方提供的一个代码托管平台,个人可以申请免费的,但是所上传的内容可以方便大家共享,如果要使用私密仓库,需要付费。

在github上添加SSH KEY:

在github上注册好账户之后,添加本机的SSH公钥,这样在本地在对远程仓库操作时就不用频繁的使用账号密码。

ssh-keygen-trsa-C"youremail@example.com"

一路默认回车之后,cat .ssh/id_rsa.pub ,然后将cat的内容添加到账户的SSH Key中。


创建第一个个人仓库

首先在github上注册一个个人账户,在New repository中直接输入新建仓库的名称即可。根据提示使用SSH的方法在本地添加一个个人仓库:

gitremoteaddorigingit@github.com:YourName/gitrepo.gitgitpush-uoriginmaster#-u更新所有分支origin默认远程仓库名称

当第一次同步了所有的本地文件之后,在对文件做了commit,就可以直接使用:

gitpushoriginmaster

这样就直接将本地更新的文件推到了远程管理库。


从远程仓库克隆

github上有很多很优秀的代码和应用,如果我们要是用别人的代码,直接可以用git clone命令将代码拉到我们本地,如果是自己的代码库可以直接拉取:

git clone git@github.com:YourName/gitrepo.git


分支管理

在进行开发的过程中,很多情况下我们需要对分支进行管理。例如,如果是本地对一个文件进行修改,那么这个文件就是线性的修改方式,如果要对多个文件进行多次修改,而且不同的修改最终会确认一个最终的版本,最终合并的这个分支就是这个文件的最终版本,需要注意的是,只有当执行了commit 命令之后,本地的master分支才会建立。

创建并切换分支:

gitbranchedev#创建dev分支gitcheckoutdev#切换分支到dev===============gitcheckout-bdev#创建并切换分支,一条命令搞定

查看分支:

gitbranch

对分支修改后git add , git commit 之后就可切换到master分支上合并。

合并dev到master分支:

gitmergedev

删除分支:

gitbranch-ddev


当在两个分支上同时修改了文件并且提交后,在git合并时就会出现冲突的报错。这是因为当我们在合并的时候程序也不知道我们到底需要更新哪一个,这就需要我们手动去更新文件,解决冲突。然后再合并。

[root@workgitrepo]#gitmergetest#在master和test分支上都commit后,再merge会报错Auto-mergingreadme.txtCONFLICT(content):Mergeconflictinreadme.txtAutomaticmergefailed;fixconflictsandthencommittheresult.[root@workgitrepo]#catreadme.txttest<<<<<<<HEAD#查看编辑的文件,系统对我们手动要修改的地方做了标注thisismaster=======thisistest>>>>>>>test

修改文件统一后,再次执行git add 和git commit就可以解决冲突了:

[root@workgitrepo]#gitlog--graph--pretty=oneline--abbrev-commit*52ed4dfconfilt|\|*310f7e7IT#显示了一个分支的修改*|a8fa78bmaster|/*b040742test

用git log --graph命令可以看到分支合并图。


合并分支时,默认使用的是fast forward模式,但是使用这种模式是不记录其它分支的修改日志的,在实际应用中,为了更加清楚分支上的修改时间,需要加上--no-ff参数,可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。


在一般的开发过程中大豆会有如下流程:

1、leader在远程仓库创建2个分支:master和dev

2、张三和李四克隆远程仓库到本地

3、张三和李四都切换到dev分支

4、张三创建分支z3,李四创建分支l4

5、开发完成后,张三合并z3到dev,李四合并l4到dev

6、张三和李四把本地库的dev分支推送到远程dev

7、leader拉取远程库里的dev和masterd,在本地将dev合并到master 并推送到远程master


BUG分支管理

如果当前正在dev分支上开发,突然线上出了一个BUG,需要立即修复,这时候我需要暂时隐藏当前的工作,也就是保存当前dev分支上的进度 git statsh:

[root@workgitrepo]#gitstashSavedworkingdirectoryandindexstateWIPondev:f241242testHEADisnowatf241242test[root@workgitrepo]#gitstatus#隐藏工作区之后,显示的工作目录为空了#Onbranchdevnothingtocommit,workingdirectoryclean

保存了当前的工作后,我们就要去修复线上的bug了,切换到master分支,并创建一个修复的issue分支:

[root@workgitrepo]#gitcheckoutmasterSwitchedtobranch'master'[root@workgitrepo]#gitcheckout-bissueSwitchedtoanewbranch'issue'[root@workgitrepo]#gitbranchdev*issuemaster

在issue上完成修复工作后,执行git add ,git commit 提交代码,然后在master上合并issue分支上的代码删除issue分支:

[root@workgitrepo]#gitbranchdev*issuemaster[root@workgitrepo]#gitaddreadme.txt[root@workgitrepo]#gitcommit-m"fixissue"[issue8b29da7]fixissue1filechanged,1insertion(+)[root@workgitrepo]#gitcheckoutmaster#回到master上合并issue分支Switchedtobranch'master'[root@workgitrepo]#gitmerge--no-ff-m"fixbugissue"issue#记录分支日志信息Mergemadebythe'recursive'strategy.readme.txt|1+1filechanged,1insertion(+)[root@workgitrepo]#gitbranch-dissue#删除issue分支Deletedbranchissue(was8b29da7).

bug修复完成之后,我们要回到自己的dev分支继续我们的工作了:

[root@workgitrepo]#gitcheckoutdevSwitchedtobranch'dev'[root@workgitrepo]#gitstatus#原来的dev分支是空的#Onbranchdevnothingtocommit,workingdirectoryclean[root@workgitrepo]#gitstashlist#查看我们隐藏的分支stash@{0}:WIPondev:f241242test[root@workgitrepo]#gitstashpop#显示出隐藏的分支,并将隐藏的分支删除#Onbranchdev#Changesnotstagedforcommit:#(use"gitadd<file>..."toupdatewhatwillbecommitted)#(use"gitcheckout--<file>..."todiscardchangesinworkingdirectory)##modified:file.txt#nochangesaddedtocommit(use"gitadd"and/or"gitcommit-a")Droppedrefs/stash@{0}(5a7f46b8a24f1a557a37b0378ee75c65387e024a)[root@workgitrepo]#gitstatus#Onbranchdev#Changesnotstagedforcommit:#(use"gitadd<file>..."toupdatewhatwillbecommitted)#(use"gitcheckout--<file>..."todiscardchangesinworkingdirectory)##modified:file.txt#nochangesaddedtocommit(use"gitadd"and/or"gitcommit-a")

恢复隐藏的分支有两种方法:

git stash apply # 恢复隐藏的分支

git stash drop # 删除隐藏的分支记录

============================

git statsh pop # 恢复隐藏的分支,并将隐藏的分支删除,用一条命令做上面两条命令的事情。


tips:

如果要开发一个新的特性,最好新建一个分支,如果开发的新分支完成一半需要删除(此时还没有提交)删除一个未提交的分支,可以使用git branch -D BranchName 强制删除。


多人协作分支管理

在进行多人协作开发的团队中,由于每个人都会去不断的修改文件,合并文件,就会出现当你想远程提交自己的代码时,碰巧别人也修改了相同的文件,这样你本地的文件和远程的文件内容就不一样了,需要手动解决冲突再进行提交。

[root@workgitrepo]#gitremote#查看远程分支origin[root@workgitrepo]#gitremote-v#查看远程分支详细信息origingit@github.com:AndySkyL/gitrepo.git(fetch)origingit@github.com:AndySkyL/gitrepo.git(push)

提交是出现冲突:

[root@workgitrepo]#gitaddreadme.txt[root@workgitrepo]#gitcommit-m"dev2"[dev41ad4f8]dev21filechanged,1insertion(+),3deletions(-)[root@workgitrepo]#gitpushorigindev#推送dev分支冲突▽![rejected]dev->dev(fetchfirst)error:failedtopushsomerefsto'git@github.com:AndySkyL/gitrepo.git'hint:Updateswererejectedbecausetheremotecontainsworkthatyoudohint:nothavelocally.Thisisusuallycausedbyanotherrepositorypushinghint:tothesameref.Youmaywanttofirstmergetheremotechanges(e.g.,hint:'gitpull')beforepushingagain.hint:Seethe'Noteaboutfast-forwards'in'gitpush--help'fordetails.[root@workgitrepo]#gitpull#根据提示使用gitpullremote:Countingobjects:3,done.remote:Compressingobjects:100%(2/2),done.remote:Total3(delta0),reused3(delta0),pack-reused0Unpackingobjects:100%(3/3),done.Fromgithub.com:AndySkyL/gitrepo*[newbranch]dev->origin/devThereisnotrackinginformationforthecurrentbranch.Pleasespecifywhichbranchyouwanttomergewith.Seegit-pull(1)fordetailsgitpull<remote><branch>Ifyouwishtosettrackinginformationforthisbranchyoucandosowith:gitbranch--set-upstream-to=origin/<branch>dev#这里已经给出提示[root@workgitrepo]#gitbranch--set-upstream-to=origin/devdevBranchdevsetuptotrackremotebranchdevfromorigin.[root@workgitrepo]#gitpull#执行此命令之后再按照之前的方式修改文件,解决冲突Auto-mergingreadme.txtCONFLICT(content):Mergeconflictinreadme.txtAutomaticmergefailed;fixconflictsandthencommittheresult.

解决冲突后提交:

[root@workgitrepo]#gitaddreadme.txt[root@workgitrepo]#gitcommit-m"fixm"[dev3267ad5]fixm[root@workgitrepo]#gitpushorigindevCountingobjects:10,done.Compressingobjects:100%(4/4),done.Writingobjects:100%(6/6),570bytes|0bytes/s,done.Total6(delta0),reused0(delta0)17a9b60..3267ad5dev->dev

从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;

在本地创建和远程分支对应的分支,使用

gitcheckout-bbranch-nameorigin/branch-name#本地和远程分支的名称最好一致;


建立本地分支和远程分支的关联,使用:

gitbranch--set-upstream-to=origin/devdev


标签管理

标签可以是每一次commit 的标识,类似于给每次commit添加一个别名:

[root@workgitrepo]#gitbranchdev*master[root@workgitrepo]#gittagv1.0[root@workgitrepo]#gittagv1.0

默认标签是打在最新提交的commit上的。

如果要对之前的某一次commit打标签后面直接接上commit ID即可:

[root@workgitrepo]#gitlog--pretty=oneline--abbrev-commite2ce160fixbugissue8b29da7fixissue881136afixbugexample

[root@workgitrepo]#gittagv0.9881136a#根据log对对应的commit打标签,可以使用-m[root@workgitrepo]#gittag#添加说明v0.9#git标签的排列默认是以标签名的字母顺序排列的v1.0

使用tag查看具体信息:

[root@workgitrepo]#gitshowv1.0commite2ce160ad30d5433c033d9be7dc5dfe23ddbfd6dMerge:881136a8b29da7Author:trying<trying@example.com>Date:WedDec1416:16:322016+0800fixbugissue

也可以在新建tag时添加说明:

gittag-av2.0-m"version2.0released"#-a指定tag名称-m添加说明

删除标签

#gittag-dv2.0Deletedtag'v2.0'(was959f8b1)

推送标签到远程

由于在本地添加的标签不会自动推送到远程,如果需要推送本地的标签到远程,使用git push origin tagname:

#gitpushoriginv1.0#推送指定的tag

#gitpushorigin--tags#一次推送所有的tag

删除远程标签

删除远程标签需要先删除本地标签:

#gittagv0.9v1.0#gittag-dv0.9#删除本地tagDeletedtag'v0.9'(was881136a)#gitpushorigin:refs/tags/v0.9#删除远程标签-[deleted]v0.9

git push origin :refs/tags/tagname

GIT高亮显示字体颜色:

#gitconfig--globalcolor.uitrue



搭建GIT服务器

如果自己不想使用github的付费仓库,可以自己搭建一个私有的git 服务器供企业内部使用。

安装git:

yuminstallgit-y

创建一个git用户:

useraddgit

禁止git 用户登录shell,编辑/etc/passwd文件,将git用户默认的shell改为:

git:x:823:823::/home/git:/usr/bin/git-shell

创建一个用于GIT仓库的目录:

mkdir/gitrepocd/gitrepo

初始化git仓库:

gitinit--baretest.git

在/home/git用户的目录下创建密钥认证文件authorized_keys,将本地的公钥导入服务端的authorized_keys文件中:

catid_rsa.pub>/home/git/.ssh/authorized_keys

然回到本地,就可以获取git服务器上的工作目录了:

[root@work~]#gitclonegit@172.16.1.10:/gitrepo/test.gitCloninginto'test'...warning:Youappeartohaveclonedanemptyrepository.

这就可以和在github上一样操作了。