标签 Git 下的文章

GitLab 是一个基于 git 的仓库管理程序,也是一个方便软件开发的强大完整应用。

GitLab 拥有一个“用户新人友好”的界面,通过图形界面和命令行界面,使你的工作更加具有效率。GitLab 不仅仅对开发者是一个有用的工具,它甚至可以被集成到你的整个团队中,使得每一个人获得一个独自唯一的平台。

GitLab 工作流逻辑符合使用者思维,使得整个平台变得更加易用。相信我,使用一次,你就离不开它了!

GitLab 工作流

GitLab 工作流 是在软件开发过程中,在使用 GitLab 作为代码托管平台时,可以采取的动作的一个逻辑序列。

GitLab 工作流遵循了 GitLab Flow 策略,这是由一系列由基于 Git 的方法和策略组成的,这些方法为版本的管理,例如分支策略、Git最佳实践等等提供了保障。

通过 GitLab 工作流,可以很方便的提升团队的工作效率以及凝聚力。这种提升,从引入一个新的项目开始,一直到发布这个项目,成为一个产品都有所体现。这就是我们所说的“如何通过最快的速度把一个点子在 10 步之内变成一个产品”。

FROM IDEA TO PRODUCTION IN 10 STEPS

软件开发阶段

一般情况下,软件开发经过 10 个主要阶段;GitLab 为这 10 个阶段依次提供了解决方案:

  1. IDEA: 每一个从点子开始的项目,通常来源于一次闲聊。在这个阶段,GitLab 集成了 Mattermost。
  2. ISSUE: 最有效的讨论一个点子的方法,就是为这个点子建立一个工单讨论。你的团队和你的合作伙伴可以在 工单追踪器 issue tracker 中帮助你去提升这个点子
  3. PLAN: 一旦讨论得到一致的同意,就是开始编码的时候了。但是等等!首先,我们需要优先考虑组织我们的工作流。对于此,我们可以使用 工单看板 Issue Board 。
  4. CODE: 现在,当一切准备就绪,我们可以开始写代码了。
  5. COMMIT: 当我们为我们的初步成果欢呼的时候,我们就可以在版本控制下,提交代码到功能分支了。
  6. TEST: 通过 GitLab CI,我们可以运行脚本来构建和测试我们的应用。
  7. REVIEW: 一旦脚本成功运行,我们测试和构建成功,我们就可以进行 代码复审 code review 以及批准。
  8. STAGING:: 现在是时候将我们的代码部署到演示环境来检查一下,看看是否一切就像我们预估的那样顺畅——或者我们可能仍然需要修改。
  9. PRODUCTION: 当一切都如预期,就是部署到生产环境的时候了!
  10. FEEDBACK: 现在是时候返回去看我们项目中需要提升的部分了。我们使用 周期分析 Cycle Analytics 来对当前项目中关键的部分进行的反馈。

简单浏览这些步骤,我们可以发现,提供强大的工具来支持这些步骤是十分重要的。在接下来的部分,我们为 GitLab 的可用工具提供一个简单的概览。

GitLab 工单追踪器

GitLab 有一个强大的工单追溯系统,在使用过程中,允许你和你的团队,以及你的合作者分享和讨论建议。

issue tracker - view list

工单是 GitLab 工作流的第一个重要重要特性。以工单的讨论为开始; 跟踪新点子的改变是一个最好的方式。

这十分有利于:

  • 讨论点子
  • 提交功能建议
  • 提问题
  • 提交错误和故障
  • 获取支持
  • 精细化新代码的引入

每一个在 GitLab 上部署的项目都有一个工单追踪器。找到你的项目中的 Issues > New issue 来创建一个新的工单。建立一个标题来总结要被讨论的主题,并且使用 Markdown 来形容它。看看下面的“专业技巧”来加强你的工单描述。

GitLab 工单追踪器提供了一个额外的实用功能,使得步骤变得更佳易于管理和考虑。下面的部分仔细描述了它。

new issue - additional settings

秘密工单

无论何时,如果你仅仅想要在团队中讨论这个工单,你可以使该工单成为秘密的。即使你的项目是公开的,你的工单也会被保密起来。当一个不是本项目成员的人,就算是 报告人级别,想要访问工单的地址时,浏览器也会返回一个 404 错误。

截止日期

每一个工单允许你填写一个截止日期。有些团队工作时间表安排紧凑,以某种方式去设置一个截止日期来解决问题,是有必要的。这些都可以通过截止日期这一功能实现。

当你对一个多任务项目有截止日期的时候——比如说,一个新的发布活动、项目的启动,或者按阶段追踪任务——你可以使用里程碑。

受托者

要让某人处理某个工单,可以将其分配给他。你可以任意修改被分配者,直到满足你的需求。这个功能的想法是,一个受托者本身对这个工单负责,直到其将这个工单重新赋予其他人。

这也可以用于按受托者筛选工单。

标签

GitLab 标签也是 GitLab 流的一个重要组成部分。你可以使用它们来分类你的工单,在工作流中定位,以及通过优先级标签来安装优先级组织它们。

标签使得你与GitLab 工单看板协同工作,加快工程进度以及组织你的工作流。

新功能: 你可以创建组标签。它可以使得在每一个项目组中使用相同的标签。

工单权重

你可以添加个工单权重使得一个工单重要性表现的更为清晰。01 - 03 表示工单不是特别重要,07 - 09 表示十分重要,04 - 06 表示程度适中。此外,你可以与你的团队自行定义工单重要性的指标。

注:该功能仅可用于 GitLab 企业版和 GitLab.com 上。

GitLab 工单看板

在项目中,GitLab 工单看板是一个用于计划以及组织你的工单,使之符合你的项目工作流的工具。

看板包含了与其相关的相应标签,每一个列表包含了相关的被标记的工单,并且以卡片的形式展示出来。

这些卡片可以在列表之间移动,被移动的卡片,其标签将会依据你移动的位置相应更新到列表上。

GitLab Issue Board

新功能: 你也可以通过点击列表上方的“+”按钮在看板右边创建工单。当你这么做的时候,这个工单将会自动添加与列表相关的标签。

新功能: 我们最近推出了 每一个 GitLab 项目拥有多个工单看板的功能(仅存在于 GitLab 企业版);这是为不同的工作流组织你的工单的好方法。

Multiple Issue Boards

通过 GitLab 进行代码复审

在工单追踪器中,讨论了新的提议之后,就是在代码上做工作的时候了。你在本地书写代码,一旦你完成了你的第一个版本,提交你的代码并且推送到你的 GitLab 仓库。你基于 Git 的管理策略可以在 GitLab 流中被提升。

第一次提交

在你的第一次提交信息中,你可以添加涉及到工单号在其中。通过这样做你可以将两个阶段的开发工作流链接起来:工单本身以及关于这个工单的第一次提交。

这样做,如果你提交的代码和工单属于同一个项目,你可以简单的添加 #xxx 到提交信息中(LCTT 译注:git commit message),xxx是一个工单号。如果它们不在一个项目中,你可以添加整个工单的整个URL(https://gitlab.com/<username>/<projectname>/issues/<xxx>)。

git commit -m "this is my commit message. Ref #xxx" 

或者

git commit -m "this is my commit message. Related to https://gitlab.com/<username>/<projectname>/issues/<xxx>"

当然,你也可以替换 gitlab.com,以你自己的 GitLab 实例来替换这个 URL。

注: 链接工单和你的第一次提交是为了通过 GitLab 周期分析追踪你的进展。这将会衡量计划执行该工单所采取的时间,即创建工单与第一次提交的间隔时间。

合并请求

一旦将你的改动提交到功能分支,GitLab 将识别该修改,并且建议你提交一次 合并请求 Merge Request (MR)。

每一次 MR 都会有一个标题(这个标题总结了这次的改动)并且一个用 Markdown 书写的描述。在描述中,你可以简单的描述该 MR 做了什么,提及任何工单以及 MR(在它们之间创建联系),并且,你也可以添加个关闭工单模式,当该 MR 被合并的时候,相关联的工单就会被关闭。

例如:

## 增加一个新页面

这个 MR 将会为这个项目创建一个包含该 app 概览的 `readme.md`。

Closes #xxx and https://gitlab.com/<username>/<projectname>/issues/<xxx>

预览:

![预览新页面](#image-url)

cc/ @Mary @Jane @John

当你创建一个如上的带有描述的 MR,它将会:

  • 当合并时,关闭包括工单 #xxx 以及 https://gitlab.com/<username>/<projectname>/issues/<xxx>
  • 展示一张图片
  • 通过邮件提醒用户 @Mary、@Jane,以及给 @John

你可以分配这个 MR 给你自己,直到你完成你的工作,然后把它分配给其他人来做一次代码复审。如果有必要的话,这个 MR 可以被重新分配多次,直到你覆盖你所需要的所有复审。

它也可以被标记,并且添加一个里程碑来促进管理。

当你从图形界面而不是命令行添加或者修改一个文件并且提交一个新的分支时,也很容易创建一个新的 MR,仅仅需要标记一下复选框,“以这些改变开始一个新的合并请求”,然后,一旦你提交你的改动,GitLab 将会自动创建一个新的 MR。

commit to a feature branch and add a new MR from the UI

注: 添加关闭工单样式到你的 MR 以便可以使用 GitLab 周期分析追踪你的项目进展,是十分重要的。它将会追踪“CODE”阶段,衡量第一次提交及创建一个相关的合并请求所间隔的时间。

新功能: 我们已经开发了审查应用,这是一个可以让你部署你的应用到一个动态的环境中的新功能,在此你可以按分支名字、每个合并请求来预览改变。参看这里的可用示例。

WIP MR

WIP MR 含义是 在工作过程中的合并请求,是一个我们在 GitLab 中避免 MR 在准备就绪前被合并的技术。只需要添加 WIP: 在 MR 的标题开头,它将不会被合并,除非你把 WIP: 删除。

当你改动已经准备好被合并,编辑工单来手动删除 WIP: ,或者使用就像如下 MR 描述下方的快捷方式。

WIP MR click to remove WIP from the title

新功能: WIP 模式可以通过斜线命令 /wip 快速添加到合并请求中。只需要在评论或者 MR 描述中输入它并提交即可。

复审

一旦你创建一个合并请求,就是你开始从你的团队以及合作方收取反馈的时候了。使用图形界面中的差异比较功能,你可以简单的添加行内注释,以及回复或者解决它们。

你也可以通过点击行号获取每一行代码的链接。

在图形界面中可以看到提交历史,通过提交历史,你可以追踪文件的每一次改变。你可以以行内差异或左右对比的方式浏览它们。

code review in MRs at GitLab

新功能: 如果你遇到合并冲突,可以快速地通过图形界面来解决,或者依据你的需要修改文件来修复冲突。

mr conflict resolution

构建、测试以及发布

GitLab CI 是一个强大的内建工具,其作用是持续集成、持续发布以及持续分发,它可以按照你希望的运行一些脚本。它的可能性是无止尽的:你可以把它看做是自己运行的命令行。

它完全是通过一个名为 .gitlab-ci.yml 的 YAML 文件设置的,其放置在你的项目仓库中。使用 Web 界面简单的添加一个文件,命名为 .gitlab-ci.yml 来触发一个下拉菜单,为不同的应用选择各种 CI 模版。

GitLab CI templates - dropdown menu

Koding

Use GitLab's Koding integration to run your entire development environment in the cloud. This means that you can check out a project or just a merge request in a full-fledged IDE with the press of a button.

可以使用 GitLab 的 Koding 集成功能在云端运行你的整个云端开发环境。这意味着你可以轻轻一键即可在一个完整的 IDE 中检出以个项目,或者合并一个请求。

使用案例

GitLab CI 的使用案例:

我们已经准备一大堆 GitLab CI 样例工程作为您的指南。看看它们吧!

反馈:周期分析

当你遵循 GitLab 工作流进行工作,你的团队从点子到产品,在每一个过程的关键部分,你将会在下列时间获得一个 GitLab 周期分析的反馈:

  • Issue: 从创建一个工单,到分配这个工单给一个里程碑或者添加工单到你的工单看板的时间。
  • Plan: 从给工单分配一个里程碑或者把它添加到工单看板,到推送第一次提交的时间。
  • Code: 从第一次提交到提出该合并请求的时间。
  • Test: CI 为了相关合并请求而运行整个过程的时间。
  • Review: 从创建一个合并请求到合并它的时间。
  • Staging: 从合并到发布成为产品的时间。
  • Production(Total): 从创建工单到把代码发布成产品的时间。

加强

工单以及合并请求模版

工单以及合并请求模版允许你为你的项目去定义一个特定内容的工单模版和合并请求的描述字段。

你可以以 Markdown 形式书写它们,并且把它们加入仓库的默认分支。当创建工单或者合并请求时,可以通过下拉菜单访问它们。

它们节省了您在描述工单和合并请求的时间,并标准化了需要持续跟踪的重要信息。它确保了你需要的一切都在你的掌控之中。

你可以创建许多模版,用于不同的用途。例如,你可以有一个提供功能建议的工单模版,或者一个 bug 汇报的工单模版。在 GitLab CE project 中寻找真实的例子吧!

issues and MR templates - dropdown menu screenshot

里程碑

里程碑 是 GitLab 中基于共同的目标、详细的日期追踪你队伍工作的最好工具。

不同情况下的目的是不同的,但是大致是相同的:你有为了达到特定的目标的工单的集合以及正在编码的合并请求。

这个目标基本上可以是任何东西——用来结合团队的工作,在一个截止日期前完成一些事情。例如,发布一个新的版本,启动一个新的产品,在某个日期前完成,或者按季度收尾一些项目。

milestone dashboard

专业技巧

工单和 MR

  • 在工单和 MR 的描述中:

    • 输入 # 来触发一个已有工单的下拉列表
    • 输入 ! 来触发一个已有 MR 的下拉列表
    • 输入 / 来触发斜线命令
    • 输入 : 来出发 emoji 表情 (也支持行中评论)
  • 通过按钮“附加文件”来添加图片(jpg、png、gif) 和视频到行内评论
  • 通过 GitLab Webhooks 自动应用标签
  • 构成引用: 使用语法 >>> 来开始或者结束一个引用
>>>
Quoted text

Another paragraph
>>>
- [ ] Task 1
- [ ] Task 2
- [ ] Task 3
订阅

你是否发现你有一个工单或者 MR 想要追踪?展开你的右边的导航,点击订阅,你就可以在随时收到一个评论的提醒。要是你想要一次订阅多个工单和 MR?使用批量订阅。

添加代办

除了一直留意工单和 MR,如果你想要对它预先做点什么,或者不管什么时候你想要在 GitLab 代办列表中添加点什么,点击你右边的导航,并且点击添加代办。

寻找你的工单和 MR

当你寻找一个在很久以前由你开启的工单或 MR——它们可能数以十计、百计、甚至千计——所以你很难找到它们。打开你左边的导航,并且点击工单或者合并请求,你就会看到那些分配给你的。同时,在那里或者任何工单追踪器里,你可以通过作者、分配者、里程碑、标签以及重要性来过滤工单,也可以通过搜索所有不同状态的工单,例如开启的、合并的,关闭的等等。

移动工单

一个工单在一个错误的项目中结束了?不用担心,点击Edit,然后移动工单到正确的项目。

代码片段

你经常在不同的项目以及文件中使用一些相同的代码段和模版吗?创建一个代码段并且使它在你需要的时候可用。打开左边导航栏,点击Snipptes。所有你的片段都会在那里。你可以把它们设置成公开的,内部的(仅为 GitLab 注册用户提供),或者私有的。

Snippets - screenshot

GitLab 工作流用户案例概要

作为总结,让我们把所有东西聚在一起理顺一下。不必担心,这十分简单。

让我们假设:你工作于一个专注于软件开发的公司。你创建了一个新的工单,这个工单是为了开发一个新功能,实施于你的一个应用中。

标签策略

为了这个应用,你已经创建了几个标签,“讨论”、“后端”、“前端”、“正在进行”、“展示”、“就绪”、“文档”、“营销”以及“产品”。所有都已经在工单看板有它们自己的列表。你的当前的工单已经有了标签“讨论”。

在工单追踪器中的讨论达成一致之后,你的后端团队开始在工单上工作,所以他们把这个工单的标签从“讨论”移动到“后端”。第一个开发者开始写代码,并且把这个工单分配给自己,增加标签“正在进行”。

编码 & 提交

在他的第一次提交的信息中,他提及了他的工单编号。在工作后,他把他的提交推送到一个功能分支,并且创建一个新的合并请求,在 MR 描述中,包含工单关闭模式。他的团队复审了他的代码并且保证所有的测试和建立都已经通过。

使用工单看板

一旦后端团队完成了他们的工作,他们就删除“正在进行”标签,并且把工单从“后端”移动到“前端”看板。所以,前端团队接到通知,这个工单已经为他们准备好了。

发布到演示

当一个前端开发者开始在该工单上工作,他(她)增加一个标签“正在进行”,并且把这个工单重新分配给自己。当工作完成,该实现将会被发布到一个演示环境。标签“正在进行”就会被删除,然后在工单看板里,工单卡被移动到“演示”列表中。

团队合作

最后,当新功能成功实现,你的团队把它移动到“就绪”列表。

然后,就是你的技术文档编写团队的时间了,他们为新功能书写文档。一旦某个人完成书写,他添加标签“文档”。同时,你的市场团队开始启动并推荐该功能,所以某个人添加“市场”。当技术文档书写完毕,书写者删除标签“文档”。一旦市场团队完成他们的工作,他们将工单从“市场”移动到“生产”。

部署到生产环境

最后,你将会成为那个为新版本负责的人,合并“合并请求”并且将新功能部署到生产环境,然后工单的状态转变为关闭。

反馈

通过周期分析,你和你的团队节省了如何从点子到产品的时间,并且开启另一个工单,来讨论如何将这个过程进一步提升。

总结

GitLab 工作流通过一个单一平台帮助你的团队加速从点子到生产的改变:

  • 它是有效的:因为你可以获取你想要的结果
  • 它是高效的:因为你可以用最小的努力和成本达到最大的生产力
  • 它是高产的:因为你可以非常有效的计划和行动
  • 它是简单的:因为你不需要安装不同的工具去完成你的目的,仅仅需要 GitLab
  • 它是快速的:因为你不需要在多个平台间跳转来完成你的工作

每一个月的 22 号都会有一个新的 GitLab 版本释出,让它在集成软件开发解决方案上变得越来越好,让团队可以在一个单一的、唯一的界面下一起工作。

在 GitLab,每个人都可以奉献!多亏了我们强大的社区,我们获得了我们想要的。并且多亏了他们,我们才能一直为你提供更好的产品。

还有什么问题和反馈吗?请留言,或者在推特上@我们@GitLab!


via: https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/

作者:Marcia Ramos 译者:svtter 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

2016 年 Git 发生了 惊天动地 地变化,发布了五大新特性¹ (从 v2.7 到 v2.11 )和十六个补丁²。189 位作者³贡献了 3676 个提交⁴到 master 分支,比 2015 年多了 15%⁵!总计有 1545 个文件被修改,其中增加了 276799 行并移除了 100973 行⁶。

但是,通过统计提交的数量和代码行数来衡量生产力是一种十分愚蠢的方法。除了深度研究过的开发者可以做到凭直觉来判断代码质量的地步,我们普通人来作仲裁难免会因我们常人的判断有失偏颇。

谨记这一条于心,我决定整理这一年里六个我最喜爱的 Git 特性涵盖的改进,来做一次分类回顾。这篇文章作为一篇中篇推文有点太过长了,所以我不介意你们直接跳到你们特别感兴趣的特性去。

  • 完成 git worktree 命令
  • 更多方便的 git rebase 选项
  • git lfs 梦幻的性能加速
  • git diff 实验性的算法和更好的默认结果
  • git submodules 差强人意
  • git stash 的90 个增强

在我们开始之前,请注意在大多数操作系统上都自带有 Git 的旧版本,所以你需要检查你是否在使用最新并且最棒的版本。如果在终端运行 git --version 返回的结果小于 Git v2.11.0,请立刻跳转到 Atlassian 的快速指南 更新或安装 Git 并根据你的平台做出选择。

[所需的“引用”]

在我们进入高质量内容之前还需要做一个短暂的停顿:我觉得我需要为你展示我是如何从公开文档生成统计信息(以及开篇的封面图片)的。你也可以使用下面的命令来对你自己的仓库做一个快速的 年度回顾!

¹ 2016 年匹配 vX.Y.0 格式的里程碑
$ git for-each-ref --sort=-taggerdate --format \
'%(refname) %(taggerdate)' refs/tags | grep "v\d\.\d*\.0 .* 2016"
² 2016 年匹配 vX.Y.Z 格式的里程碑
$ git for-each-ref --sort=-taggerdate --format '%(refname) %(taggerdate)' refs/tags | grep "v\d\.\d*\.[^0] .* 2016"
³ 2016 年做过提交的贡献者数量
$ git shortlog -s -n --since=2016-01-01 --until=2017-01-01
⁴ 2016 年的提交数量
$ git log --oneline --since=2016-01-01 --until=2017-01-01 | wc -l
⁵ 以及 2015 年的提交数量
$ git log --oneline --since=2015-01-01 --until=2016-01-01 | wc -l
⁶ 2016 年添加、删除行数
$ git diff --shortstat `git rev-list -1 --until=2016-01-01 master` \
 `git rev-list -1 --until=2017-01-01 master`

以上的命令是在 Git 的 master 分支运行的,所以不会显示其他出色的分支上没有合并的工作。如果你使用这些命令,请记住提交的数量和代码行数不是应该值得信赖的度量方式。请不要使用它们来衡量你的团队成员的贡献。

现在,让我们开始说好的回顾……

完成 Git 工作树 ( worktree )

git worktree 命令首次出现于 Git v2.5 ,但是在 2016 年有了一些显著的增强。两个有价值的新特性在 v2.7 被引入:list 子命令,和为二分搜索增加了命令空间的 refs。而 lock/unlock 子命令则是在 v2.10 被引入。

什么是工作树呢?

git worktree 命令允许你同步地检出和操作处于不同路径下的同一仓库的多个分支。例如,假如你需要做一次快速的修复工作但又不想扰乱你当前的工作区,你可以使用以下命令在一个新路径下检出一个新分支:

$ git worktree add -b hotfix/BB-1234 ../hotfix/BB-1234
Preparing ../hotfix/BB-1234 (identifier BB-1234)
HEAD is now at 886e0ba Merged in bedwards/BB-13430-api-merge-pr (pull request #7822)

工作树不仅仅是为分支工作。你可以检出多个 里程碑 ( tag ) 作为不同的工作树来并行构建或测试它们。例如,我从 Git v2.6 和 v2.7 的里程碑中创建工作树来检验不同版本 Git 的行为特征。

$ git worktree add ../git-v2.6.0 v2.6.0
Preparing ../git-v2.6.0 (identifier git-v2.6.0)
HEAD is now at be08dee Git 2.6

$ git worktree add ../git-v2.7.0 v2.7.0
Preparing ../git-v2.7.0 (identifier git-v2.7.0)
HEAD is now at 7548842 Git 2.7

$ git worktree list
/Users/kannonboy/src/git         7548842 [master]
/Users/kannonboy/src/git-v2.6.0  be08dee (detached HEAD)
/Users/kannonboy/src/git-v2.7.0  7548842 (detached HEAD)

$ cd ../git-v2.7.0 && make

你也使用同样的技术来并行构造和运行你自己应用程序的不同版本。

列出工作树

git worktree list 子命令(于 Git v2.7 引入)显示所有与当前仓库有关的工作树。

$ git worktree list
/Users/kannonboy/src/bitbucket/bitbucket       37732bd [master]
/Users/kannonboy/src/bitbucket/staging         d5924bc [staging]
/Users/kannonboy/src/bitbucket/hotfix-1234     37732bd [hotfix/1234]

二分查找工作树

git bisect 是一个简洁的 Git 命令,可以让我们对提交记录执行一次二分搜索。通常用来找到哪一次提交引入了一个指定的退化。例如,如果在我的 master 分支最后的提交上有一个测试没有通过,我可以使用 git bisect 来贯穿仓库的历史来找寻第一次造成这个错误的提交。

$ git bisect start

# 找到已知通过测试的最后提交
# (例如最新的发布里程碑)
$ git bisect good v2.0.0

# 找到已知的出问题的提交
# (例如在 `master` 上的提示)
$ git bisect bad master

# 告诉 git bisect 要运行的脚本/命令;
# git bisect 会在 “good” 和 “bad”范围内
# 找到导致脚本以非 0 状态退出的最旧的提交
$ git bisect run npm test

在后台,bisect 使用 refs 来跟踪 “good” 与 “bad” 的提交来作为二分搜索范围的上下界限。不幸的是,对工作树的粉丝来说,这些 refs 都存储在寻常的 .git/refs/bisect 命名空间,意味着 git bisect 操作如果运行在不同的工作树下可能会互相干扰。

到了 v2.7 版本,bisect 的 refs 移到了 .git/worktrees/$worktree_name/refs/bisect, 所以你可以并行运行 bisect 操作于多个工作树中。

锁定工作树

当你完成了一颗工作树的工作,你可以直接删除它,然后通过运行 git worktree prune 等它被当做垃圾自动回收。但是,如果你在网络共享或者可移除媒介上存储了一颗工作树,如果工作树目录在删除期间不可访问,工作树会被完全清除——不管你喜不喜欢!Git v2.10 引入了 git worktree lock 和 unlock 子命令来防止这种情况发生。

# 在我的 USB 盘上锁定 git-v2.7 工作树
$ git worktree lock /Volumes/Flash_Gordon/git-v2.7 --reason \
"In case I remove my removable media"
# 当我完成时,解锁(并删除)该工作树
$ git worktree unlock /Volumes/Flash_Gordon/git-v2.7
$ rm -rf /Volumes/Flash_Gordon/git-v2.7
$ git worktree prune

--reason 标签允许为未来的你留一个记号,描述为什么当初工作树被锁定。git worktree unlock 和 lock 都要求你指定工作树的路径。或者,你可以 cd 到工作树目录然后运行 git worktree lock . 来达到同样的效果。

更多 Git 变基 ( rebase ) 选项

2016 年三月,Git v2.8 增加了在拉取过程中交互进行变基的命令 git pull --rebase=interactive 。对应地,六月份 Git v2.9 发布了通过 git rebase -x 命令对执行变基操作而不需要进入交互模式的支持。

Re-啥?

在我们继续深入前,我假设读者中有些并不是很熟悉或者没有完全习惯变基命令或者交互式变基。从概念上说,它很简单,但是与很多 Git 的强大特性一样,变基散发着听起来很复杂的专业术语的气息。所以,在我们深入前,先来快速的复习一下什么是 变基 ( rebase ) 。

变基操作意味着将一个或多个提交在一个指定分支上重写。git rebase 命令是被深度重载了,但是 rebase 这个名字的来源事实上还是它经常被用来改变一个分支的基准提交(你基于此提交创建了这个分支)。

从概念上说,rebase 通过将你的分支上的提交临时存储为一系列补丁包,接着将这些补丁包按顺序依次打在目标提交之上。

对 master 分支的一个功能分支执行变基操作 (git reabse master)是一种通过将 master 分支上最新的改变合并到功能分支的“保鲜法”。对于长期存在的功能分支,规律的变基操作能够最大程度的减少开发过程中出现冲突的可能性和严重性。

有些团队会选择在合并他们的改动到 master 前立即执行变基操作以实现一次快速合并 (git merge --ff <feature>)。对 master 分支快速合并你的提交是通过简单的将 master ref 指向你的重写分支的顶点而不需要创建一个合并提交。

变基是如此方便和功能强大以致于它已经被嵌入其他常见的 Git 命令中,例如拉取操作 git pull 。如果你在本地 master 分支有未推送的提交,运行 git pull 命令从 origin 拉取你队友的改动会造成不必要的合并提交。

这有点混乱,而且在繁忙的团队,你会获得成堆的不必要的合并提交。git pull --rebase 将你本地的提交在你队友的提交上执行变基而不产生一个合并提交。

这很整洁吧!甚至更酷,Git v2.8 引入了一个新特性,允许你在拉取时 交互地 变基。

交互式变基

交互式变基是变基操作的一种更强大的形态。和标准变基操作相似,它可以重写提交,但它也可以向你提供一个机会让你能够交互式地修改这些将被重新运用在新基准上的提交。

当你运行 git rebase --interactive (或 git pull --rebase=interactive)时,你会在你的文本编辑器中得到一个可供选择的提交列表视图。

$ git rebase master --interactive

pick 2fde787 ACE-1294: replaced miniamalCommit with string in test
pick ed93626 ACE-1294: removed pull request service from test
pick b02eb9a ACE-1294: moved fromHash, toHash and diffType to batch
pick e68f710 ACE-1294: added testing data to batch email file

# Rebase f32fa9d..0ddde5f onto f32fa9d (4 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to 
# bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.

注意到每一条提交旁都有一个 pick。这是对 rebase 而言,“照原样留下这个提交”。如果你现在就退出文本编辑器,它会执行一次如上文所述的普通变基操作。但是,如果你将 pick 改为 edit 或者其他 rebase 命令中的一个,变基操作会允许你在它被重新运用前改变它。有效的变基命令有如下几种:

  • reword:编辑提交信息。
  • edit:编辑提交了的文件。
  • squash:将提交与之前的提交(同在文件中)合并,并将提交信息拼接。
  • fixup:将本提交与上一条提交合并,并且逐字使用上一条提交的提交信息(这很方便,如果你为一个很小的改动创建了第二个提交,而它本身就应该属于上一条提交,例如,你忘记暂存了一个文件)。
  • exec: 运行一条任意的 shell 命令(我们将会在下一节看到本例一次简洁的使用场景)。
  • drop: 这将丢弃这条提交。

你也可以在文件内重新整理提交,这样会改变它们被重新应用的顺序。当你对不同的主题创建了交错的提交时这会很顺手,你可以使用 squash 或者 fixup 来将其合并成符合逻辑的原子提交。

当你设置完命令并且保存这个文件后,Git 将递归每一条提交,在每个 reword 和 edit 命令处为你暂停来执行你设计好的改变,并且自动运行 squash, fixup,exec 和 drop 命令。

非交互性式执行

当你执行变基操作时,本质上你是在通过将你每一条新提交应用于指定基址的头部来重写历史。git pull --rebase 可能会有一点危险,因为根据上游分支改动的事实,你的新建历史可能会由于特定的提交遭遇测试失败甚至编译问题。如果这些改动引起了合并冲突,变基过程将会暂停并且允许你来解决它们。但是,整洁的合并改动仍然有可能打断编译或测试过程,留下破败的提交弄乱你的提交历史。

但是,你可以指导 Git 为每一个重写的提交来运行你的项目测试套件。在 Git v2.9 之前,你可以通过绑定 git rebase --interactive 和 exec 命令来实现。例如这样:

$ git rebase master −−interactive −−exec=”npm test”

……这会生成一个交互式变基计划,在重写每条提交后执行 npm test ,保证你的测试仍然会通过:

pick 2fde787 ACE-1294: replaced miniamalCommit with string in test
exec npm test
pick ed93626 ACE-1294: removed pull request service from test
exec npm test
pick b02eb9a ACE-1294: moved fromHash, toHash and diffType to batch
exec npm test
pick e68f710 ACE-1294: added testing data to batch email file
exec npm test

# Rebase f32fa9d..0ddde5f onto f32fa9d (4 command(s))

如果出现了测试失败的情况,变基会暂停并让你修复这些测试(并且将你的修改应用于相应提交):

291 passing
1 failing

1) Host request "after all" hook:
Uncaught Error: connect ECONNRESET 127.0.0.1:3001
…
npm ERR! Test failed.
Execution failed: npm test
You can fix the problem, and then run
        git rebase −−continue

这很方便,但是使用交互式变基有一点臃肿。到了 Git v2.9,你可以这样来实现非交互式变基:

$ git rebase master -x "npm test"

可以简单替换 npm test 为 make,rake,mvn clean install,或者任何你用来构建或测试你的项目的命令。

小小警告

就像电影里一样,重写历史可是一个危险的行当。任何提交被重写为变基操作的一部分都将改变它的 SHA-1 ID,这意味着 Git 会把它当作一个全新的提交对待。如果重写的历史和原来的历史混杂,你将获得重复的提交,而这可能在你的团队中引起不少的疑惑。

为了避免这个问题,你仅仅需要遵照一条简单的规则:

永远不要变基一条你已经推送的提交!

坚持这一点你会没事的。

Git LFS 的性能提升

Git 是一个分布式版本控制系统,意味着整个仓库的历史会在克隆阶段被传送到客户端。对包含大文件的项目——尤其是大文件经常被修改——初始克隆会非常耗时,因为每一个版本的每一个文件都必须下载到客户端。Git LFS( 大文件存储 ( Large File Storage ) )是一个 Git 拓展包,由 Atlassian、GitHub 和其他一些开源贡献者开发,通过需要时才下载大文件的相对版本来减少仓库中大文件的影响。更明确地说,大文件是在检出过程中按需下载的而不是在克隆或抓取过程中。

在 Git 2016 年的五大发布中,Git LFS 自身就有四个功能版本的发布:v1.2 到 v1.5。你可以仅对 Git LFS 这一项来写一系列回顾文章,但是就这篇文章而言,我将专注于 2016 年解决的一项最重要的主题:速度。一系列针对 Git 和 Git LFS 的改进极大程度地优化了将文件传入/传出服务器的性能。

长期过滤进程

当你 git add 一个文件时,Git 的净化过滤系统会被用来在文件被写入 Git 目标存储之前转化文件的内容。Git LFS 通过使用 净化过滤器 ( clean filter ) 将大文件内容存储到 LFS 缓存中以缩减仓库的大小,并且增加一个小“指针”文件到 Git 目标存储中作为替代。

污化过滤器 ( smudge filter ) 是净化过滤器的对立面——正如其名。在 git checkout 过程中从一个 Git 目标仓库读取文件内容时,污化过滤系统有机会在文件被写入用户的工作区前将其改写。Git LFS 污化过滤器通过将指针文件替代为对应的大文件将其转化,可以是从 LFS 缓存中获得或者通过读取存储在 Bitbucket 的 Git LFS。

传统上,污化和净化过滤进程在每个文件被增加和检出时只能被唤起一次。所以,一个项目如果有 1000 个文件在被 Git LFS 追踪 ,做一次全新的检出需要唤起 git-lfs-smudge 命令 1000 次。尽管单次操作相对很迅速,但是经常执行 1000 次独立的污化进程总耗费惊人。、

针对 Git v2.11(和 Git LFS v1.5),污化和净化过滤器可以被定义为长期进程,为第一个需要过滤的文件调用一次,然后为之后的文件持续提供污化或净化过滤直到父 Git 操作结束。Lars Schneider,Git 的长期过滤系统的贡献者,简洁地总结了对 Git LFS 性能改变带来的影响。

使用 12k 个文件的测试仓库的过滤进程在 macOS 上快了 80 倍,在 Windows 上 快了 58 倍。在 Windows 上,这意味着测试运行了 57 秒而不是 55 分钟。

这真是一个让人印象深刻的性能增强!

LFS 专有克隆

长期运行的污化和净化过滤器在对向本地缓存读写的加速做了很多贡献,但是对大目标传入/传出 Git LFS 服务器的速度提升贡献很少。 每次 Git LFS 污化过滤器在本地 LFS 缓存中无法找到一个文件时,它不得不使用两次 HTTP 请求来获得该文件:一个用来定位文件,另外一个用来下载它。在一次 git clone 过程中,你的本地 LFS 缓存是空的,所以 Git LFS 会天真地为你的仓库中每个 LFS 所追踪的文件创建两个 HTTP 请求:

幸运的是,Git LFS v1.2 提供了专门的 git lfs clone 命令。不再是一次下载一个文件; git lfs clone 禁止 Git LFS 污化过滤器,等待检出结束,然后从 Git LFS 存储中按批下载任何需要的文件。这允许了并行下载并且将需要的 HTTP 请求数量减半。

自定义 传输路由器 ( Transfer Adapter )

正如之前讨论过的,Git LFS 在 v1.5 中提供对长期过滤进程的支持。不过,对另外一种类型的可插入进程的支持早在今年年初就发布了。 Git LFS 1.3 包含了对 可插拔传输路由器 ( pluggable transfer adapter ) 的支持,因此不同的 Git LFS 托管服务可以定义属于它们自己的协议来向或从 LFS 存储中传输文件。

直到 2016 年底,Bitbucket 是唯一一个执行专属 Git LFS 传输协议 Bitbucket LFS Media Adapter 的托管服务商。这是为了从 Bitbucket 的一个被称为 chunking 的 LFS 存储 API 独特特性中获益。Chunking 意味着在上传或下载过程中,大文件被分解成 4MB 的 文件块 ( chunk ) 。

分块给予了 Bitbucket 支持的 Git LFS 三大优势:

  1. 并行下载与上传。默认地,Git LFS 最多并行传输三个文件。但是,如果只有一个文件被单独传输(这也是 Git LFS 污化过滤器的默认行为),它会在一个单独的流中被传输。Bitbucket 的分块允许同一文件的多个文件块同时被上传或下载,经常能够神奇地提升传输速度。
  2. 可续传的文件块传输。文件块都在本地缓存,所以如果你的下载或上传被打断,Bitbucket 的自定义 LFS 流媒体路由器会在下一次你推送或拉取时仅为丢失的文件块恢复传输。
  3. 免重复。Git LFS,正如 Git 本身,是一种可定位的内容;每一个 LFS 文件都由它的内容生成的 SHA-256 哈希值认证。所以,哪怕你稍微修改了一位数据,整个文件的 SHA-256 就会修改而你不得不重新上传整个文件。分块允许你仅仅重新上传文件真正被修改的部分。举个例子,想想一下 Git LFS 在追踪一个 41M 的 精灵表格 ( spritesheet ) 。如果我们增加在此精灵表格上增加 2MB 的新的部分并且提交它,传统上我们需要推送整个新的 43M 文件到服务器端。但是,使用 Bitbucket 的自定义传输路由,我们仅仅需要推送大约 7MB:先是 4MB 文件块(因为文件的信息头会改变)和我们刚刚添加的包含新的部分的 3MB 文件块!其余未改变的文件块在上传过程中被自动跳过,节省了巨大的带宽和时间消耗。

可自定义的传输路由器是 Git LFS 的一个伟大的特性,它们使得不同服务商在不重载核心项目的前提下体验适合其服务器的优化后的传输协议。

更佳的 git diff 算法与默认值

不像其他的版本控制系统,Git 不会明确地存储文件被重命名了的事实。例如,如果我编辑了一个简单的 Node.js 应用并且将 index.js 重命名为 app.js,然后运行 git diff,我会得到一个看起来像一个文件被删除另一个文件被新建的结果。

我猜测移动或重命名一个文件从技术上来讲是一次删除后跟着一次新建,但这不是对人类最友好的描述方式。其实,你可以使用 -M 标志来指示 Git 在计算差异时同时尝试检测是否是文件重命名。对之前的例子,git diff -M 给我们如下结果:

第二行显示的 similarity index 告诉我们文件内容经过比较后的相似程度。默认地,-M 会处理任意两个超过 50% 相似度的文件。这意味着,你需要编辑少于 50% 的行数来确保它们可以被识别成一个重命名后的文件。你可以通过加上一个百分比来选择你自己的 similarity index,如,-M80%。

到 Git v2.9 版本,无论你是否使用了 -M 标志, git diff 和 git log 命令都会默认检测重命名。如果不喜欢这种行为(或者,更现实的情况,你在通过一个脚本来解析 diff 输出),那么你可以通过显式的传递 --no-renames 标志来禁用这种行为。

详细的提交

你经历过调用 git commit 然后盯着空白的 shell 试图想起你刚刚做过的所有改动吗?verbose 标志就为此而来!

不像这样:

Ah crap, which dependency did I just rev?

# Please enter the commit message for your changes. Lines starting
# with ‘#’ will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with ‘origin/master’.
#
# Changes to be committed:
# new file: package.json
#

……你可以调用 git commit --verbose 来查看你改动造成的行内差异。不用担心,这不会包含在你的提交信息中:

--verbose 标志并不是新出现的,但是直到 Git v2.9 你才可以通过 git config --global commit.verbose true 永久的启用它。

实验性的 Diff 改进

当一个被修改部分前后几行相同时,git diff 可能产生一些稍微令人迷惑的输出。如果在一个文件中有两个或者更多相似结构的函数时这可能发生。来看一个有些刻意人为的例子,想象我们有一个 JS 文件包含一个单独的函数:

/* @return {string} "Bitbucket" */
function productName() {
  return "Bitbucket";
}

现在想象一下我们刚提交的改动包含一个我们专门做的 另一个可以做相似事情的函数:

/* @return {string} "Bitbucket" */
function productId() {
  return "Bitbucket";
}

/* @return {string} "Bitbucket" */
function productName() {
  return "Bitbucket";
}

我们希望 git diff 显示开头五行被新增,但是实际上它不恰当地将最初提交的第一行也包含进来。

错误的注释被包含在了 diff 中!这虽不是世界末日,但每次发生这种事情总免不了花费几秒钟的意识去想 啊? 在十二月,Git v2.11 介绍了一个新的实验性的 diff 选项,--indent-heuristic,尝试生成从美学角度来看更赏心悦目的 diff。

在后台,--indent-heuristic 在每一次改动造成的所有可能的 diff 中循环,并为它们分别打上一个 “不良” 分数。这是基于启发式的,如差异文件块是否以不同等级的缩进开始和结束(从美学角度讲“不良”),以及差异文件块前后是否有空白行(从美学角度讲令人愉悦)。最后,有着最低不良分数的块就是最终输出。

这个特性还是实验性的,但是你可以通过应用 --indent-heuristic 选项到任何 git diff 命令来专门测试它。如果,如果你喜欢尝鲜,你可以这样将其在你的整个系统内启用:

$ git config --global diff.indentHeuristic true

子模块 ( Submodule ) 差强人意

子模块允许你从 Git 仓库内部引用和包含其他 Git 仓库。这通常被用在当一些项目管理的源依赖也在被 Git 跟踪时,或者被某些公司用来作为包含一系列相关项目的 monorepo 的替代品。

由于某些用法的复杂性以及使用错误的命令相当容易破坏它们的事实,Submodule 得到了一些坏名声。

但是,它们还是有着它们的用处,而且,我想这仍然是用于需要厂商依赖项的最好选择。 幸运的是,2016 对子模块的用户来说是伟大的一年,在几次发布中落地了许多意义重大的性能和特性提升。

并行抓取

当克隆或则抓取一个仓库时,加上 --recurse-submodules 选项意味着任何引用的子模块也将被克隆或更新。传统上,这会被串行执行,每次只抓取一个子模块。直到 Git v2.8,你可以附加 --jobs=n 选项来使用 n 个并行线程来抓取子模块。

我推荐永久的配置这个选项:

$ git config --global submodule.fetchJobs 4

……或者你可以选择使用任意程度的平行化。

浅层化子模块

Git v2.9 介绍了 git clone —shallow-submodules 标志。它允许你抓取你仓库的完整克隆,然后递归地以一个提交的深度浅层化克隆所有引用的子模块。如果你不需要项目的依赖的完整记录时会很有用。

例如,一个仓库有着一些混合了的子模块,其中包含有其他厂商提供的依赖和你自己其它的项目。你可能希望初始化时执行浅层化子模块克隆,然后深度选择几个你想工作与其上的项目。

另一种情况可能是配置持续集成或部署工作。Git 需要一个包含了子模块的超级仓库以及每个子模块最新的提交以便能够真正执行构建。但是,你可能并不需要每个子模块全部的历史记录,所以仅仅检索最新的提交可以为你省下时间和带宽。

子模块的替代品

--reference 选项可以和 git clone 配合使用来指定另一个本地仓库作为一个替代的对象存储,来避免跨网络重新复制你本地已经存在的对象。语法为:

$ git clone --reference <local repo> <url>

到 Git v2.11,你可以使用 —reference 选项与 —recurse-submodules 结合来设置子模块指向一个来自另一个本地仓库的子模块。其语法为:

$ git clone --recurse-submodules --reference <local repo> <url>

这潜在的可以省下大量的带宽和本地磁盘空间,但是如果引用的本地仓库不包含你克隆的远程仓库所必需的所有子模块时,它可能会失败。

幸运的是,方便的 —-reference-if-able 选项将会让它优雅地失败,然后为丢失了的被引用的本地仓库的所有子模块回退为一次普通的克隆。

$ git clone --recurse-submodules --reference-if-able \
<local repo> <url>

子模块的 diff

在 Git v2.11 之前,Git 有两种模式来显示对更新你的仓库子模块的提交之间的差异。

git diff —-submodule=short 显示你的项目引用的子模块中的旧提交和新提交(这也是如果你整体忽略 --submodule 选项的默认结果):

git diff —submodule=log 有一点啰嗦,显示更新了的子模块中任意新建或移除的提交的信息中统计行。

Git v2.11 引入了第三个更有用的选项:—-submodule=diff。这会显示更新后的子模块所有改动的完整的 diff。

git stash 的 90 个增强

不像子模块,几乎没有 Git 用户不钟爱 git stash。 git stash 临时搁置(或者 藏匿)你对工作区所做的改动使你能够先处理其他事情,结束后重新将搁置的改动恢复到先前状态。

自动搁置

如果你是 git rebase 的粉丝,你可能很熟悉 --autostash 选项。它会在变基之前自动搁置工作区所有本地修改然后等变基结束再将其复用。

$ git rebase master --autostash
Created autostash: 54f212a
HEAD is now at 8303dca It's a kludge, but put the tuple from the database in the cache.
First, rewinding head to replay your work on top of it...
Applied autostash.

这很方便,因为它使得你可以在一个不洁的工作区执行变基。有一个方便的配置标志叫做 rebase.autostash 可以将这个特性设为默认,你可以这样来全局启用它:

$ git config --global rebase.autostash true

rebase.autostash 实际上自从 Git v1.8.4 就可用了,但是 v2.7 引入了通过 --no-autostash 选项来取消这个标志的功能。如果你对未暂存的改动使用这个选项,变基会被一条工作树被污染的警告禁止:

$ git rebase master --no-autostash
Cannot rebase: You have unstaged changes.
Please commit or stash them.

补丁式搁置

说到配置标签,Git v2.7 也引入了 stash.showPatch。git stash show 的默认行为是显示你搁置文件的汇总。

$ git stash show
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

将 -p 标志传入会将 git stash show 变为 “补丁模式”,这将会显示完整的 diff:

stash.showPatch 将这个行为定为默认。你可以将其全局启用:

$ git config --global stash.showPatch true

如果你使能 stash.showPatch 但却之后决定你仅仅想要查看文件总结,你可以通过传入 --stat 选项来重新获得之前的行为。

$ git stash show --stat
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

顺便一提:--no-patch 是一个有效选项但它不会如你所希望的取消 stash.showPatch。不仅如此,它会传递给用来生成补丁时潜在调用的 git diff 命令,然后你会发现完全没有任何输出。

简单的搁置标识

如果你惯用 git stash ,你可能知道你可以搁置多次改动然后通过 git stash list 来查看它们:

$ git stash list
stash@{0}: On master: crazy idea that might work one day
stash@{1}: On master: desperate samurai refactor; don't apply
stash@{2}: On master: perf improvement that I forgot I stashed
stash@{3}: On master: pop this when we use Docker in production

但是,你可能不知道为什么 Git 的搁置有着这么难以理解的标识(stash@{1}、stash@{2} 等),或许你可能将它们勾勒成 “仅仅是 Git 的癖好吧”。实际上就像很多 Git 特性一样,这些奇怪的标志实际上是 Git 数据模型的一个非常巧妙使用(或者说是滥用了的)的结果。

在后台,git stash 命令实际创建了一系列特定的提交目标,这些目标对你搁置的改动做了编码并且维护一个 reglog 来保存对这些特殊提交的引用。 这也是为什么 git stash list 的输出看起来很像 git reflog 的输出。当你运行 git stash apply stash@{1} 时,你实际上在说,“从 stash reflog 的位置 1 上应用这条提交。”

到了 Git v2.11,你不再需要使用完整的 stash@{n} 语句。相反,你可以通过一个简单的整数指出该搁置在 stash reflog 中的位置来引用它们。

$ git stash show 1
$ git stash apply 1
$ git stash pop 1

讲了很多了。如果你还想要多学一些搁置是怎么保存的,我在 这篇教程 中写了一点这方面的内容。


好了,结束了。感谢您的阅读!我希望您喜欢阅读这份长篇大论,正如我乐于在 Git 的源码、发布文档和 man 手册中探险一番来撰写它。如果你认为我忘记了一些重要的事,请留下一条评论或者在 Twitter 上让我知道,我会努力写一份后续篇章。

至于 Git 接下来会发生什么,这要靠广大维护者和贡献者了(其中有可能就是你!)。随着 Git 的采用日益增长,我猜测简化、改进的用户体验,和更好的默认结果将会是 2017 年 Git 主要的主题。随着 Git 仓库变得越来越大、越来越旧,我猜我们也可以看到继续持续关注性能和对大文件、深度树和长历史的改进处理。

如果你关注 Git 并且很期待能够和一些项目背后的开发者会面,请考虑来 Brussels 花几周时间来参加 Git Merge 。我会在那里发言!但是更重要的是,很多维护 Git 的开发者将会出席这次会议而且一年一度的 Git 贡献者峰会很可能会指定来年发展的方向。

或者如果你实在等不及,想要获得更多的技巧和指南来改进你的工作流,请参看这份 Atlassian 的优秀作品: Git 教程 。

封面图片是由 instaco.de 生成的。


via: https://medium.com/hacker-daily/git-in-2016-fad96ae22a15

作者:Tim Pettersen 译者:xiaow6 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在 LinuxCon 北美会议上 FutureAdvisor 的 Corey Quinn 说:“Git 的确让你可以做一些超级强大的事。‘强大’,在这次讲演中,这是一种对愚蠢的委婉说法”。在使用 Git 时,谁没有经历让你感觉自己像个傻子的时刻?当然,Git 是很棒的,每个人都在使用它,你可以用几个基本命令完成你的大部分工作。但它也有一些强大的功能,让我们觉得我们不知道我们在做什么。

但这真的对我们来说不公平。没有人会知道一切,每个人知道的都不同。Quinn 提醒我们:“在我许多讲演的问答部分,人们有时举手说:“嗯,我有一个傻问题。” 你看到人们在那里说:“是啊!这是一个非常愚蠢的问题”。但是当他们得到答案时,那些这么说的人也正在低头记笔记。

Quinn 在演讲的开始做了一些有趣的演示,演示了一些你可以用 Git 做到的可怕的事情,例如变基主干然后进行强制推送来搞乱整个项目、胡乱输入一些命令让 git 吐槽、提交大型二进制文件等。然后他演示了如何使这些可怕的事情不怎么可怕,如更加明智地管理大型二进制文件。“你可以提交大型二进制文件,你可以在 Git 中暴力提交,如果你需要存储大的二进制文件,这里有两个工具会可以加速载入,一个是 git-annex,这是由 Debian 开发人员 Joey Hess 开发的,而 git-lfs 是由 GitHub 支持的。”

你经常同样地错误输入么?例如,当你想要 git status 时却输入 git stitis?Quinn 有一个方案:“Git 有内置的别名支持,所以你可以将相对较长、复杂的东西命名为一个短的 Git 命令。” 此外,你还可以使用 shell 别名。

Quinn 说:“我们都听说过变基主干然后强制推送这样的搞笑恶作剧,它会改变版本历史,突然发生的事情让所有人都措手不及,每个人都被卷入了这种混乱当中。一群鲸鱼被称为“pod”,一群乌鸦中被称为“谋杀”,一群开发者被称为“合并冲突”……更严重的是,如果有人干了这种事情,你有几个选择。包括从备份中恢复主干,还原提交;或者把责任人从屋顶上尖叫着扔下去。或者,采取一定的预防措施并使用一个并不知名的 Git 功能称为分支保护。启用分支保护后,无法删除或强制推送分支,并且在接受前, 拉取请求 ( pull request ) 必须至少有一个审核。”

Quinn 演示了几个更奇妙的有用的工具,使 Git 更高效和万无一失,如 mr、vcsh 和定制的 shell 提示。你可以在下面看到完整的视频,了解更多有趣的事情。


via: https://www.linux.com/news/event/LinuxCon-Europe/2016/terrible-ideas-git-0

作者:CARLA SCHRODER 译者:geekpi 校对:Bestony

本文由 LCTT 原创编译,Linux中国 荣誉推出

在互联网成为一个巨大的、世界性的现象之前,开发团队常常被限制在一个小的物理空间内。如果公司没有资金支持的话,与世界另一方的人合作是一个非常昂贵或几乎不可能的梦想。

幸运的是,情况不再是这样了。互联网诞生了基于网络的解决方案,允许公司组成合作团体,包括彼此相距数千英里的人。

自从 2008 年首次推出以来,Bitbucket 已成为使用 Mercurial 或 Git 版本控制系统(VCS)的开发人员团队中越来越受欢迎的选择。

它既提供免费帐户,带有不限数量的私人存储库(每个账户最多 5 个用户),也提供多种付费计划,允许每个帐户有更多用户。此外,标记为“公开”的仓库对可以编辑或读取其内容的人数没有限制。

注册 Bitbucket

要使用 Bitbucket,你需要建立一个免费帐户。要这样做,请进入 https://bitbucket.org/, 然后单击 免费开始 Get started for free 按钮。

首先,你需要输入有效的电子邮件地址,然后点击继续。 你的电子邮件帐户将被验证,如果一切正常,你将被提示输入所需的密码。完成后,再次点击 继续,然后检查你的电子邮件收件箱,以确认你的帐户是否已创建:

Bitbucket Singup

Bitbucket 注册

验证电子邮件地址后,系统会要求你确定用户名。 然后将创建你的帐户,你将会进入 Bitbucket 面板,在那里开始创建团队、项目和仓库:

Bitbucket Dashboard

Bitbucket 面板

如你所见,你可以在几分钟内注册 Bitbucket。Atlassian 的人简化了这个过程,以便你可以把你的时间真正用在 Bitbucket 上 - 我们下面会进一步讲。

使用 Bitbucket

让我们浏览下注册 Bitbucket 之后必须要做的事情。它们都在顶部菜单中:

Explore Bitbucket Features

探索 Bitbucket 功能

1). 创建一个团队,通过允许多个 Bitbucket 用户共享一个账号计划的方式鼓励协作。

这将允许他们轻松管理团队拥有的仓库。要创建团队,请输入团队名称,并确保团队标识不存在。接下来,输入你要添加到群组的人员的电子邮件地址,并指明是否要将其设为管理员。最后,单击创建:

Bitbucket - Create a Team

Bitbucket – 创建一个团队

2) 创建或导入一个仓库

如果你已经使用基于 Git 的解决方案,你可以轻松地将你的仓库导入 Bitbucket。否则,你可以从头创建一个。让我们看看在每种情况下你需要做什么。

要创建新的仓库,请单击 仓库 Repositories 菜单中的 创建仓库 Create repository 选项。为新仓库和要分组到的项目选择一个名称。接下来,指明是否要将其设置为 private 并指定类型(Git 或 Mercurial)。最后,单击创建仓库:

Bitbucket - Create a New Repository

Bitbucket – 创建一个新仓库

要导入已有仓库,请从仓库下拉菜单中选择 导入 Import 仓库。要开始导入,请指定源,输入 URL 和所需的登录凭据(如果需要)。

最后,选择新的仓库设置,然后单击导入仓库。忽略有关在指定 URL 处找不到仓库的警告,因为它是虚拟的,仅用于演示目的:

Bitbucket - Import Existing Code

Bitbucket – 导入已有代码

就是这样,很简单吧。

在 Bitbucket 中使用仓库

创建一个新仓库或者导入一个仓库后,它会在面板上展示出来。这时就能执行一些常规操作,如克隆、创建分支、pull request、提交修改、添加 README 文件等等:

Bitbucket - Repository Overview

Bitbucket – 仓库概览

如果想了解如何用仓库工作,或者想要提升你的 git 技能,可以参考 Bitbucket 官方文档。

总结

如你所见,不管你是版本管理的新手还是老手,Bitbucket 都能使管理变得更简单。如果你对本文有任何疑问或评论,请不要犹豫让我们知道。我们期待听到你的声音!


作者简介:

我是 Ravi Saive,TecMint 的原创作者。一个喜爱在互联网上分享技巧和提示的计算机 geek 和 Linux 老手。我的大多数服务运行在 Linux 开源平台上。请在 Twitter、Facebook、Google+ 上关注我。


via: http://www.tecmint.com/bitbucket-for-version-control/

作者:Ravi Saive 译者:geekpi 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过这系列的前六篇文章,我们已经学会使用 Git 来对文本文件进行版本控制的管理。我们不禁要问,还有二进制文件呢,也可进行进行版本控制吗?答案是肯定的,Git 已经有了可以处理像多媒体文件这样的二进制大对象块(blob)的扩展。因此,今天我们会学习使用 Git 来管理所谓的二进制资产。

似乎大家都认可的事就是 Git 对于大的二进制对象文件支持得不好。要记住,二进制大对象与大文本文件是不同的。虽然 Git 对大型的文本文件版本控制毫无问题,但是对于不透明的二进制文件起不了多大作用,只能把它当作一个大的实体黑盒来提交。

设想这样的场景,有一个另人兴奋的第一人称解密游戏,您正在为它制作复杂的 3D 建模,源文件是以二进制格式保存的,最后生成一个 1GB 大小的的文件。您提交过一次,在 Git 源仓库历史中有一个 1GB 大小的新增提交。随后,您修改了下模型人物的头发造型,然后提交更新,因为 Git 并不能把头发从头部及模型中其余的部分离开来,所以您只能又提交 1GB 的量。接着,您改变了模型的眼睛颜色,提交这部分更新:又是 GB 级的提交量。对一个模型的一些微小修改,就会导致三个 GB 级的提交量。对于想对一个游戏所有资源进行版本控制这样的规模,这是个严重的问题。

不同的是如 .obj 这种格式的文本文件,和其它类型文件一样,都是一个提交就存储所有更新修改状态,不同的是 .obj 文件是一系列描述模型的纯文本行。如果您修改了该模型并保存回 .obj 文件,Git 可以逐行读取这两个文件,然后创建一个差异版本,得到一个相当小的提交。模型越精细,提交就越小,这就是标准的 Git 用例。虽然文件本身很大,但 Git 使用覆盖或稀疏存储的方法来构建当前数据使用状态的完整描述。

然而,不是所有的都是纯文本的,但都要使用 Git,所以需要解决方案,并且已经出现几个了。

OSTree 开始是作为 GNOME 项目出现的,旨在管理操作系统的二进制文件。它不适用于这里,所以我直接跳过。

Git 大文件存储(LFS) 是放在 GitHub 上的一个开源项目,是从 git-media 项目中分支出来的。git-media 和 git-annex 是 Git 用于管理大文件的扩展。它们是对同一问题的两种不同的解决方案,各有优点。虽然它们都不是官方的项目,但在我看来,每个都有独到之处:

  • git-media 是集中模式,有一个公共资产的存储库。你可以告诉 git-media 大文件需要存储的位置,是在硬盘、服务器还是在云存储服务器,项目中的每个用户都将该位置视为大型文件的中心主存储位置。
  • git-annex 侧重于分布模式。用户各自创建存储库,每个存储库都有一个存储大文件的本地目录 .git/annex。这些 annex 会定期同步,只要有需要,每个用户都可以访问到所有的资源。除非通过 annex-cost 特别配置,否则 git-annex 优先使用本地存储,再使用外部存储。

对于这些,我已经在生产中使用了 git-media 和 git-annex,那么下面会向你们概述其工作原理。

git-media

git-media 是使用 Ruby 语言开发的,所以首先要安装 gem(LCTT 译注:Gem 是基于 Ruby 的一些开发工具包)。安装说明在其网站上。想使用 git-meida 的用户都需要安装它,因为 gem 是跨平台的工具,所以在各平台都适用。

安装完 git-media 后,你需要设置一些 Git 的配置选项。在每台机器上只需要配置一次。

$ git config filter.media.clean "git-media filter-clean"
$ git config filter.media.smudge "git-media filter-smudge"

在要使用 git-media 的每个存储库中,设置一个属性以将刚刚创建的过滤器结合到要您分类为“ 媒体 ( media ) ”的文件类型里。别被这种术语混淆。一个更好的术语是“资产”,因为“媒体”通常的意思是音频、视频和照片,但您也可以很容易地将 3D 模型,烘焙和纹理等归类为媒体。

例如:

$ echo "*.mp4 filter=media -crlf" >> .gitattributes
$ echo "*.mkv filter=media -crlf" >> .gitattributes
$ echo "*.wav filter=media -crlf" >> .gitattributes
$ echo "*.flac filter=media -crlf" >> .gitattributes
$ echo "*.kra filter=media -crlf" >> .gitattributes

当您要 暂存 ( stage ) 这些类型的文件时,文件会被复制到 .git/media 目录。

假设在服务器已经有了一个 Git 源仓库,最后一步就告诉源仓库“母舰”所在的位置,也就是,当媒体文件被推送给所有用户共享时,媒体文件将会存储的位置。这在仓库的 .git/config 文件中设置,请替换成您的用户名、主机和路径:

[git-media]
transport = scp
autodownload = false #默认为 true,拉取资源
scpuser = seth
scphost = example.com
scppath = /opt/jupiter.git

如果您的服务器上 SSH 设置比较复杂,例如使用了非标准端口或非默认 SSH 密钥文件的路径,请使用 .ssh/config 为主机设置默认配置。

git-media 的使用和普通文件一样,可以把普通文件和 blob 文件一样对待,一样进行 commit 操作。操作流程中唯一的不同就是,在某些时候,您应该将您的资产(或称媒体)同步到共享存储库中。

当要为团队发布资产或自己备份资料时,请使用如下命令:

$ git media sync

要用一个变更后的版本替换 git-media 中的文件时(例如,一个已经美声过的音频文件,或者一个已经完成的遮罩绘画,或者一个已经被颜色分级的视频文件),您必须明确的告诉 Git 更新该媒体。这将覆盖 git-media 不会复制远程已经存在的文件的默认设置:

$ git update-index --really-refresh

当您团队的其他成员(或是您本人,在其它机器上)克隆本仓库时,如果没有在 .git/config 中把 autodownload 选项设置为 true 的话,默认是不会下载资源的。但 git-media 的一个同步命令 git media sync 可解决所有问题。

git-annex

git-annex 的处理流程略微的有些不同,默认是使用本地仓库的,但基本的思想都一样。您可以从你的发行版的软件仓库中安装 git-annex,或者根据需要从该网站上下载安装。与 git-media 一样,任何使用 git-annex 的用户都必须在其机器上安装它。

其初始化设置比 git-media 都简单。运行如下命令,其中替换成您的路径,就可以在您的服务器上创建好裸存储库:

$ git init --bare --shared /opt/jupiter.git

然后克隆到本地计算机,把它标记为 git-annex 的初始路径:

$ git clone [email protected]:/opt/jupiter.clone
Cloning into 'jupiter.clone'... 
warning: You appear to have clonedan empty repository. 
Checking connectivity... done.
$ git annex init "seth workstation" 
init seth workstation ok

不要使用过滤器来区分媒体资源或大文件,您可以使用 git annex 命令来配置归类大文件:

$ git annex add bigblobfile.flac
add bigblobfile.flac
(checksum) ok
(Recording state in Git...)

跟普通文件一样进行提交操作:

$ git commit -m 'added flac source for sound fx'

但是推送操作是不同的,因为 git annex 使用自己的分支来跟踪资产。您首次推送可能需要 -u 选项,具体取决于您如何管理您的存储库:

$ git push -u origin master git-annex
To [email protected]:/opt/jupiter.git
* [new branch] master -> master
* [new branch] git-annex -> git-annex

和 git-media 一样,普通的 git push 命令是不会拷贝资料到服务器的,仅仅只是发送了相关的消息,要真正共享文件,需要运行同步命令:

$ git annex sync --content

如果别人已经提交了共享资源,您需要拉取它们,git annex sync 命令将提示您要在本地检出你本机没有,但在服务器上存在的资源。

git-media 和 git-annex 都非常灵活,都可以使用本地存储库来代替服务器,所以它们也常用于管理私有的本地项目。

Git 是一个非常强大和扩展性非常强的系统应用软件,我们应该毫不犹豫的使用它。现在就开始试试吧!


via: https://opensource.com/life/16/8/how-manage-binary-blobs-git-part-7

作者:Seth Kenlon 译者:runningwater 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

对于新手来说,Git 是一个自由、开源、高效的分布式版本控制系统(VCS),它是基于速度、高性能以及数据一致性而设计的,以支持从小规模到大体量的软件开发项目。

Git 是一个可以让你追踪软件改动、版本回滚以及创建另外一个版本的目录和文件的软件仓库。

Git 主要是用 C 语言来写的,混杂了少量的 Perl 脚本和各种 shell 脚本。它主要在 Linux 内核上运行,并且有以下列举的卓越的性能:

  • 易于上手
  • 运行速度飞快,且大部分操作在本地进行,因此,它极大的提升了那些需要与远程服务器通信的集中式系统的速度。
  • 高效
  • 提供数据一致性检查
  • 支持低开销的本地分支
  • 提供非常便利的暂存区
  • 可以集成其它工具来支持多种工作流

在这篇操作指南中,我们将介绍在 CentOS/RHEL 7/6 和 Fedora 20-24 Linux 发行版上安装 Git 的必要步骤以及怎么配置 Git,以便于你可以快速开始工作。

使用 Yum 安装 Git

我们将从系统默认的仓库安装 Git,并通过运行以下 YUM 包管理器 的更新命令来确保你系统的软件包都是最新的:

# yum update

接着,通过以下命令来安装 Git:

# yum install git

在 Git 成功安装之后,你可以通过以下命令来显示 Git 安装的版本:

# git --version

检查 Git 的安装版本

检查 Git 安装的版本

注意:从系统默认仓库安装的 Git 会是比较旧的版本。如果你想拥有最新版的 Git,请考虑使用以下说明来编译源代码进行安装。

从源代码安装 Git

开始之前,你首先需要从系统默认仓库安装所需的软件依赖包,以及从源代码构建二进制文件所需的实用工具:

# yum groupinstall "Development Tools"
# yum install gettext-devel openssl-devel perl-CPAN perl-devel zlib-devel

安装所需的软件依赖包之后,转到官方的 Git 发布页面,抓取最新版的 Git 并使用下列命令编译它的源代码:

# wget https://github.com/git/git/archive/v2.10.1.tar.gz -O git.tar.gz
# tar -zxf git.tar.gz
# cd git-2.10.1/
# make configure
# ./configure --prefix=/usr/local
# make install
# git --version

检查 Git 的安装版本

检查 Git 的安装版本

推荐阅读: Linux 下 11 个最好用的 Git 客户端和 Git 仓库查看器。

在 Linux 设置 Git 账户

在这个环节中,我们将介绍如何使用正确的用户信息(如:姓名、邮件地址)和 git config 命令来设置 Git 账户,以避免出现提交错误。

注意:确保将下面的 username 替换为在你的系统上创建和使用的 Git 用户的真实名称。

你可以使用下面的 useradd 命令 创建一个 Git 用户,其中 -m 选项用于在 /home 目录下创建用户主目录,-s 选项用于指定用户默认的 shell。

# useradd -m -s /bin/bash username
# passwd username

现在,将新用户添加到 wheel 用户组以启用其使用 sudo 命令的权限:

# usermod username -aG wheel

创建 Git 用户账号

创建 Git 用户账号

然后通过以下命令使用新用户配置 Git:

# su username
$ sudo git config --global user.name "Your Name"
$ sudo git config --global user.email "[email protected]"

现在通过下面的命令校验 Git 的配置。

$ sudo git config --list

如果配置没有错误的话,你应该能够看到类似以下详细信息的输出:

user.name=username
user.email= [email protected]

在 Linux 设置 Git 用户

在 Linux 设置 Git 用户

总结

在这个简单的教程中,我们已经了解怎么在你的 Linux 系统上安装 Git 以及配置它。我相信你应该可以驾轻就熟。


via: http://www.tecmint.com/install-git-centos-fedora-redhat/

作者:Aaron Kili 译者:OneNewLife 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出