分类 观点 下的文章

自从 4 月 5 号 Canonical 宣布放弃 Unity 8 转投 GNOME 之后,开源社区就对此议论纷纷,赞成者有之,惋惜者有之

然而,有很多人没有注意到,就在 Ubuntu 17.04 发布的前一天(13 日),Canonical 现任 CEO Jane Silber 下台,由 Ubuntu 创始人 Mark Shuttleworth 重新接过了她的职位,而 Jane Silber 则会在董事会任职,并负责社区事务。这背后所代表的意味,或许说明了 Canonical 对过去这几年的战略方向的反思和调整。与之同时的是,Canonical 内部的部门裁撤和人员的离开。

但无论社区是如何看待的, Ubuntu 17.04 还是在次日不慌不忙地陆续发布,就在我们以为 GNOME 成为 Ubuntu 主发行版本要在一年以后才能见分晓时,Canonical 内部却呈现加速逃离 Unity 8 的情形:

Ubuntu GNOME 风味版在 17.04 的发布公告中表示它们将和主发行版版本融合,现有的 Ubuntu GNOME 用户以后将升级到 Ubuntu 上(其实还是 GNOME)。

不过这似乎还不足以代表其转投 GNOME 的迫切心,Ubuntu 桌面开发团队已经在 IRC 中讨论,在 17.10 就转到 GNOME,这比原计划的 18.04 LTS 要早一个发布版本。事实上,他们除了已经准备发布的 Ubuntu 17.10 alpha 1 实在是来不及了,alpha 2 就会默认使用 GNOME 了

但这还不是最快的。最快的是另外一个不太引人注目的 Ubuntu 官方风味版本,国内人可能知道的多一点的“优麒麟”(Ubuntu Kylin),这个发行版在 17.04 发布时,就决定抛弃 Unity 桌面,而是使用了一个基于 MATE 的自己设计的 UKUI 桌面。并且,据闻优麒麟将在 18.04 脱离 Ubuntu 主要分支行列,自己干了!

而 Kubuntu 仍旧不温不火地发布着 KDE Plasma 5.9 ,表示“我就看看”;新升级为官方分支的 Ubuntu Budgie 还沉浸在去掉“-remix”后缀而转正成功的喜悦之中,对大人们的事情表示不懂。

Canonical 放弃辛苦开发了几年的 Unity,重新投入到 GNOME 怀抱,是否代表着 Canonical 要减少在桌面和移动互联网上的投入、加大在云和物联网方面的力度?以及将来的发展如何,让我们拭目以待。

不管什么是在什么事情上,你所期待的结果,都是通过尽心设计才能得到的。所以,有拖延症的各位亲们,切莫把所有都拖到最后一分钟才去考虑解决方案哦,不然会死的很惨的。


译者简介:

GHLandy —— 生活中所有欢乐与苦闷都应藏在心中,有些事儿注定无人知晓,自己也无从说起。


via: http://turnoff.us/geek/the-depressed-developer-14/

作者:Daniel Stori 译者:GHLandy 校对:wxy 合成:GHLandy 点评:GHLandy

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

2016 年 Git 发生了 惊天动地 地变化,发布了五大新特性¹ (从 v2.7v2.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 lockunlock 子命令来防止这种情况发生。

# 在我的 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 unlocklock 都要求你指定工作树的路径。或者,你可以 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 将递归每一条提交,在每个 rewordedit 命令处为你暂停来执行你设计好的改变,并且自动运行 squashfixupexecdrop 命令。

非交互性式执行

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

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

$ 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 testmakerakemvn 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 diffgit 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 stashgit 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.showPatchgit 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中国 荣誉推出

嘿嘿,明明你有很厉害的东西想要分享给自己的同伴,可是他们并不能理解那意味着什么,然后拿一些简单的不能再简单的事情来问你。是不是感觉好尴尬呢。看来有些事儿,分享也要看人的吧,否则表错情真的是大写的失落。


译者简介:

GHLandy —— 生活中所有欢乐与苦闷都应藏在心中,有些事儿注定无人知晓,自己也无从说起。


via: http://turnoff.us/geek/the-depressed-developer-13/

作者:Daniel Stori 译者:GHLandy 校对:wxy 合成:GHLandy 点评:GHLandy

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

营销人员觉得工程师在工作中都太严谨了;而工程师则认为营销人员毫无用处。但是他们都错了。

 title=

在 B2B 行业从事多年的销售实践过程中,我经常听到工程师对营销人员的各种误解。下面这些是比较常见的:

  • “搞市场营销真是浪费钱,还不如把更多的资金投入到实际的产品开发中来。”
  • “那些营销人员只是一个劲儿往墙上贴各种广告,还祈祷着它们不要掉下来。这么做有啥科学依据啊?”
  • “谁愿意去看哪些广告啊?”
  • “对待一个营销人员最好的办法就是不听,不看,也不理睬。”

这是我最感兴趣的一点:

“市场营销无足轻重。”

最后一点说的不对,而且不仅如此,它实际上是阻碍一个公司创新的巨大绊脚石。

我来跟大家解释一下原因吧。

看到自己的身影

这些工程师的的评论让我十分的苦恼,因为我从中看到了自己当年的身影。

你们知道吗?我曾经也跟你们一样是一位自豪的技术极客。我在 Rensselaer Polytechnic 学院的电气工程专业本科毕业后便在美国空军担任军官开始了我的职业生涯,而且美国空军在那段时间还发动了沙漠风暴行动。在那里我主要负责开发并部属一套智能的实时战况分析系统,用于综合几个的数据源来构建出战场态势。

在我离开空军之后,我本打算去麻省理工学院攻读博士学位。但是上校强烈建议我去报读这个学校的商学院。“你真的想一辈子待实验室里吗?”他问我。“你想就这么去大学里当个教书匠吗?Jackie ,你在组织管理那些复杂的工作中比较有天赋。我觉得你非常有必要去了解下 MIT 的斯隆商学院。”

我觉得自己也可以同时参加一些 MIT 技术方面的课程,因此我采纳了他的建议。然而,如果要参加市场营销管理方面的课程,我还有很长的路要走,这完全是在浪费时间。因此,在日常工作学习中,我始终是用自己所擅长的分析能力去解决一切问题。

不久后,我在波士顿咨询集团公司做咨询顾问工作。在那六年的时间里,我经常听到大家对我的评论: “Jackie ,你太没远见了。考虑问题也不够周全。你总是通过自己的分析去找答案。”

确实如此啊,我很赞同他们的想法——因为这个世界的工作方式本该如此,任何问题都要基于数据进行分析,不对吗?直到现在我才意识到(我多么希望自己早一些发现自己的问题)自己以前惯用的分析问题的方法遗漏了很多重要的东西:开放的心态、艺术修养、情感——人和创造性思维相关的因素。

我在 2001 年 9 月 11 日加入达美航空公司不久后,被调去管理消费者市场部门,之前我意识到的所有问题变得更加明显。市场方面本来不是我的强项,但是在公司需要的情况下,我也愿意出手相肋。

但是突然之间,我一直惯用的方法获取到的分析结果却与实际情况完全相反。这个问题导致上千人(包括航线内外的人)受到影响。我忽略了一个很重要的人本身的情感因素。我所面临的问题需要各种各样的解决方案才能处理,而不是简单的从那些死板的数据中就能得到答案。

那段时间,我快速地学到了很多东西,因为如果我们想把达美航空公司恢复到正常状态,还需要做很多的工作——市场营销更像是一个以解决问题为导向、以用户为中心的充满挑战性的大工程,只是销售人员和工程师这两大阵营都没有迅速地意识到这个问题。

两大文化差异

工程管理和市场营销之间的这个“巨大鸿沟”确实是根深蒂固的,这跟(著名的科学家、小说家) C.P. Snow 提出的“两大文化差异”问题很相似。具有科学素质的工程师和具有艺术细胞的营销人员操着不同的语言,不同的文化观念导致他们不同的价值取向。

但是,事实上他们比想象中有更多的相似之处。一个由微软、谷歌和美国国家科学基金会共同赞助的华盛顿大学的最新研究发现了“一个伟大软件工程师必须具备哪些优秀的素质”,毫无疑问,一个伟大的销售人员同样也应该具备这些素质。例如,专家们给出的一些优秀品质如下:

  • 充满激情
  • 性格开朗
  • 强烈的好奇心
  • 技艺精湛
  • 解决复杂难题的能力

这些只是其中很小的一部分!当然,并不是所有的素质都适用于市场营销人员,但是如果用文氏图来表示这“两大文化”的交集,就很容易看出营销人员和工程师之间的关系要远比我们想象中密切得多。他们都是竭力去解决与用户或客户相关的难题,只是他们所采取的方式和角度不一致罢了。

看到上面的那几点后,我深深的陷入思考:要是这两类员工彼此之间再多了解对方一些会怎样呢?这会给公司带来很强大的动力吧?

确实如此。我在红帽公司就亲眼看到过样的情形,我身边都是一些早些年肯定被我当成“想法疯狂”而无视的人。而且我猜销售人员看到工程师后(同时或某一次),心想,“这些数据呆瓜,真是只见树木不见森林。”

现在我才明白了公司里有这两种人才的重要性。在现实工作当中,工程师和营销人员都是围绕着客户、创新及数据分析来完成工作。如果他们能够懂得相互尊重、彼此理解、相辅相成,那么我们将会看到公司里所产生的那种积极强大的动力,这种超乎寻常的革新力量要远比两个独立的团队强大得多。

听一听疯子(和呆瓜)的想法

成功案例:《开放式组织》

在红帽任职期间,我的主要工作就是想办法提升公司的品牌影响力——但是就是给我一百万年我也不会想到让公司的 CEO 去写一本书。我把公司多个部门的“想法疯狂”的同事召集在一起,希望他们帮我设计出一个新颖的解决方案来提升公司的影响力,结果他们提出让公司的 CEO 写书这样一个想法。

当我听到这个想法的时候,我很快意识到这正是典型的红帽方式:它将对整个开源社区的从业者带来很重要的参考价值,同时也有助于宣扬开源精神。通过优先考虑这两方面的作用,我们提升了红帽在整个开源软件世界中的品牌价值——红帽是一个可靠的随时准备着为客户在数字化颠覆年代指明方向的公司。

这一点才是主要的:确切的说是指导红帽工程师解决代码问题的共同精神力量。 Red Hatters 小组敦促我出版《开放式组织》,这显示出来自内部和外部社区的程序员共同推动整个开源社区发展的强大动力之一:那就是强烈的共享欲望。

最后,要把《开放式组织》这本书完成,还需要大家的共同能力,包括工程师们强大的数据分析能力和营销人员美好的艺术素养。这个项目让我更加坚定自己的想法,工程师和营销人员有更多的相似之处。

但是,有些东西我还得强调下:开放模式的实现,要求公司上下没有任何偏见,不能偏袒工程师和市场营销人员任何一方文化。一个更加理想的开放式环境能够促使员工之间和平共处,并在这个组织规定的范围内点燃大家的热情。

这对我来说如春风拂面。

(图片来源:opensource.com)


作者简介:

Jackie Yeaney —— Ellucian 公司市场总监


via: https://opensource.com/open-organization/17/1/engineers-marketers-can-learn

作者:Jackie Yeaney 译者:rusking 校对:Bestony, wxy

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

这些练习目前已经支持 33 种编程语言了。

 title=

我们中的很多人的 2017 年目标,将提高编程能力或学习如何编程放在第一位。虽然我们有许多资源可以访问,但练习独立于特定职业的代码开发的艺术还是需要一些规划。Exercism.io 就是为此目的而设计的一种资源。

Exercism 是一个 开源 的项目和服务,通过发现和协作,帮助人们提高他们的编程技能。Exercism 提供了几十种不同编程语言的练习。实践者完成每个练习,并获得反馈,从而可以从他们的同行小组的经验中学习。

这里有这么多同行! Exercism 在 2016 年留下了一些令人印象深刻的统计:

  • 有来自 201 个不同国家的参与者
  • 自 2013 年 6 月以来,29,000 名参与者提交了练习,其中仅在 2016 年就有 15,500 名参加者提交练习
  • 自 2013 年 6 月以来,15,000 名参与者就练习解决方案提供反馈,其中 2016 年有 5,500 人提供反馈
  • 每月 50,000 名访客,每周超过 12,000 名访客
  • 目前的练习已经支持 33 种编程语言,另外 22 种语言在筹备工作中

该项目为各种级别的参与者提供了一系列小小的挑战,使他们能够“即使在低水平也能发展到高度谙熟”,Exercism 的创始人 Katrina Owen 这样说到。Exercism 并不旨在教导学员成为一名职业程序员,但它的练习使他们对一种语言及其瑕疵有深刻的了解。这种熟悉性消除了学习者对语言的认知负担(使之更谙熟),使他们能够专注于更困难的架构和最佳实践的问题。

Exercism 通过一系列练习(或者还有别的?)来做到这一点。程序员下载命令行客户端,检索第一个练习,添加完成练习的代码,然后提交解决方案。提交解决方案后,程序员可以研究他人的解决方案,并学习到对同一个问题不同的解决方式。更重要的是,每个解决方案都会收到来自其他参与者的反馈。

反馈是 Exercism 的超级力量。鼓励所有参与者不仅接收反馈而且提供反馈。根据 Owen 说的,Exercism 的社区成员提供反馈比完成练习学到更多。她说:“这是一个强大的学习经验,你需要发表内心感受,并检查你的假设、习惯和偏见”。她还指出,反馈可以有多种形式。

欧文说:“只需进入,观察并发问”。

那些刚刚接触编程,甚至只是接触了一种特定语言的人,可以通过预设好的问题来提供有价值的反馈,同时通过协作和对话来学习。

除了对新语言的 “微课”学习 bite-sized learning 之外,Exercism 本身还强烈支持和鼓励项目的新贡献者。在 SitePoint.com 的一篇文章中,欧文强调:“如果你想为开源贡献代码,你所需要的技能水平只要‘够用’即可。” Exercism 不仅鼓励新的贡献者,它还尽可能地帮助新贡献者发布他们项目中的第一个补丁。到目前为止,有近 1000 人成为 Exercism 项目的贡献者。

新贡献者会有大量工作让他们忙碌。 Exercism 目前正在审查其语言发展轨迹的健康状况,目的是使所有发展轨迹可持续并避免维护者的倦怠。它还在寻求捐赠和赞助,聘请设计师提高网站的可用性。

Owen 说:“这些改进对于网站的健康以及为了 Exercism 参与者的发展是有必要的,这些变化还鼓励新贡献者加入并简化了加入的途径。” 她说:“如果我们可以重新设计,产品方面将更加可维护……当用户体验一团糟时,华丽的代码一点用也没有”。该项目有一个非常活跃的讨论仓库,这里社区成员合作来发现最好的新方法和功能。

那些想关注项目但还没有参与的人可以关注邮件列表


作者简介:

VM(Vicky)Brasseur - VM(也称为 Vicky)是技术人员、项目、流程、产品和 p^Hbusinesses 的经理。在她超过 18 年的科技行业从业中,她曾是分析师、程序员、产品经理、软件工程经理和软件工程总监。 目前,她是 Hewlett Packard Enterprise 上游开源开发团队的高级工程经理。 VM 的博客在 anonymoushash.vmbrasseur.com,tweets 是 @vmbrasseur。


via: https://opensource.com/article/17/1/exercism-learning-programming

作者:VM (Vicky) Brasseur 译者:geekpi 校对:jasminepeng

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