我尝试仅推送ID为 9973b14ca19e4571046d8d25bc986ec07199e39c 的提交。
git push bbef 9973b14ca19e4571046d8d25bc986ec07199e39c:refs/heads/feature/25062018_offline-seite_ef
我登录到Bitbucket来创建拉取请求,但我注意到,即使这是一个新的远程分支,也存在多次提交。
所以我删除了bitbucket中的远程分支,然后再次将其推送,结果相同...
为什么它不起作用?如何只推送单个提交而不是多个提交?为什么会发生?
答案 0 :(得分:2)
运行git push
时,您会将Git优惠提供给另一个Git:
(另一个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提交,然后推送到远程。