Easiest way to replay commits on new git repository
I've been using git-svn, and recently, I've been getting errors when trying to commit (I think this is due to a bug in libneon, but this is beyond the scope of this question). The solution has been to re-clone my git repository using git svn clone
. However, I have changes on the master branch in my old git repositor开发者_JAVA技巧y that I was not able to commit to svn using git svn dcommit
. I'd like to replay these changes on the new repository cloned with git svn. I think I could probably export a patch-set using git format-patch
, and then replay these changes on the new repository but I'm not entirely sure how to do this, and I wonder if there's an even easier or more elegant way to accomplish this.
From your new repository, add a remote reference to your old repository:
git remote add temp file:///path/to/old/repo/on/your/machine
Fetch from the old repo:
git fetch temp
Check out your master branch from the old repo:
git checkout temp/master -b wip
(wip stands for work-in-progress)
Rebase the changes on top of the stuff in your present repository:
git rebase master
Update master to point at your new HEAD:
git checkout master
git merge wip
Delete the remote reference to your old repo and the wip branch that you used:
git branch -d wip
git remote rm temp
What you are actually doing:
Firstly, by adding the remote reference and fetching, you are pulling the commits from your previous repository which you do not yet have in your current repository. Git knows how to do this because, no matter where or how it was made, the same commit looks the same everywhere. It is the SHA1 hash of a few well-known pieces of information, including the directory tree, the committer, timestamp, ...
So when you created a new Git repository based on the same SVN repository, all the commits had the same SHA1 sums. As a result, the new commits that you fetched into your current repository continued to point at the right stuff. This is very cool, and important to remember.
You then switched to the tip of temp's master branch and told it to rebase onto your current master. The rebase may have been unnecessary, as master from SVN may not have moved away from the master in your old repo, but it was best to be safe.
A rebase finds the nearest point of commonality between two commits by working backwards through their histories until they both point at the same parent commit. It then switches to the branch name you gave it (in this case master
) and cherry-picks each of the commits that were missing from its history from your original branch. Once complete, it points the branch you were on when you started at the last commit it applied.
Finally, the merge of master with wip was just to fast-forward master to the end. As it was a straight line, it really was just a fast-forward. You could have just as easily done a rebase or a reset --hard; any of these would have altered the master branch to point at the correct location. Merge was just the safest of these, because if something weird had happened, it would have let you know that it was not a simple fast-forward.
You could:
- add your old repo as a remote of your new repo (
git remote
) - fetch the old branch
- rebase the part of the old branch you are interested in on top of your current
master
.
See How to cherry pick a range of commits and merge into another branch:
# go to your current but incomplete new master branch
git checkout master
# mark your current master HEAD as branch 'tmp'
git checkout -b tmp
# reset your master to the old one
git branch -f master oldrepo/master
# replay the right commits on top of 'tmp' (which was your master HEAD)
git rebase --onto tmp first_SHA-1_of_old_master_to_replay~1 master
# remove tmp branch,
# your master HEAD is now on top of tmp, with the right commits replayed
git branch -d tmp
That solution will work even if the SHA1 differs from your old master
history and your new master from your second git-svn clone
.
That is why I recommend a rebase --onto
: the history of both master
s might have nothing in common if, for any reason, the second git-svn clone
don't generate exactly the same SHA1.
精彩评论