[译] 保护我们的 Git Repos,立刻停止“狐步舞”

简介: 本文讲的是[译] 保护我们的 Git Repos,立刻停止“狐步舞”,“狐步舞”式的合并是 git commit 的一个特别不好的具体顺序。如同在户外看到的“狐步舞”,这种commits序列像这个样子:
本文讲的是[译] 保护我们的 Git Repos,立刻停止“狐步舞”,

狐步舞舞者狐步舞舞者

舞者们正准备跳狐步舞。

首先,什么是“狐步舞”式的合并?

“狐步舞”式的合并是 git commit 的一个特别不好的具体顺序。如同在户外看到的“狐步舞”,这种commits序列像这个样子:

狐步舞式的合并“狐步舞”式的合并

但在公开场合很少会见到“狐步舞”。它们隐藏在树冠之间,树枝之间。我称它们“狐步舞”式,是因为他们交叉的样子,他们看起来像同步舞蹈的舞步顺序:

狐步示意图狐步示意图

还有一些人也提到“狐步舞”式的合并,但它们从来没有直接说出它的名字。例如,Junio C. Hamano 的博客有有趣的 --first-parent,还有有趣的非快进方式(Non-Fast-Forward)。David Lowe 的 nestoria.com 有关于保持一致的线性历史记录的文章。此外还有告诉你要避免使用 git pull,而是使用 git pull –rebase。为什么?主要是为了避免一般的合并和提交时的错误,此外还可以避免出现该死的“狐步舞”式的提交。

“狐步舞”式的合并真的很不好吗?是的。

水母水母

它们显然不如僧帽水母那样糟糕。但是“狐步舞”式的合并也是不好的,你不希望你的 git 仓库里有它们的身影。

“狐步舞”式的合并为什么不好?

“狐步舞”式的合并不好,因为它会改变 origin/master 分支的“第一父级”的地位。

合并提交记录的父级是有序的。第一个父级是 HEAD。第二个父级是用 git merge 命令提交的。

你可以像下面这样想:

git checkout 1st-parent
git merge 2nd-parent

如果你是 octopus 的说客:

git merge 2nd-parent 3rd-parent 4th-parent ... 8th-parent etc...

这意味着父级的记录就像它听起来一样。当你提交新的代码的时候,忽略第一个父级以外的父级,从而得到一个新的代码记录。对于常规的 commit(非 merge),第一个父级是唯一的父级,并且对于 merge 来说,它是你在输入 git merge 时所产生的记录。这种父级概念是直接植入到 Git 里的,并且在很多命令行中都有所体现,例如,git log –first-parent

“狐步舞”式的合并问题在于,它使得 origin/master 由第一父级变成了第二父级。

除了 Git 在评估提交是否有资格进行 fast-forward 时,Git 并不关心父级的先后次序。

当然你很不希望这样。你不希望“狐步舞”式的合并通过 fast-forward 的方式更新你的origin/master,使得 origin/master 第一父级的地位不稳定。

看一下当“狐步舞”式的合并被 push 上去的时候会发生什么:

狐步舞式的合并被 push“狐步舞”式的合并被 push

可以使用手指从 origin/master 开始沿着图形往下,在每个分叉的地方选择左边的分支,从而知道当前的第一父级的变更历史。

问题是,最初的第一个父级提交次序(从 origin/master 开始)是这样的:

B, A.

但是当“狐步舞”式的合并被 push 之后,父级的次序变成这样了:

D, C, A.

这时,B 节点已从 origin/master 第一父级中消失,事实上,B在它的第二父级上。当然,不会有任何资料的丢失,并且 B 节点仍然是 origin/master 的一部分。

但是,这样父级节点就会有错综复杂的关系。你是否知道,tilda 符号(例如 ~N)指定从第 N 个提交的节点到第一个父节点间的路径?

你有没有想要看看你的分支上的每个提交记录之间的差异,但是使用 git log -p 显然会漏掉一些信息,使用 git log -p -m 能获取更多的信息吗?

尝试使用 git log -p -m –first-parent 吧。

你想过要还原一个合并的分支吗?那你需要为 git revert 提供 -m parent-number 选项,这时候你就很不希望自己提供的 parent-number 是错的。

和我一起工作的人,大多数都将第一个父级作为真正的 master 分支。有意识或无意识地,人们将 git log –first-parent origin/master 视为重要事物的顺序。 至于任何其他合并进来的分支?嗯,你应该知道他们会怎么说:

topictopic

但是“狐步舞”式的合并把这些都混在了一起。请考虑下面的例子,其中 origin/master 分支的一系列的重要提交信息,与你自己的稍微不那么重要的提交并行:

topic escapedtopic escaped

现在,你终于准备把你的工作并入到 master 中。你输入 git pull,或者可能你在一个主题分支上使用 git merge master 命令。那这样发生了什么?一个“狐步舞”式的合并就这么出现了。

topic escaped btopic escaped b

一切都没有什么大问题,除了当你键入 git push,让你的远程仓库接受它时,你的历史记录看起来像这样:

topic escaped ctopic escaped c

topic escaped legotopic escaped lego

对于已经混入了“狐步舞”式的合并的 git 项目应该怎么做?

啥招都没有,随它们去吧。除非你重写 master 分支的历史而惹怒其他人,那么就去这么疯吧。

事实上,不要这样做。

如何防止未来“狐步舞”式的合并出现在我的 git 项目中?

这有几个方法。我最喜欢的的方式是下面的四步:

  1. 为你的团队安装 Atlassian Bitbucket 服务器。

  2. 安装我为 Bitbucket 服务器写的插件,名字叫“Bit Booster Commit Graph and More”。
    你可以在下面的链接中找到他们:marketplace.atlassian.com/plugins/com…marketplace.atlassian.com/plugins/com…

  3. 在你所有项目中,都点击 “Protect First Parent Hook” 上的 “Enabled” 按钮,也就是“启用”按钮:

hook enabledhook enabled

  1. 你可以在试用许可结束前免费使用31天。(感觉它好用的话,可以在试用期后进行购买)。

这是我最喜欢的方式,因为它杜绝了“狐步舞”的出现。每当有一个“狐步舞”式的合并被阻挡时,它会打印一只牛:

$ git commit -m 'my commit'
$ git pull
$ git push

remote:  _____________________________________________
remote: /                                             \
remote: | Moo! Your bit-booster license has expired!  |
remote: \                                             /
remote:  ---------------------------------------------
remote:         \   ^__^
remote:          \  (oo)\_______
remote:             (__)\       )\/\
remote:                 ||----w |
remote:                 ||     ||
remote:
remote: *** PUSH REJECTED BY Protect-First-Parent HOOK ***
remote:
remote: Merge [da75830d94f5] is not allowed. *Current* master
remote: must appear in the 'first-parent' position of the
remote: subsequent commit.

还有其他的方法。你可以禁止直接向 master 分支进行推送,并保证不在 fast-forward 的情况下合并 pull-requests。或者培训你的员工使用 git pull –rebase 命令,并且永远不要使用 git merge master。并且一旦你培训完你的员工,就不要再招聘其他员工了。

如果你可以直接访问远程仓库,则可以设置 pre-receive hook。 以下的 bash 脚本可以帮助你开始这项设置:

#/bin/bash

# Copyright (c) 2016 G. Sylvie Davies. http://bit-booster.com/
# Copyright (c) 2016 torek. http://stackoverflow.com/users/1256452/torek
# License: MIT license. https://opensource.org/licenses/MIT
while read oldrev newrev refname
do
if [ "$refname" = "refs/heads/master" ]; then
   MATCH=`git log --first-parent --pretty='%H %P' $oldrev..$newrev |
     grep $oldrev |
     awk '{ print \$2 }'`

   if [ "$oldrev" = "$MATCH" ]; then
     exit 0
   else
     echo "*** PUSH REJECTED! FOXTROT MERGE BLOCKED!!! ***"
     exit 1
   fi
fi
done

我不小心创建了一个“狐步舞”式的合并,但我还没有 push 上去。我该怎么解决?

假设你安装了预先接收的钩子,并且阻止你“狐步舞”式的合并。你下一步做什么?你有三种可能的补救办法:

  1. 普通的 rebase

使用 `rebase` 进行补救使用 `rebase` 进行补救

  1. 撤销你之前的合并,使你的 origin/master 分支成为第一父级:

撤销 merge撤销 merge

  1. 在“狐步舞”式的合并后创建第二个合并并提交,以恢复 origin/master 的第一父级的地位。

补救补救

但请不要使用上面的第三种方法,因为最后的结果被称为“僧帽水母”式的合并,这种合并甚至比“狐步舞”式的合并更糟糕。

总结

在最后,其实“狐步舞”式的合并也像其他的合并那样。两个(或多个)提交到一起融合成一个新的记录节点。就你的代码库而言,没有任何区别。无论 commit A 合并到 commit B 中还是反过来 commit B 合并到 commit A,从代码的角度来看最终结果是相同的。

但是,当涉及到你的仓库的历史记录时,以及有效地使用 git 工具集时,“狐步舞”式的合并会有一定的破坏性。通过设置相应的策略来防止其出现,可以使你仓库的历史记录更加清晰明了,并减少了需要记住的 git 命令选项的范围。





原文发布时间为:2017年7月31日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
目录
相关文章
|
开发工具 git
Git:fatal: ‘upstream‘ does not appear to be a git repositoryfatal: Could not read from remote repos
Git:fatal: ‘upstream‘ does not appear to be a git repositoryfatal: Could not read from remote repos
213 0
|
13天前
|
缓存 数据可视化 网络安全
Git命令大全
Git命令大全
45 1
|
17天前
|
开发工具 git
Git教程:深入了解删除分支的命令
【4月更文挑战第3天】
37 0
Git教程:深入了解删除分支的命令
|
1月前
|
存储 Shell Linux
【Shell 命令集合 文件管理】Linux git命令使用教程
【Shell 命令集合 文件管理】Linux git命令使用教程
34 0
|
1月前
|
开发工具 git
git常用命令整理
git常用命令整理
13 0
|
23天前
|
开发工具 git 开发者
Git常用命令大全:让你轻松驾驭版本控制
Git命令速查:`git init`新建仓库,`git clone`克隆,`git add`入暂存区,`git commit -m`提交,`git status`查看状态,`git log`查看历史,`git branch`创建分支,`git checkout`切换,`git merge`合并,`git pull`拉取更新,`git push`推送,`git remote -v`查看远程,`git checkout --`撤销本地修改,`git reset HEAD`取消暂存,`git reset --hard`回退版本。掌握这些,提升代码管理效率!
18 0
|
2天前
|
存储 Linux 开发工具
Git 分布式版本控制系统基本概念和操作命令
Git 分布式版本控制系统基本概念和操作命令
21 0
|
4天前
|
算法 Java BI
云效产品使用报错问题之平台上导出的统计数据和 git 中使用命令导出的数据统计都对不上,如何解决
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
30天前
|
算法 开发工具 git
【git 实用指南】git 增加 本地代码 git add 相关命令和复杂情况需求
【git 实用指南】git 增加 本地代码 git add 相关命令和复杂情况需求
92 0
|
1月前
|
Shell Linux 开发工具
【Shell 命令集合 系统管理 】Linux 查看当前Git仓库的提交历史 gitps命令 使用指南
【Shell 命令集合 系统管理 】Linux 查看当前Git仓库的提交历史 gitps命令 使用指南
18 0