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
   original one.

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 ">"
   character).

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
     entry ("-print").

     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 
to git-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to