Add 3.2 保持同步.

This commit is contained in:
Zhongyi Tong
2016-01-26 22:17:41 +08:00
parent f929fb3699
commit 0c54991461
2 changed files with 295 additions and 1 deletions

View File

@ -0,0 +1,294 @@
# 保持同步
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
>
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/syncing)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
SVN使用唯一的中央仓库作为开发者之间沟通的桥梁在开发者的工作拷贝和中央仓库之间传递变更集合(changeset)协作得以发生。这和Git的协作模型有所不同Git给予每个开发者一份自己的仓库拷贝拥有自己完整的本地历史和分支结构。用户通常共享一系列的提交而不是单个变更集合。Git允许你在仓库间共享整个分支而不是从工作副本提交一个差异集合到中央仓库。
下面的命令让你管理仓库之间的连接,将分支“推送”到其他仓库来发布本地历史,或是将分支“拉取”到本地仓库来查看其它开发者的贡献。
## git remote
`git remote`命令允许你创建、查看和删除和其它仓库之间的连接。远程连接更像是书签而不是直接跳转到其他仓库的链接。它用方便记住的别名引用不那么方便记住的URL而不是提供其他仓库的实时连接。
例如下图显示了你的仓库和中央仓库以及另一个开发者仓库之间的远程连接。你可以向Git命令传递origin和john的别名来引用这些仓库替代完整的URL。
![Git Tutorial: git remote](https://www.atlassian.com/git/images/tutorials/collaborating/syncing/01.svg)
### 用法
```
git remote
```
列出你和其他仓库之间的远程连接。
```
git remote -v
```
和上个命令相同但同时显示每个连接的URL。
```
git remote add <name> <url>
```
创建一个新的远程仓库连接。在添加之后,你可以将<name>作为<url>便捷的别名在其他Git命令中使用。
```
git remote rm <name>
```
移除名为<name>的远程仓库的连接。
```
git remote rename <old-name> <new-name>
```
将远程连接从<old-name>重命名为<new-name>。
### 讨论
Git被设计为给每个开发者提供完全隔离的开发环境。也就是说信息并不是自动地在仓库之间传递。开发者需要手动将上游提交拉取到本地或手动将本地提交推送到中央仓库中去。`git remote`命令正是将URL传递给这些“共享”命令的快捷方式。
#### 名为origin的远程连接
当你用`git clone`克隆仓库时它自动创建了一个名为origin的远程连接指向被克隆的仓库。当开发者创建中央仓库的本地副本时非常有用因为它提供了拉取上游更改和发布本地提交的快捷方式。这也是为什么大多数基于Git的项目将它们的中央仓库取名为origin。
#### 仓库的URL
Git支持多种方式来引用一个远程仓库。其中两种最简单的方式便是HTTP和SSH协议。HTTP是允许匿名、只读访问仓库的简易方式。比如
```
http://host/path/to/repo.git
```
但是直接将提交推送到一个HTTP地址一般是不可行的你不太可能希望匿名用户也能随意推送。如果希望对仓库进行读写你需要使用SSH协议
```
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下来的内容表示为一个远程分支因此不会影响你的本地开发。这是一个安全的方式在整合进你的本地仓库之前检查那些提交。类似于svn update你可以看到中央仓库的历史进展如何但它不会强制你将这些进展合并入你的仓库。
#### 远程分支
远程分支和本地分支一样只不过它们代表这些提交来自于其他人的仓库。你可以查看像查看本地分支一样查看远程分支但你会处于分离HEAD状态就像查看旧的提交时一样。你可以把它们视作只读的分支。如果想要查看远程分支只需要向`git branch`命令传入`-r`参数。远程分支拥有remote的前缀所以你不会将它们和本地分支混起来。比如下面的代码片段显示了从origin拉取之后你可能想要查看的分支
```
git branch -r
# origin/master
# origin/develop
# origin/some-feature
```
同样,你可以用寻常的`git checkout`和 `git log`命令来查看这些分支。如果你接受远程分支包含的更改,你可以使用`git merge`将它并入本地分支。所以不像SVN同步你的本地仓库和远程仓库事实上是一个分两步的操作先fetch然后merge。`git pull`命令是这个过程的快捷方式。
### 栗子
这个例子回顾了同步本地和远程仓库`master`分支的常见工作流:
```
git fetch origin
```
它会显示会被下载的分支:
```
a1e8fb5..45e66a4 master -> origin/master
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature
```
在下图中,远程分支中的提交显示为方块,而不是圆圈。正如你所见,`git fetch`让你看到了另一个仓库完整的分支结构。
![Git Tutorial: git fetch](https://www.atlassian.com/git/images/tutorials/collaborating/syncing/02.svg)
若想查看添加到上游master上的提交你可以运行`git log`,用 `origin/master`过滤:
```
git log --oneline master..origin/master
```
用下面这些命令接受更改并并入你的本地`master`分支:
```
git checkout master
git log origin/master
```
我们可以使用`git merge origin/master`
```
git merge origin/master
```
origin/master和master分支现在指向了同一个提交你已经和上游的更新保持了同步。
## git pull
在基于Git的协作工作流中将上游更改合并到你的本地仓库是一个常见的工作。我们已经知道应该使用`git fetch`,然后是`git merge`,但是`git pull`将这两个命令合二为一。
### 用法
```
git pull <remote>
```
拉取当前分支对应的远程副本中的更改,并立即并入本地副本。效果和`git fetch `后接`git merge origin/.`一致。
```
git pull --rebase <remote>
```
和上一个命令相同,但使用`git rebase`合并远程分支和本地分支,而不是使用`git merge`。
### 讨论
你可以将`git pull`当做Git中对应`svn update`的命令。这是同步你本地仓库和上游更改的简单方式。下图结束了pull过程中的每一步。
![Git Tutorial: git pull](https://www.atlassian.com/git/images/tutorials/collaborating/syncing/03.svg)
你认为你的仓库已经同步了,但`git fetch`发现origin中`master`的版本在上次检查后已经有了新进展。 接着`git merge`立即将`remote master`并入本地的分支。
#### 基于Rebase的Pull
`--rebase`标记可以用来保证线性的项目历史,防止合并提交(merge commits)的产生。很多开发者倾向于使用rebase而不是merge因为“我想要把我的更改放在其他人完成的工作之后”。这种情况下使用带有`--rebase`标记的`git pull`甚至更像svn update与普通的`git pull`相比而言。
事实上,使用`--rebase`的pull的工作流是如此普遍以致于你可以直接在配置项中设置它
```
git config --global branch.autosetuprebase always
```
在运行这个命令之后,所有的`git pull`命令将使用`git rebase,`而不是`git merge`。
### 栗子
下面的栗子演示了如何和一个中央仓库的`master branch`同步:
```
git checkout master
git pull --rebase origin
```
简单地将你本地的更改放到其他人已经提交的更改之后。
## git push
Push是你将本地仓库中的提交转移到远程仓库中时要做的事。它和`git fetch`正好相反fetch将提交导入到本地分支而push将提交导出到远程分支。它可以覆盖已有的更改所以你需要小心使用。这些情况请见下面的讨论。
### 用法
```
git push <remote> <branch>
```
将指定的分支推送到<remote>上包括所有需要的提交和提交对象。它会在目标仓库中创建一个本地分支。为了防止你覆盖已有的提交如果会导致目标仓库非快速向前合并时Git不允许你push。
```
git push <remote> --force
```
和上一个命令相同,但即使会导致非快速向前合并也强制推送。除非你确定你所做的事,否则不要使用`--force`标记。
```
git push <remote> --all
```
将所有本地分支推送到指定的远程仓库。
```
git push <remote> --tags
```
当你推送一个分支或是使用`--all`选项时,标签不会被自动推送上去。`--tags`将你所有的本地标签推送到远程仓库中去。
### 讨论
`git push`最常见的用法是将你的本地更改发布到中央仓库。在你积累了一些本地提交准备和同事们共享时可以用交互式rebase来清理你的提交然后推送到中央仓库去。
![Git Tutorial: git push](https://www.atlassian.com/git/images/tutorials/collaborating/syncing/04.svg)
上图显示了当你本地的master分支进展超过了中央仓库的`master`分支,当你运行`git push origin master`发布更改时发生的事情。注意,`git push`和在远程仓库内部运行`git merge master`事实上是一样的。
#### 强制推送
Git为了防止你覆盖中央仓库的历史会拒绝你会导致非快速向前合并的推送请求。所以如果远程历史和你本地历史已经分叉你需要将远程分支pull下来在本地合并后再尝试推送。这和SVN让你在提交更改集合之前要和中央仓库同步是类似的。
`--force`这个标记覆盖了这个行为让远程仓库的分支符合你的本地分支删除你上次pull之后可能的上游更改。只有当你意识到你刚刚共享的提交不正确并用`git commit --amend`或者交互式rebase修复之后你才需要用到强制推送。但是你必须绝对确定在你使用`--force`标记前你的同事们都没有pull这些提交。
#### 只推送到裸仓库
此外,你只应该推送到那些用`--bare`标记初始化的仓库。因为推送会弄乱远程分支结构,很重要的一点是,永远不要推送到其他开发者的仓库。但因为裸仓库没有工作目录,不会发生打断别人的开发之类的事情。
### 栗子
下面的栗子描述了将本地提交推送到中央仓库的一些标准做法。首先,确保你本地的`master`和中央仓库的副本是一致的提前fetch中央仓库的副本并在上面rebase。交互式rebase同样是共享之前清理提交的好机会。接下来`git push`命令将你本地`master`分支上的所有提交发送给中央仓库.
```
git checkout master
git fetch origin master
git rebase -i origin/master
# Squash commits, fix up commit messages etc.
git push origin master
```
因为我们已经确信本地的`master`分支是最新的,它应该导致快速向前的合并,`git push`不应该抛出非快速向前之类的问题。
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
>
> 如果你觉得文章对你有帮助,欢迎点击右上角的***Star***:star2:或***Fork***:fork_and_knife:。
>
> 如果你发现了错误,或是想要加入协作,请参阅[Wiki协作说明](https://github.com/geeeeeeeeek/git-recipes/issues/1)。

View File

@ -1,4 +1,4 @@
## 重写项目历史
# 重写项目历史
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
>