@ -8,12 +8,12 @@ git-recipes的所有文章都以Wiki的方式呈现,请移步[项目Wiki](http
|
||||
|
||||
## 我为什么要做这份菜单
|
||||
|
||||
在整理Git资料的时候,我发现社区贡献了非常多高质量的博客文章、指南等等。尤其英文的那些资料,除了大家熟知的《Git图解》,还有好多优秀的文章仍无人翻译。此外,这些资料往往只涉及某些特定的话题,如果能有一份菜单将这些菜谱以特定的方式串起来,那么对于Git学习者来说将会是极大的便利。尤其对于我这样热爱查阅社区资料胜过出版物的懒人 : ) 随着我的学习节奏还会不断有新的菜谱加入进来,或许不会很频繁,不过也没有确定的终点。
|
||||
在整理 Git 资料的时候,我发现社区贡献了非常多高质量的博客文章、指南等等。尤其英文的那些资料,除了大家熟知的《Git 图解》,还有好多优秀的文章仍无人翻译。此外,这些资料往往只涉及某些特定的话题,如果能有一份菜单将这些菜谱以特定的方式串起来,那么对于 Git 学习者来说将会是极大的便利。尤其对于我这样热爱查阅社区资料胜过出版物的懒人 :] 随着我的学习节奏还会不断有新的菜谱加入进来,或许不会很频繁,不过也没有确定的终点。
|
||||
|
||||
## 版权说明
|
||||
|
||||
除非另行注明,这个项目中的所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享,BY 童仲毅(geeeeeeeeek@github)。
|
||||
除非另行注明,这个项目中的所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享,BY 童仲毅(geeeeeeeeek@github)。
|
||||
|
||||
不少文章在原基础上翻译或演绎而来,页面上方均标明了原作者、原文链接以及原文采用的协议。如仍有版权疑问,请在issue中提出。
|
||||
不少文章在原基础上翻译或演绎而来,页面上方均标明了原作者、原文链接以及原文采用的协议。如仍有版权疑问,请在 Issue 中提出。
|
||||
|
||||
欢迎通过issue或者pr推荐你认为合适的资料,让这份菜单更充实一些。
|
||||
欢迎通过 Issue 或者 Pull Request 推荐你认为合适的资料,让这份菜单更充实一些。
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# Git log 高级用法
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/git-log)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/git-log)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
每一个版本控制系统的出现都是为了让你记录代码的变化。你可以看到项目的历史记录——谁贡献了什么、bug 是什么时候引入的,还可以撤回有问题的更改。但是,首先你得知道如何使用它。这也就是为什么会有 `git log` 这个命令。
|
||||
|
||||
@ -166,7 +166,7 @@ git log -3
|
||||
git log --after="2014-7-1"
|
||||
```
|
||||
|
||||
你也可以传入相对的日期,比如一周前("`1 week ago`")或者昨天("`yesterday`"):
|
||||
你也可以传入相对的日期,比如一周前(`"1 week ago"`)或者昨天(`"yesterday"`):
|
||||
|
||||
```
|
||||
get log --after="yesterday"
|
||||
@ -248,11 +248,11 @@ git log <since>..<until>
|
||||
git log master..feature
|
||||
```
|
||||
|
||||
其中的master..feature范围包含了在feature分支而不在master分支中所有的提交。换句话说,这个命令可以看出从master分支fork到feature分支后发生了哪些变化。它可以这样可视化:
|
||||
其中的 `master..feature` 范围包含了在 feature 分支而不在 master 分支中所有的提交。换句话说,这个命令可以看出从 master 分支 fork 到 feature 分支后发生了哪些变化。它可以这样可视化:
|
||||
|
||||

|
||||
|
||||
注意如果你更改范围的前后顺序(feature..master),你会获取到master分支而非feature分支上的所有提交。如果`git log`输出了全部两个分支的提交,这说明你的提交历史已经分叉了。
|
||||
注意如果你更改范围的前后顺序(feature..master),你会获取到 master 分支而非 feature 分支上的所有提交。如果 `git log` 输出了全部两个分支的提交,这说明你的提交历史已经分叉了。
|
||||
|
||||
### 过滤合并提交
|
||||
|
||||
@ -280,7 +280,7 @@ git log --merges
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Git 图解
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)基础上演绎的文章。原作者 [Mark Lodato](lodatom@gmail.com),译者 [wych](ellrywych@gmail.com)。原文采用[创用 CC 姓名标示-非商业性-相同方式分享 3.0 美国授权条款](https://creativecommons.org/licenses/by-nc-sa/3.0/us/)授权。
|
||||
|
||||
@ -33,9 +33,9 @@
|
||||
|
||||

|
||||
|
||||
绿色的5位字符表示提交的ID,分别指向父节点。分支用橙色显示,分别指向特定的提交。当前分支由附在其上的_HEAD_标识。
|
||||
绿色的5位字符表示提交的 ID,分别指向父节点。分支用橙色显示,分别指向特定的提交。当前分支由附在其上的 `_HEAD_` 标识。
|
||||
|
||||
这张图片里显示最后5次提交,_ed489_是最新提交。 _master_分支指向此次提交,另一个_maint_分支指向祖父提交节点。
|
||||
这张图片里显示最后 5 次提交,`_ed489_` 是最新提交。 `_master_` 分支指向此次提交,另一个 `_maint_` 分支指向祖父提交节点。
|
||||
|
||||
## 命令详解
|
||||
|
||||
@ -47,19 +47,19 @@
|
||||
|
||||
### Commit
|
||||
|
||||
提交时,git用stage缓存中的文件创建一个新的提交,并把此时的节点设为父节点。然后把当前分支指向新的提交节点。下图中,当前分支是_master_。
|
||||
提交时,Git 用 stage 缓存中的文件创建一个新的提交,并把此时的节点设为父节点。然后把当前分支指向新的提交节点。下图中,当前分支是 `_master_`。
|
||||
|
||||
在运行命令之前,_master_指向_ed489_,提交后,_master_指向新的节点_f0cec_并以_ed489_作为父节点。
|
||||
在运行命令之前,`_master_` 指向 `_ed489_`,提交后,`_master_` 指向新的节点`_f0cec_` 并以 `_ed489_` 作为父节点。
|
||||
|
||||

|
||||
|
||||
即便当前分支是某次提交的祖父节点,git会同样操作。下图中,在_master_分支的祖父节点_maint_分支进行一次提交,生成了_1800b_。
|
||||
即便当前分支是某次提交的祖父节点,Git 会同样操作。下图中,在 `_master_` 分支的祖父节点 `_maint_` 分支进行一次提交,生成了 `_1800b_`。
|
||||
|
||||
这样,_maint_分支就不再是_master_分支的祖父节点。此时,[merge](#merge) 或者 [rebase](#rebase) 是必须的。
|
||||
这样,`_maint_ `分支就不再是 `_master_` 分支的祖父节点。此时,[merge](#merge) 或者 [rebase](#rebase) 是必须的。
|
||||
|
||||

|
||||
|
||||
如果想更改一次提交,使用 `git commit --amend`。git会使用与当前提交相同的父节点进行一次新提交,旧的提交会被取消。
|
||||
如果想更改一次提交,使用 `git commit --amend`。Git 会使用与当前提交相同的父节点进行一次新提交,旧的提交会被取消。
|
||||
|
||||

|
||||
|
||||
@ -67,27 +67,27 @@
|
||||
|
||||
### Checkout
|
||||
|
||||
checkout命令用于从历史提交(或者stage缓存)中拷贝文件到工作目录,也可用于切换分支。
|
||||
`git checkout` 命令用于从历史提交(或者 stage 缓存)中拷贝文件到工作目录,也可用于切换分支。
|
||||
|
||||
当给定某个文件名(或者打开-p选项,或者文件名和-p选项同时打开)时,git会从指定的提交中拷贝文件到stage缓存和工作目录。比如,`git checkout HEAD~ foo.c`会将提交节点_HEAD~_(即当前提交节点的父节点)中的`foo.c`复制到工作目录并且加到stage缓存中。如果命令中没有指定提交节点,则会从stage缓存中拷贝内容。注意当前分支不会发生变化。
|
||||
当给定某个文件名(或者打开 `-p` 选项,或者文件名和-p选项同时打开)时,Git 会从指定的提交中拷贝文件到 stage 缓存和工作目录。比如,`git checkout HEAD~ foo.c` 会将提交节点 `_HEAD~_`(即当前提交节点的父节点)中的 `foo.c` 复制到工作目录并且加到 stage 缓存中。如果命令中没有指定提交节点,则会从 stage 缓存中拷贝内容。注意当前分支不会发生变化。
|
||||
|
||||

|
||||
|
||||
当不指定文件名,而是给出一个(本地)分支时,那么_HEAD_标识会移动到那个分支(也就是说,我们“切换”到那个分支了),然后stage缓存和工作目录中的内容会和_HEAD_对应的提交节点一致。新提交节点(下图中的a47c3)中的所有文件都会被复制(到stage缓存和工作目录中);只存在于老的提交节点(ed489)中的文件会被删除;不属于上述两者的文件会被忽略,不受影响。
|
||||
当不指定文件名,而是给出一个(本地)分支时,那么 `_HEAD_` 标识会移动到那个分支(也就是说,我们「切换」到那个分支了),然后 stage 缓存和工作目录中的内容会和 `_HEAD_` 对应的提交节点一致。新提交节点(下图中的 `a47c3`)中的所有文件都会被复制(到 stage 缓存和工作目录中);只存在于老的提交节点(`ed489`)中的文件会被删除;不属于上述两者的文件会被忽略,不受影响。
|
||||
|
||||

|
||||
|
||||
如果既没有指定文件名,也没有指定分支名,而是一个标签、远程分支、SHA-1值或者是像_master~3_类似的东西,就得到一个匿名分支,称作_detached HEAD_(被分离的_HEAD_标识)。这样可以很方便地在历史版本之间互相切换。比如说你想要编译1.6.6.1版本的git,你可以运行`git checkout v1.6.6.1`(这是一个标签,而非分支名),编译,安装,然后切换回另一个分支,比如说`git checkout master`。然而,当提交操作涉及到“分离的HEAD”时,其行为会略有不同,详情见在[下面](#detached)。
|
||||
如果既没有指定文件名,也没有指定分支名,而是一个标签、远程分支、SHA-1 值或者是像 `_master~3_` 类似的东西,就得到一个匿名分支,称作 `_detached HEAD_`(被分离的 `_HEAD_` 标识)。这样可以很方便地在历史版本之间互相切换。比如说你想要编译 1.6.6.1 版本的 Git,你可以运行 `git checkout v1.6.6.1`(这是一个标签,而非分支名),编译,安装,然后切换回另一个分支,比如说 `git checkout master`。然而,当提交操作涉及到「分离的 HEAD」时,其行为会略有不同,详情见在[下面](#detached)。
|
||||
|
||||

|
||||
|
||||
### HEAD 标识处于分离状态时的提交操作
|
||||
|
||||
当_HEAD_处于分离状态(不依附于任一分支)时,提交操作可以正常进行,但是不会更新任何已命名的分支。你可以认为这是在更新一个匿名分支。
|
||||
当 `_HEAD_` 处于分离状态(不依附于任一分支)时,提交操作可以正常进行,但是不会更新任何已命名的分支。你可以认为这是在更新一个匿名分支。
|
||||
|
||||

|
||||
|
||||
一旦此后你切换到别的分支,比如说_master_,那么这个提交节点(可能)再也不会被引用到,然后就会被丢弃掉了。注意这个命令之后就不会有东西引用_2eecb_。
|
||||
一旦此后你切换到别的分支,比如说 `_master_`,那么这个提交节点(可能)再也不会被引用到,然后就会被丢弃掉了。注意这个命令之后就不会有东西引用 `_2eecb_`。
|
||||
|
||||

|
||||
|
||||
@ -97,13 +97,13 @@ checkout命令用于从历史提交(或者stage缓存)中拷贝文件到工
|
||||
|
||||
### Reset
|
||||
|
||||
reset命令把当前分支指向另一个位置,并且有选择的变动工作目录和索引。也用来在从历史commit历史中复制文件到索引,而不动工作目录。
|
||||
`git reset` 命令把当前分支指向另一个位置,并且有选择的变动工作目录和索引。也用来在从历史commit历史中复制文件到索引,而不动工作目录。
|
||||
|
||||
如果不给选项,那么当前分支指向到那个提交。如果用 `--hard` 选项,那么工作目录也更新,如果用 `--soft` 选项,那么都不变。
|
||||
|
||||

|
||||
|
||||
如果没有给出提交点的版本号,那么默认用_HEAD_。这样,分支指向不变,但是索引会回滚到最后一次提交,如果用`--hard`选项,工作目录也同样。
|
||||
如果没有给出提交点的版本号,那么默认用 `_HEAD_`。这样,分支指向不变,但是索引会回滚到最后一次提交,如果用 `--hard` 选项,工作目录也同样。
|
||||
|
||||

|
||||
|
||||
@ -113,43 +113,40 @@ reset命令把当前分支指向另一个位置,并且有选择的变动工作
|
||||
|
||||
### Merge
|
||||
|
||||
merge 命令把不同分支合并起来。合并前,索引必须和当前提交相同。如果另一个分支是当前提交的祖父节点,那么合并命令将什么也不做。
|
||||
`git merge` 命令把不同分支合并起来。合并前,索引必须和当前提交相同。如果另一个分支是当前提交的祖父节点,那么合并命令将什么也不做。
|
||||
|
||||
另一种情况是如果当前提交是另一个分支的祖父节点,就导致_fast-forward_合并。指向只是简单的移动,并生成一个新的提交。
|
||||
另一种情况是如果当前提交是另一个分支的祖父节点,就导致 `_fast-forward_` 合并。指向只是简单的移动,并生成一个新的提交。
|
||||
|
||||

|
||||
|
||||
否则就是一次真正的合并。默认把当前提交(_ed489_ 如下所示)和另一个提交(_33104_)以及他们的共同祖父节点(_b325c_)进行一次[三方合并](http://en.wikipedia.org/wiki/Three-way_merge)。结果是先保存当前目录和索引,然后和父节点_33104_一起做一次新提交。
|
||||
否则就是一次真正的合并。默认把当前提交(`_ed489_` 如下所示)和另一个提交(`_33104_`)以及他们的共同祖父节点(`_b325c_`)进行一次[三方合并](http://en.wikipedia.org/wiki/Three-way_merge)。结果是先保存当前目录和索引,然后和父节点 `_33104_` 一起做一次新提交。
|
||||
|
||||

|
||||
|
||||
### Cherry Pick
|
||||
|
||||
cherry-pick命令"复制"一个提交节点并在当前分支做一次完全一样的新提交。
|
||||
`git cherry-pick` 命令「复制」一个提交节点并在当前分支做一次完全一样的新提交。
|
||||
|
||||

|
||||
|
||||
### Rebase
|
||||
|
||||
rebase是合并命令的另一种选择。合并把两个父分支合并进行一次提交,提交历史不是线性的。rebase在当前分支上重演另一个分支的历史,提交历史是线性的。
|
||||
`git rebase` 是合并命令的另一种选择。合并把两个父分支合并进行一次提交,提交历史不是线性的。rebase 在当前分支上重演另一个分支的历史,提交历史是线性的。
|
||||
|
||||
本质上,这是线性化的自动的 [cherry-pick](#cherry-pick)。
|
||||
|
||||

|
||||
|
||||
上面的命令都在_topic_分支中进行,而不是_master_分支,在_master_分支上重演,并且把分支指向新的节点。注意旧提交没有被引用,将被回收。
|
||||
上面的命令都在 `_topic_` 分支中进行,而不是 `_master_` 分支,在 `_master_` 分支上重演,并且把分支指向新的节点。注意旧提交没有被引用,将被回收。
|
||||
|
||||
要限制回滚范围,使用`--onto`选项。下面的命令在_master_分支上重演当前分支从_169a6_以来的最近几个提交,即_2c33a_。
|
||||
要限制回滚范围,使用 `--onto` 选项。下面的命令在 `_master_` 分支上重演当前分支从 `_169a6_` 以来的最近几个提交,即 `_2c33a_`。
|
||||
|
||||

|
||||
|
||||
同样有 `git rebase --interactive` 让你更方便的完成一些复杂操作,比如丢弃、重排、修改、合并提交。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# Git提交引用和引用日志
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/refs-and-the-reflog)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/refs-and-the-reflog)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
提交是 Git 的精髓所在,你无时不刻不在创建和缓存提交、查看以前的提交,或者用各种Git命令在仓库间转移你的提交。大多数的命令都对同一个提交操作,而有些会接受提交的引用作为参数。比如,你可以给 `git checkout` 传入一个引用来查看以前的提交,或者传入一个分支名来切换到对应的分支。
|
||||
|
||||
@ -115,7 +115,7 @@ bb883e4c91c870b5fed88fd36696e752fb6cf8e6 refs/tags/v0.9
|
||||
- HEAD – 当前所在的提交或分支。
|
||||
- FETCH_HEAD – 远程仓库中 fetch 到的最新一次提交。
|
||||
- ORIG_HEAD – HEAD 的备份引用,避免损坏。
|
||||
- MERGE_HEAD – 你通过`git merge`并入当前分支的引用(们)。
|
||||
- MERGE_HEAD – 你通过 `git merge` 并入当前分支的引用(们)。
|
||||
- CHERRY_PICK_HEAD – 你 `cherry pick` 使用的引用。
|
||||
|
||||
这些引用由 Git 在需要时创建和更新。比如说,`git pull` 命令首先运行 `git fetch`,而 `FETCH_HEAD` 引用随之改变。然后,运行 `git merge FETCH_HEAD` 来将 fetch 到的分支最终并入仓库。当然,你也可以使用其他任何引用,因为我相信你已经对 `HEAD` 很熟悉了。
|
||||
@ -192,7 +192,7 @@ refspec给了你完全的掌控权,可以定制Git命令如何在仓库之间
|
||||
git show HEAD~2
|
||||
```
|
||||
|
||||
但是,面对合并提交(merge commit)的时候,事情就会变得有些复杂。因为合并提交有多个父节点,所以你可以找到多条回溯的路径。对于3路合并,第一个父节点是你执行合并时的分支,第二个父节点是你传给`git merge`命令的分支。
|
||||
但是,面对合并提交(merge commit)的时候,事情就会变得有些复杂。因为合并提交有多个父节点,所以你可以找到多条回溯的路径。对于 3 路合并,第一个父节点是你执行合并时的分支,第二个父节点是你传给 `git merge` 命令的分支。
|
||||
|
||||
`~` 符号总是选择合并提交的第一个父节点。如果你想选择其他父节点,你需要用 `^` 符号来指定。比如说,`HEAD` 是一个合并提交,下面这个命令返回 `HEAD` 的第二个父节点:
|
||||
|
||||
@ -268,9 +268,7 @@ git checkout HEAD@{1}
|
||||
|
||||
它的意义在于:在任何开发场景下,你都能找到你需要的特定提交。你很容易就可以把这些技巧用在你一有的 Git 知识中,因为很多常用的命令都接受引用作为参数,包括 `git log`、`git show`、`git checkout`、`git reset`、`git revert`、`git rebase` 等等。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# Git 简易指南(上)
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。[git-guide](https://github.com/rogerdudler/git-guide/) 项目对本文亦有贡献。
|
||||
> 除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。[git-guide](https://github.com/rogerdudler/git-guide/) 项目对本文亦有贡献。
|
||||
|
||||
这节是完全面向入门者的,我假设你从零开始创建一个项目并且想用 Git 来进行版本控制,因此本文会避开分支这些相对复杂的概念。
|
||||
|
||||
@ -10,14 +10,14 @@
|
||||
|
||||
## 安装 Git
|
||||
|
||||
- Mac用户:Xcode Command Line Tools自带Git (`xcode-select --install` )
|
||||
- Mac 用户:Xcode Command Line Tools 自带 Git(`xcode-select --install`)
|
||||
|
||||
- Linux 用户:`sudo apt-get install git`
|
||||
|
||||
- Windows 用户:下载 [Git SCM](git-for-windows.github.io)
|
||||
|
||||
```
|
||||
- 对于Windows用户,安装后如果希望在全局的cmd中使用git,需要把git.exe加入PATH环境变量中,或在Git Bash中使用Git。
|
||||
- 对于 Windows 用户,安装后如果希望在全局的 cmd 中使用 Git,需要把 git.exe 加入 PATH 环境变量中,或在 Git Bash 中使用 Git。
|
||||
```
|
||||
|
||||
## 检出仓库
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
## 工作流
|
||||
|
||||
你的本地仓库由 git 维护的三棵“树”组成。第一个是你的 `工作目录`,它持有实际文件;第二个是 `缓存区(Index)`,它像个缓存区域,临时保存你的改动;最后是 `HEAD`,指向你最近一次提交后的结果。
|
||||
你的本地仓库由 Git 维护的三棵「树」组成。第一个是你的 `工作目录`,它持有实际文件;第二个是 `缓存区(Index)`,它像个缓存区域,临时保存你的改动;最后是 `HEAD`,指向你最近一次提交后的结果。
|
||||
|
||||

|
||||
|
||||
@ -59,7 +59,7 @@ git add < filename >
|
||||
git add *
|
||||
```
|
||||
|
||||
这是 git 基本工作流程的第一步。使用如下命令以实际提交改动:
|
||||
这是 Git 基本工作流程的第一步。使用如下命令以实际提交改动:
|
||||
|
||||
```
|
||||
git commit -m "代码提交信息"
|
||||
@ -67,7 +67,7 @@ git commit -m "代码提交信息"
|
||||
|
||||
现在,你的改动已经提交到了 HEAD,但是还没到你的远端仓库。
|
||||
|
||||
> 在开发时,良好的习惯是根据工作进度及时commit,并务必注意附上有意义的commit message。创建完项目目录后,第一次提交的commit message一般为"Initial commit."。
|
||||
> 在开发时,良好的习惯是根据工作进度及时 commit,并务必注意附上有意义的 commit message。创建完项目目录后,第一次提交的 commit message 一般为「Initial commit」。
|
||||
|
||||
## 推送改动
|
||||
|
||||
@ -87,16 +87,13 @@ git remote add origin <server>
|
||||
|
||||
如此你就能够将你的改动推送到所添加的服务器上去了。
|
||||
|
||||
> - 这里origin是< server >的别名,取什么名字都可以,你也可以在push时将< server >替换为origin。但为了以后push方便,我们第一次一般都会先remote add。
|
||||
> - 如果你还没有git仓库,可以在Github等代码托管平台上创建一个空(不要自动生成README.md)的repository,然后将代码push到远端仓库。
|
||||
> - 这里 origin 是 <server> 的别名,取什么名字都可以,你也可以在 push 时将 <jserver> 替换为 origin。但为了以后 push 方便,我们第一次一般都会先 remote add。
|
||||
> - 如果你还没有 Git 仓库,可以在 Github 等代码托管平台上创建一个空(不要自动生成 README.md)的仓库,然后将代码 push 到远端仓库。
|
||||
|
||||
##### 至此,你应该可以顺利地提交你的项目了。在下一节中,我们将涉及更多的命令,来完成更有用的操作。比如从远端的仓库拉取更新并且合并到你的本地,如何通过分支多人协作,如何处理不同分支的冲突等等。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# Git 钩子:自定义你的工作流
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/git-hooks)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/git-hooks)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
Git 钩子是在 Git 仓库中特定事件发生时自动运行的脚本。它可以让你自定义 Git 内部的行为,在开发周期中的关键点触发自定义的行为。
|
||||
|
||||
@ -46,7 +46,7 @@ echo "# Please include a useful commit message!" > $1
|
||||
chmod +x prepare-commit-msg
|
||||
```
|
||||
|
||||
接下来你每次运行`git commit`时,你会看到默认的提交信息都被替换了。我们会在“准备提交信息”一节中细看它是如何工作的。现在我们已经可以定制Git的内部功能,你只需要坐和放宽。
|
||||
接下来你每次运行 `git commit` 时,你会看到默认的提交信息都被替换了。我们会在「准备提交信息」一节中细看它是如何工作的。现在我们已经可以定制 Git 的内部功能,你只需要坐和放宽。
|
||||
|
||||
内置的样例脚本是非常有用的参考资料,因为每个钩子传入的参数都有非常详细的说明(不同钩子不一样)。
|
||||
|
||||
@ -152,7 +152,7 @@ fi
|
||||
|
||||
- 包含提交信息的文件名。你可以在原地更改提交信息。
|
||||
- 提交类型。可以是信息(`-m` 或 `-F` 选项),模板(`-t` 选项),merge(如果是个合并提交)或 squash(如果这个提交插入了其他提交)。
|
||||
- 相关提交的SHA1哈希字串。只有当`-c`,`-C`,或`--amend`选项出现时才需要。
|
||||
- 相关提交的 SHA1 哈希字串。只有当 `-c`、`-C` 或 `--amend` 选项出现时才需要。
|
||||
|
||||
和 `pre-commit` 一样,以非0状态退出会放弃提交。
|
||||
|
||||
@ -445,9 +445,7 @@ print "Moving '%s' from %s to %s" % (branch, old_commit, new_commit)
|
||||
|
||||
我们还看了一些常用的本地和服务端的钩子。这使得我们能够介入到整个开发生命周期中去。我们现在知道了如何在创建提交或推送的每个阶段执行自定义的操作。有了这些简单的脚本知识,你就可以对 Git 仓库为所欲为了 : )
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 代码合并:Merge、Rebase 的选择
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
`git rebase` 这个命令经常被人认为是一种 Git 巫术,初学者应该避而远之。但如果使用得当的话,它能给你的团队开发省去太多烦恼。在这篇文章中,我们会比较 `git rebase` 和类似的 `git merge` 命令,找到 Git 工作流中 rebase 的所有用法。
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
你要知道的第一件事是,`git rebase` 和`git merge` 做的事其实是一样的。它们都被设计来将一个分支的更改并入另一个分支,只不过方式有些不同。
|
||||
|
||||
想象一下,你刚创建了一个专门的分支开发新功能,然后团队中另一个成员在master分支上添加了新的提交。这就会造成提交历史被Fork一份,用Git来协作的开发者应该都很清楚。
|
||||
想象一下,你刚创建了一个专门的分支开发新功能,然后团队中另一个成员在 master 分支上添加了新的提交。这就会造成提交历史被 fork 一份,用 Git 来协作的开发者应该都很清楚。
|
||||
|
||||

|
||||
|
||||
@ -31,7 +31,7 @@ git merge master
|
||||
git merge master feature
|
||||
```
|
||||
|
||||
feature分支中新的合并提交(merge commit)将两个分支的历史连在了一起。你会得到下面这样的分支结构:
|
||||
feature 分支中新的合并提交(merge commit)将两个分支的历史连在了一起。你会得到下面这样的分支结构:
|
||||
|
||||

|
||||
|
||||
@ -54,9 +54,9 @@ git rebase master
|
||||
|
||||

|
||||
|
||||
rebase最大的好处是你的项目历史会非常整洁。首先,它不像`git merge` 那样引入不必要的合并提交。其次,如上图所示,rebase导致最后的项目历史呈现出完美的线性——你可以从项目终点到起点浏览而不需要任何的Fork。这让你更容易使用`git log` 、`git bisect` 和`gitk` 来查看项目历史。
|
||||
rebase最大的好处是你的项目历史会非常整洁。首先,它不像 `git merge` 那样引入不必要的合并提交。其次,如上图所示,rebase 导致最后的项目历史呈现出完美的线性——你可以从项目终点到起点浏览而不需要任何的 fork。这让你更容易使用 `git log`、`git bisect` 和 `gitk` 来查看项目历史。
|
||||
|
||||
不过,这种简单的提交历史会带来两个后果:安全性和可跟踪性。如果你违反了Rebase黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。此外,rebase不会有合并提交中附带的信息——你看不到feature分支中并入了上游的哪些更改。
|
||||
不过,这种简单的提交历史会带来两个后果:安全性和可跟踪性。如果你违反了 rebase 黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。此外,rebase 不会有合并提交中附带的信息——你看不到 feature 分支中并入了上游的哪些更改。
|
||||
|
||||
### 交互式的 rebase
|
||||
|
||||
@ -103,7 +103,7 @@ pick 5c67e61 Message for commit #3
|
||||
|
||||
同步两个 master 分支的唯一办法是把它们 merge 到一起,导致一个额外的合并提交和两堆包含同样更改的提交。不用说,这会让人非常困惑。
|
||||
|
||||
所以,在你运行`git rebase` 之前,一定要问问你自己“有没有别人正在这个分支上工作?”。如果答案是肯定的,那么把你的爪子放回去,重新找到一个无害的方式(如`git revert`)来提交你的更改。不然的话,你可以随心所欲地重写历史。
|
||||
所以,在你运行 `git rebase` 之前,一定要问问你自己「有没有别人正在这个分支上工作?」。如果答案是肯定的,那么把你的爪子放回去,重新找到一个无害的方式(如 `git revert`)来提交你的更改。不然的话,你可以随心所欲地重写历史。
|
||||
|
||||
### 强制推送
|
||||
|
||||
@ -116,7 +116,7 @@ git push --force
|
||||
|
||||
它会重写远程的 master 分支来匹配你仓库中 rebase 之后的 master 分支,对于团队中其他成员来说这看上去很诡异。所以,务必小心这个命令,只有当你知道你在做什么的时候再使用。
|
||||
|
||||
仅有的几个强制推送的使用场景之一是,当你在想向远程仓库推送了一个私有分支之后,执行了一个本地的清理(比如说为了回滚)。这就像是在说“哦,其实我并不想推送之前那个feature分支的。用我现在的版本替换掉吧。”同样,你要注意没有别人正在这个feature分支上工作。
|
||||
仅有的几个强制推送的使用场景之一是,当你在想向远程仓库推送了一个私有分支之后,执行了一个本地的清理(比如说为了回滚)。这就像是在说「哦,其实我并不想推送之前那个 feature 分支的。用我现在的版本替换掉吧。」同样,你要注意没有别人正在这个 feature 分支上工作。
|
||||
|
||||
|
||||
|
||||
@ -132,7 +132,7 @@ rebase可以或多或少应用在你们团队的Git工作流中。在这一节
|
||||
|
||||
在你工作流中使用 rebase 最好的用法之一就是清理本地正在开发的分支。隔一段时间执行一次交互式 rebase,你可以保证你 feature 分支中的每一个提交都是专注和有意义的。你在写代码时不用担心造成孤立的提交——因为你后面一定能修复。
|
||||
|
||||
调用`git rebase` 的时候,你有两个基(base)可以选择:上游分支(比如master)或者你feature分支中早先的一个提交。我们在“交互式rebase”一节看到了第一种的例子。后一种在当你只需要修改最新几次提交时也很有用。比如说,下面的命令对最新的3次提交进行了交互式rebase:
|
||||
调用 `git rebase` 的时候,你有两个基(base)可以选择:上游分支(比如 master)或者你 feature 分支中早先的一个提交。我们在「交互式 rebase」一节看到了第一种的例子。后一种在当你只需要修改最新几次提交时也很有用。比如说,下面的命令对最新的 3 次提交进行了交互式 rebase:
|
||||
|
||||
```
|
||||
git checkout feature
|
||||
@ -163,31 +163,31 @@ git merge-base feature master
|
||||
|
||||
记住,rebase 到远程分支而不是 master 也是完全合法的。当你和另一个开发者在同一个 feature 分之上协作的时候,你会用到这个用法,将他们的更改并入你的项目。
|
||||
|
||||
比如说,如果你和另一个开发者——John——往feature分支上添加了几个提交,在从John的仓库中fetch之后,你的仓库可能会像下面这样:
|
||||
比如说,如果你和另一个开发者 John 往 feature 分支上添加了几个提交,在从 John 的仓库中 fetch 之后,你的仓库可能会像下面这样:
|
||||
|
||||

|
||||
|
||||
就和并入master上的上游更改一样,你可以这样解决这个Fork:要么merge你的本地分支和John的分支,要不把你的本地分支rebase到John的分支后面。
|
||||
就和并入 master 上的上游更改一样,你可以这样解决这个 fork:要么 merge 你的本地分支和 John 的分支,要么把你的本地分支 rebase 到 John 的分支后面。
|
||||
|
||||

|
||||
|
||||
注意,这里的rebase没有违反Rebase黄金法则,因为只有你的本地分支上的commit被移动了,之前的所有东西都没有变。这就像是在说“把我的改动加到John的后面去”。在大多数情况下,这比通过合并提交来同步远程分支更符合直觉。
|
||||
注意,这里的 rebase 没有违反 rebase 黄金法则,因为只有你的本地分支上的 commit 被移动了,之前的所有东西都没有变。这就像是在说「把我的改动加到 John 的后面去」。在大多数情况下,这比通过合并提交来同步远程分支更符合直觉。
|
||||
|
||||
默认情况下,`git pull` 命令会执行一次merge,但你可以传入`--rebase` 来强制它通过rebase来整合远程分支。
|
||||
|
||||
### 用 Pull Request 进行审查
|
||||
|
||||
如果你将pull request作为你代码审查过程中的一环,你需要避免在创建pull request之后使用`git rebase`。只要你发起了pull request,其他开发者能看到你的代码,也就是说这个分支变成了公共分支。重写历史会造成Git和你的同事难以找到这个分支接下来的任何提交。
|
||||
如果你将 Pull Request 作为你代码审查过程中的一环,你需要避免在创建 Pull Request 之后使用 `git rebase`。只要你发起了 Pull Request,其他开发者能看到你的代码,也就是说这个分支变成了公共分支。重写历史会造成 Git 和你的同事难以找到这个分支接下来的任何提交。
|
||||
|
||||
来自其他开发者的任何更改都应该用 `git merge` 而不是 `git rebase` 来并入。
|
||||
|
||||
因此,在提交pull request前用交互式的rebase进行代码清理通常是一个好的做法。
|
||||
因此,在提交 Pull Request前用交互式的 rebase 进行代码清理通常是一个好的做法。
|
||||
|
||||
### 并入通过的功能分支
|
||||
|
||||
如果某个功能被你们团队通过了,你可以选择将这个分支 rebase 到 master 分支之后,或是使用 `git merge` 来将这个功能并入主代码库中。
|
||||
|
||||
这和将上游改动并入feature分支很相似,但是你不可以在master分支重写提交,你最后需要用`git merge` 来并入这个feature。但是,在merge之前执行一次rebase,你可以确保merge是一直向前的,最后生成的是一个完全线性的提交历史。这样你还可以加入pull request之后的提交。
|
||||
这和将上游改动并入 feature 分支很相似,但是你不可以在 master 分支重写提交,你最后需要用 `git merge` 来并入这个 feature。但是,在 merge 之前执行一次 rebase,你可以确保 merge 是一直向前的,最后生成的是一个完全线性的提交历史。这样你还可以加入 Pull Request 之后的提交。
|
||||
|
||||

|
||||
|
||||
@ -210,9 +210,7 @@ git merge temporary-branch
|
||||
|
||||
另一方面,如果你想要保存项目完整的历史,并且避免重写公共分支上的 commit, 你可以使用 `git merge`。两种选项都很好用,但至少你现在多了 `git rebase` 这个选择。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 使用分支
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/using-branches)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/using-branches)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
这份教程是 Git 分支的综合介绍。首先,我们简单讲解如何创建分支,就像请求一份新的项目历史一样。然后,我们会看到 git checkout 是如何切换分支的。最后,学习一下 git merge 是如何整合独立分支的历史。
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
## git branch
|
||||
|
||||
分支代表了一条独立的开发流水线。分支是我们在第二篇中讨论过的“编辑/缓存/提交”流程的抽象。你可以把它看作请求全新“工作目录、缓存区、项目历史”的一种方式。新的提交被存放在当前分支的历史中,导致了项目历史被fork了一份。
|
||||
分支代表了一条独立的开发流水线。分支是我们在第二篇中讨论过的「编辑/缓存/提交」流程的抽象。你可以把它看作请求全新「工作目录、缓存区、项目历史」的一种方式。新的提交被存放在当前分支的历史中,导致了项目历史被 fork 了一份。
|
||||
|
||||
`git branch` 命令允许你创建、列出、重命名和删除分支。它不允许你切换分支或是将被 fork 的历史放回去。因此,`git branch` 和 `git checkout`、`git merge` 这两个命令通常紧密地结合在一起使用。
|
||||
|
||||
@ -32,7 +32,7 @@ git branch <branch>
|
||||
git branch -d <branch>
|
||||
```
|
||||
|
||||
删除指定分支。这是一个“安全”的操作,Git会阻止你删除包含未合并更改的分支。
|
||||
删除指定分支。这是一个安全的操作,Git 会阻止你删除包含未合并更改的分支。
|
||||
|
||||
```
|
||||
git branch -D <branch>
|
||||
@ -50,12 +50,8 @@ git branch -m <branch>
|
||||
|
||||
在 Git 中,分支是你日常开发流程中的一部分。当你想要添加一个新的功能或是修复一个 bug 时——不管 bug 是大是小——你都应该新建一个分支来封装你的修改。这确保了不稳定的代码永远不会被提交到主代码库中,它同时给了你机会,在并入主分支前清理你 feature 分支的历史。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
比如,上图将一个拥有两条独立开发线的仓库可视化,其中一条是一个不起眼的功能,另一条是长期运行的功能。使用分支开发时,不仅可以同时在两条线上工作,还可以保持主要的 `master branch` 混入奇怪的代码。
|
||||
|
||||
#### 分支的顶端
|
||||
@ -70,12 +66,8 @@ Git分支背后的实现远比SVN的模型要轻量。与其在目录之间复
|
||||
|
||||
分支只是指向提交的 *指针* ,理解这一点很重要。当你创建一个分支是,Git 只需要创建一个新的指针——仓库不会受到任何影响。因此,如果你最开始有这样一个仓库:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
接下来你用下面的命令创建了一个分支:
|
||||
|
||||
```
|
||||
@ -84,12 +76,8 @@ git branch crazy-experiment
|
||||
|
||||
仓库历史保持不变。你得到的是一个指向当前提交的新的指针:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
注意,这只会 *创建* 一个新的分支。要开始在上面添加提交,你需要用 `git checkout` 来选中这个分支,然后使用标准的 `git addh` 和 `git commit` 命令。
|
||||
|
||||
#### 删除分支
|
||||
@ -119,7 +107,7 @@ git branch -D crazy-experiment
|
||||
|
||||
`git checkout` 命令允许你切换用 `git branch` 创建的分支。查看一个分支会更新工作目录中的文件,以符合分支中的版本,它还告诉 Git 记录那个分支上的新提交。将它看作一个选中你正在进行的开发的一种方式。
|
||||
|
||||
在上一篇中,我们看到了如何用`git checkout`来查看旧的提交。“查看分支”和“将工作目录更新到选中的版本/修改”很类似;但是,新的更改 *会* 保存在项目历史中——这不是一个只读的操作。
|
||||
在上一篇中,我们看到了如何用 `git checkout` 来查看旧的提交。「查看分支」和「将工作目录更新到选中的版本/修改」很类似;但是,新的更改 *会* 保存在项目历史中——这不是一个只读的操作。
|
||||
|
||||
### 用法
|
||||
|
||||
@ -127,57 +115,45 @@ git branch -D crazy-experiment
|
||||
git checkout <existing-branch>
|
||||
```
|
||||
|
||||
查看特定分支,分支应该已经通过`git branch`创建。这使得<existing-branch>成为当前的分支,并更新工作目录的版本。
|
||||
查看特定分支,分支应该已经通过 `git branch` 创建。这使得 `<existing-branch>` 成为当前的分支,并更新工作目录的版本。
|
||||
|
||||
```
|
||||
git checkout -b <new-branch>
|
||||
```
|
||||
|
||||
创建并查看<new-branch>`-b`选项是一个方便的标记,告诉Git在运行`git checkout <new-branch>`之前运行`git branch <new-branch>`。
|
||||
创建并查看 `<new-branch>`,`-b` 选项是一个方便的标记,告诉Git在运行 `git checkout <new-branch>` 之前运行 `git branch <new-branch>`。
|
||||
|
||||
```
|
||||
git checkout -b <new-branch> <existing-branch>
|
||||
```
|
||||
|
||||
和上一条相同,但将<existing-branch>作为新分支的基,而不是当前分支。
|
||||
和上一条相同,但将 `<existing-branch>` 作为新分支的基,而不是当前分支。
|
||||
|
||||
### 讨论
|
||||
|
||||
`git checkout` 和 `git branch` 是一对好基友。当你想要创建一个新功能时,你用 `git branch` 创建分支,然后用 `git checkout` 查看。你可以在一个仓库中用 `git checkout` 切换分支,同时开发几个功能。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
每个功能专门一个分支对于传统 SVN 工作流来说是一个巨大的转变。这使得尝试新的实验超乎想象的简单,不用担心毁坏已有的功能,并且可以同时开发几个不相关的功能。另外,分支可以促进了不同的协作工作流。
|
||||
|
||||
#### 分离的 `HEAD`
|
||||
|
||||
现在我们已经看到了`git checkout`最主要的三种用法,我们可以讨论上一篇中提到的“分离`HEAD`”状态了。
|
||||
|
||||
记住,`HEAD`是Git指向当前快照的引用。`git checkout`命令内部只是更新`HEAD`,指向特定分支或提交。当它指向分支时,Git不会报错,但当你check out提交时,它会进入“分离`HEAD`”状态。
|
||||
|
||||
现在我们已经看到了 `git checkout` 最主要的三种用法,我们可以讨论上一篇中提到的「分离 `HEAD`」状态了。
|
||||
|
||||
记住,`HEAD` 是 Git 指向当前快照的引用。`git checkout` 命令内部只是更新 `HEAD`,指向特定分支或提交。当它指向分支时,Git 不会报错,但当你 check out 提交时,它会进入「分离 `HEAD`」状态。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
有个警告会告诉你所做的更改和项目的其余历史处于“分离”的状态。如果你在分离`HEAD`状态开始开发新功能,没有分支可以让你回到之前的状态。当你不可避免地checkout到了另一个分支(比如你的更改并入了这个分支),你将不再能够引用你的feature分支:
|
||||
|
||||
|
||||
有个警告会告诉你所做的更改和项目的其余历史处于「分离」的状态。如果你在分离 `HEAD` 状态开始开发新功能,没有分支可以让你回到之前的状态。当你不可避免地 checkout 到了另一个分支(比如你的更改并入了这个分支),你将不再能够引用你的 feature 分支:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
重点是,你应该永远在分支上开发——而绝不在分离的 `HEAD` 上。这样确保你一直可以引用到你的新提交。不过,如果你只是想查看旧的提交,那么是否处于分离 `HEAD` 状态并不重要。
|
||||
|
||||
### 栗子
|
||||
### 例子
|
||||
|
||||
下面的栗子演示了基本的Git分支流程。当你想要开发新功能时,你创建一个专门的分支,切换过去:
|
||||
下面的例子演示了基本的 Git 分支流程。当你想要开发新功能时,你创建一个专门的分支,切换过去:
|
||||
|
||||
```
|
||||
git branch new-feature
|
||||
@ -193,7 +169,7 @@ git commit -m "Started work on a new feature"
|
||||
# 周而复始…
|
||||
```
|
||||
|
||||
这些操作都被记录在`new-feature`上,和`master`完全独立。你想添加多少提交就可以添加多少,不用关心你其它分支的修改。当你想要回到“主”代码库时,只要check out到`master`分支即可:
|
||||
这些操作都被记录在 `new-feature` 上,和 `master` 完全独立。你想添加多少提交就可以添加多少,不用关心你其它分支的修改。当你想要回到「主」代码库时,只要 check out 到 `master` 分支即可:
|
||||
|
||||
```
|
||||
git checkout master
|
||||
@ -227,27 +203,19 @@ git merge --no-ff <branch>
|
||||
|
||||
当当前分支顶端到目标分支路径是线性之时,我们可以采取 **快速向前合并** 。Git 只需要将当前分支顶端(快速向前地)移动到目标分支顶端,即可整合两个分支的历史,而不需要“真正”合并分支。它在效果上合并了历史,因为目标分支上的提交现在在当前分支可以访问到。比如,`some-feature` 到 `master` 分支的快速向前合并会是这样的:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
但是,如果分支已经分叉了,那么就无法进行快速向前合并。当和目标分支之间的路径不是线性之时,Git 只能执行 **三路合并** 。三路合并使用一个专门的提交来合并两个分支的历史。这个术语取自这样一个事实,Git 使用 *三个* 提交来生成合并提交:两个分支顶端和它们共同的祖先。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
但你可以选择使用哪一种合并策略时,很多开发者喜欢使用快速向前合并(搭配 rebase 使用)来合并微小的功能或者修复 bug,使用三路合并来整合长期运行的功能。后者导致的合并提交作为两个分支的连接标志。
|
||||
|
||||
#### 解决冲突
|
||||
|
||||
如果你尝试合并的两个分支同一个文件的同一个部分,Git 将无法决定使用哪个版本。当这种情况发生时,它会停在合并提交,让你手动解决这些冲突。
|
||||
|
||||
Git的合并流程令人称赞的一点是,它使用我们熟悉的“编辑/缓存/提交”工作流来解决冲突。当你遇到合并冲突时,运行`git status`命令来查看哪些文件存在需要解决的冲突。比如,如果两个分支都修改了`hello.py`的同一处,你会看到下面的信息:
|
||||
Git 的合并流程令人称赞的一点是,它使用我们熟悉的「编辑/缓存/提交」工作流来解决冲突。当你遇到合并冲突时,运行 `git status` 命令来查看哪些文件存在需要解决的冲突。比如,如果两个分支都修改了 `hello.py` 的同一处,你会看到下面的信息:
|
||||
|
||||
```
|
||||
# On branch master
|
||||
@ -262,11 +230,11 @@ Git的合并流程令人称赞的一点是,它使用我们熟悉的“编辑/
|
||||
|
||||
注意,提交冲突只会出现在三路合并中。在快速向前合并中,我们不可能出现冲突的更改。
|
||||
|
||||
### 栗子
|
||||
### 例子
|
||||
|
||||
#### 快速向前合并
|
||||
|
||||
我们第一个🌰演示了快速向前合并。下面的代码创建了一个分支,在后面添加了两个提交,然后使用快速向前合并将它并入主分支。
|
||||
我们第一个例子演示了快速向前合并。下面的代码创建了一个分支,在后面添加了两个提交,然后使用快速向前合并将它并入主分支。
|
||||
|
||||
```
|
||||
# 开始新功能
|
||||
@ -292,7 +260,7 @@ git branch -d new-feature
|
||||
|
||||
#### 三路合并
|
||||
|
||||
下一个栗子很相似,但需要进行三路合并,因为`master`在这个功能开发时取得了新进展。这是复杂功能和多个开发者同时工作时常见的情形。
|
||||
下一个例子很相似,但需要进行三路合并,因为 `master` 在这个功能开发时取得了新进展。这是复杂功能和多个开发者同时工作时常见的情形。
|
||||
|
||||
```
|
||||
# 开始新功能
|
||||
@ -322,9 +290,7 @@ git branch -d new-feature
|
||||
|
||||
对大多数工作流来说,`new-feature` 会是一个需要一段时间来开发的复杂功能,这也是为什么同时 `master` 会有新的提交出现。如果你的分支上的功能像上面的一样简单,你会更想将它 rebase 到 `master`,使用快速向前合并。它会通过整理项目历史来避免多余的合并提交。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 保存你的更改
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/saving-changes)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/saving-changes)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
## git add
|
||||
|
||||
@ -36,12 +36,8 @@ git add -p
|
||||
|
||||
在一个只有编辑、缓存、提交这样基本流程的项目上开发。首先,你要在工作目录中编辑你的文件。当你准备备份项目的当前状态时,你通过 `git add` 来缓存更改。当你对缓存的快照满意之后,你通过 `git commit` 将它提交到你的项目历史中去。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
`git add` 命令不能和 `svn add` 混在一起理解,后者将文件添加到仓库中。而 `git add` 发生于更抽象的 *更改* 层面。也就是说,`git add` 在每次你修改一个文件时都需要被调用,而 `svn add` 只需要每个文件调用一次。这听上去很多余,但这样的工作流使得一个项目更容易组织。
|
||||
|
||||
#### 缓存区
|
||||
@ -70,7 +66,7 @@ git commit
|
||||
|
||||
## git commit
|
||||
|
||||
`git commit`命令将缓存的快照提交到项目历史。提交的快照可以认为是项目『安全』的版本——Git永远不会改变它们,除非你这么要求。和`git add`一样,这是最重要的Git命令之一。
|
||||
`git commit`命令将缓存的快照提交到项目历史。提交的快照可以认为是项目安全的版本,Git 永远不会改变它们,除非你这么要求。和 `git add` 一样,这是最重要的 Git 命令之一。
|
||||
|
||||
尽管和它和 `svn commit` 名字一样,但实际上它们毫无关联。快照被提交到本地仓库,不会和其他 Git 仓库有任何交互。
|
||||
|
||||
@ -102,14 +98,10 @@ git commit -a
|
||||
|
||||
#### 记录快照,而不是记录差异
|
||||
|
||||
SVN和Git除了使用上存在巨大差异,它们底层的实现同样遵循截然不同的设计哲学。SVN追踪文件的 *变化* ,而Git的版本控制模型基于 *快照* 。比如说,一个SVN提交由仓库中原文件相比的差异(diff)组成。而Git在每次提交中记录文件的 *完整内容* 。
|
||||
|
||||
|
||||
SVN 和 Git 除了使用上存在巨大差异,它们底层的实现同样遵循截然不同的设计哲学。SVN 追踪文件的 *变化* ,而 Git 的版本控制模型基于 *快照* 。比如说,一个 SVN 提交由仓库中原文件相比的差异(diff)组成。而 Git 在每次提交中记录文件的 *完整内容* 。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
这让很多 Git 操作比 SVN 来的快得多,因为文件的某个版本不需要通过版本间的差异组装得到——每个文件完整的修改能立刻从 Git 的内部数据库中得到。
|
||||
|
||||
Git 的快照模型对它版本控制模型的方方面面都有着深远的影响,从分支到合并工具,再到协作工作流,以至于影响了所有特性。
|
||||
@ -146,11 +138,8 @@ Change the message displayed by hello.py
|
||||
|
||||
注意,很多开发者倾向于在提交信息中使用一般现在时态。这样看起来更像是对仓库进行的操作,让很多改写历史的操作更加符合直觉。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# 保持同步
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> 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))协议共享。
|
||||
> 这是一篇在[原文(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允许你在仓库间共享整个分支,而不是从工作副本提交一个差异集合到中央仓库。
|
||||
SVN 使用唯一的中央仓库作为开发者之间沟通的桥梁,在开发者的工作拷贝和中央仓库之间传递变更集合(changeset),协作得以发生。这和Git的协作模型有所不同,Git 给予每个开发者一份自己的仓库拷贝,拥有自己完整的本地历史和分支结构。用户通常共享一系列的提交而不是单个变更集合。Git 允许你在仓库间共享整个分支,而不是从工作副本提交一个差异集合到中央仓库。
|
||||
|
||||
下面的命令让你管理仓库之间的连接,将分支“推送”到其他仓库来发布本地历史,或是将分支“拉取”到本地仓库来查看其它开发者的贡献。
|
||||
下面的命令让你管理仓库之间的连接,将分支「推送」到其他仓库来发布本地历史,或是将分支「拉取」到本地仓库来查看其它开发者的贡献。
|
||||
|
||||
## git remote
|
||||
|
||||
@ -14,12 +14,8 @@ SVN使用唯一的中央仓库作为开发者之间沟通的桥梁,在开发
|
||||
|
||||
例如,下图显示了你的仓库和中央仓库以及另一个开发者仓库之间的远程连接。你可以向 Git 命令传递 origin 和 john 的别名来引用这些仓库,替代完整的 URL。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 用法
|
||||
|
||||
```
|
||||
@ -38,7 +34,7 @@ git remote -v
|
||||
git remote add <name> <url>
|
||||
```
|
||||
|
||||
创建一个新的远程仓库连接。在添加之后,你可以将<name>作为<url>便捷的别名在其他Git命令中使用。
|
||||
创建一个新的远程仓库连接。在添加之后,你可以将 `<name>` 作为 `<url>` 便捷的别名在其他 Git 命令中使用。
|
||||
|
||||
```
|
||||
git remote rm <name>
|
||||
@ -50,11 +46,11 @@ git remote rm <name>
|
||||
git remote rename <old-name> <new-name>
|
||||
```
|
||||
|
||||
将远程连接从<old-name>重命名为<new-name>。
|
||||
将远程连接从 `<old-name>` 重命名为 `<new-name>`。
|
||||
|
||||
### 讨论
|
||||
|
||||
Git被设计为给每个开发者提供完全隔离的开发环境。也就是说信息并不是自动地在仓库之间传递。开发者需要手动将上游提交拉取到本地,或手动将本地提交推送到中央仓库中去。`git remote`命令正是将URL传递给这些“共享”命令的快捷方式。
|
||||
Git 被设计为给每个开发者提供完全隔离的开发环境。也就是说信息并不是自动地在仓库之间传递。开发者需要手动将上游提交拉取到本地,或手动将本地提交推送到中央仓库中去。`git remote` 命令正是将 URL 传递给这些「共享」命令的快捷方式。
|
||||
|
||||
#### 名为 origin 的远程连接
|
||||
|
||||
@ -188,17 +184,13 @@ git pull --rebase <remote>
|
||||
|
||||
你可以将 `git pull` 当做 Git 中对应 `svn update` 的命令。这是同步你本地仓库和上游更改的简单方式。下图结束了 pull 过程中的每一步。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
你认为你的仓库已经同步了,但 `git fetch` 发现 origin 中 `master` 的版本在上次检查后已经有了新进展。 接着 `git merge` 立即将 `remote master` 并入本地的分支。
|
||||
|
||||
#### 基于 Rebase 的 Pull
|
||||
|
||||
`--rebase`标记可以用来保证线性的项目历史,防止合并提交(merge commits)的产生。很多开发者倾向于使用rebase而不是merge,因为“我想要把我的更改放在其他人完成的工作之后”。这种情况下,使用带有`--rebase`标记的`git pull`甚至更像svn update,与普通的`git pull`相比而言。
|
||||
`--rebase` 标记可以用来保证线性的项目历史,防止合并提交(merge commits)的产生。很多开发者倾向于使用 rebase 而不是 merge,因为「我想要把我的更改放在其他人完成的工作之后」。这种情况下,使用带有 `--rebase` 标记的 `git pull` 甚至更像 svn update,与普通的 `git pull` 相比而言。
|
||||
|
||||
事实上,使用 `--rebase` 的 pull 的工作流是如此普遍,以致于你可以直接在配置项中设置它:
|
||||
|
||||
@ -207,7 +199,7 @@ git config --global branch.autosetuprebase always # In git < 1.7.9
|
||||
git config --global pull.rebase true # In git >= 1.7.9
|
||||
```
|
||||
|
||||
在运行这个命令之后,所有的`git pull`命令将使用`git rebase,`而不是`git merge`。
|
||||
在运行这个命令之后,所有的 `git pull` 命令将使用 `git rebase` 而不是 `git merge`。
|
||||
|
||||
### 栗子
|
||||
|
||||
@ -230,7 +222,7 @@ Push是你将本地仓库中的提交转移到远程仓库中时要做的事。
|
||||
git push <remote> <branch>
|
||||
```
|
||||
|
||||
将指定的分支推送到<remote>上,包括所有需要的提交和提交对象。它会在目标仓库中创建一个本地分支。为了防止你覆盖已有的提交,如果会导致目标仓库非快速向前合并时,Git不允许你push。
|
||||
将指定的分支推送到 `<remote>` 上,包括所有需要的提交和提交对象。它会在目标仓库中创建一个本地分支。为了防止你覆盖已有的提交,如果会导致目标仓库非快速向前合并时,Git 不允许你 push。
|
||||
|
||||
```
|
||||
git push <remote> --force
|
||||
@ -286,9 +278,7 @@ git push origin master
|
||||
|
||||
因为我们已经确信本地的 `master` 分支是最新的,它应该导致快速向前的合并,`git push` 不应该抛出非快速向前之类的问题。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,98 +1,94 @@
|
||||
# 创建Pull Request
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/making-a-pull-request)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/making-a-pull-request)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
>
|
||||
> 原文以Bitbucket为例,考虑到[git-recipes](https://github.com/geeeeeeeeek/git-recipes/)主要面向Github用户,因此栗子替换成了Github。Pull Request在GitLab等平台上也有,用法和本教程基本一致。
|
||||
> 原文以 Bitbucket 为例,考虑到[git-recipes](https://github.com/geeeeeeeeek/git-recipes/)主要面向 GitHub 用户,因此栗子替换成了 GitHub。Pull Request 在 GitLab 等平台上也有,用法和本教程基本一致。
|
||||
|
||||
|
||||
|
||||
Pull request是开发者使用Github进行协作的利器。这个功能为用户提供了友好的页面,让提议的更改在并入官方项目之前,可以得到充分的讨论。
|
||||
Pull Request 是开发者使用 GitHub 进行协作的利器。这个功能为用户提供了友好的页面,让提议的更改在并入官方项目之前,可以得到充分的讨论。
|
||||
|
||||

|
||||
|
||||
最简单地来说,pull request是一种机制,让开发者告诉项目成员一个功能已经完成。一旦feature分支开发完毕,开发者使用Github账号提交一个pull request。它告诉所有参与者,他们需要审查代码,并将代码并入`master`分支。
|
||||
最简单地来说,Pull Request 是一种机制,让开发者告诉项目成员一个功能已经完成。一旦 feature 分支开发完毕,开发者使用 GitHub 账号提交一个 Pull Request。它告诉所有参与者,他们需要审查代码,并将代码并入 `master` 分支。
|
||||
|
||||
但是,pull request不只是一个通知,还是一个专注于某个提议功能的讨论版。 如果更改导致了任何问题,团队成员可以在pull request下发布反馈,甚至推送后续提交来修改这个pull request。所有的活动都在这个pull request里之间追踪。
|
||||
但是,Pull Request 不只是一个通知,还是一个专注于某个提议功能的讨论版。 如果更改导致了任何问题,团队成员可以在 Pull Request 下发布反馈,甚至推送后续提交来修改这个 Pull Request。所有的活动都在这个 Pull Request里之间追踪。
|
||||
|
||||

|
||||

|
||||
|
||||
和其他协作模型相比,这种共享提交的解决方案形成了更加线性的工作流。SVN和Git都能通过一个简单的脚本发送通知邮件;但是,如果要讨论更改,开发者不得不在邮件里回复。这会变得愈发杂乱无章,尤其是后续提交出现时。Pull request将所有这些功能放入了一个友好的网页,在每个Github仓库上方都能找到。
|
||||
和其他协作模型相比,这种共享提交的解决方案形成了更加线性的工作流。SVN 和 Git 都能通过一个简单的脚本发送通知邮件;但是,如果要讨论更改,开发者不得不在邮件里回复。这会变得愈发杂乱无章,尤其是后续提交出现时。Pull Request 将所有这些功能放入了一个友好的网页,在每个 GitHub 仓库上方都能找到。
|
||||
|
||||
### 剖析一个 Pull Request
|
||||
|
||||
当你提交一个pull request的时候,你做的事情是 *请求 (request)* 另一个开发者(比如项目维护者)来 *拉取 (pull)* 你仓库中的一个分支到他们的仓库。也就是说你需要提供4个信息来完成一个pull request:源仓库、源分支、目标仓库、目标分支。
|
||||
当你提交一个 Pull Request 的时候,你做的事情是 *请求(request)* 另一个开发者(比如项目维护者)来 *拉取(pull)* 你仓库中的一个分支到他们的仓库。也就是说你需要提供 4 个信息来完成一个 Pull Request:源仓库、源分支、目标仓库、目标分支。
|
||||
|
||||

|
||||
|
||||
Github会机智地帮你将一些值设为默认值。但是,取决于你的协作工作流,你的团队可能需要设置不同的值。上图显示了一个请求从feature分支合并到官方master分支的一个pull request,但除此之外还有好多种使用pull request的方式。
|
||||
GitHub 会机智地帮你将一些值设为默认值。但是,取决于你的协作工作流,你的团队可能需要设置不同的值。上图显示了一个请求从 feature 分支合并到官方 master分支的一个 Pull Request,但除此之外还有好多种使用 Pull Request 的方式。
|
||||
|
||||
## Pull Request是如何工作的
|
||||
|
||||
Pull request可以和feature分支工作流、Gitflow工作流或者Fork工作流一起使用。但pull request需要两个不同的分支或是两个不同的仓库,因此它们不能和中心化的工作流一起使用。在不同的工作流中使用pull request有些不同,但大致的流程如下:
|
||||
Pull Request 可以和 feature 分支工作流、GitFlow 工作流或者 Fork 工作流一起使用。但 Pull Request 需要两个不同的分支或是两个不同的仓库,因此它们不能和中心化的工作流一起使用。在不同的工作流中使用 Pull Request 有些不同,但大致的流程如下:
|
||||
|
||||
1. 开发者在他们的本地仓库中为某个功能创建一个专门的分支。
|
||||
2. 开发者将分支推送到公共的Github仓库。
|
||||
3. 开发者用Github发起一个pull request。
|
||||
2. 开发者将分支推送到公共的 GitHub 仓库。
|
||||
3. 开发者用 GitHub 发起一个 Pull Request。
|
||||
4. 其余的团队成员审查代码,讨论并且做出修改。
|
||||
5. 项目维护者将这个功能并入官方的仓库,然后关闭这个pull request。
|
||||
5. 项目维护者将这个功能并入官方的仓库,然后关闭这个 Pull Request。
|
||||
|
||||
下面的章节讨论pull request在不同的协作工作流中有哪些不同。
|
||||
下面的章节讨论 Pull Request 在不同的协作工作流中有哪些不同。
|
||||
|
||||
### Feature 分支工作流中的 Pull Request
|
||||
|
||||
Feature分支工作流使用共享的Github仓库来管理协作,开发者在单独的feature分支中添加功能。开发者在将代码并入主代码库之前,应该发起一个pull request来启动这个功能的讨论,而不是直接将它们合并到`master`。
|
||||
Feature 分支工作流使用共享的 GitHub 仓库来管理协作,开发者在单独的 feature 分支中添加功能。开发者在将代码并入主代码库之前,应该发起一个 Pull Request 来启动这个功能的讨论,而不是直接将它们合并到 `master`。
|
||||
|
||||

|
||||
|
||||
在Feature分支工作流中只有一个公共的仓库,因此pull request的目标和源仓库永远是同一个。一般来说,开发者会将他们的feature分支作为源分支,`master`作为目标分支。
|
||||
在 Feature 分支工作流中只有一个公共的仓库,因此 Pull Request 的目标和源仓库永远是同一个。一般来说,开发者会将他们的 feature分支作为源分支,`master` 作为目标分支。
|
||||
|
||||
在收到pull request之后,项目维护者将会做出决定。如果这个功能可以立即发布,他们只需要将代码合并进`master`,然后关闭pull request即可。但是,如果提议的更改有一些问题,他们可以在pull request下发布反馈。后续提交将会显示在相关评论的下方。
|
||||
在收到 Pull Request 之后,项目维护者将会做出决定。如果这个功能可以立即发布,他们只需要将代码合并进 `master`,然后关闭 Pull Request 即可。但是,如果提议的更改有一些问题,他们可以在 Pull Request 下发布反馈。后续提交将会显示在相关评论的下方。
|
||||
|
||||
你也可以发布一个未完成功能的pull request。例如,如果开发者在实现一个特殊的需求时遇到了问题,同样可以发布一个包含工作进展的pull request。其他开发者可以在这个pull request后面提供建议,甚至自己发布后续的提交来解决这个问题。
|
||||
你也可以发布一个未完成功能的 Pull Request。例如,如果开发者在实现一个特殊的需求时遇到了问题,同样可以发布一个包含工作进展的 Pull Request。其他开发者可以在这个 Pull Request 后面提供建议,甚至自己发布后续的提交来解决这个问题。
|
||||
|
||||
### Gitflow工作流中的Pull Request
|
||||
### GitFlow 工作流中的 Pull Request
|
||||
|
||||
Gitflow工作流和Feature分支工作流类似,但定义了围绕项目发布的一个严格的分支模型。在Gitflow工作流之上添加pull request使得开发者方便地讨论发布分支或是所在的维护分支。
|
||||
GitFlow 工作流和 Feature 分支工作流类似,但定义了围绕项目发布的一个严格的分支模型。在 GitFlow 工作流之上添加 Pull Request 使得开发者方便地讨论发布分支或是所在的维护分支。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
在Gitflow工作流中的Pull request和上一节中的完全一致:开发者只需在功能、发布或是快速修复分支需要审查时发布一个pull request,Github会通知到其余的团队成员。
|
||||
在 GitFlow 工作流中的 Pull Request 和上一节中的完全一致:开发者只需在功能、发布或是快速修复分支需要审查时发布一个 Pull Request,GitHub 会通知到其余的团队成员。
|
||||
|
||||
功能一般都会合并到`develop`分支,而发布和快速修复分支会被同时合并到`develop`和`master`当中。 Pull request可以用来妥善管理这些合并。
|
||||
功能一般都会合并到 `develop` 分支,而发布和快速修复分支会被同时合并到 `develop` 和 `master` 当中。 Pull Request 可以用来妥善管理这些合并。
|
||||
|
||||
### Fork 工作流中的 Pull Request
|
||||
|
||||
在Fork工作流中,开发者将一个完成的功能推送到 *他们自己的* 仓库,而不是公共的仓库。在这之后,他们发布一个pull request,告诉项目维护者代码需要审查了。
|
||||
在 Fork 工作流中,开发者将一个完成的功能推送到 *他们自己的* 仓库,而不是公共的仓库。在这之后,他们发布一个 Pull Request,告诉项目维护者代码需要审查了。
|
||||
|
||||
在这个工作流中,pull request的通知作用显得非常有用,因为项目维护者无法获知其他开发者什么时候向他们自己的Github仓库中添加了提交。
|
||||
在这个工作流中,Pull Request 的通知作用显得非常有用,因为项目维护者无法获知其他开发者什么时候向他们自己的 GitHub 仓库中添加了提交。
|
||||
|
||||

|
||||
|
||||
因为每个开发者都有他们自己的公共仓库,pull request的源仓库和目标仓库不是同一个。源仓库是开发者的公开仓库,源分支是包含提议更改的那一个。如果开发者想要将功能合并到主代码库,目标仓库便是官方的项目仓库,目标分支为`master`。
|
||||
因为每个开发者都有他们自己的公共仓库,Pull Request 的源仓库和目标仓库不是同一个。源仓库是开发者的公开仓库,源分支是包含提议更改的那一个。如果开发者想要将功能合并到主代码库,目标仓库便是官方的项目仓库,目标分支为 `master`。
|
||||
|
||||
Pull request还可以用来和官方项目之外的开发者进行协作。比如说,一个开发者正在和同事一起开发一个功能,他们可以向 *同事的* Github仓库发起一个pull request,而不是官方仓库。他们将feature分支同时作为源分支和目标分支。
|
||||
Pull Request 还可以用来和官方项目之外的开发者进行协作。比如说,一个开发者正在和同事一起开发一个功能,他们可以向 *同事的* GitHub 仓库发起一个 Pull Request,而不是官方仓库。他们将 feature 分支同时作为源分支和目标分支。
|
||||
|
||||

|
||||
|
||||
两个开发者可以在pull request中讨论和开发分支。当功能完成时,其中一位可以发起另一个pull request,请求将功能合并到官方的master分支中去。这种灵活性使得pull request成为了Fork工作流中尤为强大的协作工具。
|
||||
两个开发者可以在 Pull Request 中讨论和开发分支。当功能完成时,其中一位可以发起另一个 Pull Request,请求将功能合并到官方的 master 分支中去。这种灵活性使得 Pull Request 成为了 Fork 工作流中尤为强大的协作工具。
|
||||
|
||||
## 栗子
|
||||
|
||||
下面的🌰演示了如何将pull request用在Fork工作流中。小团队中的开发和向一个开源项目贡献代码都可以这样做。
|
||||
下面的🌰演示了如何将 Pull Request 用在 Fork 工作流中。小团队中的开发和向一个开源项目贡献代码都可以这样做。
|
||||
|
||||
在这个栗子中,Mary是一位开发者,John是项目的维护者。他们都有自己公开的Github仓库,John的仓库之一便是下面的官方项目。
|
||||
在这个栗子中,Mary 是一位开发者,John 是项目的维护者。他们都有自己公开的 GitHub 仓库,John 的仓库之一便是下面的官方项目。
|
||||
|
||||
### Mary fork了官方项目
|
||||
|
||||

|
||||
|
||||
为了参与这个项目,Mary首先要做的是fork John的Github仓库。她需要注册登录Github,找到John的仓库,点击Fork按钮。
|
||||
为了参与这个项目,Mary 首先要做的是 fork 属于 John 的 GitHub 仓库。她需要注册登录 GitHub,找到 John 的仓库,点击 Fork 按钮。
|
||||
|
||||
> 下图显示的是 geeeeeeeeek 的 WeChatLuckyMoney 仓库。
|
||||
|
||||
@ -100,23 +96,23 @@ Pull request还可以用来和官方项目之外的开发者进行协作。比
|
||||
|
||||
选好 fork 的目标位置之后,她在服务端就有了一个项目的副本。
|
||||
|
||||
### Mary克隆了她的Github仓库
|
||||
### Mary 克隆了她的 GitHub 仓库
|
||||
|
||||

|
||||
|
||||
接下来,Mary需要将她刚刚fork的Github仓库克隆下来。她在本地会有一份项目的副本。她需要运行下面这个命令:
|
||||
接下来,Mary 需要将她刚刚 fork 的 GitHub 仓库克隆下来。她在本地会有一份项目的副本。她需要运行下面这个命令:
|
||||
|
||||
```
|
||||
git clone https://github.com/user/repo.git
|
||||
```
|
||||
|
||||
请记住,`git clone`自动创建了一个名为`origin`的远端连接,指向Mary fork的仓库。
|
||||
请记住,`git clone` 自动创建了一个名为 `origin` 的远端连接,指向 Mary 所 fork 的仓库。
|
||||
|
||||
### Mary 开发了一个新功能
|
||||
|
||||

|
||||
|
||||
在她写任何代码之前,Mary需要为这个功能创建一个新的分支。这个分支将是她随后发起pull request时要用到的源分支。
|
||||
在她写任何代码之前,Mary 需要为这个功能创建一个新的分支。这个分支将是她随后发起 Pull Request 时要用到的源分支。
|
||||
|
||||
```
|
||||
git checkout -b some-feature
|
||||
@ -124,13 +120,13 @@ git checkout -b some-feature
|
||||
git commit -a -m "新功能的一些草稿"
|
||||
```
|
||||
|
||||
为了完成这个新功能,Mary想创建多少个提交都可以。如果feature分支的历史有些乱,她可以使用交互式的rebase来移除或者拼接不必要的提交。对于大项目来说,清理feature的项目历史使得项目维护者更容易看清楚pull request的所处的进展。
|
||||
为了完成这个新功能,Mary 想创建多少个提交都可以。如果 feature 分支的历史有些乱,她可以使用交互式的 rebase 来移除或者拼接不必要的提交。对于大项目来说,清理 feature 的项目历史使得项目维护者更容易看清楚 Pull Request 的所处的进展。
|
||||
|
||||
### Mary将feature分支推送到了她的Github仓库
|
||||
### Mary将feature分支推送到了她的GitHub仓库
|
||||
|
||||

|
||||
|
||||
在功能完成后,Mary使用简单的`git push`将feature分支推送到了她自己的Github仓库上(不是官方的仓库):
|
||||
在功能完成后,Mary 使用简单的 `git push` 将 feature 分支推送到了她自己的 GitHub 仓库上(不是官方的仓库):
|
||||
|
||||
```
|
||||
git push origin some-branch
|
||||
@ -138,51 +134,49 @@ git push origin some-branch
|
||||
|
||||
这样她的更改就可以被项目维护者看到了(或者任何有权限的协作者)。
|
||||
|
||||
### Mary创建了一个pull request
|
||||
### Mary创建了一个Pull Request
|
||||
|
||||

|
||||
|
||||
Github上已经有了她的feature分支之后,Mary可以找到被她fork的仓库,点击项目简介下的 *New Pull request* 按钮,用她的Github账号创建一个pull request。Mary的仓库会被默认设置为源仓库(head fork),询问她指定源分支(compare)、目标仓库(base fork)和目标分支(base)。
|
||||
GitHub 上已经有了她的 feature 分支之后,Mary 可以找到被她 fork 的仓库,点击项目简介下的 *New Pull Request* 按钮,用她的 GitHub 账号创建一个 Pull Request。Mary 的仓库会被默认设置为源仓库(head fork),询问她指定源分支(compare)、目标仓库(base fork)和目标分支(base)。
|
||||
|
||||
Mary想要将她的功能并入主代码库,所以源分支就是她的feature分支,目标仓库就是John的公开仓库,目标分支为`master`。她还需要提供一个pull request的标题和简介。
|
||||
Mary 想要将她的功能并入主代码库,所以源分支就是她的 feature 分支,目标仓库就是 John 的公开仓库,目标分支为 `master`。她还需要提供一个 Pull Request 的标题和简介。
|
||||
|
||||
> 下图展示的是将0492wzl/WeChatLuckyMoney(源仓库)的stable(源分支)合并到geeeeeeeeek/WeChatLuckyMoney(目标仓库)的stable(目标分支)。
|
||||
|
||||

|
||||
|
||||
在她创建了pull request之后,Github会给John发送一条通知。
|
||||
在她创建了 Pull Request 之后,GitHub 会给 John 发送一条通知。
|
||||
|
||||
### John审查了这个pull request
|
||||
### John审查了这个Pull Request
|
||||
|
||||

|
||||
|
||||
John可以在他自己的Github仓库下的 *Pull Request* 选项卡中看到所有的pull request。点击Mary的pull request会显示这个pull request的简介、feature分支的提交历史,以及包含的更改。
|
||||
John 可以在他自己的 GitHub 仓库下的 *Pull Request* 选项卡中看到所有的 Pull Request。点击 Mary 的 Pull Request 会显示这个 Pull Request 的简介、feature 分支的提交历史,以及包含的更改。
|
||||
|
||||
如果他认为feature分支已经可以合并了,他只需点击*Merge Pull Request*按钮来通过这个pull request,将Mary的feature分支并入他的`master`分支。
|
||||
如果他认为 feature 分支已经可以合并了,他只需点击 *Merge Pull Request* 按钮来通过这个 Pull Request,将 Mary 的 feature分支并入他的 `master` 分支。
|
||||
|
||||
但是,在这里栗子中,假设John发现了Mary代码中的一个小bug,需要她在合并前修复。他可以评论整个pull request,也可以评论feature分支中某个特定的提交。
|
||||
但是,在这里栗子中,假设 John 发现了 Mary 代码中的一个小 bug,需要她在合并前修复。他可以评论整个 Pull Request,也可以评论 feature 分支中某个特定的提交。
|
||||
|
||||

|
||||
|
||||
### Mary 添加了一个后续提交
|
||||
|
||||
如果Mary对这个反馈感到困惑,她可以在pull request后回复,把这里当做是她的功能的讨论版。
|
||||
如果 Mary 对这个反馈感到困惑,她可以在 Pull Request 后回复,把这里当做是她的功能的讨论版。
|
||||
|
||||
为了修复错误,Mary在她的feature分支后面添加了另一个提交,并将它推送到了她的Github仓库,就像她之前做的一样。这个提交被自动添加到原来的pull request后面,John可以在他的评论下方再次审查这些修改。
|
||||
为了修复错误,Mary 在她的 feature 分支后面添加了另一个提交,并将它推送到了她的 GitHub 仓库,就像她之前做的一样。这个提交被自动添加到原来的 Pull Request 后面,John 可以在他的评论下方再次审查这些修改。
|
||||
|
||||
### John接受了pull request
|
||||
### John 接受了 Pull Request
|
||||
|
||||
最后,John接受了这些修改,将feature分支并入了master分支,关闭了这个pull request。功能现在已经整合到了项目中,其他在master分支上工作的开发者可以使用标准的`git pull`命令将这些修改拉取到自己的本地仓库。
|
||||
最后,John 接受了这些修改,将 feature 分支并入了 master 分支,关闭了这个 Pull Request。功能现在已经整合到了项目中,其他在 master 分支上工作的开发者可以使用标准的 `git pull` 命令将这些修改拉取到自己的本地仓库。
|
||||
|
||||
> 如果你希望实践一下,可以按照上面的流程向这个项目发起一个pull request,修改任何你发现的错误:smile:
|
||||
> 如果你希望实践一下,可以按照上面的流程向这个项目发起一个 Pull Request,修改任何你发现的错误 :smile:
|
||||
|
||||
## 接下来怎么做?
|
||||
|
||||
你现在应该已经掌握了如何将你的pull request整合到你的工作流。记住,pull request不是替代任何Git工作流的万金油,而是一种让队员间协作锦上添花的工具。
|
||||
你现在应该已经掌握了如何将你的 Pull Request 整合到你的工作流。记住,Pull Request 不是替代任何 Git 工作流的万金油,而是一种让队员间协作锦上添花的工具。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -4,14 +4,10 @@
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/setting-up-a-repository)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
|
||||
|
||||
这一章简要地带你了解一些最重要的 Git 命令。在这节中,我会向你介绍开始一个新的版本控制项目需要的所有工具,后面的几节包含了你每天都会用到的Git操作。
|
||||
|
||||
在这节之后,你应该能够创建一个新的 Git 仓库,缓存你的项目以免丢失,以及查看你项目的历史。
|
||||
|
||||
|
||||
|
||||
## git init
|
||||
|
||||
`git init` 命令创建一个新的 Git 仓库。它用来将已存在但还没有版本控制的项目转换成一个 Git 仓库,或者创建一个空的新仓库。大多数Git命令在未初始化的仓库中都是无法使用的,所以这就是你运行新项目的第一个命令了。
|
||||
@ -24,13 +20,13 @@
|
||||
git init
|
||||
```
|
||||
|
||||
将当前的目录转换成一个Git仓库。它在当前的目录下增加了一个`.git`文件夹,于是就可以开始记录项目版本了。
|
||||
将当前的目录转换成一个 Git 仓库。它在当前的目录下增加了一个 `.git` 目录,于是就可以开始记录项目版本了。
|
||||
|
||||
``` shell
|
||||
git init <directory>
|
||||
```
|
||||
|
||||
在指定目录创建一个空的Git仓库。运行这个命令会创建一个名为`directory`,只包含`.git`子目录的空文件夹。
|
||||
在指定目录创建一个空的 Git 仓库。运行这个命令会创建一个名为 `directory`,只包含 `.git` 子目录的空目录。
|
||||
|
||||
``` shell
|
||||
git init --bare <directory>
|
||||
@ -46,7 +42,7 @@ git init --bare <directory>
|
||||
|
||||
#### 裸仓库
|
||||
|
||||
`—bare`标记创建了一个没有工作目录的仓库,这样我们在仓库中更改文件并且提交了。中央仓库应该总是创建成裸仓库,因为向非裸仓库推送分支有可能会覆盖已有的代码变动。将`—bare`看成是用来将仓库标记为储存设施,而不是一个开发环境。也就是说,对于所有的Git工作流,中央仓库是裸仓库,开发者的本地仓库是非裸仓库。
|
||||
`-—bare` 标记创建了一个没有工作目录的仓库,这样我们在仓库中更改文件并且提交了。中央仓库应该总是创建成裸仓库,因为向非裸仓库推送分支有可能会覆盖已有的代码变动。将`-—bare`看成是用来将仓库标记为储存设施,而不是一个开发环境。也就是说,对于所有的 Git 工作流,中央仓库是裸仓库,开发者的本地仓库是非裸仓库。
|
||||
|
||||

|
||||
|
||||
@ -62,13 +58,11 @@ cd path/above/repo
|
||||
git init --bare my-project.git
|
||||
```
|
||||
|
||||
首先,你用SSH连入存放中央仓库的服务器。然后,来到任何你想存放项目的地方,最后,使用`—bare`标记来创建一个中央存储仓库。开发者会将`my-project.git` 克隆到本地的开发环境中。
|
||||
|
||||
|
||||
首先,你用SSH连入存放中央仓库的服务器。然后,来到任何你想存放项目的地方,最后,使用 `-—bare` 标记来创建一个中央存储仓库。开发者会将 `my-project.git` 克隆到本地的开发环境中。
|
||||
|
||||
## git clone
|
||||
|
||||
`git clone`命令拷贝整个Git仓库。这个命令就像`svn checkout`一样,除了”工作副本“是一个完备的Git仓库——它包含自己的历史,管理自己的文件,以及环境和原仓库完全隔离。
|
||||
`git clone` 命令拷贝整个 Git 仓库。这个命令就像 `svn checkout` 一样,除了「工作副本」是一个完备的Git仓库——它包含自己的历史,管理自己的文件,以及环境和原仓库完全隔离。
|
||||
|
||||
为了方便起见,`clone` 自动创建了一个名为 `origin` 的远程连接,指向原有仓库。这让和中央仓库之间的交互更加简单。
|
||||
|
||||
@ -84,7 +78,7 @@ git clone <repo>
|
||||
git clone <repo> <directory>
|
||||
```
|
||||
|
||||
将位于`<repo>`的仓库克隆到本地机器上的`<directory>`文件夹。
|
||||
将位于 `<repo>` 的仓库克隆到本地机器上的 `<directory>` 目录。
|
||||
|
||||
### 讨论
|
||||
|
||||
@ -92,7 +86,7 @@ git clone <repo> <directory>
|
||||
|
||||
#### 仓库间协作
|
||||
|
||||
这一点很重要,你要理解Git中”工作副本“的概念和SVN仓库check out下来的”工作副本“是很不一样的。和SVN不同的是,Git不会区分工作副本和中央仓库——它们都是功能完备的Git仓库。
|
||||
这一点很重要,你要理解 Git 中「工作副本」的概念和 SVN 仓库 check out 下来的「工作副本」是很不一样的。和 SVN 不同的是,Git 不会区分工作副本和中央仓库——它们都是功能完备的 Git 仓库。
|
||||
|
||||
这就似的 Git 的协作和 SVN 截然不同。SVN 依赖于中央仓库和工作副本之间的关系,而 Git 协作模型是基于仓库和仓库之间的交互的。相对于 SVN 的提交流程,你可以在 Git 仓库之间 `push` 或 `pull` 提交。
|
||||
|
||||
@ -114,7 +108,7 @@ cd my-project
|
||||
# 开始工作
|
||||
```
|
||||
|
||||
第一行命令在本地机器的`my-project`文件夹下初始化了一个新的Git仓库,并且导入了中央仓库中的文件。接下来,你`cd`到项目目录,开始编辑文件、缓存提交、和其它仓库交互。同时注意`.git`拓展名克隆时会被去除。它表明了本地副本的非裸状态。
|
||||
第一行命令在本地机器的 `my-project` 目录下初始化了一个新的 Git 仓库,并且导入了中央仓库中的文件。接下来,你 `cd` 到项目目录,开始编辑文件、缓存提交、和其它仓库交互。同时注意 `.git` 拓展名克隆时会被去除。它表明了本地副本的非裸状态。
|
||||
|
||||
``` shell
|
||||
git config
|
||||
@ -232,11 +226,8 @@ git config --global alias.ci commit
|
||||
|
||||
它会生成上一节中所说的 `~/.gitconfig` 文件。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 代码回滚:Reset、Checkout、Revert 的选择
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
`git reset`、`git checkout` 和 `git revert` 是你的 Git 工具箱中最有用的一些命令。它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文件。
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Git 仓库有三个主要组成——工作目录,缓存区和提交历史。这张图有助于理解每个命令到底产生了哪些影响。当你阅读的时候,牢记这张图。
|
||||
|
||||
## 提交层面的操作
|
||||
@ -31,7 +29,7 @@ hotfix分支末端的两个提交现在变成了悬挂提交。也就是说,
|
||||
|
||||

|
||||
|
||||
如果你的更改还没有共享给别人,`git reset`是撤销这些更改的简单方法。当你开发一个功能的时候发现『糟糕,我做了什么?我应该重新来过!』时,reset就像是go-to命令一样。
|
||||
如果你的更改还没有共享给别人,`git reset` 是撤销这些更改的简单方法。当你开发一个功能的时候发现「糟糕,我做了什么?我应该重新来过!」时,reset 就像是 go-to 命令一样。
|
||||
|
||||
除了在当前分支上操作,你还可以通过传入这些标记来修改你的缓存区或工作目录:
|
||||
|
||||
@ -45,7 +43,7 @@ hotfix分支末端的两个提交现在变成了悬挂提交。也就是说,
|
||||
|
||||
这些标记往往和 HEAD 作为参数一起使用。比如,`git reset --mixed HEAD` 将你当前的改动从缓存区中移除,但是这些改动还留在工作目录中。另一方面,如果你想完全舍弃你没有提交的改动,你可以使用 `git reset --hard HEAD`。这是 `git reset` 最常用的两种用法。
|
||||
|
||||
当你传入HEAD以外的其他提交的时候要格外小心,因为reset操作会重写当前分支的历史。正如Rebase黄金法则所说的,在公共分支上这样做可能会引起严重的后果。
|
||||
当你传入 HEAD 以外的其他提交的时候要格外小心,因为 reset 操作会重写当前分支的历史。正如 rebase 黄金法则所说的,在公共分支上这样做可能会引起严重的后果。
|
||||
|
||||
### Checkout
|
||||
|
||||
@ -94,19 +92,17 @@ git revert HEAD~2
|
||||
|
||||
### Reset
|
||||
|
||||
当检测到文件路径时,`git reset` 将缓存区同步到你指定的那个提交。比如,下面这个命令会将倒数第二个提交中的foo.py加入到缓存区中,供下一个提交使用。
|
||||
当检测到文件路径时,`git reset` 将缓存区同步到你指定的那个提交。比如,下面这个命令会将倒数第二个提交中的 `foo.py` 加入到缓存区中,供下一个提交使用。
|
||||
|
||||
```
|
||||
git reset HEAD~2 foo.py
|
||||
```
|
||||
|
||||
和提交层面的`git reset`一样,通常我们使用HEAD而不是某个特定的提交。运行`git reset HEAD foo.py` 会将当前的foo.py从缓存区中移除出去,而不会影响工作目录中对foo.py的更改。
|
||||
和提交层面的 `git reset` 一样,通常我们使用HEAD而不是某个特定的提交。运行 `git reset HEAD foo.py` 会将当前的 `foo.py` 从缓存区中移除出去,而不会影响工作目录中对 `foo.py` 的更改。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
--soft、--mixed和--hard对文件层面的`git reset`毫无作用,因为缓存区中的文件一定会变化,而工作目录中的文件一定不变。
|
||||
`--soft`、`--mixed` 和 `--hard` 对文件层面的 `git reset` 毫无作用,因为缓存区中的文件一定会变化,而工作目录中的文件一定不变。
|
||||
|
||||
### Checkout
|
||||
|
||||
@ -114,7 +110,7 @@ Checkout一个文件和带文件路径`git reset` 非常像,除了它更改的
|
||||
|
||||

|
||||
|
||||
比如,下面这个命令将工作目录中的foo.py同步到了倒数第二个提交中的foo.py。
|
||||
比如,下面这个命令将工作目录中的 `foo.py` 同步到了倒数第二个提交中的 `foo.py`。
|
||||
|
||||
```
|
||||
git checkout HEAD~2 foo.py
|
||||
@ -124,16 +120,16 @@ git checkout HEAD~2 foo.py
|
||||
|
||||
如果你缓存并且提交了 checkout 的文件,它具备将某个文件回撤到之前版本的效果。注意它撤销了这个文件后面所有的更改,而 `git revert` 命令只撤销某个特定提交的更改。
|
||||
|
||||
和`git reset` 一样,这个命令通常和HEAD一起使用。比如`git checkout HEAD foo.py`等同于舍弃foo.py没有缓存的更改。这个行为和`git reset HEAD --hard`很像,但只影响特定文件。
|
||||
和 `git reset` 一样,这个命令通常和 HEAD 一起使用。比如 `git checkout HEAD foo.py` 等同于舍弃 `foo.py` 没有缓存的更改。这个行为和 `git reset HEAD --hard` 很像,但只影响特定文件。
|
||||
|
||||
## 总结
|
||||
|
||||
你现在已经掌握了Git仓库中撤销更改的所有工具。`git reset`、`git checkout`、和 `git revert`命令比较容易混淆,但当你想起它们对工作目录、缓存区和提交历史的不同影响,就会容易判断现在应该用哪个命令。
|
||||
你现在已经掌握了 Git 仓库中撤销更改的所有工具。`git reset`、`git checkout` 和 `git revert` 命令比较容易混淆,但当你想起它们对工作目录、缓存区和提交历史的不同影响,就会容易判断现在应该用哪个命令。
|
||||
|
||||
下面这个表格总结了这些命令最常用的使用场景。记得经常对照这个表格,因为你使用 Git 时一定会经常用到。
|
||||
|
||||
| 命令 | 作用域 | 常用情景 |
|
||||
| :----------: | :--: | :---------------- |
|
||||
| :-: | :-: | :- |
|
||||
| git reset | 提交层面 | 在私有分支上舍弃一些没有提交的更改 |
|
||||
| git reset | 文件层面 | 将文件从缓存区中移除 |
|
||||
| git checkout | 提交层面 | 切换分支或查看旧版本 |
|
||||
@ -141,7 +137,7 @@ git checkout HEAD~2 foo.py
|
||||
| git revert | 提交层面 | 在公共分支上回滚更改 |
|
||||
| git revert | 文件层面 | (然而并没有) |
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,25 +1,21 @@
|
||||
## 回滚错误的修改
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/undoing-changes)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/undoing-changes)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
这章教程提供了和项目旧版本打交道所需要的所有技巧。首先,你会知道如何浏览旧的提交,然后了解回滚项目历史中的公有提交和回滚本地机器上的私有更改之间的区别。
|
||||
|
||||
## git checkout
|
||||
|
||||
见上一章[『2.5 检出之前的提交』](https://github.com/geeeeeeeeek/git-recipes/wiki/2.5-%E6%A3%80%E5%87%BA%E4%B9%8B%E5%89%8D%E7%9A%84%E6%8F%90%E4%BA%A4)。
|
||||
见上一章[「2.5 检出之前的提交」](https://github.com/geeeeeeeeek/git-recipes/wiki/2.5-%E6%A3%80%E5%87%BA%E4%B9%8B%E5%89%8D%E7%9A%84%E6%8F%90%E4%BA%A4)。
|
||||
|
||||
## git revert
|
||||
|
||||
`git revert` 命令用来撤销一个已经提交的快照。但是,它是通过搞清楚如何撤销这个提交引入的更改,然后在最后加上一个撤销了更改的 *新* 提交,而不是从项目历史中移除这个提交。这避免了Git丢失项目历史,这一点对于你的版本历史和协作的可靠性来说是很重要的。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 用法
|
||||
|
||||
```
|
||||
@ -30,13 +26,11 @@ git revert <commit>
|
||||
|
||||
### 讨论
|
||||
|
||||
撤销(revert)应该用在你想要在项目历史中移除一整个提交的时候。比如说,你在追踪一个bug,然后你发现它是由一个提交造成的,这时候撤销就很有用。与其说自己去修复它,然后提交一个新的快照,不如用`git revert`,它帮你做了所有的事情。
|
||||
|
||||
#### 撤销(revert)和重设(reset)对比
|
||||
|
||||
理解这一点很重要——`git revert`回滚了『单独一个提交』——它没有移除后面的提交,然后回到项目之前的状态。在Git中,后者实际上被称为`reset`,而不是`revert`。
|
||||
撤销(revert)应该用在你想要在项目历史中移除一整个提交的时候。比如说,你在追踪一个 bug,然后你发现它是由一个提交造成的,这时候撤销就很有用。与其说自己去修复它,然后提交一个新的快照,不如用 `git revert`,它帮你做了所有的事情。
|
||||
|
||||
#### 撤销(revert)和重设(reset)对比
|
||||
|
||||
理解这一点很重要。`git revert` 回滚了「单独一个提交」,它没有移除后面的提交,然后回到项目之前的状态。在 Git 中,后者实际上被称为 `reset`,而不是 `revert`。
|
||||
|
||||

|
||||
|
||||
@ -60,12 +54,8 @@ git revert HEAD
|
||||
|
||||
这个操作可以用下图可视化:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
注意第四个提交在撤销后依然在项目历史中。`git revert` 在后面增加了一个提交来撤销修改,而不是删除它。 因此,第三和第五个提交表示同样的代码,而第四个提交依然在历史中,以备以后我们想要回到这个提交。
|
||||
|
||||
## git reset
|
||||
@ -112,27 +102,19 @@ git reset --hard <commit>
|
||||
|
||||
撤销(revert)被设计为撤销 *公开* 的提交的安全方式,`git reset`被设计为重设 *本地* 更改。因为两个命令的目的不同,它们的实现也不一样:重设完全地移除了一堆更改,而撤销保留了原来的更改,用一个新的提交来实现撤销。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### 不要重设公共历史
|
||||
|
||||
当有 `<commit>` 之后的提交被推送到公共仓库后,你绝不应该使用 `git reset`。发布一个提交之后,你必须假设其他开发者会依赖于它。
|
||||
|
||||
移除一个其他团队成员在上面继续开发的提交在协作时会引发严重的问题。当他们试着和你的仓库同步时,他们会发现项目历史的一部分突然消失了。下面的序列展示了如果你尝试重设公共提交时会发生什么。`origin/master` 是你本地 `master` 分支对应的中央仓库中的分支。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
一旦你在重设之后又增加了新的提交,Git 会认为你的本地历史已经和 `origin/master` 分叉了,同步你的仓库时的合并提交(merge commit)会使你的同事困惑。
|
||||
|
||||
|
||||
一旦你在重设之后又增加了新的提交,Git会认为你的本地历史已经和`origin/master`分叉了,同步你的仓库时的合并提交(merge commit)会使你的同事困惑。
|
||||
|
||||
重点是,确保你只对本地的修改使用`git reset`——而不是公共更改。如果你需要修复一个公共提交,`git revert`命令正是被设计来做这个的。
|
||||
重点是,确保你只对本地的修改使用 `git reset`,而不是公共更改。如果你需要修复一个公共提交,`git revert` 命令正是被设计来做这个的。
|
||||
|
||||
### 栗子
|
||||
|
||||
@ -202,7 +184,7 @@ git clean -n
|
||||
git clean -f
|
||||
```
|
||||
|
||||
移除当前目录下未被跟踪的文件。`-f`(强制)标记是必需的,除非`clean.requireForce`配置项被设为了`false` (默认为`true`)。它 *不会* 删除 `.gitignore`中指定的未跟踪的文件。
|
||||
移除当前目录下未被跟踪的文件。`-f`(强制)标记是必需的,除非 `clean.requireForce` 配置项被设为了 `false`(默认为 `true`)。它 *不会* 删除 `.gitignore` 中指定的未跟踪的文件。
|
||||
|
||||
```
|
||||
git clean -f <path>
|
||||
@ -250,11 +232,8 @@ git clean -df
|
||||
|
||||
注意,不像 `git reset` 的第二个栗子,新的文件没有被加入到仓库中。因此,它们不会受到 `git reset --hard` 的影响,需要 `git clean` 来删除它们。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 常见工作流比较
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/comparing-workflows)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/comparing-workflows)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
多种多样的工作流使得在项目中实施 Git 时变得难以选择。这份教程提供了一个出发点,调查企业团队最常见的 Git 工作流。
|
||||
|
||||
@ -17,12 +17,8 @@
|
||||
|
||||
## 中心化的工作流
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
过渡到分布式分版本控制系统看起来是个令人恐惧的任务,但你不必为了利用 Git 的优点而改变你现有的工作流。你的团队仍然可以用以前SVN的方式开发项目。
|
||||
|
||||
然而,使用 Git 来驱动你的开发工作流显示出了一些SVN没有的优点。首先,它让每个开发者都有了自己 *本地* 的完整项目副本。隔离的环境使得每个开发者的工作独立于项目的其它修改——他们可以在自己的本地仓库中添加提交,完全无视上游的开发,直到需要的时候。
|
||||
@ -35,25 +31,17 @@
|
||||
|
||||
开发者将中央仓库克隆到本地后开始工作。在他们的本地项目副本中,他们可以像SVN一样修改文件和提交更改;不过,这些新的提交被保存在 *本地* ——它们和中央仓库完全隔离。这使得开发者可以将和上游的同步推迟到他们方便的时候。
|
||||
|
||||
为了向官方项目发布修改,开发者将他们的本地`master`分支“推送”到中央仓库。这一步等同于`svn commit`,除了Git添加的是所有不在中央`master`分支上的本地提交。
|
||||
|
||||
|
||||
为了向官方项目发布修改,开发者将他们的本地 `master` 分支「推送」到中央仓库。这一步等同于 `svn commit`,除了Git添加的是所有不在中央 `master` 分支上的本地提交。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 管理冲突
|
||||
|
||||
中央仓库代表官方项目,因此它的提交历史应该被视作神圣不可更改的。如果开发者的本地提交和中央仓库分叉了,Git 会拒绝将他们的修改推送上去,因为这会覆盖官方提交。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在开发者发布他们的功能之前,他们需要fetch更新的中央提交,在它们之上rebase自己的更改。这就像是:“我想要在其他人的工作进展之上添加我的修改。”它会产生完美的线性历史,就像和传统的SVN工作流一样。
|
||||
在开发者发布他们的功能之前,他们需要 fetch 更新的中央提交,在它们之上 rebase 自己的更改。这就像是「我想要在其他人的工作进展之上添加我的修改」,它会产生完美的线性历史,就像和传统的 SVN 工作流一样。
|
||||
|
||||
如果本地修改和上游提交冲突时,Git 会暂停 rebase 流程,给你机会手动解决这些冲突。Git 很赞的一点是,它将 [`git status`](https://github.com/geeeeeeeeek/git-recipes/wiki/2.4-%E6%A3%80%E6%9F%A5%E4%BB%93%E5%BA%93%E7%8A%B6%E6%80%81#git-status) 和 [`git add`](https://github.com/geeeeeeeeek/git-recipes/wiki/2.3-%E4%BF%9D%E5%AD%98%E4%BD%A0%E7%9A%84%E6%9B%B4%E6%94%B9#git-add) 命令同时用来生成提交和解决合并冲突。这使得开发者能够轻而易举地管理他们的合并。另外,如果他们改错了什么,Git 让他们轻易地退出 rebase 过程,然后重试(或者找人帮忙)。
|
||||
|
||||
@ -63,12 +51,8 @@
|
||||
|
||||
### 一人初始化了中央仓库
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
首先,需要有人在服务器上创建中央仓库。如果这是一个新项目,你可以初始化一个空的仓库。不然,你需要导入一个已经存在的 Git 或 SVN 项目。
|
||||
|
||||
中央仓库应该永远是裸仓库(没有工作目录),可以这样创建:
|
||||
@ -81,30 +65,20 @@ ssh user@host git init --bare /path/to/repo.git
|
||||
|
||||
### 所有人将仓库克隆到本地
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
接下来,每个开发者在本地创建一份完整项目的副本。使用 [`git clone`](https://github.com/geeeeeeeeek/git-recipes/wiki/2.2-%E5%88%9B%E5%BB%BA%E4%BB%A3%E7%A0%81%E4%BB%93%E5%BA%93#git-clone) 命令:
|
||||
|
||||
```
|
||||
git clone ssh://user@host/path/to/repo.git
|
||||
```
|
||||
|
||||
当你克隆仓库时,Git自动添加了一个名为`origin`的远程连接,指向“父”仓库,以便你以后和这个仓库交换数据。
|
||||
当你克隆仓库时,Git 自动添加了一个名为 `origin` 的远程连接,指向「父」仓库,以便你以后和这个仓库交换数据。
|
||||
|
||||
### John 在开发他的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在他的本地仓库中,John 可以用标准的 Git 提交流程开发功能:编辑、缓存、提交。如果你对缓存区还不熟悉,你也可以不用记录工作目录中每次的变化。于是你创建了一个高度集中的提交,即使你已经在本地做了很多修改。
|
||||
|
||||
```
|
||||
@ -117,22 +91,14 @@ git commit # 提交一个文件</some-file>
|
||||
|
||||
### Mary 在开发她的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
同时,Mary 在她自己的本地仓库用相同的编辑/缓存/提交流程开发她的功能。和 John 一样,她不需要关心中央仓库的进展,她也 *完全* 不关心 John 在他自己仓库中做的事,因为所有本地仓库都是私有的。
|
||||
|
||||
### John 发布了他的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
一旦 John 完成了他的功能,他应该将本地提交发布到中央仓库,这样其他项目成员就可以访问了。他可以使用[`git push`](https://github.com/geeeeeeeeek/git-recipes/wiki/3.2-%E4%BF%9D%E6%8C%81%E5%90%8C%E6%AD%A5#git-push)命令,就像:
|
||||
|
||||
```
|
||||
@ -141,14 +107,10 @@ git push origin master
|
||||
|
||||
记住,`origin` 是 John 克隆中央仓库时指向它的远程连接。`master` 参数告诉 Git 试着将 `origin` 的 `master` 分支变得和他本地的 `master` 分支一样。中央仓库在 John 克隆之后还没有进展,因此这个推送如他所愿,没有产生冲突。
|
||||
|
||||
### Mary试图发布她的功能
|
||||
|
||||
|
||||
### Mary as试图发布她的功能
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
John 已经成功地将他的更改发布到了中央仓库上,看看当 Mary 试着将她的功能推送到上面时会发生什么。她可以使用同一个推送命令:
|
||||
|
||||
```
|
||||
@ -169,12 +131,8 @@ Git防止Mary覆盖官方的修改。她需要将John的更新拉取到她的仓
|
||||
|
||||
### Mary在John的提交之上rebase
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Mary 可以使用 [`git pull`](https://github.com/geeeeeeeeek/git-recipes/wiki/3.2-%E4%BF%9D%E6%8C%81%E5%90%8C%E6%AD%A5#git-pull) 来将上游修改并入她的仓库。这个命令和 `svn update` 很像——它拉取整个上游提交历史到Mary的本地仓库,并和她的本地提交一起整合:
|
||||
|
||||
```
|
||||
@ -183,22 +141,15 @@ git pull --rebase origin master
|
||||
|
||||
`--rebase` 选项告诉 Git,在同步了中央仓库的修改之后,将 Mary 所有的提交移到 `master` 分支的顶端,如下图所示:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
如果你忽略这个选项拉取同样会成功,只不过你每次和中央仓库同步时都会多出一个“合并提交”。在这种工作流中,rebase和生成一个合并提交相比,总是一个更好的选择。
|
||||
如果你忽略这个选项拉取同样会成功,只不过你每次和中央仓库同步时都会多出一个「合并提交」。在这种工作流中,rebase 和生成一个合并提交相比,总是一个更好的选择。
|
||||
|
||||
### Mary 解决了合并冲突
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Rebase 的工作是将每个本地提交一个个转移到更新后的 `master` 分支。也就是说,你可以一个个提交分别解决合并冲突,而不是在一个庞大的合并提交中解决。它会让你的每个提交保持专注,并获得一个干净的项目历史。另一方面,你更容易发现bug是在哪引入的,如果有必要的话,用最小的代价回滚这些修改。
|
||||
|
||||
如果 Mary 和 John 开发的功能没有关联,rebase的过程不太可能出现冲突。但如果出现冲突时,Git 在当前提交会暂停 rebase,输出下面的信息,和一些相关的指令:
|
||||
@ -207,12 +158,9 @@ Rebase的工作是将每个本地提交一个个转移到更新后的`master`分
|
||||
CONFLICT (content): Merge conflict in <some-file>
|
||||
```
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Git 的优点在于 *每个人* 都能解决他们自己的合并冲突。在这个例子中,Mary 只需运行一下 [`git status`](https://github.com/geeeeeeeeek/git-recipes/wiki/2.4-%E6%A3%80%E6%9F%A5%E4%BB%93%E5%BA%93%E7%8A%B6%E6%80%81#git-status) 就可以发现问题是什么。冲突的文件会出现在未合并路径中:
|
||||
|
||||
```
|
||||
@ -240,12 +188,8 @@ git rebase --abort
|
||||
|
||||
### Mary 成功发布了她的分支
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在她和中央仓库同步之后,Mary 可以成功地发布她的修改:
|
||||
|
||||
```
|
||||
@ -260,19 +204,15 @@ git push origin master
|
||||
|
||||
## Feature 分支的工作流
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
一旦你掌握了 [中心化工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81) 的使用方法,在你的开发流程中添加功能分支是一个简单的方式,来促进协作和开发者之间的交流。这种封装使得多个开发者专注自己的功能而不会打扰主代码库。它还保证 `master` 分支永远不会包含损坏的代码,给持续集成环境带来了是很大的好处。
|
||||
|
||||
|
||||
一旦你掌握了[中心化工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)的使用姿势,在你的开发流程中添加功能分支是一个简单的方式,来促进协作和开发者之间的交流。这种封装使得多个开发者专注自己的功能而不会打扰主代码库。它还保证`master`分支永远不会包含损坏的代码,给持续集成环境带来了是很大的好处。
|
||||
|
||||
封装功能的开发使得[pull request](https://github.com/geeeeeeeeek/git-recipes/wiki/3.3-%E5%88%9B%E5%BB%BAPull-Request)的使用成为可能,用来启动围绕一个分支的讨论。它给了其他开发者在功能并入主项目之前参与决策的机会。或者,如果你开发功能时卡在一半,你可以发起一个pull request,向同事寻求建议。重点是,pull request使得你的团队在评论其他人的工作时变得非常简单。
|
||||
封装功能的开发使得 [Pull Request](https://github.com/geeeeeeeeek/git-recipes/wiki/3.3-%E5%88%9B%E5%BB%BAPull-Request) 的使用成为可能,用来启动围绕一个分支的讨论。它给了其他开发者在功能并入主项目之前参与决策的机会。或者,如果你开发功能时卡在一半,你可以发起一个 Pull Request,向同事寻求建议。重点是,Pull Request 使得你的团队在评论其他人的工作时变得非常简单。
|
||||
|
||||
## 如何工作
|
||||
|
||||
Feature分支工作流同样使用中央仓库,`master`同样代表官方的项目历史。但是,与其直接提交在本地的`master`分支,开发者每次进行新的工作时创建一个新的分支。Feature分支应该包含描述性的名称,比如`animated-menu-items`(菜单项动画)或`issue-#1061`。每个分支都应该有一个清晰、高度集中的目的。
|
||||
Feature 分支工作流同样使用中央仓库,`master` 同样代表官方的项目历史。但是,与其直接提交在本地的 `master` 分支,开发者每次进行新的工作时创建一个新的分支。Feature 分支应该包含描述性的名称,比如 `animated-menu-items`(菜单项动画)或 `issue-#1061`。每个分支都应该有一个清晰、高度集中的目的。
|
||||
|
||||
Git 在技术上无法区别 `master` 和功能分支,所以开发者可以在 feature 分支上编辑、缓存、提交,就和中心化工作流中一样。
|
||||
|
||||
@ -280,24 +220,20 @@ Git在技术上无法区别`master`和功能分支,所以开发者可以在fea
|
||||
|
||||
### Pull Request
|
||||
|
||||
除了隔离功能开发之外,分支使得通过[pull request](https://github.com/geeeeeeeeek/git-recipes/wiki/3.3-%E5%88%9B%E5%BB%BAPull-Request)讨论修改成为可能。一旦有人完成了一个功能,他们不会立即将它并入`master`。他们将feature分支推送到中央服务器上,发布一个pull request,请求将他们的修改并入`master`。这给了其他开发者在修改并入主代码库之前审查的机会。
|
||||
除了隔离功能开发之外,分支使得通过 [Pull Request](https://github.com/geeeeeeeeek/git-recipes/wiki/3.3-%E5%88%9B%E5%BB%BAPull-Request) 讨论修改成为可能。一旦有人完成了一个功能,他们不会立即将它并入`master`。他们将 feature 分支推送到中央服务器上,发布一个 Pull Request,请求将他们的修改并入 `master`。这给了其他开发者在修改并入主代码库之前审查的机会。
|
||||
|
||||
代码审查是pull request的主要好处,但他们事实上被设计为成为讨论代码的一般场所。你可以把pull request看作是专注某个分支的讨论版。也就是说他们可以用于开发流程之前。比如,一个开发者在某个功能上需要帮助,他只需发起一个pull request。感兴趣的小伙伴会自动收到通知,看到相关提交中的问题。
|
||||
代码审查是 Pull Request 的主要好处,但他们事实上被设计为成为讨论代码的一般场所。你可以把 Pull Request 看作是专注某个分支的讨论版。也就是说他们可以用于开发流程之前。比如,一个开发者在某个功能上需要帮助,他只需发起一个 Pull Request。感兴趣的小伙伴会自动收到通知,看到相关提交中的问题。
|
||||
|
||||
一旦pull request被接受了,发布功能的行为和中心化的工作流是一样的。首先,确定你本地的`master`和上游的`master`已经同步。然后,将feature分支并入`master`,将更新的`master`推送回中央仓库。
|
||||
一旦 Pull Request 被接受了,发布功能的行为和中心化的工作流是一样的。首先,确定你本地的 `master` 和上游的 `master` 已经同步。然后,将 feature分支并入 `master`,将更新的 `master` 推送回中央仓库。
|
||||
|
||||
## 栗子
|
||||
|
||||
下面这个🌰演示了代码审查使用到的pull request,但记住pull request有多种用途。
|
||||
下面这🌰演示了代码审查使用到的 Pull Request,但记住 Pull Request 有多种用途。
|
||||
|
||||
### Mary 开始了一个新功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在她开始开发一个功能之前,Mary 需要一个独立的分支。她可以用下面的命令[创建新分支](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-checkout):
|
||||
|
||||
```
|
||||
@ -314,67 +250,47 @@ git commit
|
||||
|
||||
### Mary 去吃饭了
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Mary 在早上[给她的功能添加了一些提交](https://github.com/geeeeeeeeek/git-recipes/wiki/2.3-%E4%BF%9D%E5%AD%98%E4%BD%A0%E7%9A%84%E6%9B%B4%E6%94%B9#git-commit)。在她去吃午饭前,[将她的分支推送到中央仓库](https://github.com/geeeeeeeeek/git-recipes/wiki/3.2-%E4%BF%9D%E6%8C%81%E5%90%8C%E6%AD%A5#git-push)是个不错的想法。这是一种方便的备份,但如果Mary和其他开发者一起协作,他们也可以看到她的初始提交了。
|
||||
|
||||
```
|
||||
git push -u origin marys-feature
|
||||
```
|
||||
|
||||
这个命令将`marys-feature`推送到中央仓库(`origin`),`-u`标记将它添加为远程跟踪的分支。在设置完跟踪的分支之后,Mary调用不带任何参数的`git push`来推送她的功能。
|
||||
这个命令将 `marys-feature` 推送到中央仓库(`origin`),`-u` 标记将它添加为远程跟踪的分支。在设置完跟踪的分支之后,Mary 调用不带任何参数的 `git push` 来推送她的功能。
|
||||
|
||||
### Mary 完成了她的工作
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
当Mary吃完午饭回来,她完成了她的功能。在[并入`master`](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-merge)之前,她需要发布一个pull request,让其他的团队成员知道她所做的工作。但首先,她应该保证中央仓库包含了她最新的提交:
|
||||
当 Mary 吃完午饭回来,她完成了她的功能。在[并入 `master`](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-merge) 之前,她需要发布一个 Pull Request,让其他的团队成员知道她所做的工作。但首先,她应该保证中央仓库包含了她最新的提交:
|
||||
|
||||
```
|
||||
git push
|
||||
```
|
||||
|
||||
然后,她在她的Git界面上发起了一个pull request,请求将`marys-feature`合并进`master`,团队成员会收到自动的通知。Pull request的好处是,评论显示在相关的提交正下方,方便讨论特定的修改。
|
||||
|
||||
### Bill收到了pull request
|
||||
|
||||
然后,她在她的 Git 界面上发起了一个 Pull Request,请求将 `marys-feature` 合并进 `master`,团队成员会收到自动的通知。Pull Request 的好处是,评论显示在相关的提交正下方,方便讨论特定的修改。
|
||||
|
||||
### Bill 收到了 Pull Request
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Bill收到了pull request,并且查看了`marys-feature`。他决定在并入官方项目之前做一些小修改,通过pull request和Mary进行了沟通。
|
||||
Bill 收到了 Pull Request,并且查看了 `marys-feature`。他决定在并入官方项目之前做一些小修改,通过 Pull Request 和 Mary 进行了沟通。
|
||||
|
||||
### Mary 作了修改
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
为了做这些更改,Mary 重复了之前创建功能时相同的流程,她编辑、缓存、提交、将更新推送到中央仓库。她所有的活动显示在 Pull Request 中,Bill 可以一直评论。
|
||||
|
||||
|
||||
为了做这些更改,Mary重复了之前创建功能时相同的流程,她编辑、缓存、提交、将更新推送到中央仓库。她所有的活动显示在pull request中,Bill可以一直评论。
|
||||
|
||||
如果Bill想要的话,也可以将`marys-feature`pull到他自己的本地仓库,继续工作。后续的任何提交都会显示在pull request上。
|
||||
如果 Bill 想要的话,也可以将 `marys-feature` 分支 pull 到他自己的本地仓库,继续工作。后续的任何提交都会显示在 Pull Request 上。
|
||||
|
||||
### Mary 发布了她的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
一旦Bill准备接受这个pull request,某个人(Bill或者Mary都可)需要将功能并入稳定的项目:
|
||||
一旦 Bill 准备接受这个 Pull Request,某个人(Bill 或者 Mary 都可)需要将功能并入稳定的项目:
|
||||
|
||||
```
|
||||
git checkout master
|
||||
@ -387,69 +303,53 @@ git push
|
||||
|
||||
这个过程导致了一个合并提交。一些开发者喜欢它,因为它是功能和其余代码合并的标志。但,如果你希望得到线性的历史,你可以在执行 merge 之前将功能 rebase 到 `master` 分支的顶端,产生一个快速向前的合并。
|
||||
|
||||
一些界面会自动化接受pull request的流程,只需点击一下“Merge Pull Request”。如果你的没有的话,它至少在合并之后应该可以自动地关闭pull request。
|
||||
一些界面会自动化接受 Pull Request 的流程,只需点击一下「Merge Pull Request」。如果你的没有的话,它至少在合并之后应该可以自动地关闭 Pull Request。
|
||||
|
||||
### 同时,John 以同样的方式工作着
|
||||
|
||||
Mary和Bill一起开发`marys-feature`,在pull request上讨论的同时,John还在开发他自己的feature分支。通过将功能用不同分支隔离开来,每个人可以独立地工作,但很容易和其他开发者共享修改。
|
||||
Mary 和 Bill 一起开发 `marys-feature`,在 Pull Request 上讨论的同时,John 还在开发他自己的 feature分支。通过将功能用不同分支隔离开来,每个人可以独立地工作,但很容易和其他开发者共享修改。
|
||||
|
||||
## 接下来该怎么做
|
||||
|
||||
为了彻底了解Github上的功能分支,你应该查看[使用分支一章](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF)。现在,你应该已经看到了功能分支极大地增强了[中心化工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)中单一`master`分支的作用。除此之外,功能分支还便利了pull request的使用,在版本控制界面上直接讨论特定的提交。Gitflow工作流是管理功能开发、发布准备、维护的常见模式。
|
||||
|
||||
## Gitflow工作流
|
||||
|
||||
为了彻底了解 GitHub 上的功能分支,你应该查看[使用分支一章](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF)。现在,你应该已经看到了功能分支极大地增强了[中心化工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)中单一 `master` 分支的作用。除此之外,功能分支还便利了 Pull Request 的使用,在版本控制界面上直接讨论特定的提交。GitFlow 工作流是管理功能开发、发布准备、维护的常见模式。
|
||||
|
||||
## GitFlow 工作流
|
||||
|
||||

|
||||
|
||||
下面的 [GitFlow 工作流](http://nvie.com/posts/a-successful-git-branching-model/)一节源于 [nvie](http://nvie.com/) 网站上的作者 Vincent Driessen。
|
||||
|
||||
GitFlow 工作流围绕项目发布定义了一个严格的分支模型。有些地方比[功能分支工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#feature%E5%88%86%E6%94%AF%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)更复杂,为管理大型项目提供了鲁棒的框架。
|
||||
|
||||
下面的[Gitflow工作流](http://nvie.com/posts/a-successful-git-branching-model/)一节源于[nvie](http://nvie.com/)网站上的作者Vincent Driessen。
|
||||
|
||||
Gitflow工作流围绕项目发布定义了一个严格的分支模型。有些地方比[功能分支工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#feature%E5%88%86%E6%94%AF%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)更复杂,为管理大型项目提供了鲁棒的框架。
|
||||
|
||||
和功能分支工作流相比,这种工作流没有增加任何新的概念或命令。它给不同的分支指定了特定的角色,定义它们应该如何、什么时候交流。除了功能分支之外,它还为准备发布、维护发布、记录发布分别使用了单独的分支。当然,你还能享受到功能分支工作流带来的所有好处:pull request、隔离实验和更高效的协作。
|
||||
和功能分支工作流相比,这种工作流没有增加任何新的概念或命令。它给不同的分支指定了特定的角色,定义它们应该如何、什么时候交流。除了功能分支之外,它还为准备发布、维护发布、记录发布分别使用了单独的分支。当然,你还能享受到功能分支工作流带来的所有好处:Pull Request、隔离实验和更高效的协作。
|
||||
|
||||
## 如何工作
|
||||
|
||||
Gitflow工作流仍然使用中央仓库作为开发者沟通的中心。和[其他工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83)一样,开发者在本地工作,将分支推送到中央仓库。唯一的区别在于项目的分支结构。
|
||||
GitFlow 工作流仍然使用中央仓库作为开发者沟通的中心。和[其他工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83)一样,开发者在本地工作,将分支推送到中央仓库。唯一的区别在于项目的分支结构。
|
||||
|
||||
### 历史分支
|
||||
|
||||
和单独的 `master` 分支不同,这种工作流使用两个分支来记录项目历史。`master` 分支储存官方发布历史,`develop` 分支用来整合功能分支。同时,这还方便了在 `master` 分支上给所有提交打上版本号标签。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
工作流剩下的部分围绕这两个分支的差别展开。
|
||||
|
||||
### 功能分支
|
||||
|
||||
每个新功能都放置在自己的分支中,可以[在备份/协作时推送到中央仓库](https://github.com/geeeeeeeeek/git-recipes/wiki/3.2-%E4%BF%9D%E6%8C%81%E5%90%8C%E6%AD%A5#git-push)。但是,与其合并到 `master`,功能分支将开发分支作为父分支。当一个功能完成时,它将被[合并回 `develop`](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-merge)。功能永远不应该直接在 `master` 上交互。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
注意,功能分支加上`develop`分支就是我们之前所说的功能分支工作流。但是,Gitflow工作流不止于此。
|
||||
注意,功能分支加上 `develop` 分支就是我们之前所说的功能分支工作流。但是,GitFlow 工作流不止于此。
|
||||
|
||||
### 发布分支
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
一旦 `develop`分支的新功能足够发布(或者预先确定的发布日期即将到来),你可以从 `develop` 分支 fork 一个发布分支。这个分支的创建开始了下个发布周期,只有和发布相关的任务应该在这个分支进行,如修复 bug、生成文档等。一旦准备好了发布,发布分支将合并进 `master`,打上版本号的标签。另外,它也应该合并回 `develop`,后者可能在发布启动之后有了新的进展。
|
||||
|
||||
使用一个专门的分支来准备发布确保一个团队完善当前的发布,其他团队可以继续开发下一个发布的功能。它还建立了清晰的开发阶段(比如说,“这周我们准备4.0版本的发布”,而我们在仓库的结构中也能看到这个阶段)。
|
||||
使用一个专门的分支来准备发布确保一个团队完善当前的发布,其他团队可以继续开发下一个发布的功能。它还建立了清晰的开发阶段(比如说,「这周我们准备 4.0 版本的发布」,而我们在仓库的结构中也能看到这个阶段)。
|
||||
|
||||
通常我们约定:
|
||||
|
||||
@ -459,13 +359,9 @@ Gitflow工作流仍然使用中央仓库作为开发者沟通的中心。和[其
|
||||
|
||||
### 维护分支
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
维护或者“紧急修复”分支用来快速给产品的发布打上补丁。这是唯一可以从`master`上fork的分支。一旦修复完成了,它应该被并入`master`和`develop`分支(或者当前的发布分支),`master`应该打上更新的版本号的标签。
|
||||
维护或者「紧急修复」分支用来快速给产品的发布打上补丁。这是唯一可以从 `master` 上 fork 的分支。一旦修复完成了,它应该被并入 `master` 和 `develop` 分支(或者当前的发布分支),`master` 应该打上更新的版本号的标签。
|
||||
|
||||
有一个专门的 bug 修复开发线使得你的团队能够处理 issues,而不打断其他工作流或是要等到下一个发布周期。你可以将维护分支看作在 `master` 分支上工作的临时发布分支。
|
||||
|
||||
@ -475,13 +371,9 @@ Gitflow工作流仍然使用中央仓库作为开发者沟通的中心。和[其
|
||||
|
||||
### 创建一个开发分支
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
你要做的第一步是为默认的`master`分支创建一个互补的`develop`分支。最简单的办法是[在本地创建一个空的`develop`分支](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-branch),将它推送到服务器上:
|
||||
你要做的第一步是为默认的 `master` 分支创建一个互补的 `develop` 分支。最简单的办法是[在本地创建一个空的 develop 分支](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-branch),将它推送到服务器上:
|
||||
|
||||
```
|
||||
git branch develop
|
||||
@ -499,19 +391,15 @@ git checkout -b develop origin/develop
|
||||
|
||||
### Mary 和 John 开始了新功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
我们的栗子从 John 和 Mary 在不同分支上工作开始。他们都要为自己的功能创建单独的分支。[他们的功能分支都应该基于`develop`](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-checkout),而不是 `master`:
|
||||
|
||||
```
|
||||
git checkout -b some-feature develop
|
||||
```
|
||||
|
||||
他们都使用“编辑、缓存、提交”的一般约定来向功能分支添加提交:
|
||||
他们都使用「编辑、缓存、提交」的一般约定来向功能分支添加提交:
|
||||
|
||||
```
|
||||
git status
|
||||
@ -521,13 +409,9 @@ git commit
|
||||
|
||||
### Mary 完成了她的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在添加了一些提交之后,Mary确信她的功能以及准备好了。如果她的团队使用pull request,现在正是发起pull request的好时候,请求将她的功能并入`develop`分支。否则,她可以向下面一样,将它并入本地的`develop`分支,推送到中央仓库:
|
||||
在添加了一些提交之后,Mary 确信她的功能以及准备好了。如果她的团队使用 Pull Request,现在正是发起 Pull Request 的好时候,请求将她的功能并入 `develop` 分支。否则,她可以向下面一样,将它并入本地的 `develop` 分支,推送到中央仓库:
|
||||
|
||||
```
|
||||
git pull origin develop
|
||||
@ -541,13 +425,9 @@ git branch -d some-feature
|
||||
|
||||
### Mary 开始准备发布
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
当John仍然在他的功能分支上工作时,Mary开始准备项目的第一个官方发布。和开发功能一样,她新建了一个分支来封装发布的准备工作。这也正是发布的版本号创建的一步:
|
||||
当 John 仍然在他的功能分支上工作时,Mary s开始准备项目的第一个官方发布。和开发功能一样,她新建了一个分支来封装发布的准备工作。这也正是发布的版本号创建的一步:
|
||||
|
||||
```
|
||||
git checkout -b release-0.1 develop
|
||||
@ -559,13 +439,9 @@ git checkout -b release-0.1 develop
|
||||
|
||||
### Mary完成了她的发布
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
一旦发布准备稳妥,Mary将它并入`master`和`develop`,然后删除发布分支。合并回`develop`很重要,因为可能已经有关键的更新添加到了发布分支上,而开发新功能需要用到它们。同样的,如果Mary的团队重视代码审查,现在将是发起pull request的完美时机。
|
||||
一旦发布准备稳妥,Mary 将它并入 `master` 和 `develop`,然后删除发布分支。合并回 `develop` 很重要,因为可能已经有关键的更新添加到了发布分支上,而开发新功能需要用到它们。同样的,如果 Mary 的团队重视代码审查,现在将是发起 Pull Request 的完美时机。
|
||||
|
||||
```
|
||||
git checkout master
|
||||
@ -577,7 +453,7 @@ git push
|
||||
git branch -d release-0.1
|
||||
```
|
||||
|
||||
发布分支是功能开发(`develop`)和公开发布(master)之间的过渡阶段。不论什么时候将提交并入`master`时,你应该为提交打上方便引用的标签:
|
||||
发布分支是功能开发(`develop`)和公开发布(`master`)之间的过渡阶段。不论什么时候将提交并入 `master` 时,你应该为提交打上方便引用的标签:
|
||||
|
||||
```
|
||||
git tag -a 0.1 -m "Initial public release" master
|
||||
@ -588,12 +464,8 @@ Git提供了许多钩子,即仓库中特定事件发生时被执行的脚本
|
||||
|
||||
### 终端用户发现了一个 bug
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
正式发布之后,Mary 回过头来和 John 一起为下一个发布开发功能。这时,一个终端用户开了一个 issue 抱怨说当前发布中存在一个 bug。为了解决这个 bug,Mary(或 John)从 `master` 创建了一个维护分支,用几个提交修复这个 issue,然后直接合并回 `master`。
|
||||
|
||||
```
|
||||
@ -615,20 +487,16 @@ git branch -d issue-#001
|
||||
|
||||
## 接下来该怎么做
|
||||
|
||||
现在,希望你已经很熟悉[中心化的工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)、[功能分支工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#feature%E5%88%86%E6%94%AF%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)和Gitflow工作流。你应该已经可以抓住本地仓库、推送/拉取模式,和Git鲁棒的分支和合并模型的无限潜力。
|
||||
现在,希望你已经很熟悉[中心化的工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)、[功能分支工作流](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#feature%E5%88%86%E6%94%AF%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81)和 GitFlow 工作流。你应该已经可以抓住本地仓库、推送/拉取模式,和 Git 鲁棒的分支和合并模型的无限潜力。
|
||||
|
||||
请记住,教程中呈现的工作流只是可行的实践——而非工作中使用 Git 的金科玉律。因此,尽情地取其精华,去其糟粕吧。不变的是要让 Git 为你所用,而不是相反。
|
||||
|
||||
## Fork 工作流
|
||||
|
||||
Fork工作流和教程中讨论的其它工作流截然不同。与其使用唯一的服务端仓库作为”中央“代码库,它给予 *每个* 开发者一个服务端仓库。也就是说每个贡献者都有两个Git仓库,而不是一个:一个私有的本地仓库和一个公开的服务端仓库。
|
||||
|
||||
|
||||
Fork 工作流和教程中讨论的其它工作流截然不同。与其使用唯一的服务端仓库作为「中央」代码库,它给予 *每个* 开发者一个服务端仓库。也就是说每个贡献者都有两个 Git 仓库,而不是一个:一个私有的本地仓库和一个公开的服务端仓库。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Fork 工作流的主要优点在于贡献可以轻易地整合进项目,而不需要每个人都推送到单一的中央仓库。开发者推送到他们 *自己的* 服务端仓库,只有项目管理者可以推送到官方仓库。这使得管理者可以接受任何开发者的提交,却不需要给他们中央仓库的权限。
|
||||
|
||||
结论是,这种分布式的工作流为大型、组织性强的团队(包括不可信的第三方)提供了安全的协作方式。它同时也是开源项目理想的工作流。
|
||||
@ -639,28 +507,24 @@ Fork工作流的主要优点在于贡献可以轻易地整合进项目,而不
|
||||
|
||||
取而代之地,他们 fork 一份官方项目,在服务端创建一份副本。这份新建的副本作为他们私有的公开仓库——没有其他开发者可以在上面推送,但他们可以从上面拉取修改(在后面我们会讨论为什么这一点很重要)。在他们创建了服务端副本之后,开发者执行 `git clone` 操作,在他们的本地机器上复制一份。这是他们私有的开发环境,正如其他工作流中一样。
|
||||
|
||||
当他们准备好发布本地提交时,他们将提交推送到自己的公开仓库——而非官方仓库。然后,他们向主仓库发起一个pull request,让项目维护者知道一个更新做好了合并的准备。如果贡献的代码有什么问题的话,Pull request可以作为一个方便的讨论版。
|
||||
当他们准备好发布本地提交时,他们将提交推送到自己的公开仓库——而非官方仓库。然后,他们向主仓库发起一个 Pull Request,让项目维护者知道一个更新做好了合并的准备。如果贡献的代码有什么问题的话,Pull Request 可以作为一个方便的讨论版。
|
||||
|
||||
我为了将功能并入官方代码库,维护者将贡献者的修改拉取到他们的本地仓库,确保修改不会破坏项目,将它[合并到本地的`master`分支](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-merge),然后将`master`分支[推送](https://github.com/geeeeeeeeek/git-recipes/wiki/3.2-%E4%BF%9D%E6%8C%81%E5%90%8C%E6%AD%A5#git-push)到服务端的官方仓库。贡献现在已是项目的一部分,其他开发者应该从官方仓库拉取并同步他们的本地仓库。
|
||||
我为了将功能并入官方代码库,维护者将贡献者的修改拉取到他们的本地仓库,确保修改不会破坏项目,将它[合并到本地的 master 分支](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-merge),然后将 `master` 分支[推送](https://github.com/geeeeeeeeek/git-recipes/wiki/3.2-%E4%BF%9D%E6%8C%81%E5%90%8C%E6%AD%A5#git-push)到服务端的官方仓库。贡献现在已是项目的一部分,其他开发者应该从官方仓库拉取并同步他们的本地仓库。
|
||||
|
||||
### 中央仓库
|
||||
|
||||
“官方”仓库这个概念在Fork工作流中只是一个约定,理解这一点很重要。从技术的角度,Git并看不出每个开发者和官方的公开仓库有什么区别。事实上,官方仓库唯一官方的原因是,它是项目维护者的仓库。
|
||||
「官方」仓库这个概念在 Fork 工作流中只是一个约定,理解这一点很重要。从技术的角度,Git 并看不出每个开发者和官方的公开仓库有什么区别。事实上,官方仓库唯一官方的原因是,它是项目维护者的仓库。
|
||||
|
||||
### Fork 工作流中的分支
|
||||
|
||||
所有这些个人的公开仓库只是一个在开发者之间共享分支的约定。每个人仍然可以使用分支来隔离功能,就像在[功能分支工作流](](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#feature%E5%88%86%E6%94%AF%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81))和[Gitflow工作流中](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#gitflow%E5%B7%A5%E4%BD%9C%E6%B5%81)一样。唯一的区别在于这些分支是如何开始的。在Fork工作流中,它们从另一个开发者的本地仓库拉取而来,而在功能分支和Gitflow分支它们被推送到官方仓库。
|
||||
所有这些个人的公开仓库只是一个在开发者之间共享分支的约定。每个人仍然可以使用分支来隔离功能,就像在[功能分支工作流](](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#feature%E5%88%86%E6%94%AF%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81))和 [GitFlow 工作流中](https://github.com/geeeeeeeeek/git-recipes/wiki/3.5-%E5%B8%B8%E8%A7%81%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%AF%94%E8%BE%83#gitflow%E5%B7%A5%E4%BD%9C%E6%B5%81)一样。唯一的区别在于这些分支是如何开始的。在 Fork 工作流中,它们从另一个开发者的本地仓库拉取而来,而在功能分支和 GitFlow 分支它们被推送到官方仓库。
|
||||
|
||||
## 栗子
|
||||
|
||||
### 项目维护者初始化了中央仓库
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
和任何基于 Git 的项目一样,第一步是在服务端创建一个可以被所有项目成员访问到的官方仓库。一般来说,这个仓库同时还是项目维护者的公开仓库。
|
||||
|
||||
[公开的仓库应该永远是裸的](https://github.com/geeeeeeeeek/git-recipes/wiki/2.2-%E5%88%9B%E5%BB%BA%E4%BB%A3%E7%A0%81%E4%BB%93%E5%BA%93#git-init),不管它们是否代表官方代码库。所以项目维护者应该运行下面这样的命令来设置官方仓库:
|
||||
@ -670,31 +534,23 @@ ssh user@host
|
||||
git init --bare /path/to/repo.git
|
||||
```
|
||||
|
||||
Github同时提供了一个图形化界面来替代上面的操作。这和教程中其它工作流设置中央仓库的流程完全一致。如果有必要的话,项目维护者应该将已有的代码库推送到这个仓库中。
|
||||
GitHub 同时提供了一个图形化界面来替代上面的操作。这和教程中其它工作流设置中央仓库的流程完全一致。如果有必要的话,项目维护者应该将已有的代码库推送到这个仓库中。
|
||||
|
||||
### 开发者 fork 仓库
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
接下来,所有开发者需要fork官方仓库。你可以用SSH到服务器,运行`git clone`将它复制到服务器的另一个地址——fork其实只是服务端的clone。但同样地,Github上开发者只需点一点按钮就可以fork仓库。
|
||||
接下来,所有开发者需要 fork 官方仓库。你可以用 SSH 到服务器,运行 `git clone` 将它复制到服务器的另一个地址—— fork 其实只是服务端的 clone。但同样地,GitHub上开发者只需点一点按钮就可以 fork 仓库。
|
||||
|
||||
在这步之后,每个开发者应该都有了自己的服务端仓库。像官方仓库一样,所有这些仓库都应该是裸仓库。
|
||||
|
||||
### 开发者将 fork 的仓库克隆到本地
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
接下来开发者需要克隆他们自己的公开仓库。他们可以用熟悉的 `git clone` 命令来完成这一步。
|
||||
|
||||
我们的栗子假设使用他们使用Github来托管仓库。记住,在这种情况下,每个开发者应该有他们自己的Github账号,应该用下面的命令克隆服务端仓库:
|
||||
我们的栗子假设使用他们使用 GitHub 来托管仓库。记住,在这种情况下,每个开发者应该有他们自己的 GitHub 账号,应该用下面的命令克隆服务端仓库:
|
||||
|
||||
```
|
||||
git clone https://user@github.com/user/repo.git
|
||||
@ -716,12 +572,8 @@ git remote add upstream https://user@bitbucket.org/maintainer/repo.git
|
||||
|
||||
### 开发者进行自己的开发
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在他们刚克隆的本地仓库中,开发者可以编辑代码、[提交更改](https://github.com/geeeeeeeeek/git-recipes/wiki/2.3-%E4%BF%9D%E5%AD%98%E4%BD%A0%E7%9A%84%E6%9B%B4%E6%94%B9#git-commit),和其它分支中一样[创建分支](https://github.com/geeeeeeeeek/git-recipes/wiki/3.4-%E4%BD%BF%E7%94%A8%E5%88%86%E6%94%AF#git-branch):
|
||||
|
||||
```
|
||||
@ -740,12 +592,8 @@ git pull upstream master
|
||||
|
||||
### 开发者发布他们的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
一旦开发者准备好共享他们的新功能,他们需要做两件事情。第一,他们必须将贡献的代码推送到自己的公开仓库,让其他开发者能够访问到。他们的 `origin` 远端应该已经设置好了,所以他们只需要:
|
||||
|
||||
```
|
||||
@ -754,22 +602,18 @@ git push origin feature-branch
|
||||
|
||||
这和其他工作流不同之处在于,`origin` 远端指向开发者个人的服务端仓库,而不是主代码库。
|
||||
|
||||
第二,他们需要通知项目维护者,他们想要将功能并入官方代码库。Github提供了一个“New Pull Request”按钮,跳转到一个网页,让你指明想要并入主仓库的分支。一般来说,你希望将功能分支并入上游远端的`master`分支。
|
||||
第二,他们需要通知项目维护者,他们想要将功能并入官方代码库。GitHub 提供了一个「New Pull Request」按钮,跳转到一个网页,让你指明想要并入主仓库的分支。一般来说,你希望将功能分支并入上游远端的 `master` 分支。
|
||||
|
||||
### 项目维护者整合他们的功能
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
当项目维护者收到 Pull Request 时,他们的工作是决定是否将它并入官方的代码库。他们可以使用下面两种方式之一:
|
||||
|
||||
|
||||
当项目维护者收到pull request时,他们的工作是决定是否将它并入官方的代码库。他们可以使用下面两种方式之一:
|
||||
|
||||
1. 直接检查pull request中检查代码
|
||||
1. 直接检查 Pull Request 中检查代码
|
||||
2. 将代码拉取到本地仓库然后手动合并
|
||||
|
||||
第一个选项更简单,让维护者查看修改前后的差异,在上面评论,然后通过图形界面执行合并。然而,如果pull request会导致合并冲突,第二个选项就有了必要。在这个情况中,维护者需要从开发者的服务端仓库fetch功能分支,合并到他们本地的`master`分支,然后解决冲突:
|
||||
第一个选项更简单,让维护者查看修改前后的差异,在上面评论,然后通过图形界面执行合并。然而,如果 Pull Request 会导致合并冲突,第二个选项就有了必要。在这个情况中,维护者需要从开发者的服务端仓库 fetch 功能分支,合并到他们本地的 `master` 分支,然后解决冲突:
|
||||
|
||||
```
|
||||
git fetch https://bitbucket.org/user/repo feature-branch
|
||||
@ -788,12 +632,8 @@ git push origin master
|
||||
|
||||
### 开发者和中央仓库保持同步
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
因为主代码库已经取得了新的进展,其他开发者应该和官方仓库同步:
|
||||
|
||||
```
|
||||
@ -808,9 +648,7 @@ git pull upstream master
|
||||
|
||||
这使得 Fork 工作流对于松散的团队来说是个非常强大的工具。任何开发者都可以轻而易举地和其他开发者共享修改,任何分支都能高效地并入主代码库。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# 什么是Git
|
||||
|
||||
> BY houkensjtu([houkensjtu@github](https://github.com/houkensjtu))
|
||||
> BY houkensjtu([houkensjtu@github](https://github.com/houkensjtu))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/what-is-git)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/what-is-git)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
Git是目前世界上被最广泛使用的现代软件版本管理系统。Git本身亦是一个成熟并处于活跃开发状态的开源项目,它最初是由Linux操作系统内核的创造者Linus Torvalds在2005年创造。今天惊人数量的软件项目依赖Git进行版本管理,这些项目包括开源以及各种商业软件。Git在职业软件开发者中拥有良好的声誉,Git目前支持绝大多数的操作系统以及IDE(Integrated Development Environments)。
|
||||
Git 是目前世界上被最广泛使用的现代软件版本管理系统。Git 本身亦是一个成熟并处于活跃开发状态的开源项目,它最初是由 Linux 操作系统内核的创造者 Linus Torvalds 在 2005 年创造。今天惊人数量的软件项目依赖 Git 进行版本管理,这些项目包括开源以及各种商业软件。Git 在职业软件开发者中拥有良好的声誉,Git 目前支持绝大多数的操作系统以及 IDE(Integrated Development Environments)。
|
||||
|
||||
Git使用分散式架构,是分散式版本管理DVCS(Distributed Version Control System)的代表。相较于例如CVS或者Subversion等集中式版本管理软件,Git并不是将代码的所有修改历史保存在中心服务器中。在Git中取而代之的是,所有参与项目的开发者都拥有各自的代码完全拷贝,并在自己的拷贝上进行软件开发。
|
||||
Git 使用分散式架构,是分散式版本管理 DVCS(Distributed Version Control System)的代表。相较于例如 CVS 或者 Subversion 等集中式版本管理软件,Git 并不是将代码的所有修改历史保存在中心服务器中。在 Git 中取而代之的是,所有参与项目的开发者都拥有各自的代码完全拷贝,并在自己的拷贝上进行软件开发。
|
||||
|
||||
除了分散式的特点之外,Git 的设计也针对性能,安全性和柔软性作了特别优化。
|
||||
|
||||
@ -65,12 +65,12 @@ Git同时享有极好的社区支持和庞大的用户群体。你可以找到
|
||||
|
||||
对于 Git 的一个常见批评是它非常难以掌握。Git 中的某些术语对刚上手的朋友或者是使用其他系统的朋友可能会比较陌生,比如说,`revert` 这个命令在 Git 中和在 SVN 或者 CVS 中具有不同的含义。不过尽管如此,Git 依然向用户提供了非常强大的功能。学习掌握这些功能也许会花一些时间,但是一旦你学会了这些技能,它们会帮助你大大提高团队的开发效率。
|
||||
|
||||
对于曾经使用非分散式版本管理的团队来说,保存代码的中央服务器可能是他们所不想舍去的。不过,虽然Git的确是分散式的架构设计,但是你依然可以设立一个“官方”的代码库来强制保存所有的修改。使用Git时,由于所有的开发者都拥有完整的代码库拷贝,所以他们的工作不会被中央服务器的性能甚至有无左右。即便他们下线或者在外,他们依然可以随时查看代码库的修改历史。得益于Git的分散式特性,你可以保持自己原有的工作方式但得到Git带来的额外好处,有时候你甚至会发现自己不曾意识到有些事居然还可以这样干。
|
||||
对于曾经使用非分散式版本管理的团队来说,保存代码的中央服务器可能是他们所不想舍去的。不过,虽然 Git 的确是分散式的架构设计,但是你依然可以设立一个「官方」的代码库来强制保存所有的修改。使用 Git 时,由于所有的开发者都拥有完整的代码库拷贝,所以他们的工作不会被中央服务器的性能甚至有无左右。即便他们下线或者在外,他们依然可以随时查看代码库的修改历史。得益于 Git 的分散式特性,你可以保持自己原有的工作方式但得到 Git 带来的额外好处,有时候你甚至会发现自己不曾意识到有些事居然还可以这样干。
|
||||
|
||||
现在你明白了什么是版本管理,什么是 Git 以及为什么我们要选择使用 Git ,接下来你可以选择阅读下一篇文章,在那里我们将解释 Git 给团队和业务所带来的好处。
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 检查仓库状态
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/inspecting-a-repository/git-log)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/inspecting-a-repository/git-log)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
## git status
|
||||
|
||||
@ -41,9 +41,9 @@ git status
|
||||
|
||||
#### 忽略文件
|
||||
|
||||
未追踪的文件通常有两类。它们要么是项目新增但还未提交的文件,要么是像`.pyc` `.obj` `.exe`等编译后的二进制文件。显然前者应该出现在`git status`的输出中,而后者会让我们困惑究竟发生了什么。
|
||||
未追踪的文件通常有两类。它们要么是项目新增但还未提交的文件,要么是像 `.pyc`、`.obj`、`.exe` 等编译后的二进制文件。显然前者应该出现在 `git status` 的输出中,而后者会让我们困惑究竟发生了什么。
|
||||
|
||||
因此,Git允许你完全忽略这些文件,只需要将路径放在一个特定的`.gitignore`文件中。所有想要忽略的文件应该分别写在单独一行,*字符用作通配符。比如,将下面这行加入项目根目录的`.gitignore`文件可以避免编译后的Python模块出现在`git status`中:
|
||||
因此,Git 允许你完全忽略这些文件,只需要将路径放在一个特定的 `.gitignore` 文件中。所有想要忽略的文件应该分别写在单独一行,`*` 字符用作通配符。比如,将下面这行加入项目根目录的`.gitignore`文件可以避免编译后的Python模块出现在`git status`中:
|
||||
|
||||
```
|
||||
*.pyc
|
||||
@ -71,8 +71,6 @@ git status
|
||||
|
||||
`git log` 命令显示已提交的快照。你可以列出项目历史,筛选,以及搜索特定更改。`git status` 允许你查看工作目录和缓存区,而 `git log` 只作用于提交的项目历史。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
log 输出可以有很多种自定义的方式,从简单地筛选提交,到用完全自定义的格式显示。其中一些最常用的 `git log` 配置如下所示。
|
||||
@ -107,7 +105,7 @@ git log --stat
|
||||
git log -p
|
||||
```
|
||||
|
||||
显示代表每个提交的一堆信息。显示每个提交全部的差异(diff),这也是项目历史中最详细的视图。
|
||||
显示代表每个提交的一堆信息。显示每个提交全部的差异(diff),这也是项目历史中最详细的视图。
|
||||
|
||||
```
|
||||
git log --author="<pattern>"
|
||||
@ -148,9 +146,9 @@ commit 3157ee3718e180a9476bf2e5cab8e3f1e78a73b7
|
||||
Author: John Smith
|
||||
```
|
||||
|
||||
大多数时候都很简单直接。但是,第一行需要解释下。`commit`后面40个字的字符串是提交内容的SHA-1校验总和(checksum)。它有两个作用。一是保证提交的正确性——如果它被损坏了,提交会生成一个不同的校验总和。第二,它是提交唯一的标识ID。
|
||||
大多数时候都很简单直接。但是,第一行需要解释下。`commit` 后面 40 个字的字符串是提交内容的 SHA-1 校验总和(checksum)。它有两个作用。一是保证提交的正确性——如果它被损坏了,提交会生成一个不同的校验总和。第二,它是提交唯一的标识 ID。
|
||||
|
||||
这个ID可以用于`git log ..`这样的命令中来引用具体的提交。比如,`git log 3157e..5ab91`会显示所有ID在 `3157e`和`5ab91`之间的提交。除了校验总和之外,分支名、HEAD关键字也是常用的引用提交的方法。`HEAD`总是指向当前的提交,无论是分支还是特定提交也好。
|
||||
这个 ID 可以用于 `git log` 这样的命令中来引用具体的提交。比如,`git log 3157e..5ab91` 会显示所有ID在 `3157e` 和 `5ab91` 之间的提交。除了校验总和之外,分支名、HEAD 关键字也是常用的引用提交的方法。`HEAD` 总是指向当前的提交,无论是分支还是特定提交也好。
|
||||
|
||||
~字符用于表示提交的父节点的相对引用。比如,`3157e~1` 指向 `3157e` 前一个提交,`HEAD~3` 是当前提交的回溯3个节点的提交。
|
||||
|
||||
@ -164,7 +162,7 @@ Author: John Smith
|
||||
git log --author="John Smith" -p hello.py
|
||||
```
|
||||
|
||||
这个命令会显示`John Smith`作者对`hello.py`文件所做的所有更改的差异比较(diff)。
|
||||
这个命令会显示 `John Smith` 作者对 `hello.py` 文件所做的所有更改的差异比较(diff)。
|
||||
|
||||
..句法是比较分支很有用的工具。下面的栗子显示了在 `some-feature` 分支而不在 `master` 分支的所有提交的概览。
|
||||
|
||||
@ -172,11 +170,8 @@ git log --author="John Smith" -p hello.py
|
||||
git log --oneline master..some-feature
|
||||
```
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
## 检出之前的提交
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/viewing-old-commits)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/viewing-old-commits)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
## git checkout
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
git checkout master
|
||||
```
|
||||
|
||||
回到master分支。分支会在下一节中讲到,而现在,你只需要将它视为回到项目『当前』状态的一种方式。
|
||||
回到 master 分支。分支会在下一节中讲到,而现在,你只需要将它视为回到项目「当前」状态的一种方式。
|
||||
|
||||
```
|
||||
git checkout <commit> <file>
|
||||
@ -32,24 +32,16 @@ git checkout <commit>
|
||||
|
||||
### 讨论
|
||||
|
||||
版本控制系统背后的思想就是『安全』地储存项目的拷贝,这样你永远不用担心什么时候不可复原地破坏了你的代码库。当你建立了项目历史之后,`git checkout`是一种便捷的方式,来将保存的快照『加载』到你的开发机器上去。
|
||||
|
||||
检出之前的提交是一个只读操作。在查看旧版本的时候绝不会损坏你的仓库。你项目『当前』的状态在 `master`上不会变化。在开发的正常阶段,`HEAD`一般指向master或是其他的本地分支,但当你检出之前提交的时候,`HEAD`就不再指向一个分支了——它直接指向一个提交。这被称为『分离`HEAD`』状态 ,可以用下图可视化:
|
||||
|
||||
版本控制系统背后的思想就是「安全」地储存项目的拷贝,这样你永远不用担心什么时候不可复原地破坏了你的代码库。当你建立了项目历史之后,`git checkout` 是一种便捷的方式,来将保存的快照「加载」到你的开发机器上去。
|
||||
|
||||
检出之前的提交是一个只读操作。在查看旧版本的时候绝不会损坏你的仓库。你项目「当前」的状态在 `master` 上不会变化。在开发的正常阶段,`HEAD` 一般指向 master 或是其他的本地分支,但当你检出之前提交的时候,`HEAD` 就不再指向一个分支了——它直接指向一个提交。这被称为「分离 `HEAD`」状态 ,可以用下图可视化:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在另一方面,检出旧文件不影响你仓库的当前状态。你可以在新的快照中像其他文件一样重新提交旧版本。所以,在效果上,`git checkout` 的这个用法可以用来将单个文件回滚到旧版本 。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 栗子
|
||||
|
||||
#### 查看之前的版本
|
||||
@ -70,13 +62,13 @@ a1e8fb5 对hello.py做了一些修改
|
||||
9773e52 初始导入
|
||||
```
|
||||
|
||||
你可以这样使用`git checkout`来查看『对hello.py做了一些修改』这个提交:
|
||||
你可以这样使用 `git checkout` 来查看「对 hello.py 做了一些修改」这个提交:
|
||||
|
||||
```
|
||||
git checkout a1e8fb5
|
||||
```
|
||||
|
||||
这让你的工作目录和`a1e8fb5`提交所处的状态完全一致。你可以查看文件,编译项目,运行测试,甚至编辑文件而不需要考虑是否会影响项目的当前状态。你所做的一切 *都不会* 被保存到仓库中。为了继续开发,你需要回到你项目的『当前』状态:
|
||||
这让你的工作目录和 `a1e8fb5` 提交所处的状态完全一致。你可以查看文件,编译项目,运行测试,甚至编辑文件而不需要考虑是否会影响项目的当前状态。你所做的一切 *都不会* 被保存到仓库中。为了继续开发,你需要回到你项目的「当前」状态:
|
||||
|
||||
```
|
||||
git checkout master
|
||||
@ -94,17 +86,14 @@ git checkout master
|
||||
git checkout a1e8fb5 hello.py
|
||||
```
|
||||
|
||||
记住,和检出提交不同,这里 *确实* 会影响你项目的当前状态。旧的文件版本会显示为『需要提交的更改』,允许你回滚到文件之前的版本。如果你不想保留旧的版本,你可以用下面的命令检出到最近的版本:
|
||||
记住,和检出提交不同,这里 *确实* 会影响你项目的当前状态。旧的文件版本会显示为「需要提交的更改」,允许你回滚到文件之前的版本。如果你不想保留旧的版本,你可以用下面的命令检出到最近的版本:
|
||||
|
||||
```
|
||||
git checkout HEAD hello.py
|
||||
```
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「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)。
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# 重写项目历史
|
||||
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/))
|
||||
>
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/rewriting-history)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/rewriting-history)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。
|
||||
|
||||
## 概述
|
||||
|
||||
GIt的主要职责是保证你不会丢失提交的修改。但是,它同样被设计成让你完全掌控开发工作流。这包括了让你自定义你的项目历史,而这也创造了丢失提交的可能性。Git提供了可以重写项目历史的命令,但也警告你这些命令可能会让你丢失内容。
|
||||
Git 的主要职责是保证你不会丢失提交的修改。但是,它同样被设计成让你完全掌控开发工作流。这包括了让你自定义你的项目历史,而这也创造了丢失提交的可能性。Git 提供了可以重写项目历史的命令,但也警告你这些命令可能会让你丢失内容。
|
||||
|
||||
这份教程讨论了重写提交快照的一些常见原因,并告诉你如何避免不好的影响。
|
||||
|
||||
@ -54,14 +54,10 @@ git commit --amend --no-edit
|
||||
|
||||
## git rebase
|
||||
|
||||
变基(rebase, 事实上这个名字十分诡异, 所以在大多数时候直接用英文术语)是将分支移到一个新的基提交的过程。过程一般如下所示:
|
||||
|
||||
|
||||
变基(rebase, 事实上这个名字十分诡异, 所以在大多数时候直接用英文术语)是将分支移到一个新的基提交的过程。过程一般如下所示:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
从内容的角度来看,rebase 只不过是将分支从一个提交移到了另一个。但从内部机制来看,Git 是通过在选定的基上创建新提交来完成这件事的——它事实上重写了你的项目历史。理解这一点很重要,尽管分支看上去是一样的,但它包含了全新的提交。
|
||||
|
||||
### 用法
|
||||
@ -76,17 +72,13 @@ git rebase <base>
|
||||
|
||||
rebase 的主要目的是为了保持一个线性的项目历史。比如说,当你在 feature 分支工作时 master 分支取得了一些进展:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
要将你的feature分支整合进`master`分支,你有两个选择:直接merge,或者先rebase后merge。前者会产生一个三路合并(3-way merge)和一个合并提交,而后者产生的是一个快速向前的合并以及完美的线性历史。下图展示了为什么rebase到`master`分支会促成一个快速向前的合并。
|
||||
要将你的 feature 分支整合进 `master` 分支,你有两个选择:直接 merge,或者先 rebase 后 merge。前者会产生一个三路合并(3-way merge)和一个合并提交,而后者产生的是一个快速向前的合并以及完美的线性历史。下图展示了为什么 rebase 到 `master` 分支会促成一个快速向前的合并。
|
||||
|
||||

|
||||
|
||||
rebase是将上游更改合并进本地仓库的通常方法。你每次想查看上游进展时,用`git merge`拉取上游更新会导致一个多余的合并提交。在另一方面,rebase就好像是说:“我想将我的更改建立在其他人的进展之上。”
|
||||
rebase 是将上游更改合并进本地仓库的通常方法。你每次想查看上游进展时,用 `git merge` 拉取上游更新会导致一个多余的合并提交。在另一方面,rebase 就好像是说「我想将我的更改建立在其他人的进展之上」。
|
||||
|
||||
#### 不要 rebase 公共历史
|
||||
|
||||
@ -144,11 +136,11 @@ git rebase -i <base>
|
||||
|
||||
### 讨论
|
||||
|
||||
交互式rebase给你了控制项目历史的完全掌控。它给了开发人员很大的自由,因为他们可以提交一个“混乱”的历史而只需专注于写代码,然后回去恢复干净。
|
||||
交互式 rebase 给你了控制项目历史的完全掌控。它给了开发人员很大的自由,因为他们可以提交一个「混乱」的历史而只需专注于写代码,然后回去恢复干净。
|
||||
|
||||
大多数开发者喜欢在并入主代码库之前用交互式rebase来完善他们的feature分支。他们可以将不重要的提交合在一起,删除不需要的,确保所有东西在提交到“正式”的项目历史前都是整齐的。对其他人来说,这个功能的开发看上去是由一系列精心安排的提交组成的。
|
||||
大多数开发者喜欢在并入主代码库之前用交互式 rebase 来完善他们的 feature 分支。他们可以将不重要的提交合在一起,删除不需要的,确保所有东西在提交到「正式」的项目历史前都是整齐的。对其他人来说,这个功能的开发看上去是由一系列精心安排的提交组成的。
|
||||
|
||||
### 例子
|
||||
### 栗子
|
||||
|
||||
下面这个🌰是 `非交互式rebae` 一节中🌰的可交互升级版本。
|
||||
|
||||
@ -186,8 +178,6 @@ squash 62eed47 Fix something from the previous commit
|
||||
|
||||
保存并关闭编辑器以开始 rebase。另一个编辑器会打开,询问你合并后的快照的提交信息。在定义了提交信息之后,rebase 就完成了,你可以在 `git log` 输出中看到那个提交。整个过程可以用下图可视化:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
注意缩并的提交和原来的两个提交的 ID 都不一样,告诉我们这确实是个新的提交。
|
||||
@ -233,7 +223,7 @@ git reflog --relative-date
|
||||
c10f740 HEAD@{2}: checkout: moving from master to 2.2
|
||||
```
|
||||
|
||||
上面的引用日志显示了master和2.2 branch之间的相互切换。还有对一个更老的提交的强制重设。最近的活动用`HEAD@{0}`标记在上方显示。
|
||||
上面的引用日志显示了 master 和 2.2 的 branch 之间的相互切换。还有对一个更老的提交的强制重设。最近的活动用 `HEAD@{0}` 标记在上方显示。
|
||||
|
||||
如果事实上你是不小心切换回去的,引用日志包含了你意外地丢掉两个提交之前 master 指向的提交 0254ea7。
|
||||
|
||||
@ -245,9 +235,7 @@ git reset --hard 0254ea7
|
||||
|
||||
务必记住,引用日志提供的安全网只对提交到本地仓库的更改有效,而且只有移动操作会被记录。
|
||||
|
||||
|
||||
|
||||
> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
> 这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
>
|
||||
> 如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
>
|
||||
|
||||
@ -8,12 +8,12 @@ git-recipes的所有文章都以Wiki的方式呈现,请移步[项目Wiki](http
|
||||
|
||||
我为什么要做这份菜单
|
||||
---
|
||||
在整理Git资料的时候,我发现社区贡献了非常多高质量的博客文章、指南等等。尤其英文的那些资料,除了大家熟知的《Git图解》,还有好多优秀的文章仍无人翻译。此外,这些资料往往只涉及某些特定的话题,如果能有一份菜单将这些菜谱以特定的方式串起来,那么对于Git学习者来说将会是极大的便利。尤其对于我这样热爱查阅社区资料胜过出版物的懒人 : ) 随着我的学习节奏还会不断有新的菜谱加入进来,或许不会很频繁,不过也没有确定的终点。
|
||||
在整理 Git 资料的时候,我发现社区贡献了非常多高质量的博客文章、指南等等。尤其英文的那些资料,除了大家熟知的《Git 图解》,还有好多优秀的文章仍无人翻译。此外,这些资料往往只涉及某些特定的话题,如果能有一份菜单将这些菜谱以特定的方式串起来,那么对于 Git 学习者来说将会是极大的便利。尤其对于我这样热爱查阅社区资料胜过出版物的懒人 :] 随着我的学习节奏还会不断有新的菜谱加入进来,或许不会很频繁,不过也没有确定的终点。
|
||||
|
||||
版权说明
|
||||
---
|
||||
除非另行注明,这个项目中的所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享,童仲毅(geeeeeeeeek@github)版权所有。
|
||||
除非另行注明,这个项目中的所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享,童仲毅(geeeeeeeeek@github)版权所有。
|
||||
|
||||
其中不少资料是在原基础上翻译或演绎而来的,我都在页面最上方标明了原作者、原文链接以及原文采用的协议。如仍有版权疑问,请在issue中提出。
|
||||
其中不少资料是在原基础上翻译或演绎而来的,我都在页面最上方标明了原作者、原文链接以及原文采用的协议。如仍有版权疑问,请在 Issue 中提出。
|
||||
|
||||
欢迎通过issue或者pr推荐你认为合适的资料,让这份菜单更充实一些。
|
||||
欢迎通过 Issue 或者 Pull Request 推荐你认为合适的资料,让这份菜单更充实一些。
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
- **第1章** [图解 Git 命令](https://github.com/geeeeeeeeek/git-recipes/wiki/4.1-%E5%9B%BE%E8%A7%A3Git%E5%91%BD%E4%BB%A4)
|
||||
|
||||
如果你稍微理解git的工作原理,这篇文章能够让你理解的更透彻。
|
||||
如果你稍微理解 Git 的工作原理,这篇文章能够让你理解的更透彻。
|
||||
|
||||
**第5篇 Git 实用贴士**
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
这篇文章是[**「git-recipes」**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。
|
||||
|
||||
如果你觉得文章对你有帮助,欢迎点击右上角的***Star***:star2:或***Fork***:fork_and_knife:。
|
||||
如果你觉得文章对你有帮助,欢迎点击右上角的 ***Star***:star2: 或 ***Fork***:fork_and_knife:。
|
||||
|
||||
如果你发现了错误,或是想要加入协作,请参阅[Wiki协作说明](https://github.com/geeeeeeeeek/git-recipes/issues/1)。
|
||||
Reference in New Issue
Block a user