在新的git存储库上重放提交的最简单方法

时间:2011-03-17 14:56:36

标签: git git-svn

我一直在使用git-svn,最近,我在尝试提交时遇到了错误(我认为这是由于libneon中的一个错误,但这超出了这个问题的范围)。解决方案是使用git svn clone重新克隆我的git存储库。但是,我在旧的git存储库中的master分支上有更改,我无法使用git svn dcommit提交给svn。我想在使用git svn克隆的新存储库中重放这些更改。我想我可以使用git format-patch导出一个补丁集,然后在新的存储库上重放这些更改,但我不完全确定如何做到这一点,我想知道是否有更简单或更优雅的方式要做到这一点。

2 个答案:

答案 0 :(得分:45)

从新存储库中添加对旧存储库的远程引用:

git remote add temp file:///path/to/old/repo/on/your/machine

从旧回购获取:

git fetch temp

从旧仓库中查看您的主分支:

git checkout temp/master -b wip

(wip代表正在进行的工作)

将更改重新基于当前存储库中的内容:

git rebase master

更新master以指向新的HEAD:

git checkout master
git merge wip

删除旧回购的远程引用和您使用的wip分支:

git branch -d wip
git remote rm temp

你实际在做什么:

首先,通过添加远程引用和获取,您将从先前存储库中提取当前存储库中尚未提交的提交。 Git知道如何做到这一点,因为无论在何处或如何制作,相同的提交在任何地方看起来都是一样的。它是一些众所周知的信息的SHA1哈希,包括目录树,提交者,时间戳,......

因此,当您基于相同的SVN存储库创建新的Git存储库时,所有提交都具有相同的SHA1总和。因此,您提取到当前存储库的新提交继续指向正确的内容。这非常酷,而且很重要。

然后你切换到临时主分支的尖端并告诉它重新加入你当前的主人。可能没有必要使用rebase,因为SVN的主人可能没有离开旧回购中的主人,但最好是安全的。

通过在历史记录中向后工作直到它们都指向同一个父提交,rebase在两个提交之间找到最接近的共性点。然后它切换到你给它的分支名称(在这种情况下为master),并从原始分支中挑选其历史记录中缺少的每个提交。完成后,它指向您在应用的最后一次提交时开始的分支。

最后,master与wip的合并只是为了快速掌握到底。因为它是一条直线,它真的只是一个快速前进。你可以轻松地做一个rebase或重置 - 硬;其中任何一个都会改变主分支以指向正确的位置。合并只是其中最安全的,因为如果发生了一些奇怪的事情,它会让你知道这不是一个简单的快进。

答案 1 :(得分:9)

你可以:

  • 将您的旧回购添加为新回购的远程(git remote
  • 获取旧分支
  • 在您当前的master之上重新设置您感兴趣的旧分支部分。

请参阅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

即使SHA1与旧的master历史记录不同,您的新主广告与第二个git-svn clone不同,该解决方案也会有效。
这就是我推荐rebase --onto的原因:如果由于某种原因,第二个master未完全生成,则git-svn clone的历史可能没有任何共同之处相同的SHA1。