在 git 使用中,如何将两个不同源点的分支连在一起呢?

2023-04-03 10:20:11 +08:00
 Exp

网上搜索了很久也没有找到一个满足目标实现的方案,想在此请教一下大家。

问题的来源是这样的:部门内部原来的项目通过 svn 管理,有一个项目在某年开始在新的 svn 仓库进行了重构开发,结果导致并行存在着两个项目仓库。今年公司内部代码管理迁移到了 gitlab 托管,我将原来两个 svn 项目迁移到了同一个 git 仓库的两个“分支”。当时的参考资料没有留存,再搜索一次找到一篇文章:Git-合并两个不同的仓库,大概就是这样的流程。 其中的问题在于,如果我简单采用类似 git merge B --allow-unrelated-histories 这样的操作,分支将在现有的所有提交之后进行合并。这不是我想要的结果。

由于历史原因导致了现在同一个 git 仓库内的两个“分支”没有共同的祖先来源,本着保留提交历史记录的原因需要同时保留两个“分支”。这两个孤立的“分支”其中一条分支 A 基本不再开发,另一条分支 B 持续开发,B 分支起源时间处于第一条分支 A 的某两次提交 a1 、a2 时间节点之间。

我想:将 B 分支的起点连接在 A 分支 a1 的提交之后,达到在分支图上看 A 分支在 a1 提交之后开了新的分支 B 。具体的细节可以是 B 的源点上游直接是 A 分支的 a1 ,中间也可以增加必要的节点。相当于伪造一下项目的提交流程记录?(因为 B 分支的第一次提交内容就是项目文件的加入,可以在 A 分支上的 a1 提交后增加一个分支节点将文件全部删除提交,再续借上 B 分支(我想的))

有办法实现吗?具体命令是怎样的呢?

附:

现在的分支图:

大概想要实现的分支图:

1458 次点击
所在节点    git
9 条回复
xbcslzy
2023-04-03 10:28:36 +08:00
从 a1 切个新分支 C, 将 B 合并至 C, 删除 B 重命名 C?
Exp
2023-04-03 10:30:06 +08:00
@xbcslzy #1 如果这样操作,那么合并之后的分支图显示的,应该是 B 的所有提交之后进行了合并到 C ?
xbcslzy
2023-04-03 10:34:28 +08:00
@Exp 切完 C 先推到远程源就是 a1 啊 后面的合并什么的理论上不影响你的需求
cubecube
2023-04-03 10:36:28 +08:00
以前也幻想过这么整。。最后强行 copy 的。丢了部分历史信息
lechain
2023-04-03 10:37:13 +08:00
在 a1 处 merge 分支 b ,然后基于这个 merge 产生的节点 rebase 原本分支 a 的 a1 到最新的所有改动,当然了,rebase 操作也可以换成 cherry-pick
nothingistrue
2023-04-03 10:59:12 +08:00
有一个项目在某年开始在新的 svn 仓库进行了〖〖〖重构〗〗〗开发,想想为啥当时不是拉 SVN 分支,而是重建仓库。

如果当时不是重构,那么可以这么操作:
git checkout -b branch-temp a1
git checkout B
git rebase branch-temp

rebase 那里可能要加 --force 。因为是重构,所以这里会产生近乎 100%的冲突。

但是实际上来说,你们原始的 A 和 B 就是两个仓库,git 虽然能把它勉强合起来,但是卵用都没有。
ruanimal
2023-04-03 15:18:37 +08:00
用 git-svn 试试?
Nile20
2023-04-03 23:36:30 +08:00
在公司实现过类似的需求,当时是合并三个仓并且要保留对应的 commit 记录。像这样的需求不是很常见,没有找到简单的命令或者脚本来处理,最后是自己写的 python 脚本来实现的。
大致思路如下:
从 B 仓库的 root commit 开始,按照如下过程遍历 B 仓库内的所有 commit:
1. 清空 A 仓内 working directory 中的所有文件(保留.git 文件夹)
2. 将 B 仓 checkout 到当前待处理的 commit
3. 将 B 仓内的文件全部复制到 A 仓,然后 git add
4. 获取 B 仓当前待处理的 commit 的 meta data ( author, author date, committer, commit date ),然后使用这些信息在 A 仓的 B 分支上创建一个 commit

上述过程中,如果你能确保 A 、B 仓的起点具有完全一致的文件状态,那也可以把 1-3 改为 cherry-pick 。
获取 meta data 的过程,如果是 python 的话,建议使用 GitPython 。但是如果要创建 commit ,建议直接使用命令行,GitPython 不擅长这个。
步骤 4 将 meta data 传递给特定的环境变量,然后再运行 git 命令即可获得与原 commit 相同的提交时间、作者信息等的 commit 。但是 commit 的 id 必然会变化。如果原 commit 有签名,签名也是无法保留的(或者用你的私钥来签名?不过不太有必要)
SoloCompany
2023-04-04 01:27:17 +08:00
如果你能准确找出 a' 以及对应的 b' 并且经过对比 a'^{tree} 和 b'^{tree} (用 show --pretty=raw 查看 tree object hash, 或直接 diff 命令很简单就能得到结论) 完全相同, 那么事情就非常简单, 把 b'...B^{head} 之间的所有 commit 都 cherry-pick 到 a' 就能得到想要的 B' (或者说 from B rebase a' -i 然后选择 drop 掉 a' 之前所有 commit)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/929330

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX