重置
如果你认为这涉及到一把勺子和一个精神灯,那就带上你的 F 回家吧。Git 的 "rebase" 命令利用 Git 的分布式特性,使你能够在你的仓库中做一些真正有用和有创造性的事情。当然,就像所有强大的工具一样,rebase 也可以被滥用。让我们更深入地了解通过 rebase 可以做什么,以及在何时何地应该使用它。本文假设您熟悉软件版本控制系统的一般知识,以及 git 本身的基本知识。虽然它探讨了 Git 的基础知识,但并不旨在成为 Git 用法的入门指南。
Git 是一个分布式版本控制系统。这意味着尽管它可以像 subversion 这样的集中式代码库一样使用,但它也可以同时与几个不同仓库的相同源代码一起工作。
由于这些多个仓库在任何时候都不可能处于相同的状态,因此它具有内置的工具来同步跨仓库,并协调全球分布的团队成员的工作。
Git 的基础知识
将 Git 仓库想象成一张地图,由节点和路径组成。节点是代码状态的快照,在每个提交后创建。路径是可以应用于一个节点以将其移动到另一个节点的 diff 文件。
节点由引用标识。每个提交都有一个 ID,这是一个指向节点的引用。创建标签时也是如此。此外,Git 本身也有一些引用(例如 HEAD,它始终指向当前源分支的顶部)。
如果你开始将仓库想象成代码的地图,你现在就可以看到一切是如何流动的。引用可以很容易地创建或删除,只需创建或合并路径即可。Rebase 利用这种流动性,允许你重新映射你的代码仓库。
简单重置
最简单的 rebase 形式是 "git rebase branch name"
命令。它将当前分支重置,使其分支点是给定分支的 HEAD。
想象有一个包含两个提交的master分支。你开始着手一个新的功能,因此在那个点创建一个专用的分支(我们将它称为“Feature”)并开始工作。
与此同时,团队成员对master分支做出了一些提交,修复了一些严重的bug。你的Feature分支可以从中受益,因此你希望将这些bug修复合并到它里面。你的仓库图可能看起来像这样(“C1”到“C6”代表提交,图中的节点)
你可以从master中选择个别提交合并到你的分支中,或者将master合并到你的分支中。无论是哪种方式,都会引入修复。但它们也会在你的Feature分支中创建提交,这些提交严格来说并不属于该功能本身,你以后还需要处理它们,特别是如果这种情况经常发生。
或者你可以
git checkout Feature git rebase master
现在仓库图看起来像这样
这是一个更干净、更易于理解的仓库图。它显示了包含只与功能相关的提交的Feature分支,同时包括了master分支上批准的所有修改和bug修复。
这是谎言!
是的,如果你认为仓库日志应该是一个审计跟踪,一个记录发生事件的记录,那么它就是一个谎言。但如果你将仓库日志视为代码的地图,那么它不是谎言。它显示了Feature分支基于一个完全最新的master分支,正如它所示。因此,它显示了你的位置真相,比合并显示得更清楚,只是不显示你是如何到达那里的。你对简单rebase的价值的看法取决于你认为是否更倾向于拥有当前状态的清晰图像,还是详细准确的过去记录。你自己决定;我只是导游。
我能再来一些吗?
更复杂,更有用的一种是pull时的rebase。为此,想象你自己的本地master分支是你公共仓库中master分支的本地副本。我们将这个远程分支称为“origin”,并假设团队成员也在将其推送到它(或者以你喜欢的方式提交工作),你将其拉到本地仓库以保持其更新。
你可以使用以下命令将Feature分支与公共master保持一致:
git checkout Feature git pull origin
这最终会得到一个看起来像这样的图
这里有一个额外的合并提交,将origin连接到Feature,正好在Feature的头部。经过6-7次这样的操作后,你可以想象仓库图会变得多么混乱。
但除此之外,还有一个危险。假设经过几次这样的操作后,你发现你的方法(或者这个功能的定义被广泛修改)有严重的问题。现在你将不得不回滚一些提交,以便从更好的地方开始新的编码。
如果这个新点在合并之前(例如,如果你需要从上面的图中回滚到C8到C6),你的Feature分支将失去访问由该提交合并到公共仓库的更新的权限。这意味着你将不得不再次合并它们。清洗。搓洗。重复。
相反,你可以使用rebase将公共仓库的更改引入
git checkout Feature git pull --rebase origin
这最终会得到一个看起来像这样的仓库图
没有合并提交,你可以在Feature分支中回滚到你需要的任何地方,而无需重新与远程仓库合并。仓库图既整洁又清晰,Feature分支中的所有代码都是专门为该功能编写的。
这意味着当您完成时,创建功能分支的拉取请求将更容易。 (说到这里,你那个功能为什么花了这么长时间?)
在您的基础上Git交互
好吧,我们已经看到了rebase的一些基础知识,现在让我们看看它的最复杂和最致命的形式——交互式rebase
git rebase -i reference
给出的引用可以是map中的任何引用,或者任何内置引用,例如HEAD。例如,“git rebase -i HEAD^^^”将使用最后三个提交启动交互式rebase,而“git rebase -i fe40861”将重新整理自标记为“fe40861”的提交以来的所有提交。
当你输入交互式rebase命令时,git会在你的默认编辑器中放入类似以下文本的文本
pick 33fde07 Make some declarations align pick 953683a Don't align function arguments. pick 904e0b8 Correcting issue 26493 pick 06b98bd Add function to batch edit an item's language pick f4b68ea Correcting issue pick 10b14bf Fixed JDaemonTest # Rebase fe40861..10b14bf onto fe40861 # # 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 # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. #
最前面的行(以上以“pick …”开始的行)是包含在这次rebase中的单个提交的列表。你可以根据需要以任何新顺序重新排列提交的列表。“pick”是一个命令,告诉git你想完全接受这个提交。
最有用的下一个命令是“squash”。这个命令告诉git你希望将这个提交与上面的一个合并,将两个提交合并为一个。你可能想使用这个命令,比如你不小心在之前的提交中包含了一个错误,你在提交后的一段时间才发现。在这个上下文中,修复没有意义,因为错误的代码不是你通过代码的“停止”的有效“停止”,所以将修复捆绑在一起可以使那些后来者更容易,他们不必在无意义的提交中跋涉,并且只需回滚一个提交就可以回滚预期的代码更改。
其余的命令都很直观,也许“edit”除外,它提供了一些非常强大的选项,我稍后会解释。
在你重新排列提交列表并设置命令后,git将开始rebase。
如果你给出了edit命令,git会在它停下来时给你机会在继续之前输入任何你想要的命令。Git将在命令行上给你一个类似的提示
Stopped at commitID… commit log message You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue
记住我们说过git跟踪单个更改吗?在这个时候,你可以输入
git reset HEAD
将此提交的阶段更改从暂存区域中拉出。然后你可以继续将文件中的单个更改分阶段到一个单独的提交中,提交它,然后分阶段剩余的更改并提交它们,将单个提交转换为两个。然后,当你在这个阶段完成你需要做的事情时,输入“git rebase --continue”命令,git将继续rebase直到完成,或者直到它遇到需要你交互的其他命令。
你为什么要这样做?假设你一直专注于功能分支上的编码,在这个过程中你注意到并修复了一个你接触到的文件中的一个错误。在你提交更改后,你意识到修复本身应该是一个单独的提交,也许是因为你的团队中的一员刚刚在他们正在工作的功能中遇到了类似的事情。这使得你可以回溯并将那个更改从原始提交中分离出来,使其容易在其他分支上通过cherry picks、合并或其他rebase操作被拉取。
时间可以被重写吗?
在将仓库日志视为时间的情况下,是的。你可以随意在仓库流中移动事件。是的,这可能会像你想的那么危险和令人困惑。这意味着有规则。
重置合并(rebase)安全使用的第一条规则是永远不要重置公共仓库(公共仓库是除你之外更多人使用的仓库)。我说的是,永远不要重置公共仓库!其他人也依赖于公共仓库,如果你更改那里的历史记录,将会使所有人的仓库失去同步,造成所有人麻烦。永远不要(不,即使当潘多拉盒子打开时)重置公共仓库。
至于你自己的仓库,你可以随时重置,但仅仅因为你能够这样做并不是一个好理由。将重置视为你仓库的重构工具。只有在结果会使得事情更整洁、更容易使用和理解时才这样做。
这样的例子可能包括将几个小提交组合成一个大提交,形成一个统一的整体。这在大体上没有理由要撤销其中一个更改而不撤销其他更改时非常有用。这种情况发生的频率取决于你的工作风格。
有些人将提交视为宝贵的资源,只有当他们有有价值且重要的内容要提交时才会提交代码。使用这种工作风格的人可能不会把上述内容视为机会。其他人,比如我,将提交视为“保存”步骤的升级。在我单独处理一个问题的时候,我可能会做出5次甚至更多的提交(如果从上次提交过去的时间超过半小时,我的手就会开始发抖,我开始考虑如果不立即提交我可能会丢失什么)。我提交就像芝加哥投票一样——早且频繁。
当你在分支上进行更改时,重置合并的机会也会出现。这些更改可能对你自己的分支有用,但严格来说并不属于该功能本身。
哎呀
像其他任何强大工具一样谨慎地使用git rebase。但无论你多么小心,墨菲定律总会有办法让事情变得一团糟。
如果你正在进行交互式重置合并('git rebase -i'),你可能会看到类似于“交互式重置合并已开始”的错误消息。这意味着git已经在交互式重置合并过程中。如果你知道这是真的,且你知道重置合并仍然是好的,使用'git rebase --continue'将帮助你回到正轨。如果你不确定,可以使用'git rebase --abort'取消整个重置合并。
Git总是用ORIG_HEAD标签标记重置的起始点,所以如果在重置后你对自己所在的位置不舒服,尝试使用'git reset --hard ORIG_HEAD'返回到一个更好的地方。
ORIG_HEAD还可以以其他方式有用。你可以使用'git diff ORIG_HEAD..HEAD'来查看特定重置操作所做的更改总和。
重置合并是git的一个功能,使它成为一个更强大的开发工具。稍微玩一玩,了解它在你的工具箱中的位置,这将使你的生活变得更轻松。
在Joomla社区杂志上发表的一些文章代表了作者对特定主题的个人意见或经验,可能并不与Joomla项目的官方立场一致。
通过接受,您将访问 https://magazine.joomla.net.cn/ 之外的第三方外部服务
评论