[译] Git v2.0.0 改了些什么,你需要关心什么?

部分 Linux 的发行版仍使用 1.x 版本的 Git,故找到这篇文章来看看两版本的区别。
请注意此文章的发布日期为 2014 年 5 月,也就是 2.0.0 版本发布的时候。后续翻译将全部保持这个时间。
原文:Git v2.0.0, what changed, and why should you care

Git v2.0.0 是一个向后不兼容的版本,你可能会在从 v1.x 迁移过来的时候发现一些不同。

除非你十分的关注 Git 的 Maillist,不然你很可能不知道 v2.0 的开发已经开始了很久(三年以上)。最开始是从 Junio C Hamano 的一封邮件开始的,他向开发者请求了一些通常因向后兼容问题而不被接受的更改,但他邀请我们思考如果“从头写 Git”会怎样。这个向后不兼容的版本起初定为了“1.8.0”,人们开始向这个重要的版本提交意见。最后过去了很长时间,版本号也从本来打算的 v1.8.0 变成 v2.0。

v2.0 一些修改可能已经以别的形式提前出现了(比如说你可以配置 push.default = simple),不过我们现在总算是有了一个最终的 2.0 版本。接下来就是此版本的大修改。

git push 的默认行为更改


版本说明是这样说的:

git push [$there] 没有说明推送什么的时候,我们一直使用的是传统的 matching 模式。在 Git 2.0 中默认将使用 simple 模式,它会推送:

- 仅当前分支至相同名字的分支,且仅当当前分支设置与远端集成时

- 仅当前分支至相同名字的分支,如果你推送的不是你通常获取的远端

你可以使用配置变量 push.default 来更改这一行为。比如你是个习惯旧版本的用户一直使用的是 matching 模式,那么你可以设置变量为 matching。阅读文档了解其他详情。

你看得懂吗?考虑到 Git 的文档记录比较糟糕,即使你看不懂我也不会惊讶。就我个人来说直接看代码反而更好理解什么情况。

让我尝试解释一下。当你不带参数输入 git push 的时候,Git 会使用 push.default 配置确定要推送什么。之前 push.default 的默认值为 matching, 现在为 simple

matching 实际上是将 git push 转换成 git push origin,也就是会推送所有匹配的分支。比如你在本地有个 master 分支并且远端也有一个 master 分支,那么 master 会被推送;如果你本地和远端都有一个 fix-1 分支, 那么 fix-1 会被推送;如果你只在本地有一个 ext-feature-1,远端没有对应分支的话,那就不会被推送。

而 simple 则是推送单个分支,它使用你配置的上游分支(关于上游分支的解释可以看这篇文章)。如果你当前分支是 master,且跟踪的上游分支是 master,那么 git push 基本上就等同于 git push origin master,或者写完整就是 git push origin master:master (上游分支的名字可以不一样)。

注: 如果你不熟悉 src:dst 的语法,就是你可以将你的本地分支 src 以 dst 的名字推送到服务器,而不用更改你本地分支的名字。你要做的就是使用 git push origin foobar:feature-a,你本地的 foobar 分支就会以 feature-a 的名字推送到服务器。这和是不是 v2.0 没有关系。

但如果你当前的分支是 fix-1 而上游是 origin/mastergit push 会告诉你目标分支的名字不一样,因为它不知道该执行 git push orign fix-1:master 还是 git push orign fix-1:fix-1

另外如果你使用 git push github(不是你的上游分支的远端),Git 会直接使用当前分支的名字,也就是 git push github fix-1(fix-1 是当前分支的名字)。

这个模式比较难描述,但叫它 simple 应该没问题,因为它就是被拿来做“简单的工作”的。

我需要关心吗?

如果你不用 git push 而是习惯把名字敲全……那你不需要关心。

你很可能已经在两年前因为经常见到下面这个烦人信息而配置过 push.default了,那也不需要关心。

warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:

  git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

  git config --global push.default simple

When push.default is set to 'matching', git will push local branches
to the remote branches that already exist with the same name.

In Git 2.0, Git will default to the more conservative 'simple'
behavior, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch.

See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)

所以你很可能不用关心这个更改。

在文件夹中的 git add

版本说明是这样说的:

当在目录运行 git add -ugit add -A 且不标明路径,其会操作整个树以和 git commit -a 和其他命令保持一致(这些命令仅会在当前子目录下操作)。使用 git add -ugit add -A 来确保你的操作限制在当前子目录下。

虽然功能解释的很清楚,但并没有说清楚改了什么,让我举个例子。

假设你已经改了两个文件:READMEtest/basic.t,然后你进到 test 文件夹,然后运行 git add -u。在预发布的 v2.0 中只有 test/basic.t 会被暂存,而在发布的 v2.0 中两个文件都会被暂存。根目录下的操作没有区别。

我需要关心吗?

如果你在使用 git add -ugit add -A 的过程中没有见到过下面的警告,或者干脆没用过这两个参数,那你不需要关心。

warning: The behavior of 'git add --update (or -u)' with no path argument from a
subdirectory of the tree will change in Git 2.0 and should not be used anymore.
To add content for the whole tree, run:

  git add --update :/
  (or git add -u :/)

To restrict the command to the current directory, run:

  git add --update .
  (or git add -u .)

With the current Git version, the command is restricted to the current directory.

git add 会暂存删除

版本说明是这样说的:

git add 现在与 git add -A 相同,所以 git add dir/ 会检测到你在目录中的删除路径操作并记录移除过程。在旧版本的 Git 中,git add 会忽略移除。如果你确实需要,请在添加和修改路径时使用 git add --ignore-removal

再举个例子。假设你删除了 test/basic.t 并添加了一个新文件 test/main.t,这两个更改还没有被暂存,你使用 git add test/ 暂存它们。在预发 v2.0 中 test/basic.t 仍会保持跟踪状态,而发布的 v2.0 中 test/basic.t 会被取消暂存。

我需要关心吗?

如果你在执行 git add 的时候没有见到过下面的警告,那你不需要关心。

warning: You ran 'git add' with neither '-A (--all)' or '--ignore-removal',
whose behaviour will change in Git 2.0 with respect to paths you removed.
Paths like 'test/basic.t' that are
removed from your working tree are ignored with this version of Git.

* 'git add --ignore-removal ', which is the current default,
  ignores paths you removed from your working tree.

* 'git add --all ' will let you also record the removals.

Run 'git status' to check the paths you removed from your working tree.

其他

git diff-files 下的 -q 参数并不是 quiet,已被移除(它告诉 Git 忽略删除,你可以使用 git diff-files --diff-filter=d)。

大多数人不使用这个命令,因此不需要关心。

git request-pull 失去了一些“探测方法”导致其经常造成错误。

也是一样,大多数人不用这个命令,而且它本身就是有问题的。

git svn 的默认前缀在 Git 2.0 中已被修改。很长一段时间以来 git svn 直接在 refs/remotes 下创建它的远端跟踪分支,但现在会将其放在 refs/remotes/origin/ 下,除非使用 --perfix 参数。

如果你不用 git svn,那你不需要关心。如果你没有发现 trunkorigin/trunk 之间不同的话也不需要关心。

总结

你应该不需要担心这些不兼容的改动。当然 Git v2.0.0 有很多新功能和 bug 修复,但 v1.9.0 及其之前的版本也是一样维护的很好。

考虑到 Git v2.0.0 已经做了三年了,我认为有很多修改错过了一个很好的机会,特别是之前很多用户提到的用户界面和文档优化,并且已经有补丁尝试做这些事情了。我在另一篇文章中讨论了我认为 Git v2.0.0 应该包含哪些修改。


以下摘录一个评论:

服务端与客户端之间的向后兼容性是保留的(由客户端和服务端自行协商)。客户端在同一存储库的向后兼容性如果我没记错的话应该是保留的(我认为索引格式没有改变)。破坏更新的是命令的行为与之前不同(尽管某些命令你可以把它配置回旧的行为)。

客户端和服务端的向后兼容性只破坏了两处:一个是增加了子模块(旧客户端无法识别出存储库的子模块);另一个是 `packed-refs`(老客户端在使用老的 HTTP 协议时会无法识别)。

Jakub Narębski

发布评论

您的邮箱地址不会被公开。 必填项已用 * 标注