On Tue, 19 Jan 2016 10:03:59 -0800 (PST)
Berin Loritsch <be...@d-haven.org> wrote:
> The main problem with the index filtering approach is that I don't
> understand what the script is doing completely. I've broken it apart
> and run specific parts alone, but the whole file rename/index
> updating seems to be the problem.
The way `git filter-branch` is works explained in its manual page.
No, really ;-)
The way most HOWTOs on filtering a branch to relocate all the files in
its commits under a directory suggest to call that command use its
"--tree-filter" option which make it work like this:
1) A commit is checked out to a work tree.
2) The script passed to "--tree-filter" is run in that work tree
directory -- having access to all the files checked out in it.
3) The files left in the work tree after the script completes
are then used to update the index (the new files are added to the
index, the deleted files are deleted from the index and the changed
files are updated in the index) and then that new contents of the
index is used to record a new commit which will replace the
I would do it like this:
1) Run "Git Bash".
Change the directory there to where your repo with a branch to
filter is located.
2) Run this:
git filter-branch -f --tree-filter \
'test -e my/new/dir || mkdir -p my/new/dir
find . -mindepth 1 -maxdepth 1 \
-type d -path ./my -prune -o -print \
| xargs - n 30 mv -t ./my/new/dir' master
The "\" characters here are to indicate line wrapping;
you can omit them and write it in two lines: one starts with
the `test` command and another with the `find` command.
You can safely write the script in multiple lines: Git Bash
will allow that (each new line will be prompted by the ">"
What this script does:
1) The first command creates a directory hierarchy "my/new/dir"
unless it exists.
2) The second command, which is a `find` command piping its result
to the `xargs` command works like this:
* The `find` encantation is told to look into its current
directory (".") and won't look any deeper ("-maxdepth 1")
and not consider the current directory itself ("-mindepth 1").
It is then told to look for directories ("-type d") which
pathname is "my" ("-path ./my") and when one matches, forget
about it ("-prune") and move on.
The next rule ("-o" means "or", that is, "if the first rule
did not match, try this ...") just makes `find` to print the
The result is that the command will print the name of each
directory or file located in the work tree except for the
newly created directory, -- each on a new line.
* This stream of names is piped to the `xargs` command
which reads file names from its standard input stream one
by one and calls the specified program on packs of them.
The program specified is `mv -t ./my/new/dir`.
The `xargs` program appends the names of the files it reads
to the program it calls, and the "-n 30" option limit the
number of arguments it will append to 30 (the higher the number
the fewer runs of `mv` will be done but too high a number might
occasionally break overflowing the limit on the length of the
command line which, I beleive is around 4k bytes).
So each call to `mv` that program performs looks like
`mv -t ./my/new/dir ./dir1 ./dir2 ./foo.txt ./blah.txt ...`
and the `mv` program moves the files or directories which names
are supplied to it as its arguments under the directory
supplied using the "-t" command-line option (means "target").
So this script, on each invocation, creates the target directory
then moves everything else under that directory carefully not attempting
to move the target directory under itself.
There exist move hackish though easier-to-spell variations of this
script but I prefer this one.
I've just used it to convert a repository with 800+ commits, so I hope
it will work for you.
You received this message because you are subscribed to the Google Groups "Git
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email
For more options, visit https://groups.google.com/d/optout.