1

I'm trying to move my entire repo root into a sub-directory, for everything except one file.

For example, I have something like:

root
-Folder1
-Folder2
-.gitattributes

And for all commits and history, I want

root
-ProjectA
--Folder1
--Folder2
-.gitattributes

i.e., I want to move everything except .gitattributes to a subdirectory. If I use

 git filter-repo --to-subdirectory-filter ProjectA/

everything gets moved. I can't find the strategy for moving everything except a single file.

How do I keep the file where it is? Or how do I move just that file back up to the root with another command?

House
  • 3,356
  • 2
  • 25
  • 29

2 Answers2

2

I know this is late but there is another option which achieves the same goal and feels a little better IMO:

git filter-repo --path Folder1 --path Folder2 --to-subdirectory-filter ProjectA

You can specify many paths which you want to be moved into the subdirectory in a single move. This is particularly beneficial if you are migrating to a monorepo - the --to-subdirectory-filter should match the final destination you want in your monorepo (ex. packages/project-a). Then, in your monorepo, you would do the following:

git remote add old-project ../path/to/old/project
git fetch old-project master
git merge remotes/old-project/master --allow-unrelated-histories
git remote remove old-project

You should now see all of your files located at packages/service-a inside the monorepo, with git history preserved. SEE: https://stackoverflow.com/a/61917589/264794

Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96
0

If you can, you would list all elements except .gitattributes, and rename them in one command, using path renaming:

git filter-repo --path-rename Folder1:ProjectA/Folder1 \
                --path-rename Folder2:ProjectA/Folder2 \
                ...

The OP House suggests in the comments the more sensible approach:

  • moving everything to a subdir,
  • then moving the .gitattributes back with --path-rename ProjectA/.gitattributes:.gitattributes

I would do each step in a separately cloned repository, to make sure I can go back to the original one if it fails.
The second step would be done in a clone of the repository from the first step.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • WHOA. VonC. Man! – Robo Jan 05 '22 at 05:14
  • I did actually try this route, and ended up with a completely empty repo. The issue I see with this approach is, if somewhere in the history there was another file/folder in the root, it wouldn't be properly moved by moving all the files/folders that are currently in the root. git-filter-repo seems to have a bug related to moving files starting with a `.`, because I also tried moving everything to a subdir, then moving the `.gitattributes` back with `--path-rename ProjectA/.gitattributes:.gitattributes`, but it didn't believe there was a colon in the argument and failed to process. – House Jan 05 '22 at 15:52
  • @House I like your second approach. It should have worked. – VonC Jan 05 '22 at 17:49
  • It should, yes, but the bug prevents it (where it says the argument is invalid). I even tried using the file approach, creating a file with `ProjectA/.gitattributes=>.gitattributes`. Unfortunately, this just freezes when rewriting commits. – House Jan 05 '22 at 18:29
  • @House Can you try the second step (`--path-rename ProjectA/.gitattributes:.gitattributes`) in a clone of the repository from the first step? – VonC Jan 05 '22 at 18:46
  • The command doesn't even execute, I get `--path-rename expects one colon in its argument` when trying to run that command. filter-repo appears to have a bug that prevents it from parsing the ":." part. – House Jan 05 '22 at 19:49
  • @House And what about escaping the dot? `:\.gitignore` – VonC Jan 05 '22 at 20:56
  • This does allow the command to run, but breaks the repo by introducing a file with a bad path: `error: invalid path '\.gitattributes' fatal: Could not reset index file to revision 'HEAD'` – House Jan 06 '22 at 00:15
  • I think the move everything, then move one thing back is the right approach, but the behavior from filter-repo is unexpected. So, I'll select this as the correct answer, even though a bug prevents it from being accomplished. – House Jan 06 '22 at 00:25