Autogenerated HTML docs for v1.7.6-472-g4bfe7
[git/jnareb-git.git] / git-filter-branch.html
blob4afadbdde4a6d7bb71fb4d92d49f050e65e3b9e4
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6 <meta name="generator" content="AsciiDoc 8.4.5" />
7 <title>git-filter-branch(1)</title>
8 <style type="text/css">
9 /* Debug borders */
10 p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
12 border: 1px solid red;
16 body {
17 margin: 1em 5% 1em 5%;
20 a {
21 color: blue;
22 text-decoration: underline;
24 a:visited {
25 color: fuchsia;
28 em {
29 font-style: italic;
30 color: navy;
33 strong {
34 font-weight: bold;
35 color: #083194;
38 tt {
39 color: navy;
42 h1, h2, h3, h4, h5, h6 {
43 color: #527bbd;
44 font-family: sans-serif;
45 margin-top: 1.2em;
46 margin-bottom: 0.5em;
47 line-height: 1.3;
50 h1, h2, h3 {
51 border-bottom: 2px solid silver;
53 h2 {
54 padding-top: 0.5em;
56 h3 {
57 float: left;
59 h3 + * {
60 clear: left;
63 div.sectionbody {
64 font-family: serif;
65 margin-left: 0;
68 hr {
69 border: 1px solid silver;
72 p {
73 margin-top: 0.5em;
74 margin-bottom: 0.5em;
77 ul, ol, li > p {
78 margin-top: 0;
81 pre {
82 padding: 0;
83 margin: 0;
86 span#author {
87 color: #527bbd;
88 font-family: sans-serif;
89 font-weight: bold;
90 font-size: 1.1em;
92 span#email {
94 span#revnumber, span#revdate, span#revremark {
95 font-family: sans-serif;
98 div#footer {
99 font-family: sans-serif;
100 font-size: small;
101 border-top: 2px solid silver;
102 padding-top: 0.5em;
103 margin-top: 4.0em;
105 div#footer-text {
106 float: left;
107 padding-bottom: 0.5em;
109 div#footer-badges {
110 float: right;
111 padding-bottom: 0.5em;
114 div#preamble {
115 margin-top: 1.5em;
116 margin-bottom: 1.5em;
118 div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
119 div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
120 div.admonitionblock {
121 margin-top: 1.5em;
122 margin-bottom: 1.5em;
124 div.admonitionblock {
125 margin-top: 2.5em;
126 margin-bottom: 2.5em;
129 div.content { /* Block element content. */
130 padding: 0;
133 /* Block element titles. */
134 div.title, caption.title {
135 color: #527bbd;
136 font-family: sans-serif;
137 font-weight: bold;
138 text-align: left;
139 margin-top: 1.0em;
140 margin-bottom: 0.5em;
142 div.title + * {
143 margin-top: 0;
146 td div.title:first-child {
147 margin-top: 0.0em;
149 div.content div.title:first-child {
150 margin-top: 0.0em;
152 div.content + div.title {
153 margin-top: 0.0em;
156 div.sidebarblock > div.content {
157 background: #ffffee;
158 border: 1px solid silver;
159 padding: 0.5em;
162 div.listingblock > div.content {
163 border: 1px solid silver;
164 background: #f4f4f4;
165 padding: 0.5em;
168 div.quoteblock {
169 padding-left: 2.0em;
170 margin-right: 10%;
172 div.quoteblock > div.attribution {
173 padding-top: 0.5em;
174 text-align: right;
177 div.verseblock {
178 padding-left: 2.0em;
179 margin-right: 10%;
181 div.verseblock > div.content {
182 white-space: pre;
184 div.verseblock > div.attribution {
185 padding-top: 0.75em;
186 text-align: left;
188 /* DEPRECATED: Pre version 8.2.7 verse style literal block. */
189 div.verseblock + div.attribution {
190 text-align: left;
193 div.admonitionblock .icon {
194 vertical-align: top;
195 font-size: 1.1em;
196 font-weight: bold;
197 text-decoration: underline;
198 color: #527bbd;
199 padding-right: 0.5em;
201 div.admonitionblock td.content {
202 padding-left: 0.5em;
203 border-left: 2px solid silver;
206 div.exampleblock > div.content {
207 border-left: 2px solid silver;
208 padding: 0.5em;
211 div.imageblock div.content { padding-left: 0; }
212 span.image img { border-style: none; }
213 a.image:visited { color: white; }
215 dl {
216 margin-top: 0.8em;
217 margin-bottom: 0.8em;
219 dt {
220 margin-top: 0.5em;
221 margin-bottom: 0;
222 font-style: normal;
223 color: navy;
225 dd > *:first-child {
226 margin-top: 0.1em;
229 ul, ol {
230 list-style-position: outside;
232 ol.arabic {
233 list-style-type: decimal;
235 ol.loweralpha {
236 list-style-type: lower-alpha;
238 ol.upperalpha {
239 list-style-type: upper-alpha;
241 ol.lowerroman {
242 list-style-type: lower-roman;
244 ol.upperroman {
245 list-style-type: upper-roman;
248 div.compact ul, div.compact ol,
249 div.compact p, div.compact p,
250 div.compact div, div.compact div {
251 margin-top: 0.1em;
252 margin-bottom: 0.1em;
255 div.tableblock > table {
256 border: 3px solid #527bbd;
258 thead {
259 font-family: sans-serif;
260 font-weight: bold;
262 tfoot {
263 font-weight: bold;
265 td > div.verse {
266 white-space: pre;
268 p.table {
269 margin-top: 0;
271 /* Because the table frame attribute is overriden by CSS in most browsers. */
272 div.tableblock > table[frame="void"] {
273 border-style: none;
275 div.tableblock > table[frame="hsides"] {
276 border-left-style: none;
277 border-right-style: none;
279 div.tableblock > table[frame="vsides"] {
280 border-top-style: none;
281 border-bottom-style: none;
285 div.hdlist {
286 margin-top: 0.8em;
287 margin-bottom: 0.8em;
289 div.hdlist tr {
290 padding-bottom: 15px;
292 dt.hdlist1.strong, td.hdlist1.strong {
293 font-weight: bold;
295 td.hdlist1 {
296 vertical-align: top;
297 font-style: normal;
298 padding-right: 0.8em;
299 color: navy;
301 td.hdlist2 {
302 vertical-align: top;
304 div.hdlist.compact tr {
305 margin: 0;
306 padding-bottom: 0;
309 .comment {
310 background: yellow;
313 @media print {
314 div#footer-badges { display: none; }
317 div#toctitle {
318 color: #527bbd;
319 font-family: sans-serif;
320 font-size: 1.1em;
321 font-weight: bold;
322 margin-top: 1.0em;
323 margin-bottom: 0.1em;
326 div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
327 margin-top: 0;
328 margin-bottom: 0;
330 div.toclevel2 {
331 margin-left: 2em;
332 font-size: 0.9em;
334 div.toclevel3 {
335 margin-left: 4em;
336 font-size: 0.9em;
338 div.toclevel4 {
339 margin-left: 6em;
340 font-size: 0.9em;
342 /* Overrides for manpage documents */
343 h1 {
344 padding-top: 0.5em;
345 padding-bottom: 0.5em;
346 border-top: 2px solid silver;
347 border-bottom: 2px solid silver;
349 h2 {
350 border-style: none;
352 div.sectionbody {
353 margin-left: 5%;
356 @media print {
357 div#toc { display: none; }
360 /* Workarounds for IE6's broken and incomplete CSS2. */
362 div.sidebar-content {
363 background: #ffffee;
364 border: 1px solid silver;
365 padding: 0.5em;
367 div.sidebar-title, div.image-title {
368 color: #527bbd;
369 font-family: sans-serif;
370 font-weight: bold;
371 margin-top: 0.0em;
372 margin-bottom: 0.5em;
375 div.listingblock div.content {
376 border: 1px solid silver;
377 background: #f4f4f4;
378 padding: 0.5em;
381 div.quoteblock-attribution {
382 padding-top: 0.5em;
383 text-align: right;
386 div.verseblock-content {
387 white-space: pre;
389 div.verseblock-attribution {
390 padding-top: 0.75em;
391 text-align: left;
394 div.exampleblock-content {
395 border-left: 2px solid silver;
396 padding-left: 0.5em;
399 /* IE6 sets dynamically generated links as visited. */
400 div#toc a:visited { color: blue; }
401 </style>
402 </head>
403 <body>
404 <div id="header">
405 <h1>
406 git-filter-branch(1) Manual Page
407 </h1>
408 <h2>NAME</h2>
409 <div class="sectionbody">
410 <p>git-filter-branch -
411 Rewrite branches
412 </p>
413 </div>
414 </div>
415 <h2 id="_synopsis">SYNOPSIS</h2>
416 <div class="sectionbody">
417 <div class="verseblock">
418 <div class="verseblock-content"><em>git filter-branch</em> [--env-filter &lt;command&gt;] [--tree-filter &lt;command&gt;]
419 [--index-filter &lt;command&gt;] [--parent-filter &lt;command&gt;]
420 [--msg-filter &lt;command&gt;] [--commit-filter &lt;command&gt;]
421 [--tag-name-filter &lt;command&gt;] [--subdirectory-filter &lt;directory&gt;]
422 [--prune-empty]
423 [--original &lt;namespace&gt;] [-d &lt;directory&gt;] [-f | --force]
424 [--] [&lt;rev-list options&gt;&#8230;]</div>
425 <div class="verseblock-attribution">
426 </div></div>
427 </div>
428 <h2 id="_description">DESCRIPTION</h2>
429 <div class="sectionbody">
430 <div class="paragraph"><p>Lets you rewrite git revision history by rewriting the branches mentioned
431 in the &lt;rev-list options&gt;, applying custom filters on each revision.
432 Those filters can modify each tree (e.g. removing a file or running
433 a perl rewrite on all files) or information about each commit.
434 Otherwise, all information (including original commit times or merge
435 information) will be preserved.</p></div>
436 <div class="paragraph"><p>The command will only rewrite the <em>positive</em> refs mentioned in the
437 command line (e.g. if you pass <em>a..b</em>, only <em>b</em> will be rewritten).
438 If you specify no filters, the commits will be recommitted without any
439 changes, which would normally have no effect. Nevertheless, this may be
440 useful in the future for compensating for some git bugs or such,
441 therefore such a usage is permitted.</p></div>
442 <div class="paragraph"><p><strong>NOTE</strong>: This command honors <tt>.git/info/grafts</tt> and <tt>.git/refs/replace/</tt>.
443 If you have any grafts or replacement refs defined, running this command
444 will make them permanent.</p></div>
445 <div class="paragraph"><p><strong>WARNING</strong>! The rewritten history will have different object names for all
446 the objects and will not converge with the original branch. You will not
447 be able to easily push and distribute the rewritten branch on top of the
448 original branch. Please do not use this command if you do not know the
449 full implications, and avoid using it anyway, if a simple single commit
450 would suffice to fix your problem. (See the "RECOVERING FROM UPSTREAM
451 REBASE" section in <a href="git-rebase.html">git-rebase(1)</a> for further information about
452 rewriting published history.)</p></div>
453 <div class="paragraph"><p>Always verify that the rewritten version is correct: The original refs,
454 if different from the rewritten ones, will be stored in the namespace
455 <em>refs/original/</em>.</p></div>
456 <div class="paragraph"><p>Note that since this operation is very I/O expensive, it might
457 be a good idea to redirect the temporary directory off-disk with the
458 <em>-d</em> option, e.g. on tmpfs. Reportedly the speedup is very noticeable.</p></div>
459 <h3 id="_filters">Filters</h3><div style="clear:left"></div>
460 <div class="paragraph"><p>The filters are applied in the order as listed below. The &lt;command&gt;
461 argument is always evaluated in the shell context using the <em>eval</em> command
462 (with the notable exception of the commit filter, for technical reasons).
463 Prior to that, the $GIT_COMMIT environment variable will be set to contain
464 the id of the commit being rewritten. Also, GIT_AUTHOR_NAME,
465 GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL,
466 and GIT_COMMITTER_DATE are set according to the current commit. The values
467 of these variables after the filters have run, are used for the new commit.
468 If any evaluation of &lt;command&gt; returns a non-zero exit status, the whole
469 operation will be aborted.</p></div>
470 <div class="paragraph"><p>A <em>map</em> function is available that takes an "original sha1 id" argument
471 and outputs a "rewritten sha1 id" if the commit has been already
472 rewritten, and "original sha1 id" otherwise; the <em>map</em> function can
473 return several ids on separate lines if your commit filter emitted
474 multiple commits.</p></div>
475 </div>
476 <h2 id="_options">OPTIONS</h2>
477 <div class="sectionbody">
478 <div class="dlist"><dl>
479 <dt class="hdlist1">
480 --env-filter &lt;command&gt;
481 </dt>
482 <dd>
484 This filter may be used if you only need to modify the environment
485 in which the commit will be performed. Specifically, you might
486 want to rewrite the author/committer name/email/time environment
487 variables (see <a href="git-commit-tree.html">git-commit-tree(1)</a> for details). Do not forget
488 to re-export the variables.
489 </p>
490 </dd>
491 <dt class="hdlist1">
492 --tree-filter &lt;command&gt;
493 </dt>
494 <dd>
496 This is the filter for rewriting the tree and its contents.
497 The argument is evaluated in shell with the working
498 directory set to the root of the checked out tree. The new tree
499 is then used as-is (new files are auto-added, disappeared files
500 are auto-removed - neither .gitignore files nor any other ignore
501 rules <strong>HAVE ANY EFFECT</strong>!).
502 </p>
503 </dd>
504 <dt class="hdlist1">
505 --index-filter &lt;command&gt;
506 </dt>
507 <dd>
509 This is the filter for rewriting the index. It is similar to the
510 tree filter but does not check out the tree, which makes it much
511 faster. Frequently used with <tt>git rm --cached
512 --ignore-unmatch &#8230;</tt>, see EXAMPLES below. For hairy
513 cases, see <a href="git-update-index.html">git-update-index(1)</a>.
514 </p>
515 </dd>
516 <dt class="hdlist1">
517 --parent-filter &lt;command&gt;
518 </dt>
519 <dd>
521 This is the filter for rewriting the commit&#8217;s parent list.
522 It will receive the parent string on stdin and shall output
523 the new parent string on stdout. The parent string is in
524 the format described in <a href="git-commit-tree.html">git-commit-tree(1)</a>: empty for
525 the initial commit, "-p parent" for a normal commit and
526 "-p parent1 -p parent2 -p parent3 &#8230;" for a merge commit.
527 </p>
528 </dd>
529 <dt class="hdlist1">
530 --msg-filter &lt;command&gt;
531 </dt>
532 <dd>
534 This is the filter for rewriting the commit messages.
535 The argument is evaluated in the shell with the original
536 commit message on standard input; its standard output is
537 used as the new commit message.
538 </p>
539 </dd>
540 <dt class="hdlist1">
541 --commit-filter &lt;command&gt;
542 </dt>
543 <dd>
545 This is the filter for performing the commit.
546 If this filter is specified, it will be called instead of the
547 <em>git commit-tree</em> command, with arguments of the form
548 "&lt;TREE_ID&gt; [(-p &lt;PARENT_COMMIT_ID&gt;)&#8230;]" and the log message on
549 stdin. The commit id is expected on stdout.
550 </p>
551 <div class="paragraph"><p>As a special extension, the commit filter may emit multiple
552 commit ids; in that case, the rewritten children of the original commit will
553 have all of them as parents.</p></div>
554 <div class="paragraph"><p>You can use the <em>map</em> convenience function in this filter, and other
555 convenience functions, too. For example, calling <em>skip_commit "$@"</em>
556 will leave out the current commit (but not its changes! If you want
557 that, use <em>git rebase</em> instead).</p></div>
558 <div class="paragraph"><p>You can also use the <tt>git_commit_non_empty_tree "$@"</tt> instead of
559 <tt>git commit-tree "$@"</tt> if you don&#8217;t wish to keep commits with a single parent
560 and that makes no change to the tree.</p></div>
561 </dd>
562 <dt class="hdlist1">
563 --tag-name-filter &lt;command&gt;
564 </dt>
565 <dd>
567 This is the filter for rewriting tag names. When passed,
568 it will be called for every tag ref that points to a rewritten
569 object (or to a tag object which points to a rewritten object).
570 The original tag name is passed via standard input, and the new
571 tag name is expected on standard output.
572 </p>
573 <div class="paragraph"><p>The original tags are not deleted, but can be overwritten;
574 use "--tag-name-filter cat" to simply update the tags. In this
575 case, be very careful and make sure you have the old tags
576 backed up in case the conversion has run afoul.</p></div>
577 <div class="paragraph"><p>Nearly proper rewriting of tag objects is supported. If the tag has
578 a message attached, a new tag object will be created with the same message,
579 author, and timestamp. If the tag has a signature attached, the
580 signature will be stripped. It is by definition impossible to preserve
581 signatures. The reason this is "nearly" proper, is because ideally if
582 the tag did not change (points to the same object, has the same name, etc.)
583 it should retain any signature. That is not the case, signatures will always
584 be removed, buyer beware. There is also no support for changing the
585 author or timestamp (or the tag message for that matter). Tags which point
586 to other tags will be rewritten to point to the underlying commit.</p></div>
587 </dd>
588 <dt class="hdlist1">
589 --subdirectory-filter &lt;directory&gt;
590 </dt>
591 <dd>
593 Only look at the history which touches the given subdirectory.
594 The result will contain that directory (and only that) as its
595 project root. Implies <a href="#Remap_to_ancestor">[Remap_to_ancestor]</a>.
596 </p>
597 </dd>
598 <dt class="hdlist1">
599 --prune-empty
600 </dt>
601 <dd>
603 Some kind of filters will generate empty commits, that left the tree
604 untouched. This switch allow git-filter-branch to ignore such
605 commits. Though, this switch only applies for commits that have one
606 and only one parent, it will hence keep merges points. Also, this
607 option is not compatible with the use of <em>--commit-filter</em>. Though you
608 just need to use the function <em>git_commit_non_empty_tree "$@"</em> instead
609 of the <tt>git commit-tree "$@"</tt> idiom in your commit filter to make that
610 happen.
611 </p>
612 </dd>
613 <dt class="hdlist1">
614 --original &lt;namespace&gt;
615 </dt>
616 <dd>
618 Use this option to set the namespace where the original commits
619 will be stored. The default value is <em>refs/original</em>.
620 </p>
621 </dd>
622 <dt class="hdlist1">
623 -d &lt;directory&gt;
624 </dt>
625 <dd>
627 Use this option to set the path to the temporary directory used for
628 rewriting. When applying a tree filter, the command needs to
629 temporarily check out the tree to some directory, which may consume
630 considerable space in case of large projects. By default it
631 does this in the <em>.git-rewrite/</em> directory but you can override
632 that choice by this parameter.
633 </p>
634 </dd>
635 <dt class="hdlist1">
637 </dt>
638 <dt class="hdlist1">
639 --force
640 </dt>
641 <dd>
643 <em>git filter-branch</em> refuses to start with an existing temporary
644 directory or when there are already refs starting with
645 <em>refs/original/</em>, unless forced.
646 </p>
647 </dd>
648 <dt class="hdlist1">
649 &lt;rev-list options&gt;&#8230;
650 </dt>
651 <dd>
653 Arguments for <em>git rev-list</em>. All positive refs included by
654 these options are rewritten. You may also specify options
655 such as <em>--all</em>, but you must use <em>--</em> to separate them from
656 the <em>git filter-branch</em> options. Implies <a href="#Remap_to_ancestor">[Remap_to_ancestor]</a>.
657 </p>
658 </dd>
659 </dl></div>
660 <h3 id="Remap_to_ancestor">Remap to ancestor</h3><div style="clear:left"></div>
661 <div class="paragraph"><p>By using <a href="rev-list.html">rev-list(1)</a> arguments, e.g., path limiters, you can limit the
662 set of revisions which get rewritten. However, positive refs on the command
663 line are distinguished: we don&#8217;t let them be excluded by such limiters. For
664 this purpose, they are instead rewritten to point at the nearest ancestor that
665 was not excluded.</p></div>
666 </div>
667 <h2 id="_examples">Examples</h2>
668 <div class="sectionbody">
669 <div class="paragraph"><p>Suppose you want to remove a file (containing confidential information
670 or copyright violation) from all commits:</p></div>
671 <div class="listingblock">
672 <div class="content">
673 <pre><tt>git filter-branch --tree-filter 'rm filename' HEAD</tt></pre>
674 </div></div>
675 <div class="paragraph"><p>However, if the file is absent from the tree of some commit,
676 a simple <tt>rm filename</tt> will fail for that tree and commit.
677 Thus you may instead want to use <tt>rm -f filename</tt> as the script.</p></div>
678 <div class="paragraph"><p>Using <tt>--index-filter</tt> with <em>git rm</em> yields a significantly faster
679 version. Like with using <tt>rm filename</tt>, <tt>git rm --cached filename</tt>
680 will fail if the file is absent from the tree of a commit. If you
681 want to "completely forget" a file, it does not matter when it entered
682 history, so we also add <tt>--ignore-unmatch</tt>:</p></div>
683 <div class="listingblock">
684 <div class="content">
685 <pre><tt>git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD</tt></pre>
686 </div></div>
687 <div class="paragraph"><p>Now, you will get the rewritten history saved in HEAD.</p></div>
688 <div class="paragraph"><p>To rewrite the repository to look as if <tt>foodir/</tt> had been its project
689 root, and discard all other history:</p></div>
690 <div class="listingblock">
691 <div class="content">
692 <pre><tt>git filter-branch --subdirectory-filter foodir -- --all</tt></pre>
693 </div></div>
694 <div class="paragraph"><p>Thus you can, e.g., turn a library subdirectory into a repository of
695 its own. Note the <tt>--</tt> that separates <em>filter-branch</em> options from
696 revision options, and the <tt>--all</tt> to rewrite all branches and tags.</p></div>
697 <div class="paragraph"><p>To set a commit (which typically is at the tip of another
698 history) to be the parent of the current initial commit, in
699 order to paste the other history behind the current history:</p></div>
700 <div class="listingblock">
701 <div class="content">
702 <pre><tt>git filter-branch --parent-filter 'sed "s/^\$/-p &lt;graft-id&gt;/"' HEAD</tt></pre>
703 </div></div>
704 <div class="paragraph"><p>(if the parent string is empty - which happens when we are dealing with
705 the initial commit - add graftcommit as a parent). Note that this assumes
706 history with a single root (that is, no merge without common ancestors
707 happened). If this is not the case, use:</p></div>
708 <div class="listingblock">
709 <div class="content">
710 <pre><tt>git filter-branch --parent-filter \
711 'test $GIT_COMMIT = &lt;commit-id&gt; &amp;&amp; echo "-p &lt;graft-id&gt;" || cat' HEAD</tt></pre>
712 </div></div>
713 <div class="paragraph"><p>or even simpler:</p></div>
714 <div class="listingblock">
715 <div class="content">
716 <pre><tt>echo "$commit-id $graft-id" &gt;&gt; .git/info/grafts
717 git filter-branch $graft-id..HEAD</tt></pre>
718 </div></div>
719 <div class="paragraph"><p>To remove commits authored by "Darl McBribe" from the history:</p></div>
720 <div class="listingblock">
721 <div class="content">
722 <pre><tt>git filter-branch --commit-filter '
723 if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
724 then
725 skip_commit "$@";
726 else
727 git commit-tree "$@";
728 fi' HEAD</tt></pre>
729 </div></div>
730 <div class="paragraph"><p>The function <em>skip_commit</em> is defined as follows:</p></div>
731 <div class="listingblock">
732 <div class="content">
733 <pre><tt>skip_commit()
735 shift;
736 while [ -n "$1" ];
738 shift;
739 map "$1";
740 shift;
741 done;
742 }</tt></pre>
743 </div></div>
744 <div class="paragraph"><p>The shift magic first throws away the tree id and then the -p
745 parameters. Note that this handles merges properly! In case Darl
746 committed a merge between P1 and P2, it will be propagated properly
747 and all children of the merge will become merge commits with P1,P2
748 as their parents instead of the merge commit.</p></div>
749 <div class="paragraph"><p>You can rewrite the commit log messages using <tt>--msg-filter</tt>. For
750 example, <em>git svn-id</em> strings in a repository created by <em>git svn</em> can
751 be removed this way:</p></div>
752 <div class="listingblock">
753 <div class="content">
754 <pre><tt>git filter-branch --msg-filter '
755 sed -e "/^git-svn-id:/d"
756 '</tt></pre>
757 </div></div>
758 <div class="paragraph"><p>To restrict rewriting to only part of the history, specify a revision
759 range in addition to the new branch name. The new branch name will
760 point to the top-most revision that a <em>git rev-list</em> of this range
761 will print.</p></div>
762 <div class="paragraph"><p>If you need to add <em>Acked-by</em> lines to, say, the last 10 commits (none
763 of which is a merge), use this command:</p></div>
764 <div class="listingblock">
765 <div class="content">
766 <pre><tt>git filter-branch --msg-filter '
767 cat &amp;&amp;
768 echo "Acked-by: Bugs Bunny &lt;bunny@bugzilla.org&gt;"
769 ' HEAD~10..HEAD</tt></pre>
770 </div></div>
771 <div class="paragraph"><p><strong>NOTE</strong> the changes introduced by the commits, and which are not reverted
772 by subsequent commits, will still be in the rewritten branch. If you want
773 to throw out <em>changes</em> together with the commits, you should use the
774 interactive mode of <em>git rebase</em>.</p></div>
775 <div class="paragraph"><p>Consider this history:</p></div>
776 <div class="listingblock">
777 <div class="content">
778 <pre><tt> D--E--F--G--H
780 A--B-----C</tt></pre>
781 </div></div>
782 <div class="paragraph"><p>To rewrite only commits D,E,F,G,H, but leave A, B and C alone, use:</p></div>
783 <div class="listingblock">
784 <div class="content">
785 <pre><tt>git filter-branch ... C..H</tt></pre>
786 </div></div>
787 <div class="paragraph"><p>To rewrite commits E,F,G,H, use one of these:</p></div>
788 <div class="listingblock">
789 <div class="content">
790 <pre><tt>git filter-branch ... C..H --not D
791 git filter-branch ... D..H --not C</tt></pre>
792 </div></div>
793 <div class="paragraph"><p>To move the whole tree into a subdirectory, or remove it from there:</p></div>
794 <div class="listingblock">
795 <div class="content">
796 <pre><tt>git filter-branch --index-filter \
797 'git ls-files -s | sed "s-\t\"*-&amp;newsubdir/-" |
798 GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
799 git update-index --index-info &amp;&amp;
800 mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD</tt></pre>
801 </div></div>
802 </div>
803 <h2 id="_checklist_for_shrinking_a_repository">Checklist for Shrinking a Repository</h2>
804 <div class="sectionbody">
805 <div class="paragraph"><p>git-filter-branch is often used to get rid of a subset of files,
806 usually with some combination of <tt>--index-filter</tt> and
807 <tt>--subdirectory-filter</tt>. People expect the resulting repository to
808 be smaller than the original, but you need a few more steps to
809 actually make it smaller, because git tries hard not to lose your
810 objects until you tell it to. First make sure that:</p></div>
811 <div class="ulist"><ul>
812 <li>
814 You really removed all variants of a filename, if a blob was moved
815 over its lifetime. <tt>git log --name-only --follow --all --
816 filename</tt> can help you find renames.
817 </p>
818 </li>
819 <li>
821 You really filtered all refs: use <tt>--tag-name-filter cat --
822 --all</tt> when calling git-filter-branch.
823 </p>
824 </li>
825 </ul></div>
826 <div class="paragraph"><p>Then there are two ways to get a smaller repository. A safer way is
827 to clone, that keeps your original intact.</p></div>
828 <div class="ulist"><ul>
829 <li>
831 Clone it with <tt>git clone file:///path/to/repo</tt>. The clone
832 will not have the removed objects. See <a href="git-clone.html">git-clone(1)</a>. (Note
833 that cloning with a plain path just hardlinks everything!)
834 </p>
835 </li>
836 </ul></div>
837 <div class="paragraph"><p>If you really don&#8217;t want to clone it, for whatever reasons, check the
838 following points instead (in this order). This is a very destructive
839 approach, so <strong>make a backup</strong> or go back to cloning it. You have been
840 warned.</p></div>
841 <div class="ulist"><ul>
842 <li>
844 Remove the original refs backed up by git-filter-branch: say <tt>git
845 for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git
846 update-ref -d</tt>.
847 </p>
848 </li>
849 <li>
851 Expire all reflogs with <tt>git reflog expire --expire=now --all</tt>.
852 </p>
853 </li>
854 <li>
856 Garbage collect all unreferenced objects with <tt>git gc --prune=now</tt>
857 (or if your git-gc is not new enough to support arguments to
858 <tt>--prune</tt>, use <tt>git repack -ad; git prune</tt> instead).
859 </p>
860 </li>
861 </ul></div>
862 </div>
863 <h2 id="_git">GIT</h2>
864 <div class="sectionbody">
865 <div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
866 </div>
867 <div id="footer">
868 <div id="footer-text">
869 Last updated 2011-07-23 00:49:30 UTC
870 </div>
871 </div>
872 </body>
873 </html>