什么相当于gg中的hg pull和merge

时间:2014-09-09 19:52:03

标签: git merge mercurial

来自mercurial,我在git的术语和方法上苦苦挣扎。以下是目前的情况:

两台服务器共享同一个存储库。

  • 在服务器1上,开发人员将更改提交到file.php。
  • 在服务器2上,开发人员提交了对file.php的更改。相同的变化,但不同的提交。

我需要将这些变更集同步回来

要在mercurial中解决此问题,我将从Server 2运行以下3个命令。任何合并冲突都将在编辑器或融合中解决。

hg pull -u ssh://remote-server1//shared-repository
hg merge
hg commit -m "Branch Merge"

你如何用git做到这一点?

我做了什么

使用https://www.mercurial-scm.org/wiki/GitConcepts作为指南,我尝试了git pull,但由于我没有运行git config,因此失败了。该存储库正在制作中并由许多人共享,因此我试图避免设置用户名。

https://stackoverflow.com/a/17713604/456645之后,我运行了这个命令:

git fetch ssh://remote-server1//shared-repository

它回应

From ssh://remote-server1//shared-repository
 * branch            HEAD       -> FETCH_HEAD

我还没弄清楚如何在这种情况下正确运行git reset

git reset ssh://remote-server1//shared-repository/master 
# FAILS (fatal: Invalid object name 'ssh'.)

git reset origin/master
# FAILS (fatal: ambiguous argument 'origin/master': unknown revision or path not in the working tree.)

git reset FETCH_HEAD/master
# FAILS (fatal: ambiguous argument 'FETCH_HEAD/master': unknown revision or path not in the working tree.)

进一步看,我很困惑,只找到一个分支

git branch -a
* master

为了确保它没有自动合并,我查看了历史记录

git log -n 3 
# Here, I find the changesets that previously existed.  Nothing new

此时,我甚至不知道git fetch会发生什么。我没有看到取物的证据。

2 个答案:

答案 0 :(得分:4)

TL; DR版本

为每个存储库添加一个遥控器。我会调用两个存储库alexbob,但您可能应该选择更合适的名称。请注意,如果您git clone其中一个,那个名称将自动origin(尽管您可以选择其他名称)。下面假设您已经有一个相关的存储库,并且需要添加两者,但如果您已经有origin,则只需要添加另一个。

$ git remote add alex ssh://their.domain.name/their/path/to/repo.git
$ git remote add bob ssh://bobs.domain.name/and/his/path.git

之后,您可以轻松git fetch来自他们的所有内容(所有分支等):

$ git fetch alex
$ git fetch bob

您现在拥有"远程跟踪分支机构"名为alex/masteralex/develop等的名称,只要Alex有名为masterdevelop等的分支;如果Bob有bob/master,那么你有master等等。

现在,如果您希望合并东西,您可以创建与其中一个相对应的您自己的本地分支:

$ git checkout -b alex-master alex/master

alex-master是一个本地分支;如果您愿意,可以将其称为master,但每个本地分支名称必须是唯一的,因此您可能必须移动自己的现有master首先放弃)并与bob' s合并:

$ git merge bob/master

(这会将bob/master合并到您的本地alex-master)。如果您有权限,可以将结果推回到Alex的master

$ git push alex alex-master:master

以及Bob的master

$ git push bob alex-master:master

" refspec"作为git push的最后一个参数给出了冒号左侧的本地分支名称,以及右侧的本地分支名称。

与Mercurial不同,没有特殊的分支名称; master只是传统的,而在hg中,default有点神奇。 (好吧,git中master有一个特殊的魔术位:它改变了git merge拼写默认提交消息的方式。但这真的是关于它的。)


这有很多部分,其中一些主要是化妆品/便利性,其中一些至关重要。

首先,在git中,这些天主要通过"遥控器"来指代存储库。远程部分是一种便利构造,但在获取和保留来自另一个存储库的提交方面,这也是关键部分。

Mercurial有一些比遥控器简单得多的东西,但它提供了部分便利:在[paths]文件的.hgrc部分,您可以在短名称下列出长URL:

[paths]
short = ssh://something.very.long/with/a/very/long/path/that/is/a/pain/to/type/every/time

或其他什么。将其与.git/config中的git" remote"进行比较:

[remote "short"]
    url = ssh://something.very.long/with/a/very/long/path/etc

到目前为止,这些都是完全相同的,只是使用不同的拼写/语法。但接下来就是这样:

    fetch = +refs/heads/*:refs/remotes/short/*

(事实上,这通常是之前 url,但这两者的顺序并不重要。我们稍后会回过头来看看。


接下来,hg pull的最直接等价物确实是git fetch。但是,hg pull-ugit fetch肯定这样做,因为两个操作的内部结构完全不同,因为它们之间存在差异Mercurial分支和git分支。

Mercurial分支是一种真实的东西",而git分支则更为短暂。更具体地说,git分支更像是Mercurial书签,而不像Mercurial分支。但是,有一个概念(或者可能是#34;自负"可能是一个更好的词),这里根本没有正确翻译:具体来说,添加到Mercurial存储库的提交按顺序编号并保留在存储库中如果没有什么可以说出来的话:你最后还会找到一个匿名的头。例如,您可以使用提交图(显示为hg log --graph等),如下所示:

o
|  o
o  |
|  o
o /
|/
o

不需要任何外部名称指向这两个头;他们只是匿名的头(在一个分支内,因为根据定义,所有hg中的提交都在某个分支内)。

相比之下,在git中,没有外部名称的提交有资格被垃圾收集(hg可能会调用"剥离",尽管细节不同)。因此所有hg调用" head" 必须有某种名称。这是远程fetch =行开始生效的地方。

"但等等,"你可能会问,"我可以做git fetch ssh://...而且没有命名的遥控器!"这就是HEAD -> FETCH_HEAD位的来源。

如果您没有"远程",您仍然可以从另一个存储库引入一些分支(甚至多个分支)。然而,由此获得的任何分支的头部都需要名称。这个"名称"被填充到名为FETCH_HEAD的伪分支中。细节变得复杂,但如果你只带来一个分支,就像在这种情况下,它更容易解释和思考:基本上,git带来一个命名分支,并在你的本地存储库中给出这个名称为FETCH_HEAD

请注意,后续的git fetch通常会覆盖FETCH_HEAD,此时您带来的所有提交都有资格进行垃圾回收。因此,一旦提交了提交,就需要另一个步骤。


现在,一旦你有一些提交并希望保留它们,有不同的方法来做到这一点。最hg pull - 就像使用"遥控器"机制。在这里,fetch =行解决了这个问题。当你从遥控器git fetch时,遥控器的分支名称指向所有分支头(根据定义,因为git 需要这个)。这些分支名称是refs/heads/name形式的引用。

fetch =行告诉git如何重命名分支,以便它们在本地存储库中具有新的唯一本地名称。例如,通过将refs/heads/master重命名为refs/remotes/short/master,您可以获得short/master作为远程调用"分支master"的新本地名称。这保留了提交,我们很好(虽然我们仍然需要合并)。

或者,我们可以将一个有趣的分支结束并调用它FETCH_HEAD然后立即合并。当我们这样做时,我们选择一些本地分支(例如master),如果需要,请检查它,然后运行git merge FETCH_HEAD

一旦完成合并,我们的本地分支(在此示例中为master)可能通过合并提交指向我们通过git fetch带来的提交,因此它们不是更容易受到垃圾收集的影响:它们位于分支上,因此可以通过该分支名称进行命名。我们现在可以随时安全地覆盖FETCH_HEAD

最后一种方法 - 将内容放在一边,但命名为FETCH_HEAD,然后将本地分支与FETCH_HEAD合并 - 就是" git pull"命令呢。从这个意义上说,它只是git fetch后跟git merge。我个人试图避免使用pull脚本,因为它有很多额外的魔法可以处理各种角落情况,在过去,在一些未经考虑的角落情况下会出现问题;一般来说,我更喜欢获取,查看发生的事情,然后选择是否以及如何合并或修改我自己的代码。


最终没有单一的正确方法,但如果你不止一次这样做,我会添加一个git遥控器,并使用"远程分支"概念(fetch =内容重命名"他们的"分支到您自己的本地存储"远程跟踪分支")。

答案 1 :(得分:1)

编辑:通常情况下,一个git遥控器是一个"裸露的"存储库,这意味着您无法在服务器上签出工作副本。即使服务器仓库是一个裸仓库,这也会有效。

Clone 您本地计算机的其中一个存储库:

$ git clone ssh://remote-server1//shared-repository

进入该文件夹:

$ cd shared-repository

Add 第二个名为server2的 remote

$ git remote add server2 ssh://remote-server2//shared-repository

Fetch 以及服务器2上的存储库中的所有内容(与nq pull相同):

$ git fetch server2

Merge 将server2的主分支导入您的本地主服务器:

$ git merge server2 master

Push 结果返回服务器2:

$ git push server2 master

Push 返回服务器1的结果(来源是您克隆的远程):

$ git push origin master