lmc*_*iro 5 git git-rebase git-filter-branch git-history-graph
I have a project that has more than 3 years of history in the svn repository. It was migrated to git, but the guy who did this, just take the last version and throw out all these 3 years of history.
Now the project has the last 3-4 months of history in one repository, and I've imported the other 3 years of svn history into a new git repository.
Is there some way to connect the root commit of the second repository into the last commit of the first one?
It is something like this:
* 2017-04-21 - last commit on master
|
* 2017-03-20 - merge branch Y into master
|\
| * 2017-03-19 - commit on branch Y
| |
* | 2017-03-18 - merge branch X into master
/| * 2017-02-17 - commit on another new branch Y
* |/ 2017-02-16 - commit on branch X
| * 2017-02-15 - commit on master branch
* | 2017-01-14 - commit on new branch X
\|
* 2017-01-13 - first commit on new repository
|
* 2017-01-12 - init new git project with the last version of the code in svn repository
.
.
There is no relationship between the two different repositories yet, this is what I wanna
do. I want to connect the root commit of 2nd repository with the last commit of the first
one.
.
.
* 2017-01-09 - commit
|
* 2017-01-08 - commit
|
* 2017-01-07 - merge
/|
* | 2016-01-06 - 2nd commit the other branch
| * 2016-01-05 - commit on trunk
* | 2016-01-04 - commit on new branch
\|
* 2015-01-03 - first commit
|
* 2015-01-02 - beggining of the project
Run Code Online (Sandbox Code Playgroud)
Update:
I just learn that I need to do a The answer was to use git rebase, but how? Please, let's consider the commit dates like it was the SHA-1 codes...git filter-branch with --parent-filter option, not a git rebase.
Update 2:
I tried the command git filter-branch --parent-filter 'test $GIT_COMMIT = 443aec8880e898710796a1c4fb4decea1ca5ff66 && echo "-p 98e2b95e07b84ad1e40c3231e66840ea910e9d66" || cat' HEAD and it didn't work:
PS D:\git\rebase-test\rep2cc> git filter-branch --parent-filter 'test $GIT_COMMIT = 443aec8880e898710796a1c4fb4decea1ca5ff66 && echo "-p 98e2b95e07b84ad1e40c3231e66840ea910e9d66" || cat' HEAD
fatal: ambiguous argument '98e2b95e07b84ad1e40c3231e66840ea910e9d66 || cat': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
Run Code Online (Sandbox Code Playgroud)
Update 3:
It didn't work on Windows CMD or PowerShell, but it did work in Git Bash on windows.
首先要做的事情是:您需要一个包含所有可用历史记录的存储库。
使用最近的历史记录克隆 repo。添加具有旧历史记录的 repo 作为远程。我建议这个克隆是一个“镜像”,你通过用这个替换你的原始仓库来完成。但是,您也可以放弃--mirror,然后将所有参考推回原点(可能是强制推入,具体取决于您使用的方法)。
git clone --mirror url/of/current/repo
cd repo
git remote add history url/of/historical/repo
git fetch history
Run Code Online (Sandbox Code Playgroud)
您需要做的下一件事是弄清楚您将在哪里拼接历史记录。我认为描述这一点的术语有点模糊……您想要的是找到与两个历史记录都有提交的最新 SVN 修订版相对应的两个提交。例如,您的 SVN 存储库包含版本 1、2、3 和 4。现在您有
Recent-History Repo
C --- D --- E --- F <--(master)
Old-History Repo
A --- B --- C' --- D'
Run Code Online (Sandbox Code Playgroud)
其中A表示版本1,B表示第2版,C和C'表示第3版,并D和D'代表4.版本 E和F是原始迁移之后创建的工作。因此,您想将父项为D(E在本例中)的提交拼接到D'.
现在,我可以想到两种方法,每种方法各有利弊。
重写最近的历史
如果您可以协调所有开发人员切换到新的存储库, IMO 是最好的方式(这意味着您安排一个时间,他们都同意推送所有未完成的工作,因此他们会丢弃他们的克隆;然后您进行转换;然后他们all re-clone)是(有效地)将最近的历史重新建立在旧的历史上。
如果真的只有一个分支,那么您可以直接使用 rebase
git rebase --onto D' D master
Run Code Online (Sandbox Code Playgroud)
(其中D和D'替换为提交的 SHA ID)。
更有可能你在最近的历史中有一些分支和合并;在这种情况下,rebase 操作将很快成为一个问题。另一方面,您可以利用D具有相同树的事实D'——因此 rebase 和 re-parent 或多或少是等效的。
所以你可以使用git filter-branchwith a--parent-filter来进行重写。根据https://git-scm.com/docs/git-filter-branch上的文档中的示例,您可以执行以下操作
git filter-branch --parent-filter 'test $GIT_COMMIT = D && echo "-p D'" || cat' HEAD
Run Code Online (Sandbox Code Playgroud)
(再次D并D'用提交的 SHA ID 替换)。
这会创建您需要清理的“备份”引用。最后你会得到
A --- B --- C' --- D' --- E' --- F' <--(master)
Run Code Online (Sandbox Code Playgroud)
正是F被替换的事实F'导致需要进行硬切换(或多或少)。
现在,如果您在步骤 1 中创建了镜像克隆,则可以考虑擦除 reflog、删除遥控器并运行gc,然后这是一个新的随时可用的原始存储库。
如果您进行了常规克隆,那么您将需要对push -f原点的所有引用,这可能会在原点存储库上留下一些混乱。
使用“替换提交”
另一个选项不会创建硬切换,但它会让您永远处理一些小麻烦。您可以使用git replace. 在您的合并回购中
git replace `D` `D'`
Run Code Online (Sandbox Code Playgroud)
默认情况下,在生成日志输出或其他任何内容时,如果 git find D,它将D'在输出中替换(及其历史记录)。
有一些已知的故障。可能存在未知故障。默认情况下,不会共享使这一切正常工作的“替换引用”,因此您必须故意推送和获取它们。
| 归档时间: |
|
| 查看次数: |
907 次 |
| 最近记录: |