Git没有中心服务器,Git命令大部分是在本地执行,如果想通过Git分享代码或者与其他开发人员合作,就需要将数据放到一台其他开发人员能够连接的服务器上,这台服务器称为远程仓库。远程仓库是指托管在因特网或其他网络中的项目版本库。例如使用了GitHub作为远程仓库。
远程仓库(又称远程主机)操作命令示意图:
克隆:git clone 远程仓库URL 本地目录名
将远程仓库复制到本地,同时检出远程默认分支到本地分支。
获取:git fetch 远程仓库别名 +远程分支名:本地分支名
将远程仓库的更新(若有)复制到本地仓库,不合并到本地分支。
拉取:git pull 远程仓库别名 +远程分支名:本地分支名
将远程仓库的更新(若有)复制到本地仓库,同时将远程分支合并到本地分支。
git pull
相当于git fetch
+ git merge FETCH_HEAD
,手动解决合并冲突。
推送:git push 远程仓库别名 +本地分支名:远程分支名
将指定的本地分支复制到远程分支。
参阅:GitHub新建仓库。
假设新建了一个远程仓库(gitee.com/用户名/仓库名,示例使用Gitee,是因为克隆时下载速度极快)有3个分支:master分支(active branch活动分支,默认分支,可在远程仓库中自由设置默认分支)、new分支、aaa分支。
使用git clone
命令从现有Git远程仓库中拷贝默认分支到本地:
git clone <repository> <directory>
repository:Git远程仓库的git地址(url),包含传输协议,.git后缀可省略
directory:本地指定的目录,缺省时,克隆到当前目录
directory的名称为Git远程仓库项目在本地的新名称
directory必须为空目录,否则会触发错误:
fatal: destination path '.' already exists and is not an empty directory.
将远程仓库克隆到本地(重命名为123,在本地检出远程默认分支master):
$ git clone git@gitee.com:用户名/仓库名.git 123
Cloning into '123'...
remote: Enumerating objects: 573, done.
remote: Counting objects: 100% (573/573), done.
remote: Compressing objects: 100% (427/427), done.
remote: Total 573 (delta 123), reused 529 (delta 102)
Receiving objects: 100% (573/573), 11.31 MiB | 7.92 MiB/s, done.
Resolving deltas: 100% (123/123), done.
克隆(git clone
)操作的模拟分拆过程:
在本地硬盘内新建一个本地仓库
执行了mkdir 123
在当前目录新建一个123目录,若缺省,则命名默认为远程仓库名。
执行了git init
$ git init
Initialized empty Git repository in xxx/123/.git/
123目录新建一个空白本地仓库,git init
命令默认创建了一个空白本地分支master。空白本地分支的概念是指:分支没有内容(任何提交)、.git/config文件没有关联远程分支、.git/refs/heads目录内没有索引。
本地仓库关联远程仓库
执行了git remote add origin 远程仓库URL
xxx/123 (master)
$ git remote add origin git@gitee.com:用户名/仓库名.git
本地仓库添加(关联)远程仓库,即本地仓库与远程仓库建立了跟踪关系。
只是在配置文件(.git/config)中添加设置:
[remote "origin"] # 远程仓库origin
url = git@gitee.com:用户名/仓库名.git # 远程仓库的git地址
fetch = +refs/heads/*:refs/remotes/origin/* # fetch命令的src:dst
将远程仓库复制到本地仓库,并检出远程跟踪分支(远程默认分支)
执行了git pull
(参阅:拉取所有分支),只是在生成文件方面有些许差异:
(git clone
命令生成).git/packed-refs文件存储可关联的远程分支:
# pack-refs with: peeled fully-peeled sorted
058b0101d4b3a1426242a0d204d6b00debf8b776 refs/remotes/origin/master
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 refs/remotes/origin/new
.git/refs/remotes目录存储远程仓库的HEAD文件(指向远程默认分支):
ref: refs/remotes/origin/master
克隆远程仓库的所有分支,检出远程默认分支:
# 语法:git clone 远程仓库URL
git clone xxx.git
克隆远程仓库的所有分支,检出远程指定分支:
# 语法:git clone -b 远程分支名 远程仓库URL
# 或:git clone -b 远程分支名 --single-branch 远程仓库URL
git clone -b [branch_name] xxx.git
将远程仓库克隆到本地硬盘的指定目录(可实现远程仓库名重命名):
# 语法:git clone 远程仓库URL 本地目录名
git clone xxx.git 目录名
控制克隆深度(即只克隆最后的n次提交):
# 语法:git clone --depth n 远程仓库URL
git clone --depth 10 xxx.git # 克隆从最新开始的10次提交,剩余的不克隆
参考:Git协议深度解析。
远程仓库的url,可采用不同的传输协议。Git支持多种传输协议:
Git远程仓库的url根据搭建时的规则所制定,上述协议不一定全适用(常用的有SSH和HTTPS)或使用其它协议。
SSH(Secure Shell)是一种网络协议,用于计算机之间的加密登录。是最常用的唯一一个同时支持读写操作的网络协议。
使用冒号表示隐式使用SSH协议:git@远程服务器URL:用户帐号/远程仓库名.git
$ git clone git@github.com:用户名/仓库名.git
显式指定SSH协议(没有冒号):ssh://git@远程服务器URL/用户帐号/远程仓库名.git
$ git clone ssh://git@github.com/用户名/仓库名.git
若显式时不增加SSH端口号,则会报错:
$ git clone git@github.com/用户名/仓库名.git
fatal: repository 'git@github.com/xxx/xxx.git' does not exist
备注:SSH协议是一个需要验证授权的网络协议,使用前需要配对SSH传输密钥(本地设置SSH密钥,远程服务器的SSH key列表添加SSH公钥)。因为Git托管平台(例如:GitHub)需要识别是谁提交了推送(防止别人冒充):GitHub匹配了SSH公钥,就默认用户正确。
创建SSH keys参阅:SSH keys。
HTTP(S)协议的优美之处在于架设的简便性,但速度较慢,最大的麻烦是每次推送都必须输入账号和密码。在某些只开放http端口的公司(无法使用SSH协议)只能用HTTPS协议。
显式指定HTTPS协议:https://远程服务器URL/用户帐号/远程仓库名.git
$ git clone https://github.com/用户名/仓库名.git
使用HTTPS协议时:
若远程仓库是公开的,克隆时不会弹出窗口要求输入账号和密码,直接下载成功
若远程仓库是私有的(假设属于自己或有权限),克隆时Windows经常不会弹出窗口要求输入账号和密码(注意杀毒软件设置不要拦截弹出窗口),导致触发错误:
remote: You do not have permission to pull from the repository via HTTPS
fatal: Authentication failed for 'https://github.com/xxx/xxx.git/'
改用SSH协议可克隆成功,因为本地仓库和远程仓库之间已配对了SSH密钥。
GIT协议是一个包含在Git软件包中的特殊守护进程,它会监听一个提供类似于SSH服务的特定端口(9418),而无需任何授权。
语法:git://git.远程服务器URL/用户帐号/远程仓库名.git
$ git clone git://git.github.com/用户名/仓库名.git
所谓的远程仓库在FTP(S)协议中的表示,就是硬盘上的另一个目录。这常见于团队每一个成员都对一个共享的文件系统拥有访问权。
如果使用一个共享的文件系统,就可以在一个本地文件系统中克隆、推送和获取仓库。克隆时,只需要将远程仓库的路径作为URL使用。ftp和ftps可用于获取,但这是低效的并且已弃用;请勿使用。
语法:ftps://远程服务器/共享文件系统的路径.git
$ git clone ftps://host.xz[:port]/path/to/project.git
git remote
命令查看本地仓库关联的远程仓库(显示别名):
$ git remote
origin
git remote -v
命令查看本地仓库关联的远程仓库(显示别名和URL):
$ git remote -v
origin git@github.com:用户名/仓库名.git (fetch)
origin git@github.com:用户名/仓库名.git (push)
origin git@gitee.com:用户名/仓库名.git (push)
git remote show
命令查看本地仓库关联的远程仓库(显示别名、URL、分支等):
$ git remote show origin
* remote origin
Fetch URL: git@github.com:用户名/仓库名.git
Push URL: git@github.com:用户名/仓库名.git
Push URL: git@gitee.com:用户名/仓库名.git
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
git branch -a
命令查看本地仓库的所有分支(显示本地分支和远程跟踪分支):
$ git branch -a
* master
temp
remotes/origin/master
本地仓库添加(关联)远程仓库:
git remote add [shortname] [url]
只是在配置文件(.git/config)中添加设置:
[remote "origin"]
url = git@github.com:用户名/仓库名.git
fetch = +refs/heads/*:refs/remotes/origin/*
之后执行push/pull操作后,远程分支才正式在本地仓库创建远程跟踪分支。然后,使用git branch -a
命令可显示出远程跟踪分支。
分支的类型有:
本地分支:在本地仓库内创建的分支
.git/refs/heads目录存储本地分支的引用(reference,指向最后提交的版本)。
远程分支:在远程仓库内创建的分支
在远程仓库的code(代码)界面可查看远程分支的名称和内容。远程分支的提交历史存放在远程仓库内。Git托管平台只能显示出远程分支最后版本的内容,不能显示远程仓库。
远程跟踪分支(分支跟踪关系,track)
在本地分支与远程分支之间人为设置某种对应的跟踪关系,称为远程跟踪分支。
.git/refs/remotes/远程仓库名目录存放某个远程仓库的所有远程跟踪分支
远程跟踪分支的作用
本地分支和远程分支建立关联关系
如果本地分支和远程分支建立了关联关系,当对本地分支进行push或pull时,Git会知道推送(push)到哪个远程分支,或者从哪个远程分支拉取(pull)到本地分支。
在本地仓库内记录最后一次跟踪时的版本
无论本地分支或远程分支的版本如何更新变化,在未执行命令(pull、push)同步时,远程跟踪分支依旧保持最后一次跟踪时的版本。
在执行命令(pull、push)时,Git根据远程跟踪分支记录的版本、本地分支版本和远程分支版本三者的变化情况,同步本地分支或远程分支。最后,远程跟踪分支更新跟踪版本。
Git切换分支(git checkout 分支名
)时:
首先在refs/heads目录内查看本地分支
若有,则切换到本地分支。
然后在refs/remotes目录内查找远程跟踪分支
若有,则将远程跟踪分支检出(新建)为本地分支。
例外情况:git clone
时,在refs/remotes/远程仓库别名目录内只有一个HEAD文件,没有远程跟踪分支,此时,可在packed-refs文件中查找。
使用git branch -a
可查看本地仓库内的所有分支(本地和远程跟踪分支):
$ git branch -a
* master # 本地分支(前有*号,表示当前分支)
temp # 本地分支
remotes/origin/master # 远程跟踪分支
使用git branch -r
可查看本地仓库内的远程跟踪分支:
$ git branch -r
origin/master
使用git remote -v
可查看本地仓库关联的远程仓库:
$ git remote -v
gitee git@gitee.com:用户名/仓库名.git (fetch)
gitee git@gitee.com:用户名/仓库名.git (push)
origin git@github.com:用户名/仓库名.git (fetch)
origin git@github.com:用户名/仓库名.git (push)
跟踪关系(track)的一个重要概念是upstream/downstream。
Git是一个DVCS(Distributed Version Control System,分布式版本控制系统),在系统中没有固有的upstream(上游)和downstream(下游)。
upstream/downstream概念是相对于两个存储库,并且取决于数据流动的方式,目的是用来描述分支之间的相对位置,相当于族谱系统中的祖先ancestor/父母parent/孩子child/后代descendant之间的关系。除非本地仓库关联了对应的远程仓库,否则,您不会知道downstream是哪一个。
假设本地仓库关联了远程仓库:
简单一句话:远程仓库是本地仓库的upstream,本地仓库是远程仓库的downstream。
upstream(tracking)分支和远程跟踪分支(track)的区别:
远程跟踪分支是指分支的一种跟踪关系(track)
在本地分支与远程分支之间人为设置某种跟踪的对应关系。
一个本地分支可以跟踪多个远程分支;一个远程分支也可以被多个本地分支跟踪。
upstream分支是指正在持续跟踪中(tracking)的远程分支
从众多的跟踪关系中,人为指定一条表示正在跟踪中(tracking)。其中的远程分支称为upstream分支,对应的本地分支称为downstream分支。
设置upstream分支的目的:
设置默认值,在使用pull、push时省略输入分支名(甚至远程仓库名)
若pull/push其它远程分支,则需要写全分支名
例如:git push 远程仓库名 本地分支名:远程分支名
。
从众多的远程跟踪分支(分支跟踪关系,track)中选择一个定义为正在持续跟踪中(tracking),对应的远程分支称为upstream分支,对应的本地分支称为downstream分支。
一个本地分支可以有多个upstream分支,但在配置文件(.git/config)记录中,一个本地分支只显示出一个upstream分支(运行命令设置新的upstream分支时,将会覆盖旧记录)。
设置upstream的方法有:
git clone 远程仓库URL
本地分支(downstream分支)设置了upstream分支(远程默认分支),分支名称同名。
git pull
+ git checkout 分支名
git pull
命令创建远程跟踪分支,git checkout 分支名
在检出分支内容时,本地分支设置了upstream分支,分支名称同名。
git pull --set-upstream 远程仓库名 远程分支名:本地分支名
通过--set-upstream
参数,运行pull时,本地分支设置了upstream分支。
git push -u|--set-upstream 远程仓库名 本地分支名:远程分支名
通过-u|--set-upstream
参数,运行push时,本地分支设置了upstream分支。
git branch –-set-upstream-to=远程仓库名/远程分支 本地分支
通过--set-upstream-to=远程分支
参数,本地分支设置了upstream分支。
语法:git branch –-set-upstream-to=远程仓库名/远程分支 本地分支
$ git branch --set-upstream-to=origin/new dev
Branch 'dev' set up to track remote branch 'new' from 'origin'.
要求本地分支已存在(有内容)
不能是空白分支,否则触发错误:
$ git branch --set-upstream-to=origin/master master
fatal: branch 'master' does not exist
若不存在,请先新建本地分支:
$ git branch 本地分支名
要求已在远程仓库创建了远程分支,在本地存有远程跟踪分支
若远程跟踪分支不存在,将会触发错误:
$ git branch --set-upstream-to=gitee/222 master
error: the requested upstream branch 'gitee/222' does not exist
hint:
hint: If you are planning on basing your work on an upstream
hint: branch that already exists at the remote, you may need to
hint: run "git fetch" to retrieve it.
hint:
hint: If you are planning to push out a new local branch that
hint: will track its remote counterpart, you may want to use
hint: "git push -u" to set the upstream config as you push.
运行命令后,在配置文件(.git/config)中添加设置:
[branch "dev"] # 本地分支dev
remote = origin # 远程仓库origin
merge = refs/heads/new # 合并远程分支new到本地当前分支
设置upstream的关键步骤:查看FETCH-HEAD文件(pull时)或packed-refs文件(clone时)是否有可关联的远程分支。若有,则会在refs/remotes/远程仓库别名目录内生成远程跟踪分支。
设置upstream成功后,在配置文件(.git/config)中添加设置:
[branch "master"] # 本地分支master
remote = origin # 远程仓库origin
merge = refs/heads/master # 合并远程分支master到本地当前分支
运行git fetch
命令,是将一个远程仓库的更新(若有)拉取到本地仓库,不会合并分支。
git fetch [<options>] [<repository> [<refspec>]]
git pull
,参阅:拉取远程仓库。git fetch
的执行过程:
git fetch origin develop:tmp # 拉取远程develop分支,并放到本地tmp分支上
git diff tmp # 查看当前分支和tmp分支的区别
git merge tmp # 把tmp分支合并到当前分支
git branch -d tmp # 删除tmp分支
合并阶段,使用命令:
git checkout 远程分支名
:新建本地分支并切换(检出内容)
仅适用于本地分支空白(即本地没有同名分支)时:
$ git checkout master
若使用git checkout 远程仓库名/远程分支名
,将会进入“detached HEAD”状态。
git merge 分支名
:将指定分支合并到本地当前分支
适用于任何合并时:
本地分支空白时(即本地没有同名分支)
分支名的格式为:远程跟踪分支名(远程仓库名/远程分支名):
$ git merge origin/master
本地有同名分支时(已在该分支)
分支名的格式为:远程分支名。
$ git merge master
运行git pull
命令,将远程仓库的更新(若有)复制到本地仓库,然后指定的远程分支合并到对应的downstream分支(本地分支,若无,则新建同名分支)。git pull
相当于 git fetch
+ git merge FETCH_HEAD
。
更确切地说,git pull
是使用给定的参数运行git fetch
,然后调用git merge
将远程分支的HEAD(.git/FETCH_HEAD文件)合并到当前本地分支中。若使用--rebase
,它将运行git rebase
而不是git merge
。
git pull [<options>] [<repository> [<refspec>]]
repository:远程仓库别名或URL,缺省时使用默认值(git remote add
关联的仓库)
refspec:格式为+<src来源地>:<dst目的地>,在pull时为远程分支:本地分支
+号:合并时使用非快进(non-fast-forward)方法,相当于-f
参数(强制覆盖)
src:来源地(from,源引用)
已有的引用,名称可以是任意“SHA表达式”,例如:master~4、HEAD或分支名。
省略src(:dst)时,表示源引用为空白。等效于-d
参数(删除目标引用)。
冒号:表示命令操作方向(从左到右),from src:to dst
dst:目的地(to,目标引用)
被命令操作的引用,名称只能为分支名。
省略**:dst**时,表示目标引用与源对象引用同名。
若src和dst的分支名不同时,将会使用非快进(non-fast-forward)方法合并
用法:
git pull
或
git pull repository
拉取远程仓库所有远程分支的更新到本地,不合并到本地当前分支,不设置upstream。
.git/FETCH_HEAD文件包含所有可跟踪的远程分支,显示“not-for-merge”:
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'aaa' of gitee.com:用户名/仓库名
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'master' of gitee.com:用户名/仓库名
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 not-for-merge branch 'new' of gitee.com:用户名/仓库名
.git/refs/remotes/远程仓库别名目录存放远程跟踪分支。
git pull repository refspec
拉取远程仓库所有远程分支的更新到本地,合并到本地分支,不设置upstream。
.git/FETCH_HEAD文件初始只包含指定的远程分支:
058b0101d4b3a1426242a0d204d6b00debf8b776 branch 'master' of gitee.com:用户名/仓库名
静待一段时间后(期间无任何操作),.git/FETCH_HEAD文件变化为:
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'aaa' of gitee.com:用户名/仓库名
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'master' of gitee.com:用户名/仓库名
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 not-for-merge branch 'new' of gitee.com:用户名/仓库名
git pull --set-upstream repository refspec
拉取远程仓库所有远程分支的更新到本地,合并到本地分支,设置upstream。
.git/FETCH_HEAD文件包含所有可跟踪的远程分支:
058b0101d4b3a1426242a0d204d6b00debf8b776 branch 'master' of gitee.com:用户名/仓库名
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'aaa' of gitee.com:用户名/仓库名
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 not-for-merge branch 'new' of gitee.com:用户名/仓库名
在配置文件(.git/config)中添加设置:
[branch "master"] # 本地分支master
remote = origin # 远程仓库origin
merge = refs/heads/master # 合并远程分支master到本地当前分支
详细参数参阅官网文档。
git pull
命令的拉取过程:
前提
要求已有本地仓库(git clone
命令是自动新建本地空白仓库)
要求本地仓库已关联远程仓库
$ git remote add origin git@gitee.com:用户名/仓库名.git
.git/config文件记录了仓库的关联关系:
[remote "origin"] # 远程仓库的别名为origin
url = git@gitee.com:用户名/仓库名.git # 远程仓库的git地址
fetch = +refs/heads/*:refs/remotes/origin/* # git fetch命令的src:dst
第一阶段:将一个远程仓库的更新(若有)拉取到本地仓库
假设本地当前分支尚未跟踪远程分支。
运行git pull
命令,将远程仓库的更新(远程有,本地无)复制到本地仓库,然后提示“当前分支没有正在跟踪信息”(There is no tracking information for the current branch.),但已将可关联的远程分支存放入FETCH-HEAD文件。
$ git pull
remote: Enumerating objects: 573, done.
remote: Counting objects: 100% (573/573), done.
remote: Compressing objects: 100% (427/427), done.
remote: Total 573 (delta 124), reused 529 (delta 102)R
Receiving objects: 100% (573/573), 11.31 MiB | 5.43 MiB/s, done.
Resolving deltas: 100% (124/124), done.
From gitee.com:用户名/仓库名
* [new branch] aaa -> origin/aaa
* [new branch] master -> origin/master
* [new branch] new -> origin/new
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> master
拉取后,可在本地仓库(.git目录)查看:
.git/objects/pack/pack-xxx.pack二进制文件
存储了远程仓库所有分支的数据对象文件。
.git/FETCH-HEAD文件
存储了可关联的远程分支(存储最后一次git pull
的结果)。示例:
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'aaa' of gitee.com:用户名/仓库名
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'master' of gitee.com:用户名/仓库名
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 not-for-merge branch 'new' of gitee.com:用户名/仓库名
.git/ORIG_HEAD文件存储了FETCH-HEAD文件的上一次结果,作用是在进行危险操作时,提供回退功能。
.git/refs/remotes/远程仓库别名目录
因为FETCH-HEAD文件已有可关联的远程分支,所以该目录存储了所有远程跟踪分支的索引(upstream分支最后一次提交的哈希值)。
第二阶段:将upstream分支合并到本地当前分支
运行git checkout 分支名
,自动设置upstream分支和检出分支内容:
xxx/123 (master)
$ git checkout master
Already on 'master'
Branch 'master' set up to track remote branch 'master' from 'origin'.
设置upstream分支
设置upstream的方法参阅:设置upstream的方法。
设置upstream成功后,在配置文件(.git/config)中添加设置:
[branch "master"] # 本地分支master
remote = origin # 远程仓库origin
merge = refs/heads/master # 合并远程分支master到本地当前分支
.git/FETCH-HEAD文件变化为:
058b0101d4b3a1426242a0d204d6b00debf8b776 branch 'master' of gitee.com:用户名/仓库名
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'aaa' of gitee.com:用户名/仓库名
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 not-for-merge branch 'new' of gitee.com:用户名/仓库名
设置后,才能将远程分支的内容合并到本地分支。
将远程跟踪分支的更新内容合并到本地当前分支
若有冲突,则需要协商手动解决合并冲突。
合并后(本地分支有提交记录了):
第三阶段:切换到其它远程跟踪分支(查看其它远程分支的内容)
查看FETCH-HEAD文件是否已有可关联的远程分支(关键因素):
若有
方法一:建立upstream/downstream,不会丢失程分支的提交历史
直接运行git checkout 分支名
,检出远程跟踪分支到本地分支(Git会自动新建本地分支,与远程分支名同名,然后建立关联,最后检出分支内容)。
$ git checkout new
Switched to a new branch 'new'
Branch 'new' set up to track remote branch 'new' from 'origin'.
方法二:手动新建一个本地分支,建立upstream/downstream,不会丢弃了远程分支的提交历史
运行git checkout 分支名
新建一个本地分支bbb(.git/refs/heads目录内有显示):
xxx/123 (master)
$ git branch bbb
在本地当前分支master分叉出本地分支bbb,.git/refs/heads/bbb显示:
058b0101d4b3a1426242a0d204d6b00debf8b776
运行git branch --set-upstream-to=upstream branchname
xxx/123 (master)
$ git branch --set-upstream-to=origin/new bbb
Branch 'bbb' set up to track remote branch 'new' from 'origin'.
在配置文件(.git/config)中添加设置:
[branch "bbb"] # 本地分支bbb
remote = origin # 远程仓库origin
merge = refs/heads/new # 合并远程分支new到本地当前分支
运行git pull
若直接运行git checkout bbb
,由于bbb分支已有内容(且是不同分支的不同内容),所以触发错误:
xxx/123 (master)
$ git checkout bbb
Switched to branch 'bbb'
Your branch is behind 'origin/new' by 22 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
运行git pull
,使用Fast-forward方式合并:
xxx/123 (bbb)
$ git pull
Updating 058b010..76ae2d6
Fast-forward
…………
合并后,.git/FETCH-HEAD文件变化为:
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1 branch 'new' of gitee.com:koman/koman
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'aaa' of gitee.com:koman/koman
058b0101d4b3a1426242a0d204d6b00debf8b776 not-for-merge branch 'master' of gitee.com:koman/koman
合并后,.git/refs/heads/bbb显示:
76ae2d685b6f5c7a3aba314a15708bd066c2c1c1
方法三:手动新建一个本地空白分支,不会建立upstream/downstream,丢弃了远程分支的提交历史
运行git checkout 远程跟踪分支名
进入“detached HEAD”状态,除了在工作目录显示出远程跟踪分支的检出内容外,其它数据没有变化。
xxx/123 (master)
$ git checkout origin/aaa
Note: switching to 'origin/aaa'.
You are in 'detached HEAD' state.
…………
运行git checkout --orphan 分支名
在“detached HEAD”状态下新建一个空白的本地分支abc(.git/refs/heads目录内无显示):
xxx/123 ((058b010...))
$ git checkout --orphan abc
Switched to a new branch 'abc'
提交本地分支abc下的内容
$ git commit -m "aaa"
[abc (root-commit) f64e275] aaa
425 files changed, 73625 insertions(+)
create mode 100644 404.html
…………
本地分支abc是一个独立分支,不再是从远程分支分叉出来的分支,即已丢弃了远程分支的提交历史。
若无
则无法切换。可再次运行git pull
,尝试添加远程跟踪分支。
拉取指定远程分支,使用--set-upstream
参数设置upstream分支,同时检出分支:
$ git pull --set-upstream origin master
remote: Enumerating objects: 529, done.
remote: Counting objects: 100% (529/529), done.
remote: Compressing objects: 100% (383/383), done.
remote: Total 529 (delta 102), reused 529 (delta 102)
Receiving objects: 100% (529/529), 11.30 MiB | 2.87 MiB/s, done.
Resolving deltas: 100% (102/102), done.
From gitee.com:用户名/仓库名
* branch master -> FETCH_HEAD
* [new branch] master -> origin/master
在本地目录显示出指定远程分支master的内容
.git/objects/pack/pack-xxx.pack二进制文件存储所有远程分支的数据对象文件
.git/config文件添加了upstream分支的设置
[branch "master"]
remote = origin
merge = refs/heads/master
.git/FETCH-HEAD文件,初始只记录了指定远程分支master。但静待一段时间后(期间无任何操作),FETCH-HEAD文件自动更新包含所有远程分支(原因未明)。
058b0101d4b3a1426242a0d204d6b00debf8b776 branch 'master' of gitee.com:用户名/仓库名
.git/refs/remotes目录只存储了指定远程跟踪分支master。但静待一段时间后(期间无任何操作),refs/remotes目录自动更新包含所有远程分支(原因未明)。
058b0101d4b3a1426242a0d204d6b00debf8b776
.git/refs/heads目录存储了本地分支master的索引
058b0101d4b3a1426242a0d204d6b00debf8b776
此时,若想切换到new分支,将会触发错误(因为本地仓库没有拉取远程分支new):
$ git checkout new
error: pathspec 'new' did not match any file(s) known to git
解决方法:运行git pull
命令补全(拉取)所有远程分支
首先,运行git pull
命令补全(拉取)所有远程分支
$ git pull
remote: Enumerating objects: 45, done.
remote: Counting objects: 100% (45/45), done.
remote: Compressing objects: 100% (44/44), done.
remote: Total 44 (delta 21), reused 0 (delta 0)
Unpacking objects: 100% (44/44), 4.78 KiB | 4.00 KiB/s, done.
From gitee.com:koman/koman
* [new branch] aaa -> origin/aaa
* [new branch] new -> origin/new
Already up to date.
然后,运行git checkout new
命令检出指定分支
$ git checkout new
Switched to a new branch 'new'
Branch 'new' set up to track remote branch 'new' from 'origin'.
push.default参数的可选值:
可以使用git config -l
查看配置,使用git config
命令修改默认配置。
$ git config --global push.default matching
或
$ git config --global push.default simple
在Git_v_2.0后,push.default参数采用simple:即在运行git push
命令,只是将本地指定(或当前)分支的更新(若有)复制(合并)到远程分支(若无,则新建同名分支)。
git push [<options>] [<repository> [<refspec>]]
repository:远程仓库别名或URL,缺省时使用默认值(git remote add
关联的仓库)
refspec:格式为+<src来源地>:<dst目的地>,在push时为本地分支:远程分支
refspec的格式描述参阅:拉取远程仓库。
options
参数 | 功能 | 备注 |
---|---|---|
–all | 推送本地引用(refs/heads目录) | 不能与refspec参数一起使用 |
–mirror | 镜像所有(refs目录,包括但不限于refs/heads、refs/remotes和refs/tags) | 新创建的本地引用将被推到远程端,本地更新的引用将在远程端强制更新,删除的引用将从远程端删除。 |
–tags | 推送tags(refs/tags目录) | |
-d | 从远程仓库中删除引用 | 等效于refspec参数设置为**:dst**(空白本地引用推送到远程引用) |
-f | 强制推送(本地引用覆盖远程引用) | 允许非快进(non-fast-forward)推送 |
-u | push成功后,设置upstream引用 |
备注:
push只是推送指定分支的更新,不是推送本地仓库的所有分支
推送成功后,将会在本地创建远程跟踪分支(track)
对远程仓库有写权限且远程分支的版本低于本地分支时,才能push成功
若远程分支版本高于本地分支(已有其他人推送了若干更新),推送操作会被拒绝:
xxx/123 (new)
$ git push gitee new:aaa
To gitee.com:用户名/仓库名.git
! [rejected] new -> aaa (non-fast-forward)
error: failed to push some refs to 'git@gitee.com:用户名/仓库名.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
必须先将更新抓取(git pull)到本地,然后才可以再次推送。
git push
表示将本地当前分支推送到配置文件(.git/config)记录的upstream分支。
git push 远程仓库名
表示将本地当前分支推送到远程仓库的同名分支(若无,则在远程仓库新建远程分支)。
git push 远程仓库名 本地分支名:远程分支名
表示将本地指定分支推送到远程仓库的指定远程分支:
git push -u 远程仓库名 本地分支名:远程分支名
-u
参数,表示push时同步设置upstream分支。
git push --all 远程仓库名
--all
参数,表示将本地所有分支都推送到远程仓库的同名分支。
git push -f 远程仓库名 本地分支名:远程分支名
-f
参数,表示强制推送。除非你已确定要这样做,否则慎用-f
选项。
当本地分支版本低于远程分支版本时,push时会被拒绝(要求先pull远程分支,解决合并差异,然后再push到远程分支)。使用-f
参数时,就会使用”非快进”(non-fast-forward)方式合并(覆盖)远程分支,忽略版本判断,强制覆盖远程分支。
git push --tags 远程仓库名
push时默认不会推送标签,使用--tags
选项推送标签。
使用一个push命令,将本地分支的更新同时推送到多个远程仓库:
添加(关联)远程仓库
git remote add 远程仓库名 远程仓库URL1
git remote set-url --add 远程仓库名 远程仓库URL2
git remote set-url --add 远程仓库名 远程仓库URL3
备注:远程仓库名使用同一个名称。
添加后,在配置文件(.git/config)内显示:
[remote "origin"]
url = git@github.com:用户名/仓库名.git # 第一个远程仓库
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@gitee.com:用户名/仓库名.git # 第二个远程仓库
使用git remote -v
命令,查看远程仓库信息:
$ git remote -v
origin git@github.com:用户名/仓库名.git (fetch)
origin git@github.com:用户名/仓库名.git (push)
origin git@gitee.com:用户名/仓库名.git (push)
正常使用push命令,就能实现同时推送到多个远程仓库
git push 远程仓库名 本地分支名
感谢您的赞赏支持: