Git远程仓库

Git 支持在本地仓库进行程序项目的版本管理,这个本地的 git 仓库在程序项目的文件夹内(也就是 “.git” 文件夹内)。随着程序项目的推进,我们会把不同阶段的文件内容加入到这个 git 仓库中。这个仓库由我们直接操控,我们将它称之为“本地 git 仓库”。
除了“本地 git 仓库”外,如果需要与他人共同开发这个程序项目,还需要一个“远程 git 仓库”。程序项目,本地 git 仓库和远程 git 仓库之间的关系如图1所示。

图1:程序项目,本地仓库,远程仓库之间的关系

远程 git 仓库并不一定存储在另一台计算机中。很多人知道 git 支持 HTTP/HTTPS,SSH等协议,以允许本地 git 仓库与存在于另一台计算机中的远程 git 仓库之间传送数据。但实际上,远程 git 仓库也可以跟本地 git 仓库处于同一台电脑中,使用本地协议来进行数据的传送。

创建远程 git 仓库

以下命令可以创建一个远程 git 仓库:

1
git init --bare git仓库文件夹名称

即在git init命令加上--bare选项。这是因为远程 git 仓库也称为bare类型的仓库。例如以下命令会创建一个名为 lee.git 的远程仓库:

1
git init --bare lee.git

执行以上命令后,可以看到当前目录下多了一个 lee.git 目录,打开 lee.git 目录,可以看到目录的结构:

图2:bare类型的git仓库

可以看到 lee.git 目录下并没有 .git 这个子文件夹。

从远程仓库复制出本地仓库

使用 git clone 命令,可以从远程仓库复制出一个本地仓库。例如如下命令:

1
git clone ./lee.git local

这样就从 lee.git 复制出一个名为 local 的本地仓库。进入 local 这个目录,可以看到 .git 子文件夹,也就是说,这个复制得到的 git 仓库是一般的 git 仓库,并不是 bare 类型,我们可以在这上面进行程序项目的开发。

本地仓库和远程仓库的同步

在本地仓库的配置文件 config 中,有一个 origin 的属性,用来记录本地仓库与远程仓库之间的关系。使用git config -l可以列出 git 的配置信息:

…(其他属性)
remote.origin.url=/Users/lihao/Code/Git/./lee.git/
remote.origin.fetch=+refs/heads/:refs/remotes/origin/
…(其他属性)

如果我们对本地仓库 local 进行了修改,现在需要推送到远程仓库,可以使用以下命令:

1
git push origin master

即把 master 分支的最新数据,推送到远程仓库存储。需要指出的是,执行这个命令,不会在配置文件中记录本地仓库的分支和远程仓库分支之间的关系。如果加上--set-upstream选项(或者使用短选项-u)如下,git 就会在配置文件中记录本地仓库的分支和远程仓库的分支之间的关系。

1
git push --set-upstream origin master

执行此命令后,再使用git config -l | grep branch可以看到以下结果,这个对应关系会被下次git push使用。

branch.master.remote=origin
branch.master.merge=refs/heads/master

第一行配置指定当前这个分支对应的远程仓库;第二行配置指定当前这个分支所对应的分支名称。

使用git branch -a,可以看到和 origin 相关的分支:

*master
remotes/origin/master

remotes 开头的分支是用来跟踪远程仓库的状态。由于远程仓库可能已被他人修改,因此,我们需要将远程仓库的最新状态同步到本地仓库。使用命令git pull可以更新本地仓库状态:

1
git pull

具体来说,git pull命令会执行两个操作:

  1. git fetch
    从远程仓库取回当前所在分支的最新数据。完成这项操作后,可以将本地计算机上的远程仓库的分支状态更新至最新。
  2. git merge
    把远程仓库的分支合并到本地仓库的分支。
    执行第2个操作可能会导致冲突,如果出现冲突,需要先解决冲突,才能将本地仓库的修改通过git push到远程仓库。

远程仓库的 remote 操作

添加远程仓库

前面我们提到的本地仓库与远程仓库的操作,都是假设先有远程仓库,再复制一个本地仓库,这也是团队开发的一个标准模式。但有时程序项目并不一开始就由团队共同开发,而是先由某一个程序开发人员开头,而后才逐步过渡到团队开发的模式。
使用git clone --bare 程序项目文件夹名称 远程仓库路径命令,可以从本地仓库复制出一下远程仓库。例如使用以下命令,可以从 local 本地仓库创建一个 server.git 远程仓库。

1
git clone --bare local server.git

但是,本地仓库 local 并不会自动记录其远程仓库的属性,为此,先进入 local 本地仓库目录,然后使用以下命令来添加远程仓库:

1
git remote add origin ../server.git

这样,就为本地仓库添加了一个远程仓库的属性,其远程仓库的名称为 origin。但是,使用git remote add命令,只是设置了仓库之间的对应关系,还没创建远程仓库的追踪分支。如果使用git branch -a命令,只会看到本地仓库的分支,并没有任何远程仓库的追踪分支。为此,还需要执行

1
git remote update

让 git 在本地仓库创建追踪分支。

git remote add命令有两点需要注意:

  1. 远程仓库的名称不一定叫做 origin ,叫其他名称也可以;
  2. 远程仓库并不是唯一的,一个本地仓库可以对应多个远程仓库属性。

关于第2点,可以参考下图3。
假设 origin 这个远程仓库原来就已经存在,现在我们需要创建另一个远程仓库,并把 master 和 bug 分支推送到这个新的远程仓库中。


图3:本地仓库对应多个远程仓库的例子

要完成这项工作,需要按以下顺序执行。首先,创建一个新的远程仓库。

1
git init --bare lee2.git

这样便创建一个名称 lee2.git 的仓库。接下来,在本地计算地按顺序执行:

1
2
3
git remote add new-repo ../lee2.git
git push new-repo master
git push new-repo bug

git remote add new-repo ../lee2.git 命令假设我们在本地仓库的目录执行该命令,且远程仓库的路径跟本地仓库路径处于同一级目录,new-repo为我们自己取的名称,也可以起其他的名称。
下面的两个git push命令会将 master 和 bug 分支推送到新创建的仓库,并自动创建远程仓库的两个追踪分支。
这时,如果使用git branch -a命令,可以显示以下的追踪分支信息:

…(其他分支)
remotes/new-repo/master
remotes/new-repo/bug

删除远程仓库

git remote add相反的是git remote rm命令。例如,现在我们需要删除上面添加的new-repo远程仓库:

1
git remote rm new-repo

删除远程仓库后,本地所有属于它的追踪分支也会一起消失。如果需要还原回来,只需再使用git remote addgit remote update命令即可。

其他远程仓库操作

更改远程仓库名称:

1
git remote rename 旧名称 新名称

更新远程仓库地址:

1
git remote set-url 远程仓库名称 新的地址

显示和远程仓库相关的设置:

1
git remote -v

删除远程仓库分支:

1
git push 远程仓库的名称 --delete 分支名称

参考资料

  1. 完全学会Git GitHub Git Server的24堂课, 孙宏明著, 清华大学出版社, 2016年
  2. Git Pro, https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control