Detach subdirectory (that was renamed!) into a new repo

前端 未结 2 1066
礼貌的吻别
礼貌的吻别 2020-12-28 22:20

I have a repository and I would like to detach one of its directories into a new repo. This is a perfect place to get started, there is one caveat, however: the directory th

相关标签:
2条回答
  • 2020-12-28 23:02

    We (Matthew Flatt and me) wrote a program to do this: https://github.com/samth/git-slice

    0 讨论(0)
  • 2020-12-28 23:10

    git filter-branch can operate on ranges of commits; so what we can do is filter the 'before' and 'after' separately, and use grafts to tack them together:

    git branch rename $COMMIT_ID_OF_RENAME 
    git branch pre-rename rename~
    ## First filter all commits up to rename, but not rename itself
    git filter-branch --subdirectory-filter $OLDNAME pre-rename
    ## Add a graft, so our rename rev comes after the processed pre-rename revs
    echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
    ## The first filter-branch left a refs backup directory. Move it away so the
    ## next filter-branch doesn't complain
    mv .git/refs/original .git/refs/original0
    ## Now filter the rest
    git filter-branch --subdirectory-filter $NEWNAME master ^pre-rename
    ## The graft is now baked into the branch, so we don't need it anymore
    rm .git/info/grafts
    

    This is marginally more complex if you need to filter multiple branches or tags; branches before the rename can be included into the first filter-branch, while ones after must be included before the ^rename in the second filter-branch.

    Another option would be to add an index filter (or tree filter) instead that checks for both directories, old and new, and keeps whichever is present.

    Since you haven't provided a test repository, here's a quick sanity-check script for this scenario:

    #!/bin/bash
    
    set -u
    set -e
    set -x
    
    rm -rf .git x y foo
    
    git init
    mkdir x
    echo initial > x/foo
    git add x/foo
    git commit -m 'test commit 1'
    
    echo tc2 >> x/foo
    git commit -a -m 'test commit 2'
    
    mv x y
    git rm x/foo
    git add y/foo
    git commit -a -m 'test rename'
    
    git branch rename HEAD
    
    echo post rename >> y/foo
    git commit -a -m 'test post rename'
    
    git branch pre-rename rename~
    
    git filter-branch --subdirectory-filter x pre-rename
    echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
    
    mv .git/refs/original .git/refs/original0
    
    git filter-branch --subdirectory-filter y master ^pre-rename
    
    rm .git/info/grafts
    
    git log -u
    

    If this procedure does not work for you, then there is likely to be something else odd about your repository history that you haven't described, such as another rename hiding in the history.

    0 讨论(0)
提交回复
热议问题