分支巫术
即时分支合併是 Git 最给力的杀手锏。
问题 :外部因素要求必须切换场景。在发佈版本中突然蹦出个严重缺陷。某个特性完 成的截至日期就要来临。在项目关键部分可以提供帮助的一个开发正打算离职。所有情 况逼迫你停下所有手头工作,全力扑到到这个完全不同的任务上。
打断思维的连续性会使你的生产力大大降低,并且切换上下文也更麻烦,更大的损失。 使用中心版本控制我们必须从中心伺服器下载一个新的工作拷贝。分散式系统的情况就 好多了,因为我们能够在本地克隆所需要的版本。
但是克隆仍然需要拷贝整个工作目录,还有直到给定点的整个历史记录。儘管 Git 使用文 件共享和硬连结减少了花费,项目档案自身还是必须在新的工作目录裡重建。
方案 :Git 有一个更好的工具对付这种情况,比克隆快多了而且节省空间: git branch 。
使用这个魔咒,目录裡的档案突然从一个版本变到另一个。除了只是在历史记录裡上跳 下窜外,这个转换还可以做更多。你的档案可以从上一个发佈版变到实验版本到当前开 发版本到你朋友的版本等等。
老闆键
曾经玩过那样的游戏吗?按一个键(“老闆键”),屏幕立即显示一个电子表格或别的? 那麽如果老闆走进办公室,而你正在玩游戏,就可以快速将游戏藏起来。
在某个目录:
$ echo "I'm smarter than my boss" > myfile.txt
$ git init
$ git add .
$ git commit -m "Initial commit"
我们已经创建了一个 Git 仓库,该仓库记录一个包含特定信息的档案。现在我们键入:
$ git checkout -b boss # 之后似乎没啥变化
$ echo "My boss is smarter than me" > myfile.txt
$ git commit -a -m "Another commit"
看起来我们刚刚只是覆盖了原来的档案并提交了它。但这是个错觉。键入:
$ git checkout master # 切到档案的原先版本
嘿真快!这个档案就恢复了。并且如果老闆决定窥视这个目录,键入:
$ git checkout boss # 切到适合老闆看的版本
你可以在两个版本之间相切多少次就切多少次,而且每个版本都可以独立提交。
肮髒的工作
比如你正在开发某个特性,并且由于某种原因,你需要回退三个版本,临时加进几行打 印语句来,来看看一些东西是如何工作的。那麽:
$ git commit -a
$ git checkout HEAD~3
现在你可以到处加丑陋的临时代码。你甚至可以提交这些改动。当你做完的时候,
$ git checkout master
来返回到你原来的工作。看,所有未提交变更都结转了。
如果你后来想保存临时变更怎麽办?简单:
$ git checkout -b dirty
只要在切换到主分支之前提交就可以了。无论你什麽时候想回到髒的变更,只需键入:
$ git checkout dirty
我们在前面章节讨论加载旧状态的时候,曾经接触过这个命令。最终我们把故事说全: 档案改变成请求的状态,但我们必须离开主分支。从现在开始的任何提交都会将你的文 件提交到另一条不同的路,这个路可以之后命名。
换一个说法,在 checkout 一个旧状态之后,Git 自动把你放到一个新的,未命名的分支, 这个分支可以使用 git checkout -b 来命名和保存。
快速修订
你正在做某件事的当间,被告知先停所有的事情,去修理一个新近发现的臭虫,这个臭 虫在提交 `1b6d…`:
$ git commit -a
$ git checkout -b fixes 1b6d
那麽一旦你修正了这个臭虫:
$ git commit -a -m "Bug fixed"
$ git checkout master
并可以继续你原来的任务。你甚至可以“合併”到最新修订:
$ git merge fixes
合併
一些版本控制系统,创建分支很容易,但把分支合併回来很难。使用 Git,合併简直是家 常便饭,以至于甚至你可能对其发生没有察觉。
我们很久之前就遇到合併了。 pull 命令取出提交併合并它们到你的当前分支。如果 你没有本地变更,那这个合併就是一个“快进”,相当于中心式版本控制系统裡的一个 弱化的获取最新版本操作。但如有本地变更,Git 将自动合併,并报告任何衝突。
通常,一个提交只有一个“父提交”,也叫前一个提交。合併分支到一起产生一个至少 有两个父的提交。这就引出了问题: HEAD~10
真正指哪个提交?一个提交可能有多个 父,那我们跟哪个呢?
原来这个表示每次选择第一个父。这是可取的,因为在合併时候当前分支成了第一个父; 多数情况下我们只关注我们在当前分支都改了什麽,而不是从其他分支合併来的变更。
你可以用插入符号来特别指定父。比如,显示来自第二个父的日志:
$ git log HEAD^2
你可以忽略数字以指代第一个父。比如,显示与第一个父的差别:
$ git diff HEAD^
你可以结合其他类型使用这个记号。比如:
$ git checkout 1b6d^^2~10 -b ancient
开始一个新分支 “ancient” ,表示第一个父的第二个父的倒数第十次提交的状态。
不间断工作流
经常在硬件项目裡,计划的第二步必须等第一步完成才能开始。待修的汽车傻等在车库 裡,直到特定的零件从工厂运来。一个原型在其可以构建之前,可能苦等晶片成型。
软件项目可能也类似。新功能的第二部分不得不等待,直到第一部分发佈并通过测试。 一些项目要求你的代码需要审批才能接受,因此你可能需要等待第一部分得到批准,才 能开始第二部分。
多亏了无痛分支合併,我们可以不必遵循这些规则,在第一部分正式准备好前开始第二 部分的工作。假设你已经将第一部分提交并发去审批,比如说你现在在主分支。那麽分 岔:
$ git checkout -b part2
接下来,做第二部分,随时可以提交变更。只要是人就可能犯错误,经常你将回到第一 部分在修修补补。如果你非常幸运,或者超级棒,你可能不必做这几行:
$ git checkout master # 回到第一部分
$ 修复问题
$ git commit -a # 提交变更
$ git checkout part2 # 回到第二部分
$ git merge master # 合併这些改动
最终,第一部分获得批准:
$ git checkout master # 回到第一部分
$ submit files # 对世界发佈
$ git merge part2 # 合併第二部分
$ git branch -d part2 # 删除分支“part2”
现在你再次处在主分支,第二部分的代码也在工作目录。
很容易扩展这个技巧,应用到任意数目的部分。它也很容易追溯分支:假如你很晚才意 识到你本应在 7 次提交前就创建分支。那麽键入:
$ git branch -m master part2 # 重命名“master”分支为“part2”。
$ git branch master HEAD~7 # 以七次前提交建一个新的“master”。
分支 master
只有第一部分内容,其他内容在分支 part2
。 我们现在后一个分支; 我们创建了 master
分支还没有切换过去,因为我们想继续工作在 part2
。这是不 寻常的。直到现在,我们已经在创建之后切换到分支,如:
$ git checkout HEAD~7 -b master # 创建分支,并切换过去。
重组杂乱
或许你喜欢在同一个分支下完成工作的方方面面。你想为自己保留工作进度并希望其他 人只能看到你仔细整理过后的提交。开启一对分支:
$ git branch sanitized # 为乾淨提交创建分支
$ git checkout -b medley # 创建并切换分支以进去工作
接下来,做任何事情:修臭虫,加特性,加临时代码,诸如此类,经常按这种方式提交。 然后:
$ git checkout sanitized
$ git cherry-pick medley^^
应用分支 “medley” 的祖父提交到分支 “sanitized” 。通过合适的挑选(像选樱桃 那样)你可以构建一个只包含成熟代码的分支,而且相关的提交也组织在一起。
管理分支
列出所有分支:
$ git branch
预设你从叫 “master” 的分支开始。一些人主张别碰“master”分支,而是创建你自 己版本的新分支。
选项 -d 和 -m 允许你来删除和移动(重命名)分支。参见 git help branch 。
分支“master” 是一个有用的惯例。其他人可能假定你的仓库有一个叫这个名字的分 支,并且该分支包含你项目的官方版本。儘管你可以重命名或抹杀 “master” 分支, 你最好还是尊重这个约定。
临时分支
很快你会发现你经常会因为一些相似的原因创建短期的分支:每个其它分支只是为了保 存当前状态,那样你就可以直接跳到较老状态以修复高优先顺序的臭虫之类。
可以和电视的换台做类比,临时切到别的频道,来看看其它台那正放什麽。但并不是简 单地按几个按钮,你不得不创建,检出,合併,以及删除临时分支。幸运的是,Git 已经 有了和电视机遥控器一样方便的快捷方式:
$ git stash
这个命令保存当前状态到一个临时的地方(一个隐藏的地方)并且恢复之前状态。你的 工作目录看起来和你开始编辑之前一样,并且你可以修复臭虫,引入之前变更等。当你 想回到隐藏状态的时候,键入:
$ git stash apply # 你可能需要解决一些衝突
你可以有多个隐藏,并用不同的方式来操作他们。参见 git help slash 。也许你已 经猜到,Git 维护在这个场景之后的分支以执行魔法技巧.
按你希望的方式工作
你可能犹疑于分支是否值得一试。毕竟,克隆也几乎一样快,并且你可以用 cd 来在 彼此之间切换,而不是用 Git 深奥的命令。
考虑一下浏览器。为什麽同时支持多标籤和多窗口?因为允许两者同时接纳纳了多种风 格的用户。一些用户喜欢只保持一个打开的窗口,然后用标籤浏览多个网页。一些可能 坚持另一个极端:任何地方都没有标籤的多窗口。一些喜好处在两者之间。
分支类似你工作目录的标籤,克隆类似打开的浏览器新窗口。这些是本地操作很快,那 为什麽不试着找出最适合你的组合呢?Git 让你按你确实所希望的那样工作。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论