<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>dipplum.com &#187; scm</title>
	<atom:link href="http://dipplum.com/tag/scm/feed/" rel="self" type="application/rss+xml" />
	<link>http://dipplum.com</link>
	<description>Be  the change you wanna see in the world</description>
	<lastBuildDate>Sat, 12 Nov 2011 07:38:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>git remove file from revision history</title>
		<link>http://dipplum.com/2009/03/18/git-remove-from-history/</link>
		<comments>http://dipplum.com/2009/03/18/git-remove-from-history/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 20:30:40 +0000</pubDate>
		<dc:creator>li</dc:creator>
				<category><![CDATA[乱七八糟]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[scm]]></category>

		<guid isPermaLink="false">http://dipplum.com/2009/03/18/git-remove-from-history/</guid>
		<description><![CDATA[最近学习 git，真是非常强大，非常不好用的软件。 一个常见的需求：有一个文件，包含敏感信息，不小心加进git库里面去了。希望从源码库的所有历史记录中删除该文件的所有版本。 其他的源码管理系统也会有类似的功能。如果是 CVS，就到源码库目录下直接删除 RCS 文件。如果是 Subversion，则是用 svnadmin dump 之后，用 import filter 再倒入。 git-filter-branch 命令包含各种回溯修改 revision history 的功能，经过尝试，获得心得若干： 首先，git 的命令可扩展性很强，但对初学者来说，要记忆的命令太长，像看天书； 其次，git 往往一个命令完成不了任务，需要多个命令配合，但文档对此语焉不详，初学者无所适从； 最后，也是最难的，git 中概念太多，名字非常不直观，从传统源码管理的层次理解起来台阶太高。 为此，写了几个 bash function，封装 git 的上述功能。用法如下 git-rewrite-commits exclude_files_list：将文件从 reivision history 中删除，可指定要删除的目录； git-prune-commits：上面的命令执行之后，可能出现空的 commit 对象，用这个命令可以清空这类对象； git-rewrite-msg regex：regex 是可被 sed 接受的正则表达式，用该命令修改所有的 commit 注释； 如果直接使用 filter-branch 从 git 历史中删除文件，会将工作拷贝中的文件也删除。而如果只是想把清除 git 库中的敏感文件，用户可能希望保留工作拷贝中的这些文件。使用 git-rewrite-commits 可以起到保留要删除的文件的效果。 另外，由于 [...]]]></description>
			<content:encoded><![CDATA[<p>最近学习 git，真是非常强大，非常不好用的软件。</p>
<p>一个常见的需求：有一个文件，包含敏感信息，不小心加进git库里面去了。希望从源码库的所有历史记录中删除该文件的所有版本。</p>
<p>其他的源码管理系统也会有类似的功能。如果是 CVS，就到源码库目录下直接删除 RCS 文件。如果是 Subversion，则是用 svnadmin dump 之后，用 import filter 再倒入。</p>
<p>git-filter-branch 命令包含各种回溯修改 revision history 的功能，经过尝试，获得心得若干：</p>
<ul>
<li>首先，git 的命令可扩展性很强，但对初学者来说，要记忆的命令太长，像看天书； </li>
<li>其次，git 往往一个命令完成不了任务，需要多个命令配合，但文档对此语焉不详，初学者无所适从； </li>
<li>最后，也是最难的，git 中概念太多，名字非常不直观，从传统源码管理的层次理解起来台阶太高。 </li>
</ul>
<p>为此，写了几个 bash function，封装 git 的上述功能。用法如下</p>
<ul>
<li>git-rewrite-commits exclude_files_list：将文件从 reivision history 中删除，可指定要删除的目录；</li>
<li>git-prune-commits：上面的命令执行之后，可能出现空的 commit 对象，用这个命令可以清空这类对象；</li>
<li>git-rewrite-msg regex：regex 是可被 sed 接受的正则表达式，用该命令修改所有的 commit 注释；</li>
</ul>
<p>如果直接使用 filter-branch 从 git 历史中删除文件，会将工作拷贝中的文件也删除。而如果只是想把清除 git 库中的敏感文件，用户可能希望保留工作拷贝中的这些文件。使用 git-rewrite-commits 可以起到保留要删除的文件的效果。</p>
<p>另外，由于 git 是分布式源码管理，用这种做法因此光删除一个库中的文件历史并不够。为了避免下游的库将删除后的敏感文件又 push 回来，应该对 git 库的所有副本执行相同的清除操作，这样才保险。</p>
<p>附：相关 bash 脚本，加入 .bashrc 中生效</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> git-remove-refs<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> $<span style="color: #000000; font-weight: bold;">@</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: git-remove-refs refs_name&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">return</span>
  <span style="color: #000000; font-weight: bold;">fi</span>
  <span style="color: #c20cb9; font-weight: bold;">git</span> for-each-ref <span style="color: #660033;">--format</span>=<span style="color: #ff0000;">&quot;%(refname)&quot;</span> refs<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> <span style="color: #660033;">-I</span> Ref <span style="color: #c20cb9; font-weight: bold;">bash</span> <span style="color: #660033;">-c</span> <span style="color: #ff0000;">&quot;echo removing git ref: Ref; git update-ref -d Ref&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> git-backup-files<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #007800;">FILES</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">git</span> ls-files $<span style="color: #000000; font-weight: bold;">@`</span>
  <span style="color: #000000; font-weight: bold;">for</span> File <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #007800;">$FILES</span>
  <span style="color: #000000; font-weight: bold;">do</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> save backup <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #007800;">$File</span>
  <span style="color: #000000; font-weight: bold;">done</span>
  <span style="color: #007800;">GIT_BACKUP_TMP</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">tempfile</span><span style="color: #000000; font-weight: bold;">`</span>.tar.gz
  <span style="color: #c20cb9; font-weight: bold;">tar</span> czf <span style="color: #007800;">$GIT_BACKUP_TMP</span> <span style="color: #007800;">$FILES</span>
  <span style="color: #7a0874; font-weight: bold;">echo</span> backup <span style="color: #c20cb9; font-weight: bold;">file</span> saved at <span style="color: #007800;">$GIT_BACKUP_TMP</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> git-restore-files<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$GIT_BACKUP_TMP</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> backup <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #007800;">$GIT_BACKUP_TMP</span> restored
    <span style="color: #c20cb9; font-weight: bold;">tar</span> xzf <span style="color: #007800;">$GIT_BACKUP_TMP</span>
    <span style="color: #7a0874; font-weight: bold;">unset</span> GIT_BACKUP_TMP
  <span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> git-rewrite-commits<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> $<span style="color: #000000; font-weight: bold;">@</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: git-rewrite-commits files_to_remove&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">return</span>
  <span style="color: #000000; font-weight: bold;">fi</span>
  git-backup-files $<span style="color: #000000; font-weight: bold;">@</span>
  <span style="color: #c20cb9; font-weight: bold;">git</span> filter-branch <span style="color: #660033;">--index-filter</span> <span style="color: #ff0000;">&quot;git ls-files -z $@ | git update-index --remove -z --stdin&quot;</span>
  git-remove-refs original
  git-restore-files
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> git-prune-commits<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #000000; font-weight: bold;">!</span> <span style="color: #660033;">-z</span> $<span style="color: #000000; font-weight: bold;">@</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: git-prune-commits&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">return</span>
  <span style="color: #000000; font-weight: bold;">fi</span>
  <span style="color: #c20cb9; font-weight: bold;">git</span> filter-branch <span style="color: #660033;">--prune-empty</span>
  git-remove-refs original
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> git-rewrite-msg<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> $<span style="color: #000000; font-weight: bold;">@</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: git-rewrite-msg regex_pattern&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">return</span>
  <span style="color: #000000; font-weight: bold;">fi</span>
  <span style="color: #c20cb9; font-weight: bold;">git</span> filter-branch <span style="color: #660033;">--msg-filter</span> <span style="color: #ff0000;">&quot;sed -e <span style="color: #000099; font-weight: bold;">\&quot;</span>$1<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>
  git-remove-refs original
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://dipplum.com/2009/03/18/git-remove-from-history/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

