Skip to content

Instantly share code, notes, and snippets.

@fabiomaggio
Last active October 20, 2022 08:48
Show Gist options
  • Save fabiomaggio/ce7ecd7dffd27b32a45325204288efce to your computer and use it in GitHub Desktop.
Save fabiomaggio/ce7ecd7dffd27b32a45325204288efce to your computer and use it in GitHub Desktop.
Use git filter-branch to move all projects files to a subdir and rewrite all commits
  1. Clone project

  2. Checkout all branches that contain the files that should be moved

  3. Delete the remote

  4. Run the filter-branch command:

    git filter-branch --tree-filter 'mkdir -p /path/to/tmp; mv * /path/to/tmp; mkdir subdir; mv /path/to/tmp/* subdir/' --tag-name-filter cat --prune-empty -- --all
    • All files are first copied to a temporary dir and move from there to the new destination
    • Existing tags are updated
    • Empty commits are ignored
    • The filters are applied to all branches
  5. Add the remote

  6. Push (force) all branches and tags back to remote:

    git push -f --all
    git push -f --tags
@CalvinZheng
Copy link

Thanks fabiomaggio, this is very helpful.

In case anyone else got this problem I had, the "path/to/tmp" is supposed to be a dir outside this git folder, e.g. "../tmp", or else it will fail when trying to move dir into itself.

@zebmason
Copy link

Really helpful although I forgot to move something trivial so deleted then added in afterwards:
git filter-branch --tree-filter 'rm -f .gitignore' HEAD

@rosasurfer
Copy link

This doesn't move hidden content (files or directories starting with ".") to the subdirectory.

@kevroletin
Copy link

@rosasurfer I found find utility to be helpful (3 levels of nested quotes is a little confusing, though).

git filter-branch --tree-filter 'mkdir subdir; find . -maxdepth 1 -not -name .git -not -name subdir -exec sh -c ''mv "$@" subdir'' {} +' --tag-name-filter cat --prune-empty -- --all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment