Git工作流:中心工作流(翻译)
使用Git作为版本控制器,有众多可能的工作流(Workflow),这使得我们这些新鸟不知道在实际工作中不知道该选择哪种工作流。这里我们对最常见的Git工作流做一个对比,为企业团队提供一个参考。
中心化的工作流(Centralized Workflow)
转换到分布式的版本控制系统,看起来可能是一个令人生怯的任务,但是你并不是必须要通过改变你先现有的工作流来发挥Git的优势。你的团队可以使用和Subversion一样的方式来开发项目。
但是,使用Git来运转你们的开发工作流还是会表现出一些SVN没有的优点。首先,Git让每个开发者在本地有一个完整的项目复本。这个独立于中心库的环境使得每个开发者和其他开发者对项目的修改独立开来——他们可以在本地库上进行提交操作,而且他们可以完全不上传他们的开发,直到他们认为是上传的时机到了再上传。
其次,Git为你提供了使用Git强大的分支和合并模型。不像SVN,为了方便Git代码的集成,以及在库与库之间分享修改,Git的分支被设计成一种fail-safe的机制。
How It Works
和Subversion一样,中心化的工作流使用一个中心库作为所有代码对项目修改的一个单点入口。这里抛弃trunk的概念,默认的开发分支被称为 master分支,所有对项目的修改都被提交到这个分支。这个工作流不需要其他除master分支以外的任何分支。
开发者的开发从克隆中心库开始。在他们的本地项目复本中,他们可以和使用SVN一样,进行修改文件,提交修改的操作;但是,不同的是,这些新的提交被保存在本地——也就说这个本地副本和中心库是完全独立的。这种方式允许开发者延迟将本地的修改上传,直到一个合适的时间点再上传所有的commmits到中心库。
为了将所有本地的修改发布到官方项目(中心库)上,开发者需要将他们的本地master分支”push“到中心库。这和svn的commmit是等效的,不同之处在于git提交的是所有在本地存在而中心库没有的commit。
冲突管理
中心库代表的是官方项目,所以中心库的提交历史需要被视为庄严的且不可更改的。如过一个开发者的本地commits偏离了(diverge)中心库,git将拒绝他的push操作,因为这个操作会导致对官方提交的覆盖。
在开发者可以发布他的特性之前,他们需要获取中心库中提交,且把本地的修改重新定基(rebase)在中心库之上。这就好比再说:”我想把我的修改添加到其他人已经做的修改之上。“正如传统的SVN工作流一样,这样操作的结果是一个完美的线性历史。
如过本地的修改和上流的提交产生直接的冲突,Git将暂停重新定基(rebase)操作,并且给你机会手动解决冲突。比较好的一点是,在解决冲突的时候,使用git status 和 git add命令的方式是不变的。这有利于开发者方便的管理自己的冲突。另外,如过他们方法自己陷入到解决冲突的麻烦中,Git提供了方便的方式来放弃当前rebase,也很方便的可以再次rebase(当然,也可以去寻求他人的帮助)。
示例
我们来一步一步的操作,看看典型的小团队是怎样使用这个工作流的。我们会看到两个开发者(Hohn和Mary)是如何在同一个特性上工作,并在同一个中心库上分享自己的贡献。
初始化中心库
首先,某人需要在魔偶个服务器上创建一个中心库。如过这是个新项目,你可以初始化一个空的库。否则,你需要从显存的Git或SVN库中导入。
中心化的仓库总是从一个空库(没有工作目录)开始的,使用下面的方式创建:
ssh user@host git init --bare /path/to/repo.git
请确保你提供的是一个合法的SSH用户名,host用服务器域名或者IP地址代替,最后选择一个你想来存放库的路径。
每个人从中心库克隆
从中心库克隆之后额,每个开发者都创建了一个完整项目的本地复本。这是通过git clone 命令完成的:
git clone ssh://user@host/path/to/repo.git
当你完成对中心库的clone之后,Git会自动的添加一个名叫origin的捷径,这个origin会指向”父亲“仓库。创建这个捷径是基于你将会和”父亲“仓库进行交互的假设。
John开发他的特性
在John的本地仓库,John想是用标准的Git commit流程(edit,stage,和commit)来开发他的特性。如过你对stage不熟悉,请记住他是一种并不需要包含对工作目录的所有修改的提交方式。这使得即使你进行了大量的本地修改,你依然可以进行高度集中的提交。
git status # VIew the state of the repo
git add <some-fiel> # Stage a file
git commit # Commit a file </some-file>
记住一点,由于这些命令创建的是本地提交操作,John可以重复这些过程很多次,而不用担心在中心库上正在发生些生么。这个对一个大特性的开发是十分有用的,因为大特写需要分解成很多更简单、更原子化的块。
Mary在开发她的特性
John发布他的特性
git push origin master
这里的origin和中心库的远程连接,这个在John克隆中心库的时候创建的。参数master告诉Git,试着让中心库的master分支和John的本地master分支一样。因为中心库从John克隆到现在还没有被更新过,所以这不会导致任何的冲突,这次push操作会和预期的一样,被成功执行。
Mary尝试发布她的特性
让我们看看,在John成功发布他的修改到中心库后,如过Mary尝试push她的特性会发生什么。她使用同样的命令来push:
git push origin master
但是,由于他的本地历史偏离了中心库,GIt会拒绝她的请求,并返回如下复杂的错误信息:
error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Mary在John的commit上面rebase
git pull --rebase origin master
这里--rebase的选项告诉Git将Mary所有的commit移动到和中心库的修改同步后的master分支的末端,如下图所示:
没有--rebase选项,pull同样会起作用,但是这样做的结果是,每次有人要和中心库同步的时候,都是产生一个不必要的merge commit。对于这个工作流,用rebase代替merge commit是最佳的选择。
Mary解决一次merge冲突
Rebase的过程将所有本地的提交一个接一个(每次一个)的转移到更新后的master分支的过程。这意味这你得到的冲突时基于commit-by-commit的,而不是在整个修改上的。这样就保证了工作尽可能的聚焦在你的提交上,从而保证了一个干净的项目历史。相应的,这样做使得找出bug在哪里传参数跟更加容易。如过必要,可以对项目产生最小影响的情况下进行回滚操作。
如过Mary和John是在开发不相关de特性,那么在rebase的过程中产生冲突的可能性不大。但是如果产生了,GIt会在产生冲突的当前commit处暂停rebase,并输出如下的消息,同时给出相关的解决建议:
CONFLICT (content): Merge conflict in <some-file>
Git的伟大之处在于任何人都可以解决他们自己合并中遇到的冲突。在我们的例子中,Mary会通过git status命令查看问题发生在哪里。产生冲突的文件会显示在Unmerged路径部分:
# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>
git add <some-file>
git rebase --continue
这便是解决冲突的所有过程了。Git将会继续对下一个commit进行重复的过程,对其他产生冲突的commit使用同样的流程处理。
如过在这个过程中,你觉得没办法处理了,不要害怕。只要指向下面的命令,你就可以回到你在运行 git pullo --rebae之前了:
git rebase --abort
这便是解决冲突的所有过程了。Git将会继续对下一个commit进行重复的过程,对其他产生冲突的commit使用同样的流程处理。
如过在这个过程中,你觉得没办法处理了,不要害怕。只要指向下面的命令,你就可以回到你在运行 git pull --rebae之前了:
git rebase --abort
Marry成功发布她的特性
她完成和中心库的同步后,Mary便可以成功发布他对项目的修改了:
git push origin master
从这里,我们可以到哪儿?
正如你看到的那样,可以通过价格简单的Git命令,便可以复用传统的Subversion开发环境。对于从SVN转移过来的团队,这是很了不起的,但是这却没有充分利用到Git分布式的特性。
如过你的团队乐于使用中心化的工作流,但那时又想简单化团队协作,那么你们可以去探索下特性分支工作流(Feature Branch Workflow)。通过专注在一个独立的分支上开发一个特性,可以在将这些新东西集成到官方项目之前对他们进行升入的讨论。
Git工作流:中心工作流(翻译)的更多相关文章
- 好代码是管出来的——Git的分支工作流与Pull Request
上一篇文章介绍了常用的版本控制工具以及git的基本用法,从基本用法来看git与其它的版本控制工具好像区别不大,都是对代码新增.提交进行管理,可以查看提交历史.代码差异等功能.但实际上git有一个重量级 ...
- Git版本控制与工作流详解
这篇文章是针对git版本控制和工作流的总结,如果有些朋友之前还没使用过git,对git的基本概念和命令不是很熟悉,可以从以下基本教程入手: 专为设计师而写的GitHub快速入门教程 git – 简明指 ...
- Git - Pull Request工作流
Pull Requests是Bitbucket上方便开发者之间协作的功能.提供了一个用户友好的Web界面,在集成提交的变更到正式项目前可以对变更进行讨论. 开发者向团队成员通知功能开发已经完成,Pul ...
- Git的各种工作流
Git工作流可以理解为团队成员遵守的一种代码管理方案,在Git中有以下几种常见工作流: 集中式工作流 功能开发工作流 Gitflow工作流 Forking工作流 1)集中式工作流 这种工作方式跟svn ...
- SpringCloud实战之初级入门(三)— spring cloud config搭建git配置中心
目录 1.环境介绍 2.配置中心 2.1 创建工程 2.2 修改配置文件 2.3 在github中加入配置文件 2.3 修改启动文件 3. 访问配置中心 1.环境介绍 上一篇文章中,我们介绍了如何利用 ...
- Git版本控制与工作流
基本概念 Git是什么? Git是分布式版本控制系统,与SVN类似的集中化版本控制系统相比,集中化版本控制系统虽然能够令多个团队成员一起协作开发,但有时如果中央服务器宕机的话,谁也无法在宕机期间提交更 ...
- git学习(4)---工作流
一.目的 前三章介绍了git工具本身的操作,主要包含本地仓库操作和远程库操作两部分内容.接下来,我们将介绍怎样使用git进行项目开发,也叫做git工作流. git工作流分为三种模式:共享远程库模式.独 ...
- Git之GitFlow工作流
一. GitFlow 介绍 1.1 什么是 GitFlow GitFlow 是一种 Git 工作流,它是团队成员遵守的一种代码管理方案 . 1.2 GitFlow 常用分支说明 分支名称 分支说明 P ...
- 版本管理工具Git三种工作流
Git是分布式版本管理控制的工具.学习Git一般都是先去学习Git的命令. 但是学习完Git的基本命令之后还是不知道怎样使用Git.首先,我们要清楚的 一点是Git的使用方法其实有很多种,也就是说Gi ...
随机推荐
- DES加密和解密PHP,Java,ObjectC统一的方法
原文:DES加密和解密PHP,Java,ObjectC统一的方法 PHP的加解密函数 <?php class DesComponent { var $key = '12345678'; func ...
- SSIS从理论到实战,再到应用(4)----流程控制之For循环
原文:SSIS从理论到实战,再到应用(4)----流程控制之For循环 上期回顾: SSIS从理论到实战,再到应用(3)----SSIS包的变量,约束,常用容器 在SSIS体系中,控制流可能经常会遇到 ...
- hdu 5066 Harry And Physical Teacher(Bestcoder Round #14)
Harry And Physical Teacher Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
- 第20章 状态模式(State Pattern)
原文 第20章 状态模式(State Pattern) 状态模式 概述: 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当控制一个对象状态的条件表 ...
- 測试之路2——对照XML文件1
才来几天,老大又给了我一个新的任务.不像曾经的建100个任务project那么坑爹,却还是顿时让我感觉压力山大. 由于在这之前,我改了他写的例程,用于生成新的任务项目,事实上任务项目就是通过XML文件 ...
- 都能看懂的嵌入式linux/android alsa_aplay alsa_amixer命令行使用方法
前几天在嵌入式linux上用到alsa command,网上查的资料多不给力,仅仅有动手一点点查,最终能够用了,将这个用法告诉大家,以免大家少走弯路. 0.先查看系统支持哪几个alsa cmd: ll ...
- ToDictionary() and ToList()
ToDictionary() and ToList() 前言: 有两个简单好用的LINQ扩展方法 ToDictionary() 和ToList(),你可能知道或不知道,但是它的的确确可以简化查询转化为 ...
- java_ java多线程返回函数结果
两种方式:一种继承Thread类实现:一种通过实现Callable接口. 第一种方法: 因为实现Thread类的run方法自身是没有返回值的,所以不能直接获得线程的执行结果,但是可以通过在run方法里 ...
- 【高德API】如何利用MapKit开发全英文检索的iOS地图
原文:[高德API]如何利用MapKit开发全英文检索的iOS地图 制作全英文地图的展示并不困难,但是要制作全英文的数据检索列表,全英文的信息窗口,你就没办法了吧.告诉你,我有妙招!使用iOS自带的M ...
- 心有多宽 路就有多宽-- BreezeMH源码公布
非常多话想说,但不知道从何说起~ 去年暑假做自己的第一个外挂,然后是Breeze‘s魔兽系列工具,測试版.正式版,看着自己进大学时的梦想慢慢的变成现实,那种喜悦感无法言表,于是就想着让很多其它的在校大 ...