繁体   English   中英

GIT 如何将更改从一个存储库的分支拉到另一个存储库的分支

[英]GIT how to pull changes from a branch in one repository into a branch of another repository

我知道这对某些人来说可能听起来很愚蠢,但我在一个分支中进行了代码更改并将这些更改提交给该分支。 此代码更改位于 a.Net 解决方案的特定存储库中,并且此解决方案与许多其他 .Net 解决方案共享。

我试图用 git 子模块做的是将代码更改从这个存储库下拉到我正在处理另一个代码更改的另一个存储库的另一个分支。

有没有办法可以专门拉下那个分支?

找到我的笔记,由于标记,无法在评论中很好地发布这个,基本行是这些:

git remote add local-origin /c/git/OTHER_REPOSITORY
git pull --rebase local-origin main --allow-unrelated-histories

您可能需要git cherry-pick 使用它并不是特别困难; 这里的设置很棘手。 你可能想要git merge ,有或没有--allow-unrelated-histories

背景:提交

重要的是要认识到 Git 与分支无关,在某种意义上甚至与文件无关。 相反,Git 是关于提交的——这反过来意味着您需要了解很多关于提交的信息:提交是什么,为您做什么,以及提交与其他提交的关系。

任何 Git 存储库中的每个提交都被编号,带有一个丑陋的随机外观hash ID (正式地, object ID或 OID),如c48035d29b4e524aed3a32f0403676f0d9128863 实际上,此 ID 是提交的真实名称(另请参阅TV Tropes ):具有此特定提交任何Git 存储库都将其存储在UUID下。 1个

每个提交都会存储一些元数据,包括作者的姓名和 email 地址以及一些日期和时间戳。 元数据包括先前(或)提交 hash ID 的列表——只是原始数字,但由于这些是这些提交的真实名称,因此 Git 可以找到这些提交。 并且 - 间接地 - 每个提交都会存储每个源文件的完整快照,就像提交作者进行该提交时的形式一样。

这样的结果是,只要给定 hash ID,Git 就可以得到:

  • 提交的完整快照(如果有的话);
  • 在类似条件下,此提交的提交的完整快照。

通过比较两个快照,Git 找出“发生了什么变化”。 提交存储快照,而不是一组更改。 需要两次提交才能“看到”任何更改。


1任何 Git object 的 OID 目前只是对象数据的 SHA-1。 一旦 Git 更广泛地支持 SHA-256,提交将有两个“真名”,这将很尴尬。 目前还不清楚最终将如何处理。


这对你意味着什么

我正在尝试做的......是将代码更改从这个存储库下拉到另一个存储库的另一个分支

两个存储库实际上可以共享提交:如果存储库A有提交c48035d29b4e524aed3a32f0403676f0d9128863我们简称为“提交C1 ”——并且独立的存储库B有提交C1 ,那么根据真名法则,这是同一个提交 并且 - 至少通常情况下,在没有浅克隆的情况下 - 如果你有一些提交,你有提交的父级,以及父级的父级,等等,一直回到时间第一次提交。

所以如果你想复制一些提交C2的更改,并且你提交C2 ,你可以让 Git 将提交C2变成“提交C2中的更改”。 git show命令执行此操作并显示更改的内容,并以有关来自C2元数据的提交的一般信息为前缀。 git diff命令可用于获取快照中的差异:您可以将C2与其(第一个并且可能是唯一的)父级进行比较。 其他 Git 命令也可以做同样的事情。

一旦你有了C2和它的父级之间的差异,你就可以将这个相同的差异应用于第三次提交C3 您可以手动执行此操作,这往往非常乏味。 或者你可以让 Git 为你做,用git cherry-pick

cherry-pick 命令的工作非常简单:您检查要用作起点的提交,通常使用git switchgit checkout

git switch somebranch

然后,您给git cherry-pick原始 hash 您想要复制其效果的提交的 ID。 或者,如果您有一个分支或标记名称,当解析为原始 hash ID 时,获取正确提交的原始 hash ID,您可以使用该名称,但我们在这里只使用原始 hash ID:

git cherry-pick c48035d29b4e524aed3a32f0403676f0d9128863

Git 现在找到您在此处指定的提交(我选择了C1 )。 必须存在于您当前的存储库中。 Git 使用该提交的元数据来查找该提交的父项:必须只有一个父项,因此这是一个普通的提交。 2 Git 将提交的快照(在本例中为C1 )与其父快照进行比较,找出更改的内容,然后找出如何这些更改组合到当前提交中。

这种组合在技术上是一种合并操作——“作为动词合并”,我喜欢这样称呼它——这意味着你可能会遇到合并冲突。 如果您确实遇到合并冲突,您可以按照通常的方式解决它们。 完成后,您可以使用git cherry-pick --continuegit commit来完成。 如果没有合并冲突, cherry-pick会继续并运行git commit来为您完成工作。 最终结果是普通提交,而不是合并,默认情况下 Git 会重新使用您现在复制的提交中的提交消息

新的提交是不同的——它有自己的新 UUID,它包含了你的名字和你的 email 地址以及当前日期和时间,以帮助确保它的唯一性——但它“做同样的事情”(有相同的差异,更多或更少)作为您刚刚复制的提交。


2您可以挑选一个根提交——一个没有父提交的提交——Git 将调用每个文件“新添加”。 如果您出于某种原因选择合并提交,这是一个具有多个父级的提交,您可以告诉git cherry-pick假装哪个父级是唯一的父级,以便它可以获得适当的差异。 但总的来说,无论如何你只会挑选一个“普通”(单亲)提交。


挂钩

从这个存储库到...另一个存储库

如果这两个存储库不是彼此的克隆,或者不是过去的,那么很可能不仅您的新提交不在两个存储库中(您只将它添加到一个),而且它的提交也不在两个存储库中存储库(一开始就没有)。

对于git cherry-pick ,这是一个show-stopper (意思是 3)。 为了使用git cherry-pick ,您必须将要复制的提交其父提交都放入您自己的存储库中。

幸运的是,这很简单:只需使用git remote add将包含您关心的两个提交的存储库添加到您现有的克隆 然后使用该遥控器运行git fetch 例如,假设您刚刚进行的提交位于$HOME/work/project23/中,并且您想要挑选到$HOME/work/project45/ HOME/work/project45/ 中的存储库中。 所以您现在位于第二个存储库 ( project45 ) 中:

git remote add project23 $HOME/work/project23
git fetch project23

您现在project23存储库中project45来自 project23 的所有提交 这确实会使存储库有些膨胀,但只要您有足够的磁盘空间,就无需再挑剔了。 您现在可以运行git cherry-pick命令。

当你完成并想要清理时,运行:

git remote remove project23

这将删除名称project23和对其他 Git 存储库的引用。 Git 将保留所有复制的提交一段时间,但最终会清除它们并且您的存储库将缩小,并且git push不会将所有这些提交复制到其他地方:它们只是占据那个特定克隆中的空间,直到 Git 绕过清理。

(如果你想强制 Git 提前清理,你可以运行git gc --prune=now ,但除非你的磁盘空间严重不足,否则我不建议这样做。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM