(window.webpackJsonp=window.webpackJsonp||[]).push([[126],{457:function(s,a,e){"use strict";e.r(a);var t=e(3),n=Object(t.a)({},(function(){var s=this,a=s._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"git-工具-重写历史"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#git-工具-重写历史"}},[s._v("#")]),s._v(" Git 工具 - 重写历史")]),s._v(" "),a("p",[s._v("许多时候,在使用 Git 时,你可能想要修订提交历史。 Git 很棒的一点是它允许你在最后时刻做决定。 你可以在将暂存区内容提交前决定哪些文件进入提交,可以通过 "),a("code",[s._v("git stash")]),s._v(" 来决定不与某些内容工作, 也可以重写已经发生的提交就像它们以另一种方式发生的一样。 这可能涉及改变提交的顺序,改变提交中的信息或修改文件,将提交压缩或是拆分, 或完全地移除提交——在将你的工作成果与他人共享之前。")]),s._v(" "),a("p",[s._v("在本节中,你可以学到如何完成这些工作,这样在与他人分享你的工作成果时你的提交历史将如你所愿地展示出来。")]),s._v(" "),a("table",[a("thead",[a("tr",[a("th",[s._v("Note")]),s._v(" "),a("th",[s._v("在满意之前不要推送你的工作Git 的基本原则之一是,由于克隆中有很多工作是本地的,因此你可以 "),a("strong",[s._v("在本地")]),s._v(" 随便重写历史记录。 然而一旦推送了你的工作,那就完全是另一回事了,除非你有充分的理由进行更改,否则应该将推送的工作视为最终结果。 简而言之,在对它感到满意并准备与他人分享之前,应当避免推送你的工作。")])])]),s._v(" "),a("tbody",[a("tr",[a("td"),s._v(" "),a("td")])])]),s._v(" "),a("h2",{attrs:{id:"修改最后一次提交"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#修改最后一次提交"}},[s._v("#")]),s._v(" 修改最后一次提交")]),s._v(" "),a("p",[s._v("修改你最近一次提交可能是所有修改历史提交的操作中最常见的一个。 对于你的最近一次提交,你往往想做两件事情:简单地修改提交信息, 或者通过添加、移除或修改文件来更改提交实际的内容。")]),s._v(" "),a("h3",{attrs:{id:"修改提交信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#修改提交信息"}},[s._v("#")]),s._v(" 修改提交信息")]),s._v(" "),a("p",[s._v("如果,你只是想修改最近一次提交的提交信息,那么很简单:")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("git")]),s._v(" commit "),a("span",{pre:!0,attrs:{class:"token parameter variable"}},[s._v("--amend")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("上面这条命令会将最后一次的提交信息载入到编辑器中供你修改。 当保存并关闭编辑器后,编辑器会将更新后的提交信息写入新提交中,它会成为新的最后一次提交。")]),s._v(" "),a("h3",{attrs:{id:"修改实际内容"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#修改实际内容"}},[s._v("#")]),s._v(" 修改实际内容")]),s._v(" "),a("p",[s._v("另一方面,如果你想要修改最后一次提交的实际内容,那么流程很相似:首先作出你想要补上的修改, 暂存它们,然后用 "),a("code",[s._v("git commit --amend")]),s._v(" 以新的改进后的提交来 "),a("strong",[s._v("替换")]),s._v(" 掉旧有的最后一次提交,")]),s._v(" "),a("p",[s._v("使用这个技巧的时候需要小心,因为修正会改变提交的 SHA-1 校验和。 它类似于一个小的变基——"),a("strong",[s._v("如果已经推送了最后一次提交就不要修正它")]),s._v("。")]),s._v(" "),a("table",[a("thead",[a("tr",[a("th",[s._v("Tip")]),s._v(" "),a("th",[s._v("修补后的提交可能需要修补提交信息当你在修补一次提交时,可以同时修改提交信息和提交内容。 如果你修补了提交的内容,那么几乎肯定要更新提交消息以反映修改后的内容。另一方面,如果你的修补是琐碎的(如修改了一个笔误或添加了一个忘记暂存的文件), 那么之前的提交信息不必修改,你只需作出更改,暂存它们,然后通过以下命令避免不必要的编辑器环节即可:"),a("code",[s._v("$ git commit --amend --no-edit")])])])]),s._v(" "),a("tbody",[a("tr",[a("td"),s._v(" "),a("td")])])]),s._v(" "),a("h2",{attrs:{id:"修改多个提交信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#修改多个提交信息"}},[s._v("#")]),s._v(" 修改多个提交信息")]),s._v(" "),a("p",[s._v("为了修改在提交历史中较远的提交,必须使用更复杂的工具。 Git 没有一个改变历史工具,但是可以使用变基工具来变基一系列提交,基于它们原来的 HEAD 而不是将其移动到另一个新的上面。 通过交互式变基工具,可以在任何想要修改的提交后停止,然后修改信息、添加文件或做任何想做的事情。 可以通过给 "),a("code",[s._v("git rebase")]),s._v(" 增加 "),a("code",[s._v("-i")]),s._v(" 选项来交互式地运行变基。 必须指定想要重写多久远的历史,这可以通过告诉命令将要变基到的提交来做到。")]),s._v(" "),a("p",[s._v("例如,如果想要修改最近三次提交信息,或者那组提交中的任意一个提交信息, 将想要修改的最近一次提交的父提交作为参数传递给 "),a("code",[s._v("git rebase -i")]),s._v(" 命令,即 "),a("code",[s._v("HEAD~2^")]),s._v(" 或 "),a("code",[s._v("HEAD~3")]),s._v("。 记住 "),a("code",[s._v("~3")]),s._v(" 可能比较容易,因为你正尝试修改最后三次提交;但是注意实际上指定了以前的四次提交,即想要修改提交的父提交:")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("git")]),s._v(" rebase "),a("span",{pre:!0,attrs:{class:"token parameter variable"}},[s._v("-i")]),s._v(" HEAD~3\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("再次记住这是一个变基命令——在 "),a("code",[s._v("HEAD~3..HEAD")]),s._v(" 范围内的每一个修改了提交信息的提交及其 "),a("strong",[s._v("所有后裔")]),s._v(" 都会被重写。 不要涉及任何已经推送到中央服务器的提交——这样做会产生一次变更的两个版本,因而使他人困惑。")]),s._v(" "),a("p",[s._v("运行这个命令会在文本编辑器上给你一个提交的列表,看起来像下面这样:")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("pick f7f3f6d changed my name a bit\npick 310154e updated README formatting and added blame\npick a5f4a0d added cat-file\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Rebase 710f0f8..a5f4a0d onto 710f0f8")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Commands:")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# p, pick = use commit")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# r, reword = use commit, but edit the commit message")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# e, edit = use commit, but stop for amending")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# s, squash = use commit, but meld into previous commit")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v('# f, fixup = like "squash", but discard this commit\'s log message')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# x, exec = run command (the rest of the line) using shell")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# b, break = stop here (continue rebase later with 'git rebase --continue')")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# d, drop = remove commit")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# l, label