我通过以下方式将存储库从 mercurial 迁移到 git:
git init gitrepo
cd gitrepo
hg_fastexport -r <../hgclone>
(我希望我没有忘记任何事情)然后我在 GitLab 中创建了一个存储库,并在 gitrepo(hg-fastexport 将源代码导出到的地方)中创建了分支并像
git checkout -b v4.1
git push origin refs/heads/v4.1:refs/heads/v4.1
虽然它适用于 2 个分支,但它也显示在 Gitab 中,最后一个分支始终获取主分支的内容,而不是 v4.1 分支。
目前还不清楚您的实际问题是什么,所以我会为您编一个:
Git 如何在两个不同的分支中具有相同的提交?(汞不能。
这样做的原因是,在 Mercurial 中,提交没有独立于其分支的存在,而分支完全由其提交组成。 也就是说,每个提交都只属于一个分支。 分支名称是一个实体,表示"记录的分支是此实体的每个提交"。
相比之下,在 Git 中,提交独立于分支。 提交存在或不存在,只是因为它存在或不存在。 提交不会记录哪些分支(如果有)包含它。 分支名称只是一 (1) 个哈希 ID 的别名,它作为别名的哈希ID 可以随时更改。
在这两个 VCS 中,每个提交都会记录其父提交 ID:如果提交是普通的非合并提交,则至少记录两个 ID,如果提交是合并提交,则至少两个 ID(Git 中两个或更多,Mercurial 中正好两个)。 这意味着在任何一个 VCS 中,如果我们被赋予一些特定的提交,我们可以检查该提交并找到它的父级或(如果是合并的)父级。 然后,我们可以检查父项并找到它们的父项,依此类推。
如果我们对所有 Mercurial 所谓的head执行此操作,我们会在 Mercurial 存储库中找到所有提交。 提交充当有向、无循环图或 DAG 中的顶点(或节点);连接这些节点的弧是父 ID。 我们发现这种方式的每个提交都恰好在一个分支上,并且每个提交都记录了它所在的(单个)分支。
相比之下,在 Git 中,我们真的不知道从哪里开始。 我们可以详尽地枚举整个存储库以查找所有对象(Git 在其存储库数据库中有四种类型的对象),挑选所有提交对象,并从这里形成 DAG。 但是,这些提交没有分支标识:我们不知道提交在哪个分支上! 此外,这种详尽的枚举需要很长时间(甚至在大型存储库中也需要几分钟),因此我们几乎从不打扰。
相反,我们采用完全不同的方法:我们从存储在一个分支名称中的哈希 ID 开始,例如master
. 使用这个分支名称,我们找到一个提交。 根据定义,该提交是在master
. 然后,我们使用存储在该提交的哈希 ID 找到该提交的父级。 根据定义,这些提交也在master
上。 我们重复此过程,直到通过 DAG 跟踪所有可访问的父弧,我们已经确定了可从名称master
访问的每个提交,并且所有这些提交都在master
上。
但可能还有更多的分支名称。 所以我们从另一个名字开始,比如v4.1
. 此名称包含一个哈希 ID,用于查找提交。 根据定义,该提交是在v4.1
. 然后,我们找到该提交的父级,就像以前一样。 根据定义,这些提交也在v4.1
上。 我们重复此过程,直到通过DAG跟踪所有可访问的父弧,我们已经确定了可以从名称v4.1
访问的每个提交,并且所有这些提交都在v4.1
上。
请注意,在大多数提交 DAG 中,通常有一个初始提交,所有其他提交都是从该提交派生的。 在 Mercurial 中,这个提交位于一个分支上,可能是名为default
的分支。 在 Git 中,这一次提交在每个分支上。
因此,Git 提交和 Mercurial 提交之间的根本区别在于 Git 提交同时位于多个分支上。包含任何给定 Git 提交的分支集是动态确定的,方法是咨询所有分支并通过DAG 跟踪所有分支,直到我们看到此特定提交可以从分支尖端的一个特定提交访问或不访问。 如果可以通过这种方式访问,则它位于该分支上;如果不是,那就不是。
这样做的结果是分支创建是不同的
在 Git 和 Mercurial 中,要创建一个新分支,您需要告诉 VCS"创建一个新分支",但除了在一个新的空存储库中之外,立即操作非常不同。1
在 Git 中,要使分支名称存在,该名称必须标识一个特定的提交。 Git 称之为分支的提示,我们说分支名称指向该特定提交。 但是在一个新的空仓库中,没有提交,所以不能存在分支名称!
Mercurial 有一个类似的问题:一个分支由该分支中的所有提交组成。 在一个新的空仓库中,没有提交,所以不存在分支!
尽管如此,Git 和 Mercurial 都有当前分支的概念。 当前分支是将在其上进行新提交的分支。 这允许两个 VCS 将当前分支名称记录为实际上尚不存在的分支。 完成此操作后,创建新提交会产生创建分支的副作用。 两个 VCS 都为一个新的、完全为空的存储库执行此操作:第一次提交创建当前分支(通常为default
和master
)。
在Mercurial中,这一切都非常简单和自动:你创建一个新的提交;它的分支是记录的"当前分支";如果这是第一次在分支xyzzy
上创建提交,那么,现在xyzzy
上至少有一个提交,所以xyzzy
存在。
但是当 Git 创建一个新的分支xyzzy
并且有一些现有的提交和分支时,Git 只是立即创建xyzzy
,指向当前提交。 假设您之前在master
上,并且刚刚创建了xyzzy
。 名称xyzzy
和master
现在指向同一个提交:现在之前在master
上的所有提交都在master
和xyzzy
上。
简而言之,这在 Git 中是完全正常的。在分支v1.4
上创建一个新提交将使该新提交仅在分支v1.4
上,至少在发生其他事情使其他分支也包含该提交之前。 在分支上创建新提交时,会告诉 Git 将该分支提示设置为指向新创建的提交。 新创建的提交的父 ID 将是之前的提示(因为这是您签出的),因此分支现在包含它之前包含的每个提交,以及刚刚进行的新提交。
1你可以使用git checkout --orphan
使 Git 的行为更像 Mercurial,但如果你这样做,你所做的下一次提交将创建一个新的根提交 - 一个没有父级的新提交,在提交 DAG 中创建一个单独的子图。 这几乎从来都不是你想要的:在 Git 中,你希望提交同时在多个分支上。 您始终希望这种"孤立分支"行为的一次是在一个新的空存储库中创建第一次提交。
git checkout -b v4.1
-b
告诉 git 从您当时所在的任何分支(可能是master
)创建一个新分支,然后切换到它,这意味着分支v4.1
将指向与源分支完全相同的提交(再次,可能master
)...
您似乎忘记在推送之前提交更改。
分支v4.1
将仅包含您在提交更改后所做的更改。
我发现了我犯的错误。也许问题不是那么清楚,但是当我创建一个新分支时,该分支将始终具有主节点的内容。它将不包含分支。原因是,在我从 mercury 迁移到 git 之后,我忘记了查看 HEAD。似乎那时我正在处理主节点或分支,但是当我忘记签出(新迁移的 HEAD)时,新分支和主节点的内容保持不变。
我将在这里提供一张收据,该收据导致了正确的存储库。
克隆 Mercurial 目录:
- hg clone http:mercurial.com ./hgclone
初始化 git 目录:
- git init git-dir
-
CD Git-dir
-
将 Mercurial 迁移到 git:hg-fast-export -r ../hgclone
- git 结帐头
- 添加 git 存储库:git 远程添加源$remoterepo
- 添加当前目录:git add .
- commit:git commit -m "Initial Commit">
- 推送:git push -u 源主
列出用于创建分支并将其更新到远程 git 目录 -吉特分支
签出并将分支添加到远程 Git 目录:
- 吉特结帐分支
- git add .
- git push origin refs/heads/branch:refs/heads/branch
这些是将汞存储库导出到 git 并使用正确的分支将它们存储到远程 git 存储库的基本步骤。