我在master上创建了一个本地Git分支(我们称其为BranchB)。然后,我在该分支(到BranchB)上提交了更改。但是当需要将其推送到远程存储库时,给我带来了太多咖啡,我写了git push origin master
而不是git push
来将新分支推送到存储库。
然后我进入GitHub查看master上的提交。我最近不小心推动的更改没有出现在这里?
那当我在分支B上推送到master时到底发生了什么?这是否会推送自我指定master以来在master上所做的提交。
答案 0 :(得分:3)
您在此处作为推送参数的<refspec>
是master
,其中完整的规范形式为<src>:<dst>
,<src>
是推送的来源和<dst>
目标参考。省略一个时,git假设它是<src>
,并且没有给出<dst>
。在这种情况下,并且如果分支具有<repository>.push
配置集(因此在大多数情况下),则此引用将用作推送的源。
是的,它将主服务器(没有新提交)推送到其远程副本。无害无操作。
(也许用git config -l | grep origin
或类似的方法检查您自己的配置。)
您将用显式的方式将BranchB推送到master上:
git push origin BranchB:master
这是我从文档中了解的内容,即git-push手册页中的the <refspec>
paragraph。似乎对您的结果有意义。
答案 1 :(得分:3)
简短的回答:您还好。 Git最有可能说:
Everything up-to-date
,什么也没做。否则,您只会将您在master
上提交的提交发送到GitHub Git的master
。
更长的答案仍然是你还好,但是你可能在对Git分支的一些误解下工作。他们不会咬你... 。
每个Git提交均由其哈希ID唯一标识。给定一个哈希ID,Git可以找到提交。提交内部还有另一个哈希ID,即提交的 parent 提交,即该提交之前的提交。当然,在提交中还包括进行提交的人的姓名和电子邮件地址,他们的日志消息以及(尽管是间接的)构成该提交的所有文件的完整快照。
这意味着从任何给定提交中,我们都可以向后工作到上一个提交。因此,如果我们有一系列的提交:
... <-F <-G <-H
我们只需要 last 这样的提交的哈希ID,例如H
。然后,Git将能够读取H
并获取其父级G
的哈希ID,并读取G
并获取F
的ID,依此类推。
master
这样的分支 name 因此只标识一个提交 Git查找任何分支的 last 提交的哈希ID的方式是通过分支名称。名称本身master
或BranchB
或其他任何名称仅包含哈希ID:
...--F--G--H <-- master, BranchB
这两个 名称都存储相同的哈希ID。因此,master
上的所有提交也都在BranchB
上。
要进行 new 提交,Git将保存快照,保存您的姓名和电子邮件等,并保存 current 提交的哈希ID {{1 }}。这将成为新的提交H
,并为其分配新的唯一哈希ID:
I
其中一个名称必须立即更改!
...--F--G--H <-- master, BranchB
\
I
会记住您所在的分支为了知道要更新哪个名称,Git将特殊名称HEAD
附加到一个分支。如果HEAD
附加到HEAD
,则Git将更新该名称:
BranchB
就是这么简单。
嗯,“那么简单”并不是那么简单:分支名称 do 这样移动,而Git find 通过最晚开始并向后工作来提交。您可以随时要求Git将任何分支名称移至任何现有提交。假设我们强迫Git将...--F--G--H <-- master
\
I <-- BranchB (HEAD)
移回提交BranchB
。然后我们如何找到提交H
?
如果我们这样做这样做,则很难找到I
。 (有很多机制,但是让我们不必担心它们。)简单的部分是,只要分支名称向前移动 forward -我们就一次进行新的提交,还是我们进行的一堆提交工作都很好,因为从I
过去到I
的某个地方,我们总是可以回到I
。 / p>
这就是Git的特殊术语快进的意思。如果从 new “ last”提交中,我们仍然可以回到旧的“ last”提交,则分支名称更新是一项快速操作。
这是I
的来源。运行git push
时,您的Git会通过某个URL调用其他Git。您的Git和他们的Git进行了交谈。您的Git会根据需要将新的提交移交给他们的Git,然后您的Git要求他们的Git设置他们的分支名称之一。
请记住,就像您一样,他们的Git是一个Git存储库。因此,他们的Git有他们自己的分支名称。他们已经有一个git push
:
master
您的Git会调用他们的Git并询问他们:嘿,为什么不设置...--F--G--H <-- master
指向提交master
?他们会说: 已经做到了。您会说:哦,好吧,再见!然后您的Git会打印:
H
或者,您可以发送一些新的提交哈希ID。您的Git会向其Git提供您的新提交,以及将这一新提交链接回Everything up-to-date
所需要的数量,或者无论您走到哪里,您的Git和他们的Git都会共享一些较早的提交。然后,您的Git将作为其Git:嘿,如何将H
设置为此其他哈希ID?他们可能会说好,或者他们会说:< em>不! 这不是一个快进!现在,您知道快进意味着什么,您知道,如果他们拒绝了您的请求,那是因为无论提交他们的 master
的名字,当您查看您的 master
并向后工作时,就不会出现在向后链中。
也就是说,假设您被殴打了—其他人,在其他地方,向他们发送了新的提交:
master
您的Git进行了一些新的提交(并且您正在...--F--G--H--L <-- master
上):
master
因此您的Git向他们发送了 J--K <-- master (HEAD)
/
...--F--G--H <-- origin/master
\
I <-- BranchB
链,并要求他们将其J-K
设置为master
,但这会丢失他们的K
-您甚至都不会有。您必须获得他们的L
并弄清楚如何保留他们的L
。
只要他们没有任何您的 L
请求会放弃的提交,尽管它们会接受您的请求。因此,如果他们没有拥有git push
,并且您运行L
,则会发送git push origin master
并要求他们将其主文件设置为{{1 }},他们会的。
即使您将J-K
重新连接到K
,也是如此:
HEAD
BranchB
让您的Git调用他们的Git,向他们提供您的提交 J--K <-- master
/
...--F--G--H <-- origin/master
\
I <-- BranchB (HEAD)
,并要求他们将git push origin master
移动到您的K
所在的位置。 / p>
master
让您的Git调用他们的Git,向他们提供您的提交master
,并要求他们在其中移动(或创建)他们的git push origin BranchB
。
请注意,您也可以I
向他们提供两个尖端提交(上图中的BranchB
和git push origin master BranchB
),并发出两个请求。或者,作为RomainValeri noted,您可以为单词K
之后的每个单词设置完整的 refspec 参数,例如I
或origin
。它们让您的Git像以前一样发送您的提交,然后请求它们设置目标分支名称(冒号之后的名称)以匹配您源分支的技巧提交(从冒号之前的名称)。通常,混合这样的名称并不是一个好主意-如果没有别的,那就太令人困惑了。但是在某些特殊情况下,它是有用的快捷方式。