Git subdirectory filter with existing directory structure

I’m splitting out a Git repository using the –subdirectory-filter option of filter-branch which is working great except it pulls everything up to the root of the repository.

I currently have

  • How to count number of commits per file pathname by author in a Git repository?
  • Managing aesthetic code changes in git
  • GIT pull : replace local version with the remote version
  • Error when changing to master branch: my local changes would be overwritten by checkout
  • To put the prefix ?<revision-number> to codes by Git/Svn
  • How can I completely remove/destroy commits from a git repository?
  • ABC
      - DEF
          - GHI
          - JKL
      - MNO

    And the result of this command:

    git filter-branch -f --subdirectory-filter ABC/DEF --prune-empty -- --all

    Generates this:


    Where what I really want is this:

      - DEF
          - GHI
          - JKL

    I can’t see anything in the Git docs that shows a filter option which preserves (or sets) the directory structure and I haven’t been able to find a command I can run after the filtering to remap the structure to how I want it.

    Is this possible?

  • Pushing fails - Empty repository at remote server with GitKraken
  • Push existing project into Github
  • 'git' is not recognized as an internal or external command
  • How To Protect a GIT branch (like master)
  • Visual Studio Team Explorer - View Git Commands
  • Git subtree merge strategy, possible without merging history?
  • 2 Solutions collect form web for “Git subdirectory filter with existing directory structure”

    I found an answer here which does the trick.

    The command:

    git filter-branch -f --index-filter 'git ls-files -s \
    | sed "s-\t-&ABC/DEF/-" \
    | GIT_INDEX_FILE=$ git update-index --index-info \
    && mv $ $GIT_INDEX_FILE'

    works perfectly

    I’ve only given this cursory testing myself, but I think you can use git filter-branch with --tree-filter to rewrite the branch, but removing all files apart from those in the subdirectory ABC/DEF, with something like the following:

    git filter-branch --tree-filter \
        'find . -path ./ABC/DEF -prune -o -type f -print0 | xargs -0 rm -f' \
        --prune-empty HEAD

    Note that the find command only removes files, not directories, but since git doesn’t store empty directories, this should still produce the result you want.

    Git Baby is a git and github fan, let's start git clone.