首页 > 解决方案 > 对本地主服务器进行更改后,我们应该使用推送或合并到远程主服务器吗?

问题描述

我从 git 克隆了一个 android 项目,并创建了一个名为devBranchfrom的本地分支master

我做了很多改变,devBranch我也远程推送了它。

现在,一旦我完成了所有更改,devBranch我将这些更改合并到主本地分支。

现在我想将本地主机中的这些新更改推送到远程主机。

什么是合适的方法?我应该使用推送还是合并,为什么?

标签: androidgit

解决方案


比较git push不是git merge很明智:

  • git push命令是关于向负责其他存储库的其他 Git 发送一些提交,以便其他存储库获得新的提交,然后要求其他 Git 调整某些分支和/或其他名称在另一个存储库中。

  • git merge命令很复杂,但以其中一种典型方式使用时,就是在您自己的存储库的当前分支中进行新的提交。这个新的提交通常是一个合并提交,有两个父级,而不是更常见的一个父级的普通提交。

现在,有些情况下git merge 不会进行新的提交,而是执行快进操作。快进操作是分支名称的更改,以便存储在该名称中的新提交哈希 ID 标识其哈希 ID 先前存储在该名称中的提交的后代。(这是一个非常专业的术语,需要一些图论才能理解。请参见下面的简单示例。)

git push命令还可用于不发送提交,但仍请求其他 Git 存储库对其分支名称之一进行更改。无论您的 Git 是否发送任何新提交,此更改都可以是一个快进操作。实际上,如果分支名称更改是非快进操作,则该git push命令需要--forceor--force-with-lease选项。

既然两者都git merge可以git push进行这种快进动作,那么至少有一种情况,两者有几分可比性。但是,这种特殊情况的主要区别在于,git merge它在您的存储库中git push执行快进,而在其他Git 存储库中执行快进。

可以说,底线很简单:

  • 如果您需要进行合并提交,则必须在本地进行。该git push命令不能这样做。
  • 如果您不需要进行合并提交,请问问自己谁的分支名称需要什么样的更新。要更新您自己的分支名称,请在本地工作。要更新其他一些 Git 存储库,请使用git push.

请记住,存储库共享提交(通过哈希 ID),但有自己的私有分支名称。你的名字不是其他任何人的名字,也不需要以同样的方式使用——但人类是人类,我们倾向于以同样的方式使用相同的名字,因为如果称你为 Fred 而你的同事称你,那就太混乱了Piotr 当你的名字实际上是 Rahul。

画出快进意味着什么

为了理解 Git 的快进概念,让我们从分支名称保存提交哈希 ID 的事实开始,提交也保存提交哈希 ID。每当某事物拥有提交哈希 ID 时,我们就说该事物(无论它是什么)指向该提交。所以一个提交指向另一个提交,一个分支名称指向一个提交。

任何给定提交的实际名称都是一些丑陋的散列 ID,faefdd61ec7c7f6f3c8c9907891465ac9a2a1475例如。这些输入起来太烦人了,人类也很难记住,所以让我们用大写字母来绘制我们自己的 Git 提交图片段来代替每个提交。在这里,我们连续提交了三个提交,最后一个(最新的)提交是 commit H

... <-F <-G <-H

由于H最新的提交,我们将有一个分支名称指向它:

... <-F <-G <-H   <--master

同时,提交H本身实际上存储了早期提交的原始(和真实)哈希 ID G。所以H指向G. CommitG反过来将之前提交的哈希 ID 存储在其中FG指向F. 这就是我们在这里绘制的。

任何提交的任何部分,一旦完成,就无法更改。这意味着我们实际上不必将提交之间的内部、向后指向的箭头绘制箭头:我们可以将它们绘制为连接线。当我们开始添加更多的提交时,这很有用H,使用另一个名称来查找它们:

...--F--G--H   <-- master
            \
             I--J   <-- dev

在这里,分支名称dev指向 commit J,向后指向 commit I,向后指向 commit H,依此类推。同时,名称 master仍然指向现有的 commit H

我们现在可以让 Git “master向前滑动名称”。如果我们只进行一次提交,master最终会指向I,如下所示:

...--F--G--H--I   <-- master
               \
                J   <-- dev

请注意提交没有改变:我们刚刚将提交画I高了一行,因为没有其他好的方法可以在 StackOverflow 上绘制它们。名称发生了变化,或者更准确地说,存储名称中的值发生了master变化,因此master现在指向I.

如果我们master一直向前滑动,我们会得到:

...--F--G--H
            \
             I--J   <-- dev, master

现在根本没有理由继续纠结:

...--H--I--J   <-- dev, master

就够了。

这个操作——移动主“向前”一个或多个提交——是 Git 所说的快进,因为即使masternow 指向Ior J,我们也可以通过从我们现在通过该名称找到的任何提交开始,向后工作到 wheremaster是以前。它commit 处H,并J指向Iwhich 指向H. 所以 commitH保留名为master.

但是如果我们从这个开始:

...--F--G   <-- master

然后添加一个新名称dev也指向现有提交G

...--F--G   <-- dev, master

然后进行一个新的提交master,使它指向这个新的提交H,然后检查分支dev并进行一个新的提交,dev这样它就指向dev了新的提交I?我们现在将拥有:

          H   <-- master
         /
...--F--G
         \
          I   <-- dev

master(位于 commit 的位置H),我们可以返回到 commit G,然后是 commit F,依此类推。从——dev提交I——我们也可以返回到G等等F。但是这些连接提交的箭头完全是向后的箭头。我们不能从G到“前进” H。Git 的连接只指向backs。在我们返回之前,我们需要名称master以便找到 commit 。H

如果我们强制 Git 将名称移动master到 commit I,我们最终会得到:

          H   ???
         /
...--F--G
         \
          I   <-- dev, master

提交仍然存在,但我们无法找到它的哈希 ID 。提交H丢失:它仍然存在(一段时间),但除非我们强制 Git 合理地快速恢复它,否则 Git 最终会完全删除它,因为它是不必要的。1 这种提交H丢失的强制名称运动是非快进的

如果我们想加入提交HI保持两者的工作完成,我们将需要使用git merge(或类似的东西)。


1在正常的存储库中,Git 留下的痕迹可以让我们至少再恢复 30 天的提交。在服务器上的裸存储库中,恢复时间要短得多。


推荐阅读