GIT团队合作探讨之一-保持工作同步的概念和实践
感谢英文原文作者,这是我看到的关于git协同工作写的最清晰简洁的文章了:
https://www.atlassian.com/git/tutorials/syncing/git-push
SVN使用一个单一的中央库,作为所有开发人员的通信中枢,而合作是通过在开发人员的拷贝和中央库之间传递变更集来实现的。这和GIT的合作模型大不相同。GIT下面,每一位开发人员都有一个repo的完整拷贝,本地工作完成后,开发人员就有了自己的本地历史和分支结构。开发人员通常需要分享一些列commits(而不是单一一个变更集)。GIT不像SVN那样从本地copy向中央库递交单个变更集,GIT实际上是让你在不同的库之间分享分支。
下面的米in高龄允许你管理和其他库之间的connections,通过pushing branches到其他的repo来发布Local history,而通过pulling branches来获取其他人员的贡献到local repo.
git remote
git remote 命令允许你create,view,delete和其他库的connection. Remote connection更像一个bookmark书签,而不是一个直接链接到其他的库中。这些remote connection并不会提供对其他库的实时访问机制,他们仅仅作为一种能够用以引用其他repo的并不友好的url而方便使用的名字而已。
例如,下图中显示了从你的repo分别指向“中央库”和其他开发人员库。我们并不用使用全名称的URL来引用其他库,你只需要传入origin和john短connection名称给其他的git命令即可。
用法:
git remote
git remote -v //列出所有指向其他repo的connections详细信息
git remote add <name> <url> //创建一个指向一个remote repo的新的connection.在上述命令执行后,你就可以通过使用<name>来作为引用<url>的便利手段了,比如:
git remote rm <name> //通过这个命令来删除和remote repo的一个<name>连接
git remote rename <old-name> <new-name> //重命名从old到new
探讨:
Git被设计成给每一个开发人员一个完整独立的开发环境。这意味着信息并不会自动地在不同repo之间流动。相反,开发人员需要手工地pull upstream commits到本地repo,或者手动地push local commits到中央repo。git remote命令实际上仅仅是座位一种方便传递repo url到这些"sharing"命令的一种手段。
origin remote
当你clone一个repo时(git clone命令),git将自动创建一个被命名为origin的remote connection,这个origin connection将自动指向被clone的库。这对开发人员创建中央库的本地copy并且实现本地开发非常有用,因为通过origin,开发人员可以非常方便地pull upstream或者publish local commits.这种行为也是为什么大多数git-based 项目就称呼他们的中央库为origin的原因吧。
Repository URLs
Git支持非常多的方式来引用一个remote repo。两种最简单的方法是:HTTP或者SSH。HTTP是一种允许匿名访问的read-only的协议模式,例如:
http://host/path/to/repo.git
但是通常不允许push commit到一个HTTP地址。为了写操作,你需要使用SSH协议(加上一个帐号密码):
ssh://user@host/path/to/repo.git
你需要在host主机上有一个有效的SSH帐号。
例子:
除了origin,为了方便合作,通常你可能需要指向你的同事的repo的一个remote connection。
例如,如果你的同僚John,他可能维护了一个可以公开访问的repo:dev.example.com/john.git.你可以这样来增加一个remote connection:
git remote add john http://dev.example.com/john.git
通过这种方式来访问个别开发人员的repo的模式使得git能够在“中央库”之外来达到沟通合作。这种模式对于小团队大项目非常有用。也正因为这种模式使得在git中“中央库”的概念越来越淡化,甚至可以没有central repo,因为每个人都可以称为中央库(如果你愿意的话)
git fetch
git fetch命令从remote repo中import commits到本地repo.这个命令的结果是remote repo的commits被作为本地repo的一个remote branch的形式来保存在本地repo中。也就是说remote branch代表了我们的remote repo的真实内容。这种方式给你在真正集成远端变更之前来review确认他们的变更的一个机会
用法
git fetch <remote> //从远端repo中fetch所有的分支。
git fetch <remote> <branch> //仅fetch远端repo的指定的branch分支
探讨:
Fetching是当你希望看到别人的工作成果时你需要做的。既然获取到的commits以一个remote branch来代表,也就意味着fetch方式对你本地开发工作没有任何影响。这种模式给你集成应用别人的改动之前来review提供了方便。这一点和svn update命令类似,它允许你看看中央库有哪些变更,但是并不强迫你实际merge这些变更到你的repo中。
remote branches
remote branches和local branch是完全一样的,不同的是:remote branch代表着来自其他repo的commits(这里其他repo:有可能是其他人的,也可能是你自己的)。你也可以check out一个remote branch,但是这时你将会进入detached HEAD状态(就像checkout一个老的commit一样)。你可以把remote branch视为只读的branch. Remote branch会由一个remote connection名称来做前缀,这样你永远也不会将remote branch和local branch混淆起来。例如:
git branch -r
# origin/master
# origin/develop
# origin/some-feature
//上面的命令就会列出remote名为origin的repo中存在着master,develop,some-feature分支
再次指出,你可以通过checkout那些remote branch并且通过git log命令来检查这些branch的变更。如果你批准了一个remote branch的变更,你可以通过git merge命令来merge这个分支的内容到你的本地分支上去。从这里看出,要获取别人的变更,需要两个过程:fetch和merge。但是git pull命令也提供了一种合二为一的方式。
下面给出一个实际的典型的场景:同步您的本地repo和远端repo的master分支:
$git fetch origin
a1e8fb5..45e66a4 master -> origin/master
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature
//上面的命令说明origin这个remote我们有master,develop,some-feature三个分支都已经拉回来了,分别放在origin/master。。。分支上。
在下面的图中,所有来自remote branch的commits都以方框表示。正如你看到的,git fetch给了你另一个repo整个分支结构的能力!
为了检查到底有了哪些改动在upstream master上,你可以通过给git log命令传入一个origin/master作为filter参数来实现:
git log --oneline master..origin/master
为了批准并且merge这些remote branch上的他人的变更(到你的local branch),你需要这么做:
git checkout master //切换到本地分支环境
git log origin/master //检查remote变更集
git merge origin/master //merge到本地
通过上面的命令完成后origin/master和master就同时指向了相同的commit,你就和upstream developments完全同步了。
git pull
在git-based协作工作流模型中,merge upstream变更到local repo是一个非常普通的任务,虽然通过git fetch+merge两步可以完成这个任务,但是git也提供了一种合二为一的命令git pull
git pull <remote> //获取remote的current branch并且立即merge到local分支,相当于以下命令:
git fetch <remote> & git merge origin/<current-branch>
git pull --rebase <remote>//和上面命令的区别是:使用git rebase而不是git merge来合入remote branch的变更
探讨:
你可以将git pull看作svn update相同功能的版本。它是一种便利地同步本地repo和upstream change的手段。下面几张图描绘了这个pull的过程。
你可能想当然地认为你的repo和remote是同步的,但是git fetch却发现了remote origin的master分支在你最后一次pull/fetch后已经向前走了几步:
pulling via rebase
上面命令例子中提到--rebase参数,这个参数可以通过阻止非必要的merge commit(这是默认的git pull merge模型中必然产生的无意义commit)产生,从而保证一个线性地历史记录。很多开发人员更喜欢rebase,而不是merge。这就像说这么句话:”我想把我的改动放在别人已经做过的工作之上“。
事实上,正是由于--rebase是一个如此common的工作流,以至于已经有了一个特定的配置选项:
git config --global branch.autosetuprebase always //执行这条命令后,所有的git pull命令将集成git rebase,而不是git merge!!!
例子:
下面的例子演示如何和中央库上的master branch来保持同步
git checkout master
git pull --rebase origin
上面的命令将你的local change直接放置于任何其他人的工作之上,从而你也就有了别人的贡献
git push
push是你如何将本地commits传到remote repo上去的方法,这和git fetch是相反的操作,然而fetch/pull是导入commits到local branch上去(也需要通过remote origin/branch做中转),push则是输出你的本地commits到remote repo的local branch(通过本地的remote orgin/branch做中转)中去。这有可能会覆盖变更,所以你需要小心使用,下面就谈谈这些潜在可能存在的问题:
用法:
git push <remote> <branch>
上述命令将本地的<branch> 上的所有commit和内部objects push到<remote>库中,并且这条命令的结果会在<remote> repo中创建一个local branch。为了阻止你可能覆盖remote repo中<branch>分支上的commits,GIT在得知push操作并不会在remote repo中产生一个fast-forward merge时,git会禁止你做push操作。也就是说,默认情况下,你的local branch相比remote origin的local branch(以origin/<branch>来代替)更新的情况下,才允许你push.(换句话说就是remote repo的branch没有做过变更!)
当然,git也为高级用户提供了--force命令来强制允许push操作:
git push <remote> --force//注意一定要小心使用,除非你知道你在干什么,否则别用
git push <remote> --all //push所有的本地branch到指定的remote上去
git push <remote> --tags//默认情况下tags并不会自动push上,使用该标志则push所有本地创建的tag
探讨:
git push最常见的使用场景是发布你的本地修改到中央库中。在你积累了多个本地commit后,并且希望将这些变更分享给团队其他成员,你(optionally)可以通过rebase interactive 来将这些commit梳理一下,然后push到中央库中。
上面这张图展示了当你local master相对于中央库的master分支已经向前走了几步后,你通过执行git push origin master命令来发布你的本地commit到底发生了什么。注意一点:git push基本上就像是在remote repo中执行git merge localmaster命令一样,仔细体会一下
关于Force Pushing:
我们知道当git push会产生一个non-fast-forward merge时,git会拒绝执行这个git push命令,因为一旦执行这条命令,你就会覆盖中央库的历史。
正因为此,如果remote history已经和你的local history分叉了(diverged),你需要首先git pull(git fetch/git merge)到你的本地,并且做好可能的冲突解决,随后再次push。这和SVN如何确保你通过在commit一个change set之前,必须做svn update来和中央库保持同步是类似的概念。
--force标志将取消上面这种默认行为,产生的后果是:remote repo的branch将完全反映你的local history,其他自从你上次git pull操作后upstream分叉出来的所有变更历史都将会丢失。一个可能使用这个--force标志的场景是:当你发现你刚刚分享发布的commits是不对的,而你通过git commit --amend或者一个interactive rebase操作解决了这个问题从而再次发布。然而,你必须确认:没有团队成员pull过你在--force之前push的哪些commits.
Only push to Bare Repositories
而且,你应该只向那些通过--bare标志创建的repo去做push操作。既然push会将remote repo的local branch的结构弄的混乱(原因是push时会在remote repo中创建local branch),因此很重要的一点是:不要向另外一个开发人员的本地repo做push操作(当然也不是很绝对哦!!),由于bare库没有working directory,所以不可能打断任何人的开发工作。
例子:
下面的例子描述了将本地变更向中央库发布的标准方法。首先,通过git fetch/git rebase操作来确保你的本地master分支是up-to-date的(已经包含了所有的remote变更,run local changes on top of them). interactive rebase在这时也是一个在分享发布你的变更前清理他们的很好的机会。然后,git push命令则将所有你的local master变更发布到central repo中去。
git checkout master
git fetch origin master
git rebase -i origin/master
#squash commits, fix up commit messages etc.
git push origin master
既然我们确保我们的local master 是uptodate的,这将会产生一个fast-forward merge,git push再也不会抱怨non-fast-forward问题了。
GIT团队合作探讨之一-保持工作同步的概念和实践的更多相关文章
- GIT团队合作探讨之四--不同工作流优缺辨析
由于git非常强大,它可以支持非常多的协作模式,而可能正因为选择太多反而有时候对于我们如何开始开展团队协作无从下手.本文试图阐述企业团队中应用最为广泛的git 工作流,为大家理清思路,最大限度发挥gi ...
- GIT团队合作探讨之二--Pull Request
pull request是github/bitbucket给开发人员实现便利合作提供的一个feature.他们提供一个用户友好的web界面在进代码之前来讨论这些变更. 简单说,pull request ...
- GIT团队合作探讨之三--使用分支
这篇文章是一个作为对git branch的综合介绍.首先,我们会看看创建branch,这有点像是请求一个新的项目历史.然后,我们看看git checkout是如何能够被用来选择一个branch,最后看 ...
- 版本管理·玩转git(团队合作)
如果你想让一位叫"伙夫"的程序员,和你一起开发,首先你得在你的代码仓库把伙夫添加到此项目中来,让其成为开发者. 具体步骤: 项目->管理->项目成员管理->开发者 ...
- [GIt] 团队工作效率分析工具gitstats
copy : http://www.cnblogs.com/ToDoToTry/p/4311637.html 如果你是团队领导,关心团队的开发效率和工作激情:如果你是开源软件开发者,维护者某个repo ...
- 8小时入门Git之团队合作学习记录
Git几个重要的区域 工作流程
- 使用GitHub进行团队合作
原文: Team Collaboration With GitHub GitHub已经成为的一切开放源码软件的基石.开发人员喜欢它,基于它进行协作,并不断通过它开发令人惊叹的项目.除了代码托管,G ...
- GitHub 系列之「团队合作利器 Branch」
Git 相比于 SVN 最强大的一个地方就在于「分支」,Git 的分支操作简直不要太方便,而实际项目开发中团队合作最依赖的莫过于分支了,关于分支前面的系列也提到过,但是本篇会详细讲述什么是分支.分支的 ...
- 从0开始学习 GITHUB 系列之「团队合作利器 BRANCH」【转】
本文转载自:http://stormzhang.com/github/2016/07/09/learn-from-github-from-zero6/ 版权声明:本文为 stormzhang 原创文章 ...
随机推荐
- Unity QualitySettings.antiAliasing 抗锯齿
QualitySettings.antiAliasing 抗锯齿 Description 描述 Set The AA Filtering option. 设置AA过滤选项. The AntiAliaz ...
- 快速修改数据库日志的增长修改为50M[转]
尚未亲测..请君慎重使用.. SET NOCOUNT ON ), @sqlTotal NVARCHAR(MAX),@sqlSingle NVARCHAR(MAX),@sql NVARCHAR(MAX) ...
- js中的new操作符与Object.create()的作用与区别
js中的new操作符与Object.create()的作用与区别 https://blog.csdn.net/mht1829/article/details/76785231 2017年08月06日 ...
- Robot Framework_Ride(Settings)
Settings 不管是测试套件还是测试用例都会有一个“Settings>>”的按钮,因为它默认是被折叠起来的,所以,一般不太容易发现它,更不知道点击它之后是可以展开的 1.测试用例的 S ...
- Linux~win10上开启ubuntu子系统
在进行win10之后,我们可以在它上面安装一个linux子系统,然后就可以使用linux了,你不需要安装虚拟机,也不需要安装双系统! 1 通过Win10任务栏中的Cortana搜索框搜索打开“启用或关 ...
- Java日记
总结关于Java web一些知识 VisualVM性能分析 —— 更好的理解JVM中的参数 JVM初始 —— 理解JVM 自己的Java开发规范 —— 个人Java开发是遵循的 ...
- web_02Java ee实现验证码,网站访问次数功能
Web Web_02版本: 实现功能 1,验证码 2,网站访问次数统计 设计内容 1,servlet 2,jsp 3,js *重点 1,验证码相关: 1,Servlrt类实现验证码的生成 CheckC ...
- wcf datetime json format
wcf 内置的json序列化工具,有时需要替换,或者特殊情况的处理,需要修改. 我也遇到了Dto属性类型是datetime,json的反序列化 和 序列号不友好. 这是国外网站的一个方案:Replac ...
- PHP之数组和函数的基本教程
[PHP数组的分类] 按照下标的不同,PHP数组分为关联数组与索引数组 索引数组:下标从0开始,依次增长: 关联数组:下标为字符串格式,每个下标字符串与数字的值一一关联对应(有点像对象的键值对) [关 ...
- Asp.net core如何使用Session
转自:https://tahirnaushad.com/2017/08/18/asp-net-core-session-state/ Asp.net core使用session: 在nuget 安装M ...