远程仓库

寒江蓑笠翁大约 21 分钟gitVCSGit

远程仓库

之前的所有演示都基于本地仓库的,git同样也支持远程仓库,如果想要与他人进行协作开发,可以将项目保存在一个中央服务器上,每一个人将本地仓库的修改推送到远程仓库上,其他人拉取远程仓库的修改,这样一来就可以同步他人的修改。对于远程仓库而言,对于公司而言,都会有自己的内网代码托管服务器,对于个人开发者而言,可以选择自己搭建一个代码托管服务器,又或者是选择第三方托管商。如果你有精力折腾的话可以自己搭,不过我推荐选择第三方的托管商,这样可以将更多精力专注于项目开发上,而且能让更多人发现你的优秀项目。

第三方托管

自建托管网站就是自己搭建的,第三方代码托管网站就是第三方搭建的,他们通过提供优质的代码托管服务,来吸引各式各样的开发人员与开源项目,时至今日,很多托管商基本上都不在局限于代码托管的功能。使用第三方托管商提供的平台,可以让开发者更专注于项目开发,而有些第三方托管商会将自己的项目开源,以供进行私有化部署,并为此提供配套的企业级服务。做的比较好的第三方托管商有以下几个

  • Github
  • GitLab
  • BiteBucket
  • Gitee
  • sourceforge
  • Coding

其中,GitHub是使用最普及的,可以说,干程序员这行就没有不知道GitHub的,本文将选择Github来作为远程仓库进行讲述。

Git代理

在本文开始讲解怎么进行远程仓库的操作之前,有一个相当重要的东西需要解决,那就是网络问题。在国内,Github是无法正常访问的,正常访问Github网站以及它提供的代码托管服务都会相当的缓慢,慢到只有几KB/s,在这种情况下,只能通过魔法上网来解决。

首先你需要自己付费购买代理服务,一般代理商都会给你提供相应的代理工具,比如我使用的代理工具是Clash for windows,它的本地代理端口是7890,并且同时支持http和socks5协议

在知晓了代理端口以后,就可以给Git bash 配置代理了

# http
$ git config --gloabl http.proxy http://127.0.0.1:7890
$ git config --gloabl https.proxy http://127.0.0.1:7890
# socks5
$ git config --global http.proxy socks5://127.0.0.1:7890
$ git config --global https.proxy socks5://127.0.0.1:7890

上面的是全局设置,你可以只为特定的域名设置代理

git config --global http.https://github.com.proxy http://127.0.0.1:7890
git config --global http.https://github.com.proxy socks5://127.0.0.1:7890

代理设置完毕后,再使用远程托管服务就会流畅许多。

克隆仓库

在GitHub上有着成千上万的开源仓库,如果你想要获取一个开源仓库的源代码,最好的方式就是克隆仓库,比如Go这门编程语言的开源仓库,事实上这是镜像仓库,源仓库在谷歌。

通过Code按钮可以获取该仓库的url

然后在本地找一个你觉得合适的位置来放置该项目,随后执行命令

$ git clone https://github.com/golang/go.git

Go源代码的大小有500MB左右,在将代码克隆到本地以后,你就可以开始独自研究,修改,并编译这些源代码了。

$ ls
CONTRIBUTING.md  PATENTS    SECURITY.md  codereview.cfg  go.env  misc/  test/
LICENSE          README.md  api/         doc/            lib/    src/

实际上git clone的url参数也可以是本地仓库,例如

$ git clone /home/bob/project/git-learn/

git在将仓库克隆到本地时或者检出远程分支时,会自动创建跟踪分支,跟踪分支是与远程分支有着直接关系的本地分支,比如远程分支叫origin/main,那么本地的跟踪分支就与之同名叫main,先查看下分支情况

$ git branch --all
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/op

可以看到这里有四个分支,首先main属于跟踪分支,origin/main属于远程跟踪分支,它是对于远程仓库中的分支的引用。我们后续在工作区的修改都是基于跟踪分支,远程跟踪分支是不可写的,git会在每一次fetch时更新远程跟踪分支。通过给git branch命令加上-vv参数,可以查看本地所有的跟踪分支。

$ git branch -vv
* main f5602b9 [origin/main] Revert "revert example"

可以看到git只为main分支自动创建了跟踪分支。假设远程仓库初始状态如下

将代码克隆到本地后,本地仓库的状态如下图,在最开始时两个分支都指向的同一个提交。

当你在本地做了一些修改并提交,发现远程仓库上有新提交,并使用git fetch抓取了修改后,于是两个分支各自指向了不同的提交。

这时,为了同步修改,你需要将远程跟踪分支与本地跟踪分支使用git merge合并,于是两个分支又指向了同一个提交。

最终你将提交通过git push推送到了远程仓库,而此时远程仓库的状态就如下图。

这基本上就是一般远程仓库的工作流程。

关联仓库

在本地已有仓库的情况下,可以通过git remote命令将其与远程仓库关联,已知远程仓库的URL为

https://github.com/246859/git-example.git

那么执行git remote add <name> <url>来将其关联

$ git remote add github https://github.com/246859/git-example.git

通过git remote -v来查看本地仓库与之关联的远程仓库

$ git remote -v
github  https://github.com/246859/git-example.git (fetch)
github  https://github.com/246859/git-example.git (push)

仓库关联成功以后通过show子命令来查看细节

$ git remote show github
* remote github
  Fetch URL: https://github.com/246859/git-example.git
  Push  URL: https://github.com/246859/git-example.git
  HEAD branch: main
  Remote branches:
    main tracked
    noop tracked
    op   tracked
  Local refs configured for 'git push':
    main pushes to main (up to date)
    op   pushes to op   (up to date)

如果后续不再需要了可以删除掉

$ git remote remove github

通过git remote rename来修改关联名称

$ git remote rename github gitea

或者使用git remote set-url来更新url

$ git remote set-url schema://host/repo

一个本地仓库也可以多同时关联多个仓库

$ git remote add gitea https://gitea.com/246859/example.git

$ git remote -v
gitea   https://gitea.com/246859/example.git (fetch)
gitea   https://gitea.com/246859/example.git (push)
github  https://github.com/246859/git-example.git (fetch)
github  https://github.com/246859/git-example.git (push)

实际上gitea这个url并不存在,只是我随便编的,git在关联远程仓库时并不会去尝试抓取它,除非加上-f参数,因为url不存在,抓取的结果自然会失败。

$ git remote add -f gitea https://gitea.com/246859/example.git
Updating gitea
remote: Not found.
fatal: repository 'https://gitea.com/246859/example.git/' not found
error: Could not fetch gitea

拉取修改

在本地仓库与远程仓库刚关联时,仓库内的代码多半是不一致的,为了同步,首先需要拉取远程仓库的修改。

$ git fetch github
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 28 (delta 6), reused 27 (delta 5), pack-reused 0
Unpacking objects: 100% (28/28), 2.34 KiB | 14.00 KiB/s, done.
From https://github.com/246859/git-example
 * [new branch]      main       -> github/main
 * [new tag]         v1.0.0     -> v1.0.0
 * [new tag]         v1.0.1     -> v1.0.1
 * [new tag]         v1.0.3     -> v1.0.3

然后查看本地分支就会发现多出来了一个分支remotes/github/main

$ git branch -a
  conflict
  feature_V3
  feature_v2
  jkl
* main
  op
  test
  v1
  v2
  remotes/github/main

该分支就是远程仓库上的分支,git fetch命令就是将远程仓库上的修改抓取到了本地的remotes/github/main分支上,但实际上我们的工作分支是main分支,所以我们需要改将其合并

$ git merge github/main

如果想抓取所有远程分支的修改,可以带上--all参数。

$ git fetch --all

提示

如果提示fatal: refusing to merge unrelated histories ,可以加上--allow-unrelated-histories参数,之所以发生这个问题是因为两个仓库的历史不相关,是独立的。

跟踪分支

在抓取修改后,git并不会创建跟踪分支,在这种情况下,需要手动创建一个分支,然后将指定的远程分支设置为其上游分支

$ git checkout -b <branch>
$ git branch -u <remote>/<branch>

或者使用更简洁但具有同样效果的命令

$ git checkout -b <branchname> <remote>/<branch> 

以及加上--track参数来自动创建同名的本地跟踪分支

$ git checkout --track <remote>/<branch>

或者你也可以只带分支名,当git发现有与之同名的远程分支就会自动跟踪

$ git checkout <branch>

当不再需要跟踪分支时,可以直接通过如下来撤销该分支的上游

$ git branch --unset-upstream <branch>

拉取合并

每一次抓取修改后都需要手动合并或许有点麻烦,为此git提供了git pull命令来一次性完成这个步骤。格式是如下

$ git pull <remote> <remote-branch>:<local-branch>

如果要合并的本地分支就是当前分支,则可以省略冒号以及后面的参数,例如

$ git pull github main
From https://github.com/246859/git-example
 * branch            main       -> FETCH_HEAD
Already up to date.

同样的,它也支持 --allow-unrelated-histories参数,以及所有git fetch支持的参数。

推送修改

当你在本地完成了修改,并提交到了本地仓库时,如果想要将提交推送到远程仓库,就需要用到git push命令。

$ git push <remote>

该命令执行时,默认会推送当前分支的提交,如果当前分支在远程仓库上并不存在,远程仓库就会自动创建该分支,git也在控制台中输出了整个创建的过程。

$ git push github
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'op' on GitHub by visiting:
remote:      https://github.com/246859/git-example/pull/new/op
remote:
To https://github.com/246859/git-example.git
 * [new branch]      op -> op

或者你也可以推送指定分支以及指定远程分支的名称

$ git push github op:noop
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'noop' on GitHub by visiting:
remote:      https://github.com/246859/git-example/pull/new/noop
remote:
To https://github.com/246859/git-example.git
 * [new branch]      op -> noop

如果想要删除远程分支,只需要加上一个--delete参数即可,例如

$ git push github --delete noop
To https://github.com/246859/git-example.git
 - [deleted]         noop

SSH

在与远程仓库进行交互的时候,默认使用的是HTTP方式,它的缺点很明显,就是每一次都要手动输入账号密码,为此,使用SSH协议来替代HTTP会更好。

github支持ssh协议
github支持ssh协议

接下来要在本地创建ssh密钥对,打开gitbash,执行如下命令,过程中会要求输入一些信息,根据自己情况来定。

$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/Stranger/.ssh/id_rsa):
/c/Users/Stranger/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/Stranger/.ssh/id_rsa
Your public key has been saved in /c/Users/Stranger/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:bbkk3VPOsowFTn9FQYeDl1aP3Ib+BpdC1x9vaAsFOQA Stranger@LAPTOP-9VDMJGFL
The key's randomart image is:
+---[RSA 4096]----+
|        E....o.*=|
|            +o*=+|
|          o  =*+*|
|         = =.*.+=|
|        S B B.O.=|
|         + = B.* |
|          o o . o|
|               . |
|                 |
+----[SHA256]-----+

默认情况下,它会生成在~/.ssh/目录下,git也是默认从这里去读取你的密钥文件。id.rsa是私钥文件,不可以泄露,否则这个密钥对就没有安全意义了。id.rsa.pub是公钥文件,这是需要向外部暴露的。来到github的setting中,添加新的SSH Keys。

将公钥文件的内容复制到输入框中,再点击按钮添加公钥。完事后执行如下命令测试下

$ ssh -T git@github.com
Hi 246859! You've successfully authenticated, but GitHub does not provide shell access.

可以看到成功通过SSH认证了,再通过SSH方式克隆一个远程仓库试一试。

$ git clone git@github.com:246859/git-example.git
Cloning into 'git-example'...
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 28 (delta 6), reused 27 (delta 5), pack-reused 0
Receiving objects: 100% (28/28), done.
Resolving deltas: 100% (6/6), done.

可以看到成功了,在github密钥管理界面,也能看到密钥的使用情况。

如此便配置好了通过SSH方式使用git。

上次编辑于:
贡献者: 246859