我有一个项目,DemoA是由git存储库构建的,Project1。
不幸的是,DemoA从Project1开始只是一个文件的副本,然后才变成一个实际的长期项目。我现在想让Project1成为DemoA的子模块,但是 - 更重要的是 - 想要在DemoA中合并对从Project1派生的代码所做的更改。
我在DemoA上做了一个子树分割,创建了一个分支P1,它对DemoA中的Project1代码库进行了所有更改。
我还设法在将DemoA实例化为存储库之前添加对DemoA所做的更改。
Project1
A - B - C - D - E
Demo1/P1
(untracked changes) F - G - H - I
where the files in E are identical to F
我想要的是什么:
Project 1
A - B - C - D - E - G - H - I
显然E和F的哈希是不同的,所以当我将Demo1 / P1作为遥控器添加到Project1并尝试合并时,它抱怨没有共同的祖先。
我试过using format-patch,但是git am抱怨了
错误:file.xyz:已存在于索引
中
我正在尝试rebase onto a different branch,正在做:
git rebase -s recursive -X subtree=project1dir --onto (E-hash) (F-hash) emptybranch
但我显然不明白实际上在做什么,因为它似乎并没有真正做任何事情。
有干净的方法吗?我不介意这个过程的一些手册,但我想保留历史。
答案 0 :(得分:2)
这一切都是中等难度(实际难度级别因环境和您对Git的熟悉程度而异)。
如果E
和F
中的文件完全相同,那么(或)一种简单的方法就是放入移植(使用git replace
或移植文件)以便Git假装G
的父提交是提交E
。也就是说,你有:
A--B--C--D--E <-- master
F-------------G--H--I <-- refs/remotes/rem/P1
和git diff master rem/P1~4
根本不产生输出(master
名称提交E
,rem/P1~4
名称提交F
,而E
的两棵树}和F
完全匹配。
你希望,或许至少作为中间产品,你有这个:
A--B--C--D--E <-- master
\
F G--H--I <-- refs/remotes/rem/P1
也就是说,你希望Git至少在某些目的和一段时间内假装提交G
已提交E
作为其父级。
git replace
模拟旧的可怕的黑客移植物 Git grafts正是这样做的:他们告诉Git 假装某些提交的父级是其他一些提交。但是这些已经被弃用,而不是更通用的git replace
。您可以使用git replace
创建一个类似于(但至少取代大多数Git命令)G'
的新提交G
,其中一个区别在于G'
E
作为其父母。
然后,您可以使用git filter-branch
重新复制存储库中的提交,以便此替换变为真实且永久的,而不仅仅是副本。当然,您将为新提交获取新的提交哈希值(G'
可以保留其哈希值,但您必须获得新的H'
和I'
)。请参阅this answer by Jakub Narębski,然后How do git grafts and replace differ? (Are grafts now deprecated?),其中VonC链接到Jakub的答案。
(Git移植仍然有用,你可以将提交G
和E
的哈希值放到.git/info/grafts
:echo $(git rev-parse rem/P1~3) $(git rev-parse master) > .git/info/grafts
中。但是他们是一个可怕的黑客,如果你做这种技巧,最好立即运行你的过滤器分支,就像Jakub指出的那样。)
git rebase
您也可以在尝试时使用git rebase --onto
,但必须使用现有的(普通的,本地的)分支名称启动此rebase(我不确定emptybranch
来自何处)指向提交I
。我想也许您缺少的步骤可能是制作这个常规的普通本地分支名称:
git checkout -b rewrite rem/P1
例如,假设名称rem/P1
解析为提交I
。或者git checkout -b rewrite <hash-of-I>
,如果你面前有那个哈希,便于剪切/粘贴。那时你会有这个:
A--B--C--D--E <-- master
F-------------G--H--I <-- HEAD -> rewrite, rem/P1
也就是说,您现在处于这个新的rewrite
分支上,该分支指向提交I
。现在,您可以git rebase --onto master HEAD~3
复制当前分支上的最新3次提交 - G
,H
和I
。副本将为G'
,H'
和I'
,G'
的父级为E
- master
点的提交 - H'
的父级为G'
,依此类推:
G'-H'-I' <-- HEAD -> rewrite
/
A--B--C--D--E <-- master
F-------------G--H--I <-- rem/P1
现在您可以删除远程及其远程跟踪分支,因为您拥有所需的提交链。您也可以随时快进master
指向提交I'
,如果这是您想要的。