Marcx
Marcx

Reputation: 6836

GIT change Base/Root Folder

I have a long (~2 years) repo with a lots of commits/branches, now for some reasons I need to change the root folder of the repository to one folder above.

Some examples to clarify the concept.

I have my repository inside a folder:

c:\workspace\test\src\

so in my repo has all the changes in files/subfolder of the above one.

I would like to move the repository to:

c:\workspace\test

being able from now on to add all the changes in the test folder mantaining the old repository history..

so all the old commits that are marked in folder "\", now should be checked in folder "\src"

for the old commits I can or can not have (it really does not matter) the actual content of the folder..

is that possible?

I hope what I explained is comprehensible..

Upvotes: 6

Views: 7962

Answers (5)

rhymes_with_dorange
rhymes_with_dorange

Reputation: 101

First, clone your repo so that you can work on it in isolation, and so that your original stays intact in case anything goes wrong here.

git clone --no-hardlinks c:\workspace\test\src c:\sandbox

write a script that makes the appropriate changes at any single commit. I'm not familiar with Windows scripting, but you'll want your script to create a new subdirectory named src (i.e., c:\sandbox\src), then move everything except the .git directory and any .git* files (e.g., .gitignore) into that new subdirectory. Ensure that your script will work properly on any commit in the repo, not just on the current state. Then run:

git filter-branch --tree-filter c:\absolute\path\to\your\script

This will cause git to checkout each commit in the repo, run your script, and then replace the commit with the end result. Next, if you have any ignored or uncommitted files, you'll want to copy them into the appropriate places in your new repo. Check to make sure that the filter-branch had the intended effect and the new repo looks how you wanted it to. Once you're sure that you're happy, delete c:\workspace\test and then move c:\sandbox to c:\workspace\test.

I prefer to use --tree-filter, as shown here, rather than --index-filter. It's less efficient (since it has to checkout each commit rather than editing the index directly), but I find it much more intuitive. If needed, it will also allow you to make changes to the content of files in the repo (updating absolute paths, perhaps).

Upvotes: 0

jthill
jthill

Reputation: 60487

git filter-branch --index-filter '
    git read-tree $(printf "040000 tree %s\tsrc\n" `git rev-parse HEAD:` | git mktree)
    ' -- --branches --tags
mv .git ..
cd ..

Do see the docs in those commands; the usage is very straightforward. The advice in filter-branch's docs about getting it to do its work on a tmpfs is likely to be worthwhile with two years of history to deal with.

You might want to grep -ri c.workspace.test .git to check for absolute paths in your configs and such, to verify they're still valid.

Upvotes: 0

Eliot
Eliot

Reputation: 5659

I think you mean that the top-level directory of your repo is c:\workspace\test\ and you want c:\workspace\test\src\ to be the new top-level directory. First, check that this is the case:

cd c:\workspace\test\src
git rev-parse --show-toplevel #print repo top-level directory

It should print something like c:\workspace\test\ if that is really your top-level directory.

If it is, you can use the git filter-branch rebasing command to make the 'src' directory the new top-level. Please be careful that this is what you really want to do as it will destructively modify your old history! Any commits affecting this branch will be rebased to contain the src folder as the new top-level. Back up your current branch first.

cd c:\workspace\test\
git branch oldRoot #this backs up your current branch to a new branch called "oldRoot"    
git filter-branch --subdirectory-filter src HEAD #this modifies your history

Warning!!! Note that:

  1. The new history won't apply cleanly, if you have your changes backed up to a remote you will need to either:
    1. Start using a new remote branch (safer), or:
    2. Do a force push to overwrite the remote history.
  2. If anyone else was collaborating with you on this repo, they may be in for a heap of trouble. Make sure they get their changes merged in first, as it will be difficult for them to merge them in after you do the rebase.

For more info, read the "Making a Subdirectory the New Root" and "The Perils of Rebasing" sections in the Git Book.

Upvotes: 3

twalberg
twalberg

Reputation: 62469

Sounds like you should only need to do this:

  1. rename c:\workspace\test\src to c:\workspace\src
  2. delete the directory c:\workspace\test, which is presumably now empty
  3. rename c:\workspace\src to c:\workspace\test

git repositories don't generally keep a track of their parent directories, so moving the repository from one place to another should be harmless. Now, whatever scripts/build files/whatever you have in your repository that may contain hard-coded paths may be a completely different story...

Upvotes: 0

Guillaume Darmont
Guillaume Darmont

Reputation: 5018

If I understand correctly your question, if you start from a clean git repo (git status says 'nothing to commit, working directory clean'), you simply have to move the .git directory from c:\workspace\test\src\ to c:\workspace\test\.

Then you have to do a 'big' commit with all files in your new layout. Git will see this new commit as a big move. No new content is needed, as files would be the same. Git will only register the new tree layout (with src) in his .git dir.


Re-reading the question make me think you may want to have your old commits available in src subdirectory

If this is the case, you need to fully rewrite your Git repository history using something like git filter-branch --tree-filter '...'

Upvotes: 0

Related Questions