# 远程仓库

远程(remote)版本库也叫上游(origin)版本库

通常我们并不常亲自建立远程仓库,而是委托给『第三方』。

常见的操作是,先在第三方上创建『远程 Git 文档库』,然后复制(Clone)出一个『本地 Git 文档库』。

# 1. 在托管网站上创建远程仓库

常见的代码托管仓库有:

  • 国外:github、gitlib
  • 国内:gitee、Coding

在托管网站上创建项目后,通常项目目录下是空的,可以通过以下 2 种途径初始化该项目:

  • 创建新版本库

    git clone git@148.70.1.4:HeMiao/reader-html.git
    cd reader-html
    touch README.md
    git add README.md
    git commit -m "add README"
    git push -u origin master
    
  • 已存在的文件夹或 Git 仓库

    cd <existing_folder>
    git init
    git remote add origin git@148.70.1.4:HeMiao/reader-html.git
    git add .
    git commit
    git push -u origin master
    

# 2. 克隆远程仓库至本地

git clone <远程文档库的路径> <本地文档库的文件夹名称>

更具体的的格式为:

git clone <http://Web服务器地址/远程文档库路径> <本地文档库名称>

例如:

git clone https://github.com/<用户名>/<项目名>.git

如果你在托管网站上添加了你本机的 ssh-key,那么还可以使用如下格式:

git clone <Git账号>@<SSH服务器地址>:<远程文档库路径> <本地文档库路径>

例如:

git clone git@github.com:<用户名>/<项目名>.git

本地 Git 文档库 和 远程 Git 文档库之间是有『关系』的。这种关系体现在 Git 的配置项的 origin 属性上。使用 git config -l 可以看到:

...
remote.origin.url=远程Git文档库地址
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
...

在日常工作中,git clone 命令一个项目通常只会执行一次。

# 3. 推送

当我们完成对本地文档库的修改,可以将这些修改『推送』到远程 Git 仓库:

git push origin [分支名称]

git push 有两种模式:

  • 推送本地『所有』分支,

  • 推送『当前』分支。

  • 如多使用第一种模式,配置:

    git config --global push.default matching
    
  • 第二种模式,配置:

    git config --global push.default simple
    

第二种模式更安全,推荐使用第二种。

无论哪种传送模式,只要执行 git push --all 都是推送所有分支。

# 4. 推送冲突

如果远程分支并非你一个人独有,那么很有可能由于别人的提交,导致远程分支向前演进,从而导致 push 失败。此时需要『三步合并法』解决冲突问题。

  1. 从远程 Git 文档库取回当前所在分支的最新数据。

  2. 把远程 Git 文档库的分支合并到本地 Git 的分支。这一步可能会出现冲突。解决冲突,合并代码。

  3. add-commit-push 三联,提交并推送本地数据至远程 Git 文档库。

git pull 命令可以完成前两部操作。它等价于:先执行 git fetch,再执行 git rebase origin/master

# 5. fetch 和 pull

如果你有一个远程 Git 分支,比如在 GitHub 上的分支,当远程分支上包含当前分支没有的提交时,可以使用取回。

比如,当合并了另一个分支或你的同事推送了一个快速修复时。

通过在这个远程分支上执行 git fetch ,我们就可在本地获取这些修改。这不会以任何方式影响你的本地分支:fetch 只是单纯地下载新的数据而已

git-top-10-10

现在我们可以看到自上次推送以来的所有修改了。这些新数据也已经在本地了,我们可以决定用这些新数据做什么了。


尽管 git fetch 可用于获取某个分支的远程信息,但我们也可以执行 git pullgit pull 实际上是两个命令合成了一个:git fetch + git merge

当我们从来源拉取修改时,我们首先是像 git fetch 那样取回所有数据,然后最新的修改会自动合并到本地分支中。

git-top-10-11

很好,我们现在与远程分支完美同步了,并且也有了所有最新的修改!

# 6. 大道理、小细节和套话

  1. xxx 只和 xxx 玩,yyy 只和 yyy 玩:

    当你要推送(push,逻辑上就是上传)本地的 xxx 分支时,你上传的目的地一定是远程的 xxx 分支;

    当你要拉取(push,逻辑上就是下载)远程的 yyy 分支时,你下载的目的地一定是本地的 yyy 分支;

    理论上虽然可以,但是实际上我们并不会让本地的 xxx 分支和远程的 yyy 分支有推拉关系。即,本地 xxx 分支只和远程 xxx 分支『玩』,本地 yyy 分支只和远程的 yyy 分支『玩』。

  2. 推拉(push/pull)都是在更新:

    推送(push)操作的执行的潜在前提是:你的本地 xxx 分支上的代码一定更『新』(版本更高),否则,你为什么要上传呢?

    拉取(pull)操作的执行的潜在前提是:你的远程 xxx 分支上的代码一定更『新』(版本更高),否则,你为什么要下载呢?

    推拉都是在更新,只是『方向』不同:推送,是用本地 xxx 分支更新远程 xxx 分支;拉取,是用远程 xxx 分支更新本地 xxx 分支。

  3. 合理使用『简称』少费口舌:

    通过 git push 命令推送本地 xxx 分支代码到远程 xxx 分支,实现远程 xxx 分支的代码的更新,简称:通过推送 xxx 分支来更新远程 xxx 分支。

    通过 git pull 命令拉取远程 yyy 分支代码到本地 yyy 分支,实现本地 yyy 分支的代码的更新,简称:通过拉取 yyy 分支来更新本地 yyy 分支。

  4. 故意推拉『旧代码』是为了放弃:

    可以推送(上传)旧代码,在此之前,你的远程 xxx 分支的代码更新,版本更高,而你推送(上传)的旧代码会覆盖掉远程的新代码;

    也可以拉取(下载)旧代码,在此之前,你的本地 yyy 分支的代码更新,版本更高,而你拉取(下载)的旧代码会覆盖掉本地新代码;

    通常情况下,你不太可能会用旧代码更新新代码,如果你这么干了,意味着你是想废弃新代码中『新』的那部分内容。

『完』