想象一下,您正在开发一项全新的功能。这将是辉煌的,但需要一段时间。你已经这样做了好几天,也许好几周了。您的功能分支已经比主分支提前6次提交。您是一名优秀的开发人员并做出了有意义的语义提交。但有一件事:你慢慢开始意识到这个疯狂的东西还需要更多时间才能真正准备好合并回主分支。m1-m2-m3-m4(master)\f1-f2-f3-f4-f5-f6(feature)你也知道有些地方其实是新的feature,很少交叉。它们可以更早地合并到master分支中。不幸的是,您想要合并到master分支中的部分存在于您的六个提交之一中的某处。更糟糕的是,它还包括依赖于您的功能分支的先前提交。有人可能会争辩说您应该在最佳位置进行两次提交,但没有人是完美的。m1-m2-m3-m4(master)\f1-f2-f3-f4-f5-f6(feature)^|mixedcommit当你准备提交的时候,你没有预见到你可能要逐渐将这个特性合并到master分支中。哎呀!您不会期望这需要这么长时间。你需要的是一种回溯历史的方法,并将其拆分为两个提交,这样代码就可以安全地分开并移植到master分支。用图片说话正是我们所需要的。m1-m2-m3-m4(master)\f1-f2-f3a-f3b-f4-f5-f6(feature)将工作分成两个commit后,我们可以cherry-pick前面的部分到主分支。原来Git自带了一个强大的命令gitrebase-i,可以让我们做到这一点。它使我们能够改变历史。更改历史记录可能会有问题,根据经验,应尽快避免与他人分享历史记录。但在我们的例子中,我们只是改变了本地特性分支的历史。没有人会受到伤害。去做就对了!好吧,让我们仔细看看f3提交到底修改了什么。原来我们修改了两个文件:userService.js和wishlistService.js。例如,对userService.js的更改可以直接合并到master分支,但wishlistService.js不能。因为wishlistService.js甚至不存在于master分支中。它是在f1提交中引入的。专业提示:即使是对一个文件的更改,git也可以获取它。但是让我们简化这个博客的情况。我们已经建立了一个公共演示存储库,我们将用它来练习。为了便于跟踪,每个提交消息都以上图中使用的假SHA为前缀。下面是git分离commitf3时的分支图。现在,我们需要做的第一件事是使用git的签出功能签出我们的功能分支。使用gitrebase-imaster启动rebase。现在下一个git将使用配置的编辑器打开(默认为Vim)一个临时文件。这个文件给了你一些变基选项,它有一个提示(蓝色文本)。对于每次提交,我们可以选择的操作有pick、rwork、edit、squash、fixup和exec。每个动作也可以通过其缩写形式p、r、e、s、f和e来引用。描述每个选项超出了本文的范围,所以让我们专注于我们的具体任务。我们要为f3提交选择编辑选项,所以我们把内容改成这样。现在我们保存文件(在Vim中,按下并输入:wq,***按下Enter)。接下来我们注意到git在编辑选项中选择的提交处停止了变基。这意味着git开始应用f1、f2、f3,就好像它是常规rebase一样,但在f3生效后停止。事实上,我们可以通过查看我们停止的日志来证明这一点。要将f3拆分为两个提交,我们所要做的就是将git的指针重置为前一个提交(f2),同时保持工作目录不变。这就是gitreset在混合模式下所做的。由于混合模式是gitreset的默认模式,我们可以直接使用gitresethead~1。只需这样做并在运行后使用gitstatus查看发生了什么。gitstatus告诉我们userService.js和wishlistService.js已经被修改。如果我们运行gitdiff,我们可以准确地看到在f3中做了哪些更改。如果我们看一下日志,我们会发现f3不见了。现在我们已经准备好提交之前的f3提交,原来的f3提交已经消失了。请记住,我们仍处于变基过程中。我们的f4、f5、f6提交还没有丢失,它们接下来会回来。让我们创建两个新的提交:首先让我们为userService.js创建一个可以提交到master分支的提交。运行gitadduserService.js,然后运行??gitcommit-m"f3a:addupdateUsermethod"。奇妙!让我们为wishlistService.js的更改创建另一个提交。运行gitaddwishlistService.js,然后运行??gitcommit-m"f3b:addaddItemsmethod"。让我们看一下日志。这就是我们想要的,除了f4、f5、f6仍然缺失。这是因为我们仍在进行变基交互,我们需要告诉git继续变基。继续执行以下命令:gitrebase--continue。让我们再次检查日志。就是这样。我们现在有了我们想要的历史。先前的提交f3现在已拆分为两个提交f3a和f3b。剩下的最后一件事是挑选f3a提交到master分支。为了完成最后一步,我们首先切换到master分支。我们使用gitcheckoutmaster。现在我们可以使用cherry-pick命令来获取f3a提交。在这种情况下,我们可以通过其SHA值bd47ee1来引用它。现在提交f3a位于master分支的顶部。这就是我们需要的!这篇文章的篇幅可能看起来工作量很大,但对于git高级用户来说真的只是片刻。注意:Christoph目前正在与PascalPrecht一起写一本关于Gitrebase的书,你可以在leanpub上订阅它,并在它准备好出版时得到通知。本文作者ChristophBurgdorf从10岁起就是一名程序员。他是HannoverJSMeetup网站的创始人,并且一直活跃于AngularJS社区。他还对GTI了如指掌,他在那里举办了一个思维导图研讨会,帮助初学者掌握这项技术。Ben的教程最初发布在他的博客上。via:https://www.codementor.io/git-tutorial/git-rebase-split-old-commit-master作者:cburgdorf译者:geekpi校对:wxy
