gknpezgssb/blog

Git系列之远程相关命令

gknpezgssb opened this issue · 0 comments

原文地址
SVN使用中心仓库作为开发者们的联络中心,并通过开发者们与中心仓库之间工作副本的变更集的传递来进行协作。这不同于Git中每个开发者都拥有自己的仓库副本,自己的本地历史与分支结构的协作模式。使用者通常需要共享一系列的提交而非一个单一的变更集。Git让你能够在不同仓库间分享整个分支而非从工作备份向中心仓库提交一个变化集。

下面的命令能让你管理与其他仓库的连接,通过push来推送本地分支到其他仓库,通过pull分支进本地仓库来查看他人贡献的内容。
##git remote

git remote命令让你创建,浏览,删除与其他仓库的连接。远程连接更像是书签而非直接的连接到其他仓库。其通过提供一个方便的名称作为不那么方便的URL的引用,而非提供其他仓库实时的入口。

例如,下图展示了你仓库中的两个远程连接,分别对应了中心仓库和另一个开发者的仓库。你可以将originjohn这样的简写传给Git命令而不必使用完成的URL来引用它们。

图片描述

###用法

git remote

列出本地的所的远程远程。

git remote -v

与上述命令相似,多了每个连接的URL地址。

git remote add <name> <url>

创建一个与远程仓库的新连接。在添加完成之后,你将能够在其他Git命令中使用便捷的*替代*。

git remote rm <name>

移除本地名为**的远程连接。

git remote rename <old-name> <new-name>

重命名**。
###论述
Git被设计来为每一个开发者提供一个完全独立的开发环境。这意味着流不会自动地在仓库之间传递。而是需要,开发者手动的来去上游提交的数据进本地仓库或手动推送本地提交到中心仓库。Git的远程命令只是一个简单的方式来实现将URL传递给这些共享命令(此处的共享即位前问所说共享工作之意)。
####远程origin仓库
当你使用git clone命令克隆一个仓库时,会自动创建一个指向克隆仓库的名为origin的远程连接。这对于需要创建中心仓库本地副本的开发者是很有用的,因其提供了一个简单的方式来pull上游改动以及推送本地提交。这也是为什么大部分基于Git的项目把他们的远程仓库叫做origin的原因。

####仓库URL
Git支持多种方式来引用远程仓库。最简单的两种是通过HTTP和SSH协议来访问远程仓库。使用HTTP是一种允许匿名只读的方式访问一个仓库的简单的方式:

http://host/path/to/repo.git

但是通常你不可能向HTTP地址推送提交(你不会允许任何匿名推送吧)。对于可读写的访问你应该使用SSH来替代HTTP:

ssh://user@host/path/to/repo.git

在你的主机上需要一个有效的SSH账号,此外,Git还支持开箱即用的SSH认证方式。

###实例

由于origin机制,连接团队的仓库变得很方便。例如,假设你的合作者John在dev.example.com/john.git上维护一个开源仓库,你可以添加一个连接使用以下方法:

git remote add john http://dev.example.com/john.git

拥有这样的对某个开发者仓库访问的能力,让在中心仓库之外的的合作变为可能。这对于构建大项目的小型团队是非常有用的。

##git fetch

git fetch命令将把提交从远程仓库引入你的本地仓库。提交结果将存放在本地的远程分支而非平常工作的普通分支中。这让你在把它们合并进你的项目副本前有机会去审查改变。

###用法

git fetch <remote>

从仓库中获取所有的分支。也从其他仓库中下载所有所需的提交和文件。

git fetch <remote> <branch>

与上面命令作用相同,只是只获取特定的分支。
###论述
当你想要查看别人在项目中工作时,你就需要fetch。由于fetch的内容形成了一条远程分支,所以这绝对不会对你本地的开发工作产生影响。这使得fetch成为一个安全的方式用来在合并之前审查提交。这与SVN中的update相似,能够让你看到中心仓库中的进展,但不会强制将变化合并进你的仓库。

####远程分支
远程分支就像本地分支一样,除了他们表示别的仓库中的提交。你可以像检出(checkout)本地分支一样检出远程分支。但这会使你处于分离HEAD的状态(想想你checkout旧提交是的情景)。你可以把它们当作可读分支。查看远程分支你需要在git branch命令中加入**-r**参数。远程分支会带上他们所属远程作为前缀,这样我们就不会把它们与本地分支混淆在一起。例如下面的代码片段展示了,在你从远程fetch后的分支状态:

git branch -r
# origin/master
# origin/develop
# origin/some-feature

你可以使用常用的git loggit checkout命令来检查这些分支。如果你认可了远程分支包含的变化,你可以把使用git merge命令它们合并进本地分支。这与SVN中同步将远程分支与本地分支合并是不同的,在Git中是两个过程:fetch然后merge。git pull命令能方便地用一个命令实现这一过程。
###例子
本例将演示将本地仓库与中心仓库主分支同步的典型工作流。

git fetch origin

该命令将显示被下载的分支

a1e8fb5..45e66a4 master -> origin/master
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature

如上,新分支中的提交将显示在‘[]‘中而非’()‘中。如你所见,git fetch命令使得可以访问其他仓库中的所有分支结构。

图片描述

为了查看被添加到上游主分支上的提交,你可以执行git log命令使用origin/master作为过滤。

git log --oneline master..origin/master

检查过更改后你可以使用下面命令将它们合并进你的本地分支:

git checkout master
git log origin/master

之后你可以执行git merge origin/master:

git merge origin/master

origin/mastermaster分支现在指向相同的提交并且你也同步了上游的开发。
##git pull

合并上游变化是给予Git的工作流中常见的任务。我们已经知道可以使用git fetch后在使用git merge来达到这一目的,不过git pull将这两者合二为一。

###用法

git pull <remote>

fetch一个特定的当前分支的远程副本立即与当前副本合并。这与执行git fetch <remote>命令后再执行git merge origin/<current-branch>有同样的效果。

git pull --rebase <remote>

与上面的命令相同,只是使用rebase替代了merge

###论述
你可以把git pull当作Git版本的update。这是一个本地仓库同步上游修改的简单方式。下图表示git pull过程的每个步骤:

图片描述

####通过rebase来pull
使用**--rebase选项可以确保线形的历史线而没有不必要的合并提交。相比于merge许多开发者更喜欢rebase,它好像在说,“我想要把我的修改换到其他人的之上”。从这点上看,使用带--rebase**的git pull比普通的git pull命令更像SVN的update

事实上,带**--rebase**的pull是一种常见的工作流,其拥有一个专门的配置选项。

git config --global branch.autosetuprebase always

执行命令之后,所有的git pull命令将默认使用rebase而非merge。

###例子

下面的例子展示了怎样同步中心仓库master分支:

git checkout master
git pull --rebase origin

这仅仅将你的修改移动到其他提交之上。
##git push
push将你的提交传输到远程仓库上。这是git fetch的逆过程,只不过fetch引进提交到本地分支,push输出提交到远程分支。这有可能重写修改,所以使用的时候要小心,这些问题将在后续讨论。

###用法

git push <remote> <branch>

该命令向远程推送特定的分支以及所有必要的提交与内部对象。这也将本地分支创建进目标仓库。为了防止你重写提交,当导致了目标仓库的non-fast-forwardmerge时,Git不会让你进行推送。

git push <remote> --force

与上一个命令基本相同,但无论是否出现“non-fast-forward”错误,都会强制推送。除非你非常确定你要做什么,否则不要使用带**--force**参数的命令。

git push <remote> --all

向特定的远程仓库推送你所有的本地分支。

git push <remote> --tags

当你推送远程分支或使用**--all选项时,tag不会自动推送。带--tages**的命令会向远程仓库推送你所有的本地tag。

###论述
使用git push命令最常见的场景就是向中心仓库图送你的本地修改。当你完成了一些本地提交并且准备好与你团队的成员分享时,你可以使用动态rebase来整理,然后把它们推送到中心仓库。

图片描述

上图展示了当你本地的主分支比中心仓库主分支又了进展后你使用git push origin master命令发布修改后发生了什么。注意git push命令本质上和在远程仓库中执行git merge master是一样的。

####强制发布
当导致non-fast-forward合并时,Git通过拒绝你的推送请求来阻止你对中心仓库历史线的重写。所以,如果远程历史线需要从你的历史线中分叉出来,你需要拉取远程分支并与你本地的进行合并,然后再推送。这与SVN中,通过在提交修改集前使用svn update来实现中心仓库的同步是相似的。

--force会覆盖并且通过删除最近拉取后可能发生的任意的上游变化来确保远程分支与本地匹配。唯一需要强制推送的情形是当你意识到你之前分享的提交不正确你使用git commit --amend或动态rebase来修正它们。然而你要绝对确信团队中没有成员在你执行强制推送前已经拉取了你的提交。

####只推送到空仓库
此外,你因该只向用**--bare**创建的仓库进行推送。由于推送会使远程分支混乱,所以切忌向其他开发者的仓库进行推送。但是由于裸仓库不存在工作目录(working directory),就不可能打扰到任何其他开发者。

###例子
下面例子展示了一个标准的发送本地贡献到中心仓库的方法。首先,确认你的主分支已fetch线上最新分支,并且你的修改已经rebase到顶端。动态rebase也是一个在分享前清理提交的好办法。然后使用git push命令传送所有本地主分支的提交到中心分支去。

git checkout master
git fetch origin master
git rebase -i origin/master
# Squash commits, fix up commit messages etc.
git push origin master

由于本地主分支已是最新的,会导致Git使用fast-forwardmerge而不会产生任何上文所述的non-fast-forward的问题。