8

is it possible with Git's tools to move files into a new folder while modifying its full history, as if the files had been there from their first add?

I came up on this after merging some repos together: I moved the files from several repos to distinct folders inside one "super" repo, however the merged history behaves very bad with git rebase and git svn tools as totally different files may collide at their old locations of course.

3 Answers 3

7

So now this got the job done:

git filter-branch --tree-filter '(ls -A; mkdir TheSubdir; echo TheSubdir) | xargs mv'

Strange but nice: the .git dir stays where it should; maybe git is preventing its movement somehow?

Sign up to request clarification or add additional context in comments.

2 Comments

The 'filter' shell commands are run in an subdir .git-rewrite by git, with nothing but the current revision files inside. Cool.
We got error (probably because repo was empty on some commit). Solution was add true to pipeline's end to skip error like git filter-branch --tree-filter '(ls -A; mkdir xid; echo xid) | xargs mv | true '
5

In order to modify your full history, you will need to rewrite every commit. git filter-branch is the best way to do this. In particular, for your case, git filter-branch --tree-filter some-command will check out every version of your history, run your command in which you can modify the working tree as you see fit (such as moving the directories in question), and then rewrite that commit to contain the new contents of the tree.

5 Comments

Ok cool. So basically, git filter-branch checks out every revision and checks it in again, replacing the old one? Sounds wild, I thought I would just rewrite the stored pathes.. Anyway, I give it a try!
@dronus Yep, that's pretty much what it does.
@dronus Actually, for your case, in which you're just moving things around, you should be able to do a git filter-branch --index-filter, which is like --tree-filter but doesn't actually check the files out, it requires you to manipulate everything in the index directly. It will be faster to run than --tree-filter, but will be a little harder to write since you'll need to be modifying the index directly instead of just moving files. There's an example towards the end of the filter-branch documentation that demonstrates how to do it.
I don't know why, but --index-filter doesn't iterate all revisions in my branch. Maybe has something to do with merges enroute etc. But --tree-filter worked very well; see below.
@dronus Yeah, as I said, it's a little harder with --index-filter, because it doesn't actually check out the revisions. You need to do all of the work via the index; there's an example in the documentation I linked to. Anyhow, the only reason you'd want to do that is because it's faster; if --tree-filter is fast enough for you, it's perfectly fine, and much simpler to user.
0

The command in the accepted answer will fail for files/directories containing spaces etc. The following version is safe:

git filter-branch -f --tree-filter 'mkdir TheSubdir; \
find . -maxdepth 1 -name TheSubdir -prune -o -name . -true -o -print0 | \
xargs -0 mv -t TheSubdir'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.