views:

40

answers:

2

I have a project under git. One day I moved all project files from current directory to foo/bar/ under the project. I did it using git mv. Then I added some more files and did some changes to already existing files.

As a result, now when I look at the history of foo/bar/file.c, I can only see changes that I did after I moved the file.

I tried to fix this in various ways (filter-branch with subdirectory filter, etc), but nothing helped, so I am pretty stacked here. I'll appreciate any help that you can give me. Thanks!

+1  A: 

To rewrite the history with the files moved:

If you want the project's history to look as though all files have always been in the directory foo/bar, then you need to do a little surgery. Use git filter-branch with the "tree filter" to rewrite the commits so that anywhere foo/bar doesn't exist, it is created and all files are moved to it:

git filter-branch --tree-filter 'if [[ ! -e foo/bar ]]; then mkdir -p foo/bar; git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files foo/bar; fi'

Now the history will be recorded as if all files were always located in foo/bar. In most cases, you can probably stop and leave it at this.

The only potential minor issue is there may now be a commit in your history that introduces no changes. This would only be the case if when you originally moved the files to foo/bar that move was the only change made in that particular commit. There's not necessarily anything wrong with this, but it is a little odd to have a commit that doesn't change anything. If this is the case, then you can simply find that commit and delete it. Probably the easiest way to do this is with git rebase -i.

To see the history of a moved file:

If you just want to see the history of a file that has been moved or renamed at some point in the past, then simply use the --follow option to git log:

git log --follow foo/bar/file.c
Dan Moulding
Thanks Dan. This really helps. I would still like to fix the history to look like as if I was always working in foo/bar/...
Alexander Sandler
Thanks again. I am afraid the filter-branch command produces an error.Rewrite 33cb04e1cdf272d65d32f8cd6c02e5d1647bea10 (1/98)eval: 1: [[: not foundThis error appears for every commit that I've made - 98 in total.
Alexander Sandler
@Alexander: Thank you for the clarification. I have amended my answer now that I understand your question better.
Dan Moulding
@Alexander: I wrote and tested this for Bash. You may need to use Bash.
Dan Moulding
@Dan, you're right. I am using zsh and not bash, but I am afraid in bash it produces the same error message.
Alexander Sandler
`filter-branch` is in fact aware of the no-op commit issue, and has the `--prune-empty` option to tell it to ignore commits which leave the tree untouched.
Jefromi
@Alexander: You may want to try putting the one-liner (everything in the single quotes) in an actual script, with a bash shebang line. I think `filter-branch` is probably trying to run this in `sh`, not `bash`.
Jefromi
I made some progress. It seems that double brackets in if statement were causing this error. Single brackets work better, it still doesn't work though. The problem is that before I moved everything to foo/bar/ I had directory named foo with some content in the project. So now it complains "cannot move `foo' to a subdirectory of itself, `foo/bar/foo'".
Alexander Sandler
@Alexander: You'll just need to adjust the script accordingly. Something like: `if [[ ! -e foo/bar ]]; then mkdir -p foo/bar; git ls-tree --name-only $GIT_COMMIT | grep -v ^foo$ | xargs -I files mv files foo/bar; fi` That uses grep to filter out `foo` from the list of files to be moved. Note that I'm also assuming that the `bar` subdirectory never existed until you moved everything under it. If that isn't the case, then you'll need to account for that in the script as well.
Dan Moulding