Git使用教程五

本文已经是Git使用教程的第5篇文章了,接下来应该还会再介绍2篇,这样Git相关的内容暂时告一段落了,相信只要熟练使用这7篇文章涉及到的命令,已经可以满足日常开发的需要了。当然了关于Git的使用还有许多内容,包括许多的底层命令和高级命令,还有结合gerrit搭建等等,这些内容后续有时间会再整理一些。

在本文中,重点介绍Git中操作远程仓库3个相关命令,它们分别是fetch、pull和push。在介绍前面所说的3个命令之前,需要先了解一些有关远程仓库的知识点,比如操作中常常涉及到一个关键字origin的使用,这个origin代表了什么,本地分支与远程分支时如何建立关联关系的等等,上述这些内容都是本文需要着重介绍的。

origin

在介绍git操作远程仓库之前,先了解一些有关origin关键字的知识。在使用git命令操作时,如果命令中有origin关键字,一般操作都和远程仓库有关。多数情况下,可以理解origin就是一个与本地分支同名的远程仓库的别名。

建立本地分支与远程分支关联

如果远程仓库没有本地分支对应的仓库名称,如下是使用push将一个本地分支名为develop的分支推送至远程仓库的操作。

$ git push
fatal: The current branch develop has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin develop

$ git push --set-upstream origin develop
Total 0 (delta 0), reused 0 (delta 0)
remote: Powered By Gitee.com
To https://gitee.com/xxxx/gitest.git
 * [new branch]      develop -> develop
Branch 'develop' set up to track remote branch 'develop' from 'origin'.

上面的git push命令也可以写成git push -u origin develop。 $ git push -u origin develop Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 249 bytes | 49.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: Powered By Gitee.com To https://gitee.com/xxxx/gitest.git * [new branch] develop -> develop Branch 'develop' set up to track remote branch 'develop' from 'origin'.

上面命令将本地的develop分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。后续使用git push即可将本地develop分支推送至远程同名的develop分支。

可以使用如下命令在新建一个与本地分支不同名称的远程分支:

git push --set-upstream origin dev:dev02
#或者
git push origin dev:dev02

为了便于管理,Git要求每一个远程主机都必须指定一个主机名,git remote就用于管理主机名。

不带选项的时候,git remote命令列出所有远程主机。

$ git remote
#或者
$ git remote show
origin

使用-v选项,可以参看远程主机的网址。

$ git remote -v
origin  https://gitee.com/xxxx/gitest.git (fetch)
origin  https://gitee.com/xxxx/gitest.git (push)

克隆版本库的时候,所使用的远程主机自动被Git命名为origin。如果想用其他的主机名,需要用git clone命令的-o选项指定。

$ git clone -o origin01 https://gitee.com/xxxx/gitest.git gitest03
Cloning into 'gitest03'...
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 12 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.

$ git remote
origin01

使用如下命令可以查看远程主机的详细信息:

$ git remote show origin01
* remote origin01
  Fetch URL: https://gitee.com/xxxx/gitest.git
  Push  URL: https://gitee.com/xxxx/gitest.git
  HEAD branch: master
  Remote branches:
    dev    tracked
    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项目,可以使用如下方式建立与远程仓库的关联。

$ git init
$ git remote add origin https://gitee.com/xxxx/gitest.git
$ git push origin master

切换远程分支

使用如下命令可以查看所有分支信息,其中以remotes/origin01开始的代表的是远程分支,远程分支其实是远程分支在本地对应的一个副本。

$ git branch -av
* master                   ed54b49 second commit
  remotes/origin01/HEAD    -> origin01/master
  remotes/origin01/develop 1976ca4 third commit
  remotes/origin01/master  ed54b49 second commit

直接使用git checkout xxx命令可以切换到上面展示的任意分支,但是如果是切换到远程分支,会有如下提示信息。

$ git checkout origin01
#或者
$ git checkout remotes/origin01/master
Note: checking out 'origin01'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at ed54b49 second commit

上述提示表明,当前的HEAD处于游离态,它指向的其实是一个提交点,在当前环境下,所做的任何更改都不会影响其它分支的checkout。当然了,如果想要保存在当前分支的更改,可以重新新建一个分支作为checkout的目标分支。

这里的所说的远程分支,其实就是下文fetch拉取下来对应的远程分支,然后再使用merge命令就可以合并到本地分支了。

git fetch

git fetch命令用于从远程仓库下载对象和引用。

git fetch [<options>] [<repository> [<refspec>…?]]
git fetch [<options>] <group>
git fetch --multiple [<options>] [(<repository> | <group>)…?]
git fetch --all [<options>]

示例一

如下示例用于拉取远程分支master的更新,然后merge到本地master分支。

$ git fetch origin master
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From https://gitee.com/xxxx/gitest
 * branch            master     -> FETCH_HEAD
   2e380bf..27fd886  master     -> origin/master
   
$ git merge origin/master
Updating 2e380bf..27fd886
Fast-forward
 README | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

示例二

使用如下命令可以拉取所有的远程分支。

$ git fetch
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 14 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (14/14), done.
From https://gitee.com/xxxx/gitest
 * [new branch]      develop    -> origin/develop
 * [new branch]      master     -> origin/master
 

示例三

取回远程主机的更新以后,可以在它的基础上,使用git checkout命令创建一个新的分支。

$ git checkout -b master02 origin/master
Switched to a new branch 'master02'
Branch 'master02' set up to track remote branch 'master' from 'origin'.

示例四

拉取远程特定分支内容到本地对应分支。

git fetch origin +pu:pu maint:tmp

即使没有快进,pu分支将被更新,因为它的前缀是加号; tmp不会。

有时候使用上述命令时会报如下错误:

$ git fetch origin +master:master
fatal: Refusing to fetch into current branch refs/heads/master of non-bare repository

其实上述提示就是说,当前就是在master分支,使用refspec方式拉取master分支是被拒绝的。如果将当前分支切换为develop分支,然后再执行上面命令即可运行成功。

git pull

git pull命令的作用是:取回远程主机某个分支的更新,再与本地的指定分支合并。git pull命令相当于git fetch + git merge

git pull [<options>] [<repository> [<refspec>…​]]

git pull使用给定的参数运行git fetch,并调用git merge将检索到的分支头合并到当前分支中。 使用--rebase,它运行git rebase而不是git merge。git pull是git fetch后跟git merge FETCH_HEAD的缩写。

从远程取回origin主机的develop分支,与本地的master分支合并。

$ git pull origin develop:master

如果是远程分支develop与本地当前分支合并,那么冒号后面的参数可以省略。

$ git pull origin develop

上面命令表示,取回origin/develop分支,再与当前分支合并。实质上,这等同于先做git fetch,再执行git merge。

$ git fetch origin
$ git merge origin/develop

如果当前分支与远程分支存在对应关系,git pull可以省略远程分支名。

$ git pull origin

上面命令表示,本地的当前分支自动与对应的origin主机“追踪分支”(remote-tracking branch)进行合并。

如果当前分支只有一个追踪分支,连远程主机名都可以省略。

$ git pull

git push

git push用于将本地的更新推送至远程分支,该命令与git pull很相似,只是git pull是从远程分支拉取到本地,而git push是将本地分支推送至远程。

git push不仅可以推送本地文件内容的更新,还可以推送本地分支到远程分支,即如果远程分支没有与本地分支对应的分支名,那么会在远程新建一个对应的分支名称。

git push [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
	   [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
	   [-u | --set-upstream] [-o <string> | --push-option=<string>]
	   [--[no-]signed|--signed=(true|false|if-asked)]
	   [--force-with-lease[=<refname>[:<expect>]]]
	   [--no-verify] [<repository> [<refspec>…​]]

推送至远程分支

$ git push origin master

上面命令表示,将本地的master分支推送到origin主机的master分支。如果master不存在,则会被新建。

$ git push origin

上面命令表示,将当前分支推送到origin主机的对应分支。

如果当前分支只有一个追踪分支,那么主机名都可以省略。

$ git push 

如果当前分支与多个主机存在追踪关系,那么这个时候-u选项会指定一个默认主机,这样后面就可以不加任何参数使用git push。

$ git push -u origin master

上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。

不带任何参数的git push,默认只推送当前分支,这叫做simple方式。此外,还有一种matching方式,会推送所有有对应的远程分支的本地分支。Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式

如果要修改这个设置,可以采用git config命令。

$ git config --global push.default matching
# 或者
$ git config --global push.default simple

无论是使用自定义的origin01主机名还是使用默认的origin主机名,在使用push命令时方式都是一样的。

删除远程分支

$ git push origin :develop
# 或者
$ git push origin --delete develop

新建一个与本地分支不同名称的远程分支

$ git push --set-upstream origin dev:dev02
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 552 bytes | 138.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote: Powered By Gitee.com
To https://gitee.com/xxxx/gitest
 * [new branch]      dev -> dev02
Branch 'dev' set up to track remote branch 'dev02' from 'origin'.

上述命令执行成功后,后续在执行push时可以使用如下两种方式:

$git push origin HEAD:dev02
# 或者
$git push origin HEAD

如果使用的是如下命令推送至远程分支,后续有更新仍然采用同样的命令推送至远程分支,因为dev和dev02并没有建立关联关系。

$ git push origin dev:dev02

小结

本文涉及的操作命令也不多,就是3个有关远程分支操作的命令。需要知道fetch和pull命令的差异性,有关push命令的介绍相对多一些,因为它不仅涉及到push本地分支内容的更改,而且还可以push分支本身到远程分支,包括新建远程分支以及删除远程分支。

上面所介绍的3个命令,其实也是开发中最常使用的3个命令,也是容易出问题的几个命令,有时候push本地内容就push不上去了,或者有时候pull下来就出现冲突了。上文也对部分问题有所涉及,但是开发中遇到的问题肯定远不止如此,因此只有遇到问题时具体分析,慢慢一个一个解决。正所谓生活中本来就有许多坑,走的路多了,早晚掉进其中一个^_^。

接下来主要介绍如下几个命令:rebase、cherry-pick、stash、rm、mv,rebase和cherry-pick是两个非常有用的命令,仅这两个命令应该就需要单独一个篇幅进行介绍,最后一篇应该就是整理一些剩余的比较常用的命令了。

参考资料

Git教程

Git Community Book 中文版

评论

您确定要删除吗?删除之后不可恢复