83

Git beginner question:

I have a small private webproject which is versioned locally with msysgit. There is no exterior repository, as it's only for me, so i can bascially do whatever I want.

I've had this set up in the project directory, ie in "webroot".

Now a second directory had to be created, placed parallel to webroot. Let's call it assets.

So structure is now as follows:

\ project directory
----\webroot
----\assets

I'd love to include this new directory in the git repository, so that I'd also version changes to files stored there, but of course I can't use "git add ../assets". Neither am I inclined to create a new git project in project_directory, as this would loose all my previous commits.

So how do I go about moving the repository out of "webroot" up into "project_directory", while keeping my commits and then being able to include "assets"?

Sorcy
  • 2,375
  • 4
  • 25
  • 33

5 Answers5

79

So, you want your git repo to look like this:

<projectdir>
    /.git
    /webroot
    /assets

To do this, you must move the existing files in your repo into a new webroot subdirectory.

cd <git repo root>
mkdir webroot
git mv <all your files> webroot
git commit --all -m "moved all existing files to new 'webroot' directory"

Then, on your local filesystem you want to relocate your clone one directory above where it is now:

cd <projectdir>
mv webroot/* .
rmdir webroot

Then you want to add the assets directory (and files) to the git repo:

git add assets
git commit -m "added assets to the repo"
Tim Henigan
  • 55,120
  • 11
  • 81
  • 76
  • 2
    Okay, apparently I've not given enough information. The repository already IS inside /projectdir/webroot/, as this is where it was originally created. Since the assets directory came to pass I'd prefer it if the repository was acting as if it was created in /projectdir/, which alas it was not. git mv will not let me move files outside the repository. – Sorcy Mar 26 '11 at 12:37
  • @Sorcy: I believe I understand what you want to do. I updated my answer to clarify it. – Tim Henigan Mar 26 '11 at 13:24
  • Thanks, that's exactly the solution I was looking for. :) – Sorcy Mar 26 '11 at 19:56
  • 2
    I found hat this solution requires `mv webroot/.* .` as well, in order to move the repo and .gitignore files. – katriel Jul 16 '15 at 17:00
  • `git mv * webroot` won't work because bash wildcard * will be also substitued with webroot, making the command be `git mv webroot webroot`. Git will fail at that. The other folder that it had problems with was .git. So I had to use special bash env variable `GLOBIGNORE=webroot:.git` so that * won't be substitued with those two directories. Thanks to that I didn't have to make dozens of manual git mv - my directory has a lot of folders and files. I only had to move the .git folder manually. – Koshmaar Jul 25 '16 at 18:46
  • Why `rmdir`? Doesn't `webroot` contain all the files you wanted to keep tracked? – Juan De la Cruz Jul 27 '18 at 01:07
  • This is the most correct and easiest way, if there are not too many files. But instead of `mv webroot/* .; rmdir webroot`, use `mv webroot tmp; mv tmp/.git tmp/* .; rmdir tmp`. – Curt Jan 05 '21 at 10:36
19

You can also just move your .git dir up one level and update your worktree.

cd projectdir
mv ./webroot/.git ./.git
git config core.worktree /absolute-path-to-project-dir
git add assets
git commit -m 'adding assets folder'

Not positive but I'm pretty sure the path to core.worktree has to be absolute.

braitsch
  • 12,644
  • 5
  • 39
  • 33
  • Here's the order that worked for me. While I'm in the folder where I want to move the .git file: `mv .git / ../` – anevaude Feb 21 '15 at 20:46
  • I did this in a similar situation and I had to re-add files to the repo that had already been added when they were in the previous location. So essentially, I think I lost the git history for those files. – aneccodeal Nov 11 '20 at 23:59
12

I assume you meant to rewrite the history to contain all the files in all revisions as if they had always been in a subdirectory webroot/ instead of in the root

The git filter-branch manpage has the answer, here an improved version that rewrites all existing refs (branches) and tags:

time git filter-branch --index-filter 'git ls-files -s |
         sed "s-\t\"*-&webroot/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && 
     mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --tag-name-filter cat -- --all

Care has been taken to make this an index-only operation so that the process will run fast even for big repos. Remember to (when satisfied) get rid of the original refs (.git/refs/original/*) and repack the repo to loose the obsolete tree objects.

sehe
  • 328,274
  • 43
  • 416
  • 565
  • 2
    Can you explain how to get rid of the original refs and repack the repo? Is it just GC or something else? – NateS Nov 19 '16 at 13:19
  • This is exactly what I want. Thank you! For people who are confused, this operation should be done AFTER finishing [what Tim Henigan suggested](https://stackoverflow.com/a/5408577/8301681). – Youwei Liang Apr 21 '21 at 03:44
4

Your commits are not locally tied to the "webroot" folder they are stored within the git repo.

You could simply remove the webroot directory recheckout the repository in the new location "/project directory" add the assets directory and commit.

rm -Rf webroot
git clone path-to-repo
git add assets 
git commit -m "Added assets directory"
git push
Nick
  • 673
  • 1
  • 10
  • 25
0

The following command would rewrite your Git history. It would look like as if the content was in webroot all along. Usually rewriting history is troublesome if multiple people are working with a repo. Since you are working alone on it, it should be fine.

git filter-branch --index-filter '
    git read-tree --prefix="webroot/" $GIT_COMMIT && \
    git ls-files \
      | sed "s/\/.*//" \
      | sort \
      | uniq \
      | grep -v "^webroot" \
      | xargs -L1 git rm -r --cached > /dev/null'
Lars Schneider
  • 5,210
  • 4
  • 30
  • 54