1GIT-FILTER-BRANCH(1) Git Manual GIT-FILTER-BRANCH(1)
2
3
4
6 git-filter-branch - Rewrite branches
7
9 git filter-branch [--env-filter <command>] [--tree-filter <command>]
10 [--index-filter <command>] [--parent-filter <command>]
11 [--msg-filter <command>] [--commit-filter <command>]
12 [--tag-name-filter <command>] [--subdirectory-filter <directory>]
13 [--prune-empty]
14 [--original <namespace>] [-d <directory>] [-f | --force]
15 [--] [<rev-list options>...]
16
17
19 Lets you rewrite Git revision history by rewriting the branches
20 mentioned in the <rev-list options>, applying custom filters on each
21 revision. Those filters can modify each tree (e.g. removing a file or
22 running a perl rewrite on all files) or information about each commit.
23 Otherwise, all information (including original commit times or merge
24 information) will be preserved.
25
26 The command will only rewrite the positive refs mentioned in the
27 command line (e.g. if you pass a..b, only b will be rewritten). If you
28 specify no filters, the commits will be recommitted without any
29 changes, which would normally have no effect. Nevertheless, this may be
30 useful in the future for compensating for some Git bugs or such,
31 therefore such a usage is permitted.
32
33 NOTE: This command honors .git/info/grafts file and refs in the
34 refs/replace/ namespace. If you have any grafts or replacement refs
35 defined, running this command will make them permanent.
36
37 WARNING! The rewritten history will have different object names for all
38 the objects and will not converge with the original branch. You will
39 not be able to easily push and distribute the rewritten branch on top
40 of the original branch. Please do not use this command if you do not
41 know the full implications, and avoid using it anyway, if a simple
42 single commit would suffice to fix your problem. (See the "RECOVERING
43 FROM UPSTREAM REBASE" section in git-rebase(1) for further information
44 about rewriting published history.)
45
46 Always verify that the rewritten version is correct: The original refs,
47 if different from the rewritten ones, will be stored in the namespace
48 refs/original/.
49
50 Note that since this operation is very I/O expensive, it might be a
51 good idea to redirect the temporary directory off-disk with the -d
52 option, e.g. on tmpfs. Reportedly the speedup is very noticeable.
53
54 Filters
55 The filters are applied in the order as listed below. The <command>
56 argument is always evaluated in the shell context using the eval
57 command (with the notable exception of the commit filter, for technical
58 reasons). Prior to that, the $GIT_COMMIT environment variable will be
59 set to contain the id of the commit being rewritten. Also,
60 GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME,
61 GIT_COMMITTER_EMAIL, and GIT_COMMITTER_DATE are taken from the current
62 commit and exported to the environment, in order to affect the author
63 and committer identities of the replacement commit created by git-
64 commit-tree(1) after the filters have run.
65
66 If any evaluation of <command> returns a non-zero exit status, the
67 whole operation will be aborted.
68
69 A map function is available that takes an "original sha1 id" argument
70 and outputs a "rewritten sha1 id" if the commit has been already
71 rewritten, and "original sha1 id" otherwise; the map function can
72 return several ids on separate lines if your commit filter emitted
73 multiple commits.
74
76 --env-filter <command>
77 This filter may be used if you only need to modify the environment
78 in which the commit will be performed. Specifically, you might want
79 to rewrite the author/committer name/email/time environment
80 variables (see git-commit-tree(1) for details). Do not forget to
81 re-export the variables.
82
83 --tree-filter <command>
84 This is the filter for rewriting the tree and its contents. The
85 argument is evaluated in shell with the working directory set to
86 the root of the checked out tree. The new tree is then used as-is
87 (new files are auto-added, disappeared files are auto-removed -
88 neither .gitignore files nor any other ignore rules HAVE ANY
89 EFFECT!).
90
91 --index-filter <command>
92 This is the filter for rewriting the index. It is similar to the
93 tree filter but does not check out the tree, which makes it much
94 faster. Frequently used with git rm --cached --ignore-unmatch ...,
95 see EXAMPLES below. For hairy cases, see git-update-index(1).
96
97 --parent-filter <command>
98 This is the filter for rewriting the commit’s parent list. It will
99 receive the parent string on stdin and shall output the new parent
100 string on stdout. The parent string is in the format described in
101 git-commit-tree(1): empty for the initial commit, "-p parent" for a
102 normal commit and "-p parent1 -p parent2 -p parent3 ..." for a
103 merge commit.
104
105 --msg-filter <command>
106 This is the filter for rewriting the commit messages. The argument
107 is evaluated in the shell with the original commit message on
108 standard input; its standard output is used as the new commit
109 message.
110
111 --commit-filter <command>
112 This is the filter for performing the commit. If this filter is
113 specified, it will be called instead of the git commit-tree
114 command, with arguments of the form "<TREE_ID> [(-p
115 <PARENT_COMMIT_ID>)...]" and the log message on stdin. The commit
116 id is expected on stdout.
117
118 As a special extension, the commit filter may emit multiple commit
119 ids; in that case, the rewritten children of the original commit
120 will have all of them as parents.
121
122 You can use the map convenience function in this filter, and other
123 convenience functions, too. For example, calling skip_commit "$@"
124 will leave out the current commit (but not its changes! If you want
125 that, use git rebase instead).
126
127 You can also use the git_commit_non_empty_tree "$@" instead of git
128 commit-tree "$@" if you don’t wish to keep commits with a single
129 parent and that makes no change to the tree.
130
131 --tag-name-filter <command>
132 This is the filter for rewriting tag names. When passed, it will be
133 called for every tag ref that points to a rewritten object (or to a
134 tag object which points to a rewritten object). The original tag
135 name is passed via standard input, and the new tag name is expected
136 on standard output.
137
138 The original tags are not deleted, but can be overwritten; use
139 "--tag-name-filter cat" to simply update the tags. In this case, be
140 very careful and make sure you have the old tags backed up in case
141 the conversion has run afoul.
142
143 Nearly proper rewriting of tag objects is supported. If the tag has
144 a message attached, a new tag object will be created with the same
145 message, author, and timestamp. If the tag has a signature
146 attached, the signature will be stripped. It is by definition
147 impossible to preserve signatures. The reason this is "nearly"
148 proper, is because ideally if the tag did not change (points to the
149 same object, has the same name, etc.) it should retain any
150 signature. That is not the case, signatures will always be removed,
151 buyer beware. There is also no support for changing the author or
152 timestamp (or the tag message for that matter). Tags which point to
153 other tags will be rewritten to point to the underlying commit.
154
155 --subdirectory-filter <directory>
156 Only look at the history which touches the given subdirectory. The
157 result will contain that directory (and only that) as its project
158 root. Implies the section called “Remap to ancestor”.
159
160 --prune-empty
161 Some kind of filters will generate empty commits, that left the
162 tree untouched. This switch allow git-filter-branch to ignore such
163 commits. Though, this switch only applies for commits that have one
164 and only one parent, it will hence keep merges points. Also, this
165 option is not compatible with the use of --commit-filter. Though
166 you just need to use the function git_commit_non_empty_tree "$@"
167 instead of the git commit-tree "$@" idiom in your commit filter to
168 make that happen.
169
170 --original <namespace>
171 Use this option to set the namespace where the original commits
172 will be stored. The default value is refs/original.
173
174 -d <directory>
175 Use this option to set the path to the temporary directory used for
176 rewriting. When applying a tree filter, the command needs to
177 temporarily check out the tree to some directory, which may consume
178 considerable space in case of large projects. By default it does
179 this in the .git-rewrite/ directory but you can override that
180 choice by this parameter.
181
182 -f, --force
183 git filter-branch refuses to start with an existing temporary
184 directory or when there are already refs starting with
185 refs/original/, unless forced.
186
187 <rev-list options>...
188 Arguments for git rev-list. All positive refs included by these
189 options are rewritten. You may also specify options such as --all,
190 but you must use -- to separate them from the git filter-branch
191 options. Implies the section called “Remap to ancestor”.
192
193 Remap to ancestor
194 By using rev-list(1) arguments, e.g., path limiters, you can limit the
195 set of revisions which get rewritten. However, positive refs on the
196 command line are distinguished: we don’t let them be excluded by such
197 limiters. For this purpose, they are instead rewritten to point at the
198 nearest ancestor that was not excluded.
199
201 Suppose you want to remove a file (containing confidential information
202 or copyright violation) from all commits:
203
204 git filter-branch --tree-filter 'rm filename' HEAD
205
206
207 However, if the file is absent from the tree of some commit, a simple
208 rm filename will fail for that tree and commit. Thus you may instead
209 want to use rm -f filename as the script.
210
211 Using --index-filter with git rm yields a significantly faster version.
212 Like with using rm filename, git rm --cached filename will fail if the
213 file is absent from the tree of a commit. If you want to "completely
214 forget" a file, it does not matter when it entered history, so we also
215 add --ignore-unmatch:
216
217 git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
218
219
220 Now, you will get the rewritten history saved in HEAD.
221
222 To rewrite the repository to look as if foodir/ had been its project
223 root, and discard all other history:
224
225 git filter-branch --subdirectory-filter foodir -- --all
226
227
228 Thus you can, e.g., turn a library subdirectory into a repository of
229 its own. Note the -- that separates filter-branch options from revision
230 options, and the --all to rewrite all branches and tags.
231
232 To set a commit (which typically is at the tip of another history) to
233 be the parent of the current initial commit, in order to paste the
234 other history behind the current history:
235
236 git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD
237
238
239 (if the parent string is empty - which happens when we are dealing with
240 the initial commit - add graftcommit as a parent). Note that this
241 assumes history with a single root (that is, no merge without common
242 ancestors happened). If this is not the case, use:
243
244 git filter-branch --parent-filter \
245 'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD
246
247
248 or even simpler:
249
250 echo "$commit-id $graft-id" >> .git/info/grafts
251 git filter-branch $graft-id..HEAD
252
253
254 To remove commits authored by "Darl McBribe" from the history:
255
256 git filter-branch --commit-filter '
257 if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
258 then
259 skip_commit "$@";
260 else
261 git commit-tree "$@";
262 fi' HEAD
263
264
265 The function skip_commit is defined as follows:
266
267 skip_commit()
268 {
269 shift;
270 while [ -n "$1" ];
271 do
272 shift;
273 map "$1";
274 shift;
275 done;
276 }
277
278
279 The shift magic first throws away the tree id and then the -p
280 parameters. Note that this handles merges properly! In case Darl
281 committed a merge between P1 and P2, it will be propagated properly and
282 all children of the merge will become merge commits with P1,P2 as their
283 parents instead of the merge commit.
284
285 NOTE the changes introduced by the commits, and which are not reverted
286 by subsequent commits, will still be in the rewritten branch. If you
287 want to throw out changes together with the commits, you should use the
288 interactive mode of git rebase.
289
290 You can rewrite the commit log messages using --msg-filter. For
291 example, git svn-id strings in a repository created by git svn can be
292 removed this way:
293
294 git filter-branch --msg-filter '
295 sed -e "/^git-svn-id:/d"
296 '
297
298
299 If you need to add Acked-by lines to, say, the last 10 commits (none of
300 which is a merge), use this command:
301
302 git filter-branch --msg-filter '
303 cat &&
304 echo "Acked-by: Bugs Bunny <bunny@bugzilla.org>"
305 ' HEAD~10..HEAD
306
307
308 The --env-filter option can be used to modify committer and/or author
309 identity. For example, if you found out that your commits have the
310 wrong identity due to a misconfigured user.email, you can make a
311 correction, before publishing the project, like this:
312
313 git filter-branch --env-filter '
314 if test "$GIT_AUTHOR_EMAIL" = "root@localhost"
315 then
316 GIT_AUTHOR_EMAIL=john@example.com
317 export GIT_AUTHOR_EMAIL
318 fi
319 if test "$GIT_COMMITTER_EMAIL" = "root@localhost"
320 then
321 GIT_COMMITTER_EMAIL=john@example.com
322 export GIT_COMMITTER_EMAIL
323 fi
324 ' -- --all
325
326
327 To restrict rewriting to only part of the history, specify a revision
328 range in addition to the new branch name. The new branch name will
329 point to the top-most revision that a git rev-list of this range will
330 print.
331
332 Consider this history:
333
334 D--E--F--G--H
335 / /
336 A--B-----C
337
338
339 To rewrite only commits D,E,F,G,H, but leave A, B and C alone, use:
340
341 git filter-branch ... C..H
342
343
344 To rewrite commits E,F,G,H, use one of these:
345
346 git filter-branch ... C..H --not D
347 git filter-branch ... D..H --not C
348
349
350 To move the whole tree into a subdirectory, or remove it from there:
351
352 git filter-branch --index-filter \
353 'git ls-files -s | sed "s-\t\"*-&newsubdir/-" |
354 GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
355 git update-index --index-info &&
356 mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
357
358
360 git-filter-branch is often used to get rid of a subset of files,
361 usually with some combination of --index-filter and
362 --subdirectory-filter. People expect the resulting repository to be
363 smaller than the original, but you need a few more steps to actually
364 make it smaller, because Git tries hard not to lose your objects until
365 you tell it to. First make sure that:
366
367 · You really removed all variants of a filename, if a blob was moved
368 over its lifetime. git log --name-only --follow --all -- filename
369 can help you find renames.
370
371 · You really filtered all refs: use --tag-name-filter cat -- --all
372 when calling git-filter-branch.
373
374 Then there are two ways to get a smaller repository. A safer way is to
375 clone, that keeps your original intact.
376
377 · Clone it with git clone file:///path/to/repo. The clone will not
378 have the removed objects. See git-clone(1). (Note that cloning with
379 a plain path just hardlinks everything!)
380
381 If you really don’t want to clone it, for whatever reasons, check the
382 following points instead (in this order). This is a very destructive
383 approach, so make a backup or go back to cloning it. You have been
384 warned.
385
386 · Remove the original refs backed up by git-filter-branch: say git
387 for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git
388 update-ref -d.
389
390 · Expire all reflogs with git reflog expire --expire=now --all.
391
392 · Garbage collect all unreferenced objects with git gc --prune=now
393 (or if your git-gc is not new enough to support arguments to
394 --prune, use git repack -ad; git prune instead).
395
397 Part of the git(1) suite
398
399
400
401Git 1.8.3.1 11/19/2018 GIT-FILTER-BRANCH(1)