Git远程库
git的远程仓库如何建立?
git下半部分
远程仓库(远程版本库)
Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。
怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。
实际情况通常是这样:
找一台电脑充当服务器的角色,每天24小时开机,
其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,
并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。
注册一个GitHub账号,就可以免费获得Git远程仓库。
由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:
- 创建SSH Key
在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa
和id_rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
1 | ssh-keygen -t rsa -C "youremail@example.com" |
注意这里的-C
是大写的
,然后一路enter,使用默认值
之后我们可以在 用户主目录(~) 找到一个.ssh
的文件目录,内部有id_rsa
和id_rsa.pub
,这两个就是SSH Key的密钥对,前者是私钥,不能泄露出来,后者是公钥,可以告诉任何人
- 登录Github
点击步骤:
setting -> SSH and GPG keys -> New SSH -> 随便输入一个Title -> 把id_rsa.pub文件的内容复制到key文本框内
为什么GitHub需要SSH Key呢?
因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。
如果你不想让别人看到Git库,有两个办法
一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。
另一个办法是自己动手,搭一个Git服务器,因为是你自己的Git服务器,所以别人也是看不见的。这个方法我们后面会讲到的,相当简单,公司内部开发必备。
添加远程库
我们还得再github上建一个库
点击步骤:
new repository -> 输入库的名称 -> 其他默认,点击Create repository
目前,这个库是空的
我们可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联
现在我们在本地的仓库下运行
1 | $ git remote add origin git@github.com:YourGitHubId/learngit.git |
添加后,远程库的名字就是origin
,这是git默认的叫法
输入git push -u origin master
就可以把本地库的所有内容推送到远程库
使用这个命令,其实是吧当前分支master
推送到了远程
由于远程库是空的,我们加了-u
参数,Git不但会把本地的master
分支内容推送到远程新的master
分支,还会把本地的master
分支和远程的master
分支关联起来,以后推送或者拉取时就可以简化命令
注意:执行这条命令,你的版本库必须有东西
如果你的版本库是空的,则会报错
1 | error: src refspec master does not match any |
成功后我们就可以在github上看到远程库的内容和本地的一模一样
从此,只要本地做了提交,就可以通过命令
1 | git push origin master |
把本地master
分支的最新修改推送至GitHub
SSH警告
当第一次使用Git的clone
或者push
命令连接到Github上时,会得到一个警告
1 | The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established. |
这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。
Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了:
1 | Warning: Permanently added 'github.com' (RSA) to the list of known hosts. |
这个警告只会出现一次,后面的操作就不会有任何警告了。
从远程仓库克隆
现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
登录GitHub,建立一个新的仓库
勾选Initialize this repository with a README
,这样GitHub会自动给我们创建一个README.md
的文件
使用命令
1 | $ git clone git@github.com:YourGitHubId/gitskills.git |
就可以克隆到你当前的位置了
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/YourId/gitskills.git
这样的地址。实际上,Git支持多种协议,默认的git://
使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
分支管理
分支有什么用呢?
创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上。
创建与合并分支
HEAD
指向当前分支, master
指向提交
- 在最开始
matser
是一条线,Git用master
指向最新的提交,再用HEAD
指向master
,就能确定当前分支,以及当前分支的提交点
- 每次提交
master
分支都会向前移动一步,随着不断的提交,master
分支也就会越来越长
- 当我们创建新的分支,例如
dev
Git创建了一个新的指针dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上
由于是指针,所以Git创建分支非常快
从现在开始,对工作区的修改和提交就是对dev
分支,比如新提交一次后,dev指针往前移动一步,而master指针不变:
假如我们在dev
上的工作完成了,就可以把dev
合并到master
上,直接把master
指向dev
的当前提交,就完成了合并
合并完成后,可以删除dev
分支,删除dev
分支就是把dev
指针给删掉,删掉后我们就剩下了一条masrer
分支
知道原理我们开始实战:
第一步:
新建一个文件夹->git init
->新建一个文件,随便加上些内容->git add
->git commit
第二步:
创建一个分支,输入命令
1 | git branch dev |
第三步:
切换到该分支
1 | git checkout dev |
1 | BlackKnight@LAPTOP-JQFP1S4M MINGW64 /d/gitLearn (master) |
(
第二步第三部可以合为一步:
1 | git checkout -b dev |
创建并切换一气呵成
)
第四步:
输入命令
1 | git branch |
查看当前分支
1 | $ git branch |
处于哪一个分支,前面会有一个*号
第五步:
修改文件内容,并且git add
执行git commit
,然后切换回master
分支
,查看文件,发现修改的内容不见了
第六步:
合并dev
分支的内容到master
上
,输入命令
1 | git merge dev |
git merge
命令用于合并指定分支到当前分支
再次查看文件,发现修改回来了
1 | $ git merge dev |
注意到上面有Fast-forward
信息,意思是“快进模式”,也就是会直接把master
指向dev
的当前提交,所以合并速度十分快,之后会将其他的合并方式
第七步:
合并完成后,可以删除dev
分支了
1 | git branch -d dev |
输入git branch
查看分支状态
1 | $ git branch |
发现只有一个分支了
解决冲突
合并分支,可能遇到冲突的问题
准备一个新的分支
1 | $ git checkout -b featurel |
修改文件的内容,最后一行加一个bye world,并且添加add
提交commit
切换到master
分支git checkout master
更改文件内容,最后一行加hello world
,然后继续add
和commit
现在,分支就变成了这个样子
合并分支
1 | $ git merge featurel |
消息告诉我们,文件存在冲突,必须手动解决冲突再提交
打开我们的文件
1 | <<<<<<< HEAD |
git用这种方式标记出不同分支的内容
我们修改为bye world后再add
提交commit
现在分支成为了这个样子
用git log --graph
可显示分支图
1 | * commit 24143f569703452d66dd7c4df3c65ed48a70aec5 |
最后删除分支
分支管理策略
合并分支时,Git会尽量用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
我们实战一下--no-ff
方式的git merge
首先创建并切换dev
分支
1 | git checkout -b dev |
修改文件内容,并且提交一个新的commit
然后切换回master
然后合并分支,
注意--no-ff
参数表示禁用Fast forward
模式
,因为会自动创建一个commit我们需要加-m
1 | $ git merge --no-ff -m 'merge with no-ff' dev |
我们用git log --graph
查看分支
1 | * commit 061646bf6b4321746b6f27f1926a528f7dec16e3 (HEAD -> master) |
策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以
Bug分支
假设你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是你当前正在dev上进行到一半的工作还没有提交
Git还提供了一个stash功能,
可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
1 | $ git stash |
用git status
查看发现是干净的(除非有没有被Git管理的文件)
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支
修复完成后,切换到master分支,并完成合并,最后删除分支
接着回去dev
1 | git checkout dev |
发现工作区是干净的,输入
1 | $ git stash list |
工作现场还在,只是保存到另一个地方了
需要恢复有两个办法
第一种:
git stash apply
恢复后,stash内容并不删除,需要git stash drop
来删除
第二种:
git stash pop
恢复的同时删除
这是再查git stash list
就看不到任何内容了
你可以多次stash,恢复的时候,先用git stash list
查看,然后恢复指定的stash,用命令:
1 | $ git stash apply stash@{0} |
Feature分支
软件开发中,总有新的功能要不断添加进来。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
于是准备开发,在当你add
并且提交新的分支之后,切回主分支
但是经理要求阉割此功能,于是我们要删除这个功能
1 | $ git branch -d wq |
git阻止了操作,提醒你删除后将丢失数据,强行删除用大写的D
现在我们强行删除
1 | $ git branch -D wq |
删除成功
多人协作
当你从远程仓库克隆时,实际上Git自动把本地的master
分支和远程的master
分支对应起来了,并且,远程仓库的默认名称是origin
。
要查看远程库的信息
1 | git remote |
加v可以获得更详细的信息
1 | git remote -v |
这条命令显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
推送分支,就是把该分支上的所有本地提交推送到远程库
1 | git push origin master |
如果要推送其他分支,比如dev
,就改为
1 | git push origin dev |
master
分支是主分支,因此要时刻与远程同步;dev
分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;bug
分支只用于在本地修复bug
,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug
;feature
分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
抓取分支
当你从远程库clone时,默认情况下,你只能看到本地的master分支
所以想要在dev
上开发就必须创建远程的origin
的dev
分支到本地
1 | git checkout -b dev origin/dev |
现在就可以在dev
上修改推送了
多人推送,难免会发生冲突
解决办法,先把最新的提交pull
下来
1 | $ git pull |
在本地合并解决冲突在推送,但是我们需要先建立本地dev
与远程origin/dev
的链接
1 | $ git branch --set-upstream-to=origin/dev dev |
解决冲突,再推就可以了
因此,多人协作的工作模式通常是这样:
首先,可以试图用
git push origin <branch-name>
推送自己的修改;如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull
试图合并;如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用
git push origin <branch-name>
推送就能成功!
如果git pull
提示no tracking information
,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
标签
创建标签
切换到需要标签的分支
1 | $ git tag v1.0 |
查看所有标签
1 | git tag |
也可以找到commit id
来打标签
1 | git tag v0.9 f52c633 |
标签不是按时间顺序列出,而是按字母排序的。
还可以创建带有说明的标签,-a
指定标签名-m
指定说明文字
1 | git tag -a v0.1 -m "version 0.1 released" 1094adb |
可以用git show <tagname>
查看标签信息:
1 | $ git show v1.0 |
如果标签打错了,也可以删除:
1 | $ git tag -d v0.1 |
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除
如果要推送某个标签到远程,使用命令git push origin
1 | $ git push origin v1.0 |
或者,一次性推送全部尚未推送到远程的本地标签:
1 | $ git push origin --tags |
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
1 | $ git tag -d v0.9 |
然后,从远程删除。删除命令也是push,但是格式如下:
1 | $ git push origin :refs/tags/v0.9 |