一、原理和用途
本质:
远程文档库 vs 本地文档库,即 库与枯库之间,基于相同branch的merge(rebase)操作的 clone和经SCM批准的相互更新
相比 库内分支之间:checkout ( -b ) / merge (无须认证)
库与库之间:pull / push (须认证)
push是唯一一个在本地 修改远程文档库数据的命令:git push / git push --delete
pull = fetch + merge
push之前要先pull,以此确保,push最终在远程文档库端造成的merge是FF类型的merge。
为什么用专用的远程文档库:
A. 系统安全:不想协同开发者为了branch新分支,而登录我的开发系统,所以需要共用的远程文档库
B. 文档库安全: 如果把我的本地文档库兼作共用的远程文档库,那么别人的push会企图改变我的文档库。文档库是本地开发的追踪基线,不应该由本地SCM之外的任何人、系统作库的整体更新。
coder编辑本地working directory <-->通过git<--> 更新本地文档库 -<->通过git<--> 更新远程文档库
| | |
开发者 base IDE SCM base GIT SCM base git(+git server admin)
特征:
远程文档库不是working directory的“附属” .git 子目录,也没有working directory存在的意义,因为它不直接面对开发者。
它本身是一个孤立的目录:<文档库名字>.git
因此,它叫bare类型文档库,创建时声明 : --bare
二、用法
本地文档库和远程文档库之间的三重联系:
A. 双向的数据(有效代码)的同步
B. 在本地文档库,注册属性 -- 远程文档库url :
remote.<远程文档库名字>.url = <远程文档库的https或ssh路径>
* https:https://web_server_IP/库的路径
ssh: gitaccount@ssh_server_ip:库的路径
* 远程文档库名字,在默认注册属性时,叫origin
对应命令: git remote add
C. 在本地文档库,注册属性 -- 分支追踪信息:
branch.<分支名称>.remote = <远程文档库名字>
branch.<分支名称>.merge = refs/heads/<对应的远程文档库中的分支的名字>
* master分支,会默认注册,
对应命令: git remote update 、git push --upstream
所有的操作都是对针对这三重联系
管理命令
1. 创建远程文档库,并clone的两种方法,实现A+B的联系:
method a. 从远程文档库所在系统A创建,然后复制到本地系统B一个本地文档库:
step1. [serverA] # git init --bare <远程文档库名字>.git
step2. [serverB] # git clone <远程文档库的https或ssh路径> <本地文档库的名字> // 如果不指定本地名字,默认与远程文档库同名。此处,建立了A+B的联系
method b. 从本地系统B的文档库 复制出远程文档库到系统A:
step1. [serverB] # git clone --bare <本地文档库的working directory文件夹名字> <远程文档库的https或ssh路径> 此处,建立了A的联系。却没有任何操作帮助“子”注册得到父的信息,需要手工建立B的联系:
step2. [serverB] # git remote add <远程文档库名字> <远程文档库的https或ssh路径> 此处,建立了B的联系
* 库名随意,不一定叫origin。
* 支持一个本地文档库有多个远程文档库
How?代码人格分裂??我可以想出的应用场景:
远程文档库fork出另一个远程文档库,用于不同的项目组后续开发。然鹅,一个coder给两个项目共用(悲催)。她本地的文档库,必然有两个分支,对应两个项目的新功能。代码共享相同的base代码,她的代码贡献commit到同一个本地版本库,但却push到不同的远程版本库对应的分支上。
git remote add <远程文档库名字1> <远程文档库1的https或ssh路径>
git remote add <远程文档库名字2> <远程文档库2的https或ssh路径> //注册多个远程文档库url,即建立B联系
远程版本库注册信息,记录在本地版本库的配置里 :
git ls-remote 查看所有远程库list
git remote -v 列出本地全部的和远程库相关的config
git remote show <远程文档库名字> 列出这个远程库的具体信息
* 要改变某注册的过的远程库的url
git remote set-url <远程文档库名字> <远程文档库新的https或ssh路径>
* 添加过的远程库,要从注册信息中删掉或者改名字。A+B的信息会被一起更新:
git remote rm <远程文档库名字> //取消这个远程库,是git remote add + git remote update的逆
git remote rename <旧的远程文档库名字> <新的远程文档库名字> //更改这个远程库的名字
2. 建立分支追踪信息,实现C联系:
master分支追踪信息是默认建立的
情景 1. 对于新建的分支:
git push --up-stream <远程版本库名字> <对应的远程文档库中的分支的名字>
情景 2. 对于所有的固有分支:
git remote update
建立的分支追踪信息记录在本地版本库的配置里 (git config -l | grep <分支名称>)
* C联系的效用:
1. 有多分支时,git push的发起者,本意只是提交某些或某个分支。使用:
git push <远程版本库名字> <对应的远程文档库中的分支的名字>
根据已注册的分支追踪信息,git确定出 发起者要push的是哪个本地分支的变更。
2. 服务懒人,当他的命令是简单的: git push
git push --all 忽略config值,所有注册过的分支都会被push
没有--all,效用取决于 git config -l | grep push.default:
(1)push.default=simple --> 当前checkout分支,如果被注册过,push当前分支
(2)push.default=matching --> 所有被-u push过的分支,都会被push
这是一个危险的动作。所以建议:git config --global push.default simple
* 查看所有注册过的远程对应分支
git branch -a
3. 有效代码的双向同步(A联系):
1. 下载(更新本地文档库) = 从 远程版本库 取回当前本地所在分支 对应的分支 的head版本的数据,并在本地发生merge或rebase操作 (更新本地commit演进图)
git pull = git fetch <远程文档库的名字>/<远程文档库对应的分支> + git merge <远程文档库的名字>/<远程文档库对应的分支>
git pull --rebase = git fetch <远程文档库的名字>/<远程文档库对应的分支> + git rebase <远程文档库的名字>/<远程文档库对应的分支>
2. 解决冲突 = 使之后的push,在远程版本库发生FF合并
3. 上载 (更新远程文档库)
git push = 从 本地版本库 取出当前分支的HEAD版本数据, 提交到远程版本库,远程版本库发生FF merge。
git push -u <远程库的名字> <远程库对应的分支名字>
git push <远程库的名字> <远程库对应的分支名字>
git push // push.default=simple的情况
三、文档库的fork
1. 库内的branch,类比库级别的fork:
branch可以: 被动merge回master、 或rebase master的新HEAD
fork出的文档库可以: 主动请求pull request合并回源文档库、或rebase 源文档库的HEAD
2. fork不是git-native的操作。所以只能在github、gitlab上点按钮了。
3. pull request操作需要源库的批准,才能被合并到源库。