V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
git
Pro Git
Atlassian Git Tutorial
Pro Git 简体中文翻译
GitX
Exp
V2EX  ›  git

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

  •  
  •   Exp · 2023-04-03 10:20:11 +08:00 · 1653 次点击
    这是一个创建于 598 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    问题的来源是这样的:部门内部原来的项目通过 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 分支(我想的))

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

    附:

    现在的分支图: 现在的分支图

    大概想要实现的分支图: 希望的分支图

    9 条回复    2023-04-04 01:27:17 +08:00
    xbcslzy
        1
    xbcslzy  
       2023-04-03 10:28:36 +08:00
    从 a1 切个新分支 C, 将 B 合并至 C, 删除 B 重命名 C?
    Exp
        2
    Exp  
    OP
       2023-04-03 10:30:06 +08:00
    @xbcslzy #1 如果这样操作,那么合并之后的分支图显示的,应该是 B 的所有提交之后进行了合并到 C ?
    xbcslzy
        3
    xbcslzy  
       2023-04-03 10:34:28 +08:00
    @Exp 切完 C 先推到远程源就是 a1 啊 后面的合并什么的理论上不影响你的需求
    cubecube
        4
    cubecube  
       2023-04-03 10:36:28 +08:00
    以前也幻想过这么整。。最后强行 copy 的。丢了部分历史信息
    lechain
        5
    lechain  
       2023-04-03 10:37:13 +08:00 via Android
    在 a1 处 merge 分支 b ,然后基于这个 merge 产生的节点 rebase 原本分支 a 的 a1 到最新的所有改动,当然了,rebase 操作也可以换成 cherry-pick
    nothingistrue
        6
    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
        7
    ruanimal  
       2023-04-03 15:18:37 +08:00
    用 git-svn 试试?
    Nile20
        8
    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
        9
    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)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1467 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 17:13 · PVG 01:13 · LAX 09:13 · JFK 12:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.