
[英]Why is a git merge required if I want to amend last remote commit?
[英]git: why would a merge commit be required for replacements?
我们的git repo是从其他VCS(Perforce)导入的,但是标准导入无法恢复分支关系(即,分支1.1源自分支1.0)。 为了解决这个问题,我们添加了git replace --graft <commit> <parent>
: git replace --graft <commit> <parent>
记录从创建每个分支到其父提交的缺失关系。
因此,我们有一个git存储库,该库在.git / refs / replace中有一些替换。 (这些可能应该已经通过某种方式的重新定位而删除,但现在可能为时已晚)
这些替代品必须使用以下方法手动拉出:
git pull origin 'refs/replace/*:refs/replace/*'
一位同事没有意识到这一点,但是可以以某种方式将更改推送到仓库中,从而:
git pull origin 'refs/replace/*:refs/replace/*'
导致合并冲突,例如:
Simple merge did not work, trying automatic merge.
ERROR: /some/file: Not handling case c6aa12b3f446c57921a68c5fc73dae9e086c2bdb -> -> bb909246180daf894ccdb59cc4a4ff398ac62bad
fatal: merge program failed
Automated merge did not work.
Should not be doing an octopus.
Merge with strategy octopus failed
我不明白这里要合并的内容。 如果我使用:
git pull origin 'refs/replace/*:refs/replace/*' -s ours
合并成功,并且我最终(在提交之后)显示如下合并消息:
commit 67d7f7cc40826e8a84beed3af9999d39e411e65d
Merge: 718dbe3 c9333d1 b870b22 d3f10f7 77d0835 de79e03 d7f0e7c 97ca1f8 Author: xxxxx
Date: Tue Jul 11 11:33:55 2017 +0100
Merge commits 'refs/replace/00029d7b3e531215f6ce5afb32862b49d652e896', 'refs/replace/03d715c9890e5cec95ac62d1c9ecc54cb78b9f62', '
git声称已更改了几个文件,尽管这些文件最近未更改。 我怀疑它们是两个旧分支之间的区别。
合并/拉动之后,我们在.git / refs / replace中进行替换。
我同事的报告声称,推动的变化包括移植了他所需要的丢失的分支关系中的2个。 这些根本不会出现在.git / refs / replace中。
如果将它们与早先推送的内容混为一谈,则还有其他一些问题:
他如何能够在不首先解决合并冲突的情况下进行推送?
同样,如果您从存储库克隆而不拉取替换,则他添加的关系仍将被拉取。 有两个带有提交消息的讲故事提交,例如
Former-commit-id: bc735afc1d8bb842733cb94767afb8b42599eb6a
但是没有.git / refs / replace目录描述替换项。
我的同事如何才能将自己的嫁接作为永久更改回购协议而永久撤回,而在较早的回购协议中则自动撤回? 并且根本没有.git / refs / replace目录?
有人可以启发我这里发生的事情吗?
我还能做些什么使其他分支机构的关系永久化而无需重写历史记录? 我的同事似乎已经做到了,但我不知道如何做。
总结答案:
在git中,推送的相反是获取而不是拉
我的同事不会因为没有一个而出现合并问题。 这是我使用'pull'而不是'fetch'的产物。
谢谢您的帮助。
我认为99%的困惑来自于您使用pull
而不是fetch
复制替换代表的事实。 我希望这是为了让章鱼将所有替换参考合并到您的当前分支中,这当然是荒谬的。
永久更改提交的方法是重写历史记录,从长远来看,您可能应该继续做下去,而不要过于依赖替换机制。 显然,这需要团队的协调,但这是一次性的成本,然后此后回购将更加无缝地工作。
标题问题(“为什么需要合并提交才能进行替换?”)的答案是: 不需要。
这是使用Git的重要规则:切勿使用git pull
。 :-)
(一旦您精通Git,就可以放宽此规则, 仅在确切知道将要发生的情况时才使用git pull
。)
在这种情况下,您应该运行:
git fetch origin 'refs/replace/*:refs/replace/*'
然后就此停下来
如果您打算继续使用替代品,则可能希望将其添加到每个远程服务器的fetch =
行中。 (请注意,一旦开始使用替代品,您往往会陷入困境,因此这可能是一个合理的选择。另一种选择,例如Mark Adelsberger的回答 ,是将替代品连接起来,例如,使用op git filter-branch
。)此“添加fetch
设置”必须在每个git clone
之后手动完成,因为普通克隆不会获取替换名称空间名称。 (这也与以前的镜像克隆问题有关: 镜像克隆会奴役地获取所有 refs/*
引用,其中包括替换名称空间。)
git pull
命令是为了方便快捷。 它首先运行git fetch
,这是从其他存储库获取提交和其他项的实际操作。 然后,它运行另一个Git命令。
在大多数情况下,从另一个Git存储库获取项目(例如提交)后,您必须采取一些措施以自己使用这些项目。 获得它们只是将它们复制到您的存储库中,为它们提供某种参考名称-通常是远程跟踪分支名称 ,例如refs/remotes/origin/somebranch
。
采取的措施通常是git rebase
,有时是git merge
。 git pull
命令将为您运行git merge
,即,执行错误的操作,除非您告诉它改为为您运行git rebase
。 当然,这仍然可能是错误的操作-在这种情况下,它是 。
您要提供的引用位于refs/replace/
名称空间中,而不是refs/heads/
名称空间(具有分支名称),而不是refs/tags/
名称空间(具有标签名称)。 refs/replace/
name-space保存替换项目 。
与分支名称的正常使用相比,替换和标记具有一个奇怪的功能: 无需使用任何操作即可使用它们。 随着分支机构的名称,当你获得refs/heads/master
从莫妮克的仓库,你把它重命名为refs/remotes/monique/master
,这样就可以让你的 master
-a分公司, refs/heads/
她 -独立的master
,您只能将其保留为远程跟踪分支。 然后,您将采取部分合并或调整基准的操作,以将她的工作并入您的工作。
但是,使用标签名称,您可以使用Monique的refs/tags/v2.3
并将其称为refs/tags/v2.3
。 现在,您俩都共享了标签v2.3
,并且无需执行任何其他操作:您的Git将在您自己的refs/tags/
名称空间中查找标签名称v2.3
。
替换也是如此。 在Git中,替换对象由具有特殊模式的refs/replace/
名称空间名称表示:与refs/replace/master
或类似名称相比,我们找到了refs/replace/b06d3643105c8758ed019125a4399cb7efdcce2c
类的名称。 该名称映射到替换对象本身。 也就是说,那个长而有毛的长名称映射到另一个长而丑陋的Git哈希ID,Git可以使用该ID来访问其他 Git对象。
为了便于记忆,我将使用blah
代替下面的b06d3643105c8758ed019125a4399cb7efdcce2c
。 因此, refs/replace/blah
映射到另一个ID,我们可以将其称为bazinga
。
当您的Git即将对哈希ID为blah
的内部对象执行某项操作时,它会注意到存在refs/replace/blah
。 然后,它不使用常规的blah
对象,而是查找bazinga
对象,并使用该对象。 (使用--no-replace-objects
Git跳过此“检查refs/replace/
”步骤。)
这就是替换的工作方式,因此,当您使用它们时,您应该只获取它们并停止。
如果查看.git/config
文件,您将看到以下形式的行:
[remote "origin"]
url = ...
fetch = +refs/heads/*:refs/remotes/origin/*
添加以下形式的行(保留原始fetch =
位置):
fetch = +refs/replace/*:refs/replace/*
将使每个git fetch origin
自动拾取任何新的替换对象。 有关此内容的更多信息,请参见我对这些“ git fetch”语法之间的区别有何回答?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.