Git推送单提交不起作用

时间:2018-06-25 11:20:06

标签: git bitbucket push

我尝试仅推送ID为 9973b14ca19e4571046d8d25bc986ec07199e39c 的提交。

git push bbef 9973b14ca19e4571046d8d25bc986ec07199e39c:refs/heads/feature/25062018_offline-seite_ef

我登录到Bitbucket来创建拉取请求,但我注意到,即使这是一个新的远程分支,也存在多次提交。

所以我删除了bitbucket中的远程分支,然后再次将其推送,结果相同...

enter image description here

为什么它不起作用?如何只推送单个提交而不是多个提交?为什么会发生?

2 个答案:

答案 0 :(得分:2)

运行git push时,您会将Git优惠提供给另一个Git:

  • 特定提交(按哈希ID或名称), plus
  • 导致 特定提交的整个提交历史。

(另一个Git会告诉您的Git何时停止提供先前的提交,因为另一个Git已经拥有了它们。)这正是您所看到的。

这将有助于停止,备份和绘制提交图(或至少一部分)。您可以运行git log --graph-我通常更喜欢“来自DOG的帮助”变体git log --all --decorate --online --graph A ll D ecorate O < / strong> neline G raph = ADOG-让Git为您绘制粗略的图形。一些GUI用自己的方式绘制图形。

请记住,在Git中,分支名称只是一(1)个哈希ID的人类可读名称。每个提交在提交时都会分配一个唯一的哈希ID,但是每个提交还包含其 parent 提交的哈希ID(通常只有一个或两个用于合并提交),并且这些字符串一起提交到分支分支中,并在合并提交时重新合并在一起。像在Git中一样,垂直绘制图形(顶部是新的提交),还是在右边水平地绘制图形,就像我在StackOverflow帖子中那样。重要的实际上是绘制图形,因为一旦完成此操作,Git所做的就很明显了:

A  <-B  <-C   <--master

这表示一个很小的三提交存储库中的提交总数。每个大写字母代表实际的哈希ID。分支 name master会记住 last 提交(提交C)的实际哈希ID。提交C本身会记住其先前或 parent 提交B的哈希ID。 B会记住A的哈希ID,并且由于A是第一个提交,因此它没有父。

只要Git需要,它就会从您告诉它的提交(默认情况下为当前提交)开始,然后向后浏览该图。如果您的Git将一个特定的提交推送到其他Git,则您的Git必须将该提交推送到每个父级,直到您的提交与他们的提交匹配为止。因此,假设您有:

...--*--*------o--o---o--X--o--o   <-- branch
         \           /
          o--o------o

其中*代表服务器已经提交的提交(例如,您已经推送了这些,或者从服务器获得了它们),而o代表了您提交的没有提交的提交。此时,如果沿着底行推动第三个提交(向右),它们将收到三个提交:所有三个提交都来自底行。这是因为从该提交开始并向后工作,需要三次提交才能使新的提交与现有的提交结合起来。如果您在*之后推送前两行提交之一,则Git将发送一两次提交。如果您推送合并后的提交,则您的Git将至少推送六个提交。在此处推动提交X会推动七个:X本身,以及所需的前六个。

如果要推送添加到第二个加星标提交的单个提交,则必须首先 make 添加到第二个加星标提交的单个提交:

          Y   <-- new-name
         /
...--*--*------o--o---o--X--o--o   <-- branch
         \           /
          o--o------o

设置完成后,如果您推送提交Y,它们已经有加星标的提交(当然),因此您的Git实际上将推送单个提交,即提交Y

如何进行单次提交

为了创建提交Y,首先,您需要 1 创建指向最终提交*的新分支名称。找到其哈希ID或唯一标识其哈希的任何其他名称,然后检查该特定提交并为其创建名称:

git checkout -b new-name <hash-id>

这将使图形本身保持不变,但是使新名称指向该提交。 2 git checkout -b命令在创建名称的同时将您置于该新分支上。 (请注意,此时,将新分支推送到服务器将发送服务器 no 提交,并且也仅在服务器上创建名称。)

        /----------------------------- new-name (HEAD)
        |
        v
...--*--*------o--o---o--X--o--o   <-- branch
         \           /
          o--o------o

现在您可以运行:

git cherry-pick <hash-of-desired-commit-X>

在这种情况下为:

git cherry-pick 9973b14ca19e4571046d8d25bc986ec07199e39c

这让Git检查提交9973b14ca19e4571046d8d25bc986ec07199e39c。 Git将提取其父提交的快照和该提交的快照,并将它们进行比较(例如git diff)。 3 然后,Git会将这些更改应用于当前提交,以创建一个是X副本的新提交:

          Y  <-- new-name (HEAD)
         /
...--*--*------o--o---o--X--o--o   <-- branch
         \           /
          o--o------o

now 您拥有所需的内容:可以自己推送的提交,因为Y的历史(其父辈和祖父母等)已经存在了。在服务器上


1 从技术上讲,您可以使用“分离式HEAD”模式在没有名称的情况下执行此操作。在这一点上,我建议不要这样做。

2 您还可以使用git branch创建分支名称:

git branch new-name <hash-id>

然后,您必须运行git checkout new-name才能在该分支上获得,即,将HEAD附加到该名称。

3 从技术上讲,cherry-pick实际上是一种合并操作,导致非合并提交:merge-as-a-verb,进行合并,但不是作为形容词或名词。这样,在简单补丁无法解决的情况下就可以进行自动选择。但是,这种特殊的复杂性在这里基本上是无关紧要的:仅当Cherry-pick导致合并冲突时才重要。

答案 1 :(得分:-1)

您认为您只推送了一次提交,但实际上您推送了很多提交。提交9973b14提交取决于feature / 25062018_offline-seite_ef分支中不存在的其他提交,因此它们将被推送到一起。这就是Git的工作方式。

您需要基于远程功能/ 25062018_offline-seite_ef分支创建一个本地分支,然后挑选9973b14提交,然后推送到远程。