开发者

How do I change a file's path in git's history?

Here is what I have - a git repo of my c开发者_Go百科ode:

projects
       |-proj1 (no git repo here yet)
             |-subproj1 <- current git repo here

Here is what I want - a git repo which is now tracking a new project that uses my code:

projects
       |-proj1 <-git repo moved to here, but still tracking files in subproj1
             |-subproj1 (no git repo here)

I'd like to keep the history intact and therefore the new repository will be referring to files that are one level deeper than the original. What is the most pain free way to do this?


Rewriting history can be done with the git filter-branch command. In fact, moving a directory tree into a subdirectory is one of the cut&paste-ready examples given in the git filter-branch manpage:

git filter-branch --index-filter '
  git ls-files -s |
  sed "s-\t\"*-&subproj1/-" |
  GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
  mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE
' HEAD


Git isn't exactly good at tracking files getting moved around, so if you want to preserve file history, you're going to have to make it so the old repository always had its files in the sub-directory you now need it to be in.

git-filter-branch works decently enough, but is no longer recommended. The man page now points to git-filter-repo, which lets you retroactively move files around (among other things you can do with git-filter-branch) in a much simpler way.

Copied from my own answer here:

export SUBTREE_PREFIX="subproj1"

git remote add -f "${SUBTREE_PREFIX:?}-remote" https://my-git-repo.invalid/subproj1.git

git checkout "${SUBTREE_PREFIX:?}-remote"/master -b "${SUBTREE_PREFIX:?}-master"

# --force is to skip the "freshly cloned repo" check.
# All the refs we'll be operating on are fresh, even if the repo isn't

# Remove --dry-run once you've checked .git/filter-repo/fast-export.filtered
# to be sure that everything is correct.
git filter-repo --refs "${SUBTREE_PREFIX:?}-master" --to-subdirectory-filter "${SUBTREE_PREFIX:?}" --force --dry-run

git checkout master
git merge "${SUBTREE_PREFIX:?}-master" --allow-unrelated-histories

# Repeat for however many repos you need to add

See also How do you merge two Git repositories?


Just create the directory structure you want inside the repo - i.e. move all files and folders to "subproj1" folder.

Then stage all added and deleted files and git will work out that they are in fact renames:

git add .
git add -u .
git commit -m "Moved to a subfolder"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜