[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"content-remove-sensitive-data-from-git-with-rebase":3,"$fk6gfusd7qtt3":22},{"id":4,"type":5,"slug":6,"title":7,"date":8,"category":9,"tags":10,"body_markdown":13,"permalink":14,"excerpt_src":15,"media_type":15,"media_title":15,"media_author":15,"media_url":15,"rating":15,"layout":15,"pv":16,"admin_only":16,"created_at":17,"updated_at":17,"deleted_at":15,"status":18,"html":19,"excerpt":20,"cover":21},127,"article","remove-sensitive-data-from-git-with-rebase","使用Rebase操作抹去Git仓库中的敏感信息","2019-11-29 20:38","tech",[11,12],"Git","Rebase","\n使用Git的时候，有时候会碰到需要从Git仓库中永久“抹除”某些敏感信息的情况。例如不小心提交了密码之类的信息到仓库，此时只抹掉这些信息重新提交是没有用的，因为其他人仍然可以通过Git历史看到这些敏感信息。因此需要一种方法将这些信息彻底从仓库中抹去。\n\n如果去网上搜索的话，能很容易找到使用`branch-filter`来处理的方法，例如\n\n```sh\ngit filter-branch --tree-filter \"find . -name '*.*' -exec sed -i '' -e 's\u002FOLDSTRING\u002FNEWSTRING\u002Fg' {} \\;\" -f\n```\n\n写法有很多种，但是思路都差不多，就是遍历一遍所有的提交，对这些提交执行指定的命令（例如用`sed`替换指定的内容，或者移除相关文件），然后重新生成新的提交和分支。\n\n不过这种思路对于我来说却不太受用，原因有几个：\n\n1. 命令行掌握不太好，看到这种命令都不太认识，完全不敢直接放在项目中去跑\n2. 直接进行字符串级别的替换，在某些情况下不够用，例如想通过更复杂的编辑手段（新增文本、修改文本、删除文本同时操作）抹除敏感信息\n3. 直接对整个仓库\u002F整个文件进行字符串级别的替换还是有些不放心，毕竟要修改的部分是明确的，却无法明确地指定这个命令只修改这一部分信息\n\n那怎么办呢？其实在这种场景下，也可以尝试使用`git rebase`来解决问题。\n\n## rebase是干什么的\n\n`rebase`顾名思义，就是重新确定一个提交（一个分支）的“基”，这个“基”就是指它的祖先元素。具体的做法是，首先将提交退回到“基”所在的点，然后将之前做过的提交在这个“基”的基础上重复做一遍。相当于修改了当前分支衍生出来的基础，因此中文也被译为“变基”。\n\n\u003C!-- more -->\n\n还是举个例子：\n\n新建一个仓库，然后做两次提交`A1`、`A2`：\n\n```sh\n# 初始化\nmkdir test\ncd test\ngit init\n\n# 两次提交\necho \"A1\">>1.txt\ngit add .\ngit commit -m A1\n\necho \"A2\">>2.txt\ngit add .\ngit commit -m A2\n```\n\n接下来分成两个分支，分别进行提交`B1`、`B2`和`C1`、`C2`：\n\n```sh\n# 创建新分支\ngit checkout -b new\n\n# 新分支提交B1 B2\necho \"B1\">>1.txt\ngit add .\ngit commit -m B1\n\necho \"B2\">>2.txt\ngit add .\ngit commit -m B2\n\n# 切换主分支\ngit checkout master\n\n# 主分支提交C1 C2\necho \"C1\">>1.txt\ngit add .\ngit commit -m C1\n\necho \"C2\">>2.txt\ngit add .\ngit commit -m C2\n```\n\n于是得到一张这样的分支图：\n\n![分支图](\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F01.png)\n\n此时`new`和`master`两个分支分别指向`B2`和`C2`两次提交，而他们的共同祖先（即前文中说的“基”，这个说法不严谨，仅为理解），则是`A2`这次提交。此时我们就可以用`rebase`来改变其中某一个分支的走向。例如，让`C1`在`B2`的基础上修改，即让`master`分支的提交顺序变成`A1-A2-B1-B2-C1-C2`：\n\n```sh\n# 对哪个分支rebase就切换到哪个分支\ngit checkout master\n\ngit rebase new\n```\n\n而此时就出现了冲突，因为`C1`和`B1`两次提交都对`1.txt`做了修改。\n\n```sh\nA1\n\u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD\nB1\n=======\nC1\n>>>>>>> C1\n```\n\n我们选择手工解决冲突，将`B1`放前面，`C1`放后面，解决完之后继续`rebase`\n\n```sh\n# 用add标记解决完冲突\ngit add 1.txt\ngit rebase --continue\n```\n\n此时分支图会变成这样，表明C1这次提交已经变基成功。但同时也能看到C2在变基的时候也产生了冲突。\n\n![分支图](\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F02.png)\n\n这里和上面一样处理即可。完成后就能看到变基后的分支图。\n\n![分支图](\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F03.png)\n\n需要说明的是，尽管提交的描述信息（commit message）没变，但是`C1`、`C2`这两次提交实际上是新产生的，因此它们的commit id和之前的提交是完全不同的。\n\n通过这个例子，能清楚地看到`rebase`命令的作用，即改变提交（分支）的基础。一般来说，在多人协作过程中，适合将同一分支互相拉取变更的操作使用`rebase`来完成，这样可以保持同一分支的提交历史是线性的，方便回溯。\n\n## 使用rebase改变Git历史\n\n在上面`rebase`的例子中，还有一个点值得注意，以`C1`这次提交为例，`rebase`前后两种情况下，虽然都是在`1.txt`结尾添加`C1`这行文字，但是基础和结果都是不同的。在`rebase`之前，`1.txt`的内容是由`A1`变成`A1\\nC1`，而在`rebase`之后则是由`A1\\nB1`变为`A1\\nB1\\nC1`。\n\n可见在`rebase`的时候，不止是提交的父节点（“基”）会变，文件内容也有所变化。而我们之前在`rebase`时面临的冲突，也正是因为这个变化所带来的。但同时，正因为有这样一个变化，使得我们有机会通过`rebase`的方式来永久改写Git仓库中某一个文件的历史。\n\n仍然看上面的例子，现在只看`rebase`之后的情况。在`C1`这次提交中，我们为文件`1.txt`在结尾处添加了内容`C1`。假设这个`C1`是一个很敏感的信息（例如密码），我们要如何将它从仓库历史中抹去呢？\n\n![分支图](\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F04.png)\n\n首先我们在C1提交之前找到一个点，例如B2，然后基于它新建一个分支。（例如`new`这个分支。）接下来在这个分支上，对文件`1.txt`进行修改，例如我们增加一行`C2`。即`1.txt`内容变为\n\n```\nA1\nB1\nC2\n```\n\n并进行一次提交。\n\n![分支图](\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F05.png)\n\n接下来，我们对C2这次提交（即`master`分支）进行`rebase`操作：\n\n```sh\n> git checkout master\n> git rebase new\n```\n\n此时git会告诉我们，产生了冲突。\n\n```\nFirst, rewinding head to replay your work on top of it...\nApplying: C1\nUsing index info to reconstruct a base tree...\nM\t1.txt\nFalling back to patching base and 3-way merge...\nAuto-merging 1.txt\nCONFLICT (content): Merge conflict in 1.txt\nerror: Failed to merge in the changes.\nPatch failed at 0001 C1\nhint: Use 'git am --show-current-patch' to see the failed patch\n\nResolve all conflicts manually, mark them as resolved with\n\"git add\u002Frm \u003Cconflicted_files>\", then run \"git rebase --continue\".\nYou can instead skip this commit: run \"git rebase --skip\".\nTo abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n```\n\n冲突内容正是原来的`C1`和我们刚在新分支上添加的`C2`：\n\n```\nA1\nB1\n\u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD\nC2\n=======\nC1\n>>>>>>> C1\n```\n\n前文假设，`C1`是我们要删除的敏感信息，因此此时手工解决冲突，将`C1`删除，留下`C2`。然后`git rebase --continue`即可。\n\n可以看到我们的提交记录变成了这样：\n\n![分支图](\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F06.png)\n\n敏感信息被彻底删除了。\n\n## 小结\n\n上面只是展示了一种简单的情况，但已经足够说明使用`rebase`来删除代码库中敏感信息的核心思路和关键步骤了。\n\n有一些值得注意的细节：\n\n1. 由于C1提交和重写C1的提交都只修改了一行代码，因此在`rebase`过程中，把这一行的冲突解决完，并且`git rebase --continue`时，会提示没有变更（因为唯一的变更在冲突解决过程中被编辑好了），此时需要使用`git rebase --skip`跳过这次提交。\n2. 上面我们是使用`rebase`操作时，编辑冲突的时机来编辑代码文件，从而将`C1`这个敏感信息删除的。如果无法保证一定产生冲突，则可以使用`git rebase -i`（交互式变基）来手工指定需要对哪些提交进行编辑，从而在不一定有冲突时，也有机会编辑代码文件，来将敏感信息删除。关于交互式变基，可参考网络上相关文档。\n3. 如果敏感信息在第一次提交就被带入版本库了，则上面说的“在C1提交之前找到一个点”无法完成。此时可以用`git checkout --orphan branch-name`来创建一个完全空白且没有父节点的分支，并且将当前分支的提交基于这个新的空分支来进行`rebase`，从而获得编辑代码删除敏感信息的机会。\n\n最后，一个提醒：不论用什么方法来修改版本库历史，都是在重写历史，虽然看起来提交的commit message是一样的，但是却是完全全新的提交和分支发展路径。当推送到代码库时，需要使用`git push --force`来强制推送，其他人则需要使用`git pull --rebase`来重写本地分支。\n","\u002Farticle\u002Fremove-sensitive-data-from-git-with-rebase.html",null,0,"2026-08-28 04:37:17","published","\u003Cp>使用Git的时候，有时候会碰到需要从Git仓库中永久“抹除”某些敏感信息的情况。例如不小心提交了密码之类的信息到仓库，此时只抹掉这些信息重新提交是没有用的，因为其他人仍然可以通过Git历史看到这些敏感信息。因此需要一种方法将这些信息彻底从仓库中抹去。\u003C\u002Fp>\n\u003Cp>如果去网上搜索的话，能很容易找到使用\u003Ccode>branch-filter\u003C\u002Fcode>来处理的方法，例如\u003C\u002Fp>\n\u003Cpre>\u003Ccode>git filter-branch --tree-filter &quot;find . -name '*.*' -exec sed -i '' -e 's\u002FOLDSTRING\u002FNEWSTRING\u002Fg' {} \\;&quot; -f\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>写法有很多种，但是思路都差不多，就是遍历一遍所有的提交，对这些提交执行指定的命令（例如用\u003Ccode>sed\u003C\u002Fcode>替换指定的内容，或者移除相关文件），然后重新生成新的提交和分支。\u003C\u002Fp>\n\u003Cp>不过这种思路对于我来说却不太受用，原因有几个：\u003C\u002Fp>\n\u003Col>\n\u003Cli>命令行掌握不太好，看到这种命令都不太认识，完全不敢直接放在项目中去跑\u003C\u002Fli>\n\u003Cli>直接进行字符串级别的替换，在某些情况下不够用，例如想通过更复杂的编辑手段（新增文本、修改文本、删除文本同时操作）抹除敏感信息\u003C\u002Fli>\n\u003Cli>直接对整个仓库\u002F整个文件进行字符串级别的替换还是有些不放心，毕竟要修改的部分是明确的，却无法明确地指定这个命令只修改这一部分信息\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>那怎么办呢？其实在这种场景下，也可以尝试使用\u003Ccode>git rebase\u003C\u002Fcode>来解决问题。\u003C\u002Fp>\n\u003Ch2>rebase是干什么的\u003C\u002Fh2>\n\u003Cp>\u003Ccode>rebase\u003C\u002Fcode>顾名思义，就是重新确定一个提交（一个分支）的“基”，这个“基”就是指它的祖先元素。具体的做法是，首先将提交退回到“基”所在的点，然后将之前做过的提交在这个“基”的基础上重复做一遍。相当于修改了当前分支衍生出来的基础，因此中文也被译为“变基”。\u003C\u002Fp>\n\u003Cp>还是举个例子：\u003C\u002Fp>\n\u003Cp>新建一个仓库，然后做两次提交\u003Ccode>A1\u003C\u002Fcode>、\u003Ccode>A2\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode># 初始化\nmkdir test\ncd test\ngit init\n\n# 两次提交\necho &quot;A1&quot;&gt;&gt;1.txt\ngit add .\ngit commit -m A1\n\necho &quot;A2&quot;&gt;&gt;2.txt\ngit add .\ngit commit -m A2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>接下来分成两个分支，分别进行提交\u003Ccode>B1\u003C\u002Fcode>、\u003Ccode>B2\u003C\u002Fcode>和\u003Ccode>C1\u003C\u002Fcode>、\u003Ccode>C2\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode># 创建新分支\ngit checkout -b new\n\n# 新分支提交B1 B2\necho &quot;B1&quot;&gt;&gt;1.txt\ngit add .\ngit commit -m B1\n\necho &quot;B2&quot;&gt;&gt;2.txt\ngit add .\ngit commit -m B2\n\n# 切换主分支\ngit checkout master\n\n# 主分支提交C1 C2\necho &quot;C1&quot;&gt;&gt;1.txt\ngit add .\ngit commit -m C1\n\necho &quot;C2&quot;&gt;&gt;2.txt\ngit add .\ngit commit -m C2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>于是得到一张这样的分支图：\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F01.png\" alt=\"分支图\">\u003C\u002Fp>\n\u003Cp>此时\u003Ccode>new\u003C\u002Fcode>和\u003Ccode>master\u003C\u002Fcode>两个分支分别指向\u003Ccode>B2\u003C\u002Fcode>和\u003Ccode>C2\u003C\u002Fcode>两次提交，而他们的共同祖先（即前文中说的“基”，这个说法不严谨，仅为理解），则是\u003Ccode>A2\u003C\u002Fcode>这次提交。此时我们就可以用\u003Ccode>rebase\u003C\u002Fcode>来改变其中某一个分支的走向。例如，让\u003Ccode>C1\u003C\u002Fcode>在\u003Ccode>B2\u003C\u002Fcode>的基础上修改，即让\u003Ccode>master\u003C\u002Fcode>分支的提交顺序变成\u003Ccode>A1-A2-B1-B2-C1-C2\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode># 对哪个分支rebase就切换到哪个分支\ngit checkout master\n\ngit rebase new\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>而此时就出现了冲突，因为\u003Ccode>C1\u003C\u002Fcode>和\u003Ccode>B1\u003C\u002Fcode>两次提交都对\u003Ccode>1.txt\u003C\u002Fcode>做了修改。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>A1\n&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD\nB1\n=======\nC1\n&gt;&gt;&gt;&gt;&gt;&gt;&gt; C1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>我们选择手工解决冲突，将\u003Ccode>B1\u003C\u002Fcode>放前面，\u003Ccode>C1\u003C\u002Fcode>放后面，解决完之后继续\u003Ccode>rebase\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode># 用add标记解决完冲突\ngit add 1.txt\ngit rebase --continue\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>此时分支图会变成这样，表明C1这次提交已经变基成功。但同时也能看到C2在变基的时候也产生了冲突。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F02.png\" alt=\"分支图\">\u003C\u002Fp>\n\u003Cp>这里和上面一样处理即可。完成后就能看到变基后的分支图。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F03.png\" alt=\"分支图\">\u003C\u002Fp>\n\u003Cp>需要说明的是，尽管提交的描述信息（commit message）没变，但是\u003Ccode>C1\u003C\u002Fcode>、\u003Ccode>C2\u003C\u002Fcode>这两次提交实际上是新产生的，因此它们的commit id和之前的提交是完全不同的。\u003C\u002Fp>\n\u003Cp>通过这个例子，能清楚地看到\u003Ccode>rebase\u003C\u002Fcode>命令的作用，即改变提交（分支）的基础。一般来说，在多人协作过程中，适合将同一分支互相拉取变更的操作使用\u003Ccode>rebase\u003C\u002Fcode>来完成，这样可以保持同一分支的提交历史是线性的，方便回溯。\u003C\u002Fp>\n\u003Ch2>使用rebase改变Git历史\u003C\u002Fh2>\n\u003Cp>在上面\u003Ccode>rebase\u003C\u002Fcode>的例子中，还有一个点值得注意，以\u003Ccode>C1\u003C\u002Fcode>这次提交为例，\u003Ccode>rebase\u003C\u002Fcode>前后两种情况下，虽然都是在\u003Ccode>1.txt\u003C\u002Fcode>结尾添加\u003Ccode>C1\u003C\u002Fcode>这行文字，但是基础和结果都是不同的。在\u003Ccode>rebase\u003C\u002Fcode>之前，\u003Ccode>1.txt\u003C\u002Fcode>的内容是由\u003Ccode>A1\u003C\u002Fcode>变成\u003Ccode>A1\\nC1\u003C\u002Fcode>，而在\u003Ccode>rebase\u003C\u002Fcode>之后则是由\u003Ccode>A1\\nB1\u003C\u002Fcode>变为\u003Ccode>A1\\nB1\\nC1\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Cp>可见在\u003Ccode>rebase\u003C\u002Fcode>的时候，不止是提交的父节点（“基”）会变，文件内容也有所变化。而我们之前在\u003Ccode>rebase\u003C\u002Fcode>时面临的冲突，也正是因为这个变化所带来的。但同时，正因为有这样一个变化，使得我们有机会通过\u003Ccode>rebase\u003C\u002Fcode>的方式来永久改写Git仓库中某一个文件的历史。\u003C\u002Fp>\n\u003Cp>仍然看上面的例子，现在只看\u003Ccode>rebase\u003C\u002Fcode>之后的情况。在\u003Ccode>C1\u003C\u002Fcode>这次提交中，我们为文件\u003Ccode>1.txt\u003C\u002Fcode>在结尾处添加了内容\u003Ccode>C1\u003C\u002Fcode>。假设这个\u003Ccode>C1\u003C\u002Fcode>是一个很敏感的信息（例如密码），我们要如何将它从仓库历史中抹去呢？\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F04.png\" alt=\"分支图\">\u003C\u002Fp>\n\u003Cp>首先我们在C1提交之前找到一个点，例如B2，然后基于它新建一个分支。（例如\u003Ccode>new\u003C\u002Fcode>这个分支。）接下来在这个分支上，对文件\u003Ccode>1.txt\u003C\u002Fcode>进行修改，例如我们增加一行\u003Ccode>C2\u003C\u002Fcode>。即\u003Ccode>1.txt\u003C\u002Fcode>内容变为\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>A1\nB1\nC2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>并进行一次提交。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F05.png\" alt=\"分支图\">\u003C\u002Fp>\n\u003Cp>接下来，我们对C2这次提交（即\u003Ccode>master\u003C\u002Fcode>分支）进行\u003Ccode>rebase\u003C\u002Fcode>操作：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&gt; git checkout master\n&gt; git rebase new\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>此时git会告诉我们，产生了冲突。\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>First, rewinding head to replay your work on top of it...\nApplying: C1\nUsing index info to reconstruct a base tree...\nM\t1.txt\nFalling back to patching base and 3-way merge...\nAuto-merging 1.txt\nCONFLICT (content): Merge conflict in 1.txt\nerror: Failed to merge in the changes.\nPatch failed at 0001 C1\nhint: Use 'git am --show-current-patch' to see the failed patch\n\nResolve all conflicts manually, mark them as resolved with\n&quot;git add\u002Frm &lt;conflicted_files&gt;&quot;, then run &quot;git rebase --continue&quot;.\nYou can instead skip this commit: run &quot;git rebase --skip&quot;.\nTo abort and get back to the state before &quot;git rebase&quot;, run &quot;git rebase --abort&quot;.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>冲突内容正是原来的\u003Ccode>C1\u003C\u002Fcode>和我们刚在新分支上添加的\u003Ccode>C2\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>A1\nB1\n&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD\nC2\n=======\nC1\n&gt;&gt;&gt;&gt;&gt;&gt;&gt; C1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>前文假设，\u003Ccode>C1\u003C\u002Fcode>是我们要删除的敏感信息，因此此时手工解决冲突，将\u003Ccode>C1\u003C\u002Fcode>删除，留下\u003Ccode>C2\u003C\u002Fcode>。然后\u003Ccode>git rebase --continue\u003C\u002Fcode>即可。\u003C\u002Fp>\n\u003Cp>可以看到我们的提交记录变成了这样：\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F06.png\" alt=\"分支图\">\u003C\u002Fp>\n\u003Cp>敏感信息被彻底删除了。\u003C\u002Fp>\n\u003Ch2>小结\u003C\u002Fh2>\n\u003Cp>上面只是展示了一种简单的情况，但已经足够说明使用\u003Ccode>rebase\u003C\u002Fcode>来删除代码库中敏感信息的核心思路和关键步骤了。\u003C\u002Fp>\n\u003Cp>有一些值得注意的细节：\u003C\u002Fp>\n\u003Col>\n\u003Cli>由于C1提交和重写C1的提交都只修改了一行代码，因此在\u003Ccode>rebase\u003C\u002Fcode>过程中，把这一行的冲突解决完，并且\u003Ccode>git rebase --continue\u003C\u002Fcode>时，会提示没有变更（因为唯一的变更在冲突解决过程中被编辑好了），此时需要使用\u003Ccode>git rebase --skip\u003C\u002Fcode>跳过这次提交。\u003C\u002Fli>\n\u003Cli>上面我们是使用\u003Ccode>rebase\u003C\u002Fcode>操作时，编辑冲突的时机来编辑代码文件，从而将\u003Ccode>C1\u003C\u002Fcode>这个敏感信息删除的。如果无法保证一定产生冲突，则可以使用\u003Ccode>git rebase -i\u003C\u002Fcode>（交互式变基）来手工指定需要对哪些提交进行编辑，从而在不一定有冲突时，也有机会编辑代码文件，来将敏感信息删除。关于交互式变基，可参考网络上相关文档。\u003C\u002Fli>\n\u003Cli>如果敏感信息在第一次提交就被带入版本库了，则上面说的“在C1提交之前找到一个点”无法完成。此时可以用\u003Ccode>git checkout --orphan branch-name\u003C\u002Fcode>来创建一个完全空白且没有父节点的分支，并且将当前分支的提交基于这个新的空分支来进行\u003Ccode>rebase\u003C\u002Fcode>，从而获得编辑代码删除敏感信息的机会。\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>最后，一个提醒：不论用什么方法来修改版本库历史，都是在重写历史，虽然看起来提交的commit message是一样的，但是却是完全全新的提交和分支发展路径。当推送到代码库时，需要使用\u003Ccode>git push --force\u003C\u002Fcode>来强制推送，其他人则需要使用\u003Ccode>git pull --rebase\u003C\u002Fcode>来重写本地分支。\u003C\u002Fp>\n","\u003Cp>使用Git的时候，有时候会碰到需要从Git仓库中永久“抹除”某些敏感信息的情况。例如不小心提交了密码之类的信息到仓库，此时只抹掉这些信息重新提交是没有用的，因为其他人仍然可以通过Git历史看到这些敏感信息。因此需要一种方法将这些信息彻底从仓库中抹去。\u003C\u002Fp>\n\u003Cp>如果去网上搜索的话，能很容易找到使用\u003Ccode>branch-filter\u003C\u002Fcode>来处理的方法，例如\u003C\u002Fp>\n\u003Cpre>\u003Ccode>git filter-branch --tree-filter &quot;find . -name '*.*' -exec sed -i '' -e 's\u002FOLDSTRING\u002FNEWSTRING\u002Fg' {} \\;&quot; -f\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>写法有很多种，但是思路都差不多，就是遍历一遍所有的提交，对这些提交执行指定的命令（例如用\u003Ccode>sed\u003C\u002Fcode>替换指定的内容，或者移除相关文件），然后重新生成新的提交和分支。\u003C\u002Fp>\n\u003Cp>不过这种思路对于我来说却不太受用，原因有几个：\u003C\u002Fp>\n\u003Col>\n\u003Cli>命令行掌握不太好，看到这种命令都不太认识，完全不敢直接放在项目中去跑\u003C\u002Fli>\n\u003Cli>直接进行字符串级别的替换，在某些情况下不够用，例如想通过更复杂的编辑手段（新增文本、修改文本、删除文本同时操作）抹除敏感信息\u003C\u002Fli>\n\u003Cli>直接对整个仓库\u002F整个文件进行字符串级别的替换还是有些不放心，毕竟要修改的部分是明确的，却无法明确地指定这个命令只修改这一部分信息\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>那怎么办呢？其实在这种场景下，也可以尝试使用\u003Ccode>git rebase\u003C\u002Fcode>来解决问题。\u003C\u002Fp>\n\u003Ch2>rebase是干什么的\u003C\u002Fh2>\n\u003Cp>\u003Ccode>rebase\u003C\u002Fcode>顾名思义，就是重新确定一个提交（一个分支）的“基”，这个“基”就是指它的祖先元素。具体的做法是，首先将提交退回到“基”所在的点，然后将之前做过的提交在这个“基”的基础上重复做一遍。相当于修改了当前分支衍生出来的基础，因此中文也被译为“变基”。\u003C\u002Fp>\n","https:\u002F\u002Fassets.toobug.net\u002Fassets\u002Fremove-sensitive-data-from-git-with-rebase\u002F01.png",{"total":16,"totalRoots":16,"comments":23,"pv":16},[]]