开发者

How to move a subdirectory from a branch in one git repository to a branch in a different repository, preserving history?

I've got a directory containing utility libraries that were developed in a branch in one git repository, but it turns out they really belong in a different directory in a different project. I've read through and attempted Greg Bayer's Moving Files from one Git Repository to Another, Preserving History multiple times, but I'm unable to preserve history. I'm attempting to do this all under non-master branches to be more safe as the project is not ready to merge back to master yet anyway.

Here's what I'm doing so far:

Preparing the "DirectoryName" directory to be moved from branch "SomeBranch" of "Repo1" repository:

cd ~/Desktop
git clone git@github.com:username/Repo1.git
cd Repo1
git checkout -b SomeBranch origin/SomeBranch
git remote rm origin
git filter-branch --subdirectory-filter DirectoryName
mkdir DirectoryName
git mv *.php *.txt DirectoryName
git add DirectoryName
git commit -m "Stripped everything down to just DirectoryName."

Merging the "DirectoryName" directory into the "SomeBranch" branch of the "Repo2" repository:

cd ~/Desktop
git clone git@github.com:username/Repo2.git
cd Repo2
git checkout -b SomeBranch origin/SomeBranch
git remote rm origin
git remote add Repo1 ../Repo1/
git pull Repo1 SomeBranch
git remote rm Repo1

When I do this I can successfully strip everything down to "DirectoryName" in Repo1 (and I can pull it over to Repo2 as well), but the history is lost. If I do a git log -- DirectoryName or git log -- DirectoryName/SomeFile.php, I only see the "Stripped everything down to just DirectoryName." commit). So, clearly something is wrong with my git filter-branch command, but I'm not familiar enough with it to figure out what.

Any suggestions would be greatly appreciated as we're undergoing some fundamental changes to our codebase, so I'll need to be doing this relatively frequently for a while as stuff moves around (but we want to preserve the history).

Update: As I mentioned git log -- DirectoryName (or git log -- DirectoryName/SomeFile.php; either in Repo1 or Repo2) does not show any commits other that the "Stripped everything down to just DirectoryName." commit, but if I do git log I see the correct commit history. Am I just using git log incorrectly or is there some corruption that's causing th开发者_开发百科e commits to not show up correctly?

Another Update: git log -- DirectoryName does show the correct commits in my original, unmodified Repo1, but it does not show the correct commits after the git filter-branch (and I've tried git filter-branch --subdirectory-filter DirectoryName -- --all but that mucks with the "master" branch as well and doesn't appear to be necessary... same result). That said, the commit history is there after running git filter-branch, I can see it all with git log master.. it just no longer seems to pertain to the directory or the files. Any ideas?


It sounds as if what you've done is fine, it's just a misunderstanding about git log that's causing problems.

git just stores the state of the tree at each commit, rather than recording the changes that took the tree from the state in one commit to the next. If you're using git log to find the history of a particular file or directory, however, you can tell it to try to look for renames when the history of the file appears to run out. You can do that with:

git log --follow -- DirectoryName

Or if that doesn't work, try it for just a single file, e.g.

git log --follow -- DirectoryName/whatever.txt


Here's how I'd do it:

  1. Create patches for all the commits that touch the files in the subdir:

    $ c=1; git log --format=%h -- subdir/*|tac|while read commit; do 
    git format-patch --stdout -1 $commit > $(printf '%04d' $c).patch
    c=$((c+1))
    done
    

    Note that if there are single commits that touches both files in the subdir and outside of subdir then the patch will also include the diff on the other file so you'll have to prune those hunks, or do a filter branch to remove those files once you done step two below:

  2. Use git am to apply the patches on the branch in the other repo:

    $ git am *.patch
    
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜