Jon*_*onN 0 git mercurial push tortoisegit sourcetree
我已经使用TortoiseHg/Mercurial多年了,现在第一次使用 Git 与SourceTree和TortoiseGit GUI。从这个链接我了解到PUSH在Git上与Mercurial不同。 Mercurial PUSH仅影响远程存储库,但不影响工作区。 另一方面,使用 Git 进行 推送不仅会更新存储库,还会更新工作区(以及 Mercurial 没有的索引)。
我的问题是Git是否具有与 Mercurial PUSH等效的功能?我可以推送到远程存储库并保持工作区和索引不变吗?我知道Git FETCH相当于 Mercurial PULL,因为它们都不会修改本地工作区。实际上,我正在寻找Git 的反向FETCH 。这是可能的还是我必须始终打开远程存储库并执行FETCH操作?
编辑:TL;DR 摘要:
\n\n使用 Git 时,您可以推送到人类使用的具有工作树的存储库。您不应该推送到该存储库中的当前分支,至少在没有特殊考虑的情况下是这样。所以 Git 默认阻止这个。
Mercurial 允许您推送到此类存储库,包括推送到“当前分支”\xe2\x80\x94,这句话在 Mercurial\xe2\x80\x94 中的含义有所不同,因为在 Mercurial 中,Git 所称的“分离头”是正常且可用状态。这可以在 Git 中完成,只是不太实用。
因此,Git 提供并且您通常应该使用裸存储库作为推送目标。它们没有工作树,因此 Git 允许推送到它们,甚至推送到“当前分支”(Git 的概念,而不是 Mercurial 的概念)。
完整回复原文如下。
\n\n正如MrTux 所说,这种说法是错误的:
\n\n\n\n\n另一方面,使用 Git进行推送不仅会更新存储库,还会更新工作区(以及 Mercurial 没有的索引)。
\n
在推送更新存储库时(像往常一样添加新提交),它至少不会、默认情况下不会更新索引,也不会更新工作树。(从 Git 2.4.0 开始,可以在 Git 版本中进行配置以执行此操作。)
\n\n这里的问题是一些相当深刻的哲学概念之间的不匹配。对此的回答是:
\n\n\n\n\n我的问题是 Git 是否具有与 Mercurial PUSH等效的功能?我可以推送到远程存储库并保持工作区和索引不变吗?
\n
是“是的,使用分离的 HEAD”,但这个答案并不像您想象的那么有用。
\n\n在 Mercurial 中,当前修订版本(称为.
,与 Git 中的名称相对应HEAD
)会被签出,并且可能会被修改,其方式与在 Git 中使用 Git“分离头”时的方式大致相同(尽管有一些重要区别)。索引本身\xe2\x80\x94存在并暴露在Git中,但不以这种形式存在,并且隐藏在Mercurial\xe2\x80\x94中,并不直接相关。
问题在于,在 Mercurial 中,当前分支与当前修订版完全分开。在 Git 中,两者深深地交织在一起。显然,当前修订版位于 Mercurial 的某个分支上:所有修订版均位于 Mercurial 中的某个分支上。但在 Mercurial 中,所有修订都只在一个分支上。在 Git 中,修订\xe2\x80\x94a 提交\xe2\x80\x94 可能同时位于多个分支上:无、一个、两个、十个或数千个。虽然提交是不变且永久的(在 Git 和 Mercurial 中),但包含提交的分支集在 Mercurial 中是固定且不变的,但在 Git 中完全是流动的。
\n\nGit(故意1)放弃了这样的想法:分支名称不仅仅是一个临时的、短暂的标签。分支名称的使用只是为了标识一个特定的提交,目前主要供人类使用,但也供在git push
和期间使用git fetch
。
因此,由于HEAD
在 Git 中包含分支名称\xe2\x80\x94let\'s 将其称为cb
当前分支 \xe2\x80\x94 并且分支名称包含提交 ID,因此如果我们将名称更改为,我们将遇到可怕的麻烦-ID 以意外方式映射。如果收到推送更新cb
,当我们(通过HEAD
)使用它作为当前修订版时,我们会感到困惑:我们会相信我们的索引和工作树适用于cb
现在指向的提交,而不是cb
使用过的提交更新前点。
同样,这在 Mercurial 中不是问题,因为在 Mercurial 中,系统知道哪个是当前版本。将新的修订(提交)推送到分支不会影响我们当前的修订,事实上,如果我们在没有更新的情况下进行新的提交,我们只会得到一个新的提交,它是一个新的头(小写,不是 Git 的全部)帽子的HEAD
事情)。这个新头将没有名称,除非我们使用书签,但没有名称的头是 Mercurial 中的常见状态。我们只是跑去hg heads
找这些未命名的头,并对hg update -r
这些头进行修改(例如将它们合并,通常与其他头合并)。
在 Git 中,你可以精确地得到这种状态:那就是“分离的 HEAD”。分离的 HEAD 直接包含提交 ID,而不是分支名称。现在,Git 不会丢失当前修订版(或者更确切地说,提交哈希 ID),因此可以安全地推送到此存储库。
\n\n问题是,当你有一个分离的 HEAD 时,虽然你可以进行新的提交,但它们只能通过名称来记住HEAD
。它们不在树枝上。(如果您愿意,您可以称为HEAD
“匿名分支”。它有名称HEAD
,但HEAD
实际上不是分支名称,因为所有分支名称都半秘密地以 , 开头refs/heads/
,但HEAD
不是。)为了让 Git 更永久地记住它,您可以必须给这个东西一个分支名称:
git checkout -b newbranch\n
Run Code Online (Sandbox Code Playgroud)\n\n其HEAD
从“分离”变为“附加”,到新分支newbranch
。分支名称newbranch
现在存储提交哈希 ID,名称HEAD
现在存储分支名称newbranch
。
但现在你无法推动newbranch
!
因此,只要HEAD
不是“分离”,就有一些分支你不能,或者至少不应该推送到......并且为了HEAD
正常工作,它最终必须重新附加到一个分支,也许是一个新分支。
请注意,您可以推送到任何其他分支。所有其他分支都不在索引中,也不在工作树中。
\n\nGit 2.4.0 及更高版本中的新功能是您可以设置receive.denyCurrentBranch
为updateInstead
. 当这样设置时,接收端的 Git 会git push
检查:
HEAD
其中是否有分支的名称,如果有,推送是否会更新该分支名称?receive.denyCurrentBranch
:\n\ntrue
或refuse
:拒绝推送false
或者ignore
:接受推送,保留索引和工作树,依赖使用此存储库的人知道要做什么warn
:接受推送,向正在执行推送的人打印警告(理想情况下,这是同一个人知道该怎么做,否则警告是无用的)。updateInstead
:再检查一件事(见下文)。在这种updateInstead
模式下,事情变得复杂。参见文档中git config
的描述以及文档中push-to-checkout
对钩子的描述。简而言之,如果索引和工作树是干净的,则通常会允许推送,并且接收存储库将更新到新的分支提示。githooks
不过,一般来说,最好的选择是更简单的规则:只是不要这样做。2 不要推送到有人在其中工作的存储库。这是个坏主意。仅推送到从未有人在其中工作的存储库。将 Git 存储库配置为“裸”可以保证没有人可以在其中工作,因为它没有工作树。
\n\n1这要么是一个绝妙的想法,要么是一个糟糕的想法,或者可能两者兼而有之。无论哪种方式,它都是完全不同的。
\n\n2这可以称为反耐克规则。:-)
\n