裸 Git 存储库怎么能领先于我的工作存储库?
How can bare Git repository be ahead of my working repository?
我制作了我的 Git 工作存储库的裸存储库克隆。远程裸仓库位于网络驱动器上,我一直在推送它,所以我在不同的物理媒体上有备份。我现在在尝试推送到裸存储库时遇到错误,因为我的本地存储库 落后于 远程存储库。对远程存储库的所有修改都是通过从我的工作存储库推送的。如果没有对远程仓库进行其他更改,我的本地仓库怎么会落后于远程仓库?
这是我在尝试推送到远程仓库时遇到的错误
git -c diff.mnemonicprefix=false -c core.quotepath=false push -v --tags --set-upstream AlcatrazVehicleBW1 BitworksDevelopment:BitworksDevelopment FixSetOsDateTime:FixSetOsDateTime HeapUseBy3rdPartyLibBugFix:HeapUseBy3rdPartyLibBugFix M_Bitworks20161226CLOSED:M_Bitworks20161226CLOSED Orig_Port_to_Vx7_Review_changes_by_jdn:Orig_Port_to_Vx7_Review_changes_by_jdn ReSquashM_BitworksIntoMaster:ReSquashM_BitworksIntoMaster master:master
Pushing to //bw1/Public/Bitworks/Projects/Alcatraz/Vehicle.git
To //bw1/Public/Bitworks/Projects/Alcatraz/Vehicle.git
= [up to date] FixSetOsDateTime -> FixSetOsDateTime
= [up to date] HeapUseBy3rdPartyLibBugFix -> HeapUseBy3rdPartyLibBugFix
= [up to date] Orig_Port_to_Vx7_Review_changes_by_jdn -> Orig_Port_to_Vx7_Review_changes_by_jdn
= [up to date] master -> master
* [new branch] M_Bitworks20161226CLOSED -> M_Bitworks20161226CLOSED
* [new branch] ReSquashM_BitworksIntoMaster -> ReSquashM_BitworksIntoMaster
! [rejected] BitworksDevelopment -> BitworksDevelopment (non-fast-forward)
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/FixSetOsDateTime'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/HeapUseBy3rdPartyLibBugFix'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/Orig_Port_to_Vx7_Review_changes_by_jdn'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/master'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/M_Bitworks20161226CLOSED'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/ReSquashM_BitworksIntoMaster'
error: failed to push some refs to '//bw1/Public/Bitworks/Projects/Alcatraz/Vehicle.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
它拒绝的分支 BitworksDevelopment 已在本地存储库中移动以指向 master 分支的头部,以试图丢弃旧的 BitworksDevelopment 被 squash 合并到 master 的分支。目的是从当前的 master head 开始新的开发分支。我的理解是推送会覆盖远程 AlcatrazVehicleBW1 裸存储库上的跟踪分支指针。看来又出现了一个我不明白的 Git 概念。
The branch it is rejecting BitworksDevelopment was moved in the local repository to point to the head of the master branch in an attempt to discard the old BitworksDevelopment branch which was squash merged into master.
嗯,那就是问题所在。请注意,这里最简单的事情就是 删除 这个分支名称。
... because my local repository is behind the remote repository
那是来自Git的抱怨,但是抱怨是……好吧,"wrong"是个错误的词;也许更好的词是 "presumptive".
请记住,在 Git 中,分支 names 仅指向 一个特定的提交 。该提交是 "tip of the branch":
...--A--B <-- br1
\
C--D--E <-- br2
\
F <-- br3
此处,提交 A
和 B
在 所有三个分支 上,分支名称 br1
指向 B
,因此 B
是 br1
上的 提示提交 。 C
到 E
的提交在两个分支上,E
是 br2
的尖端,而 F
仅在一个分支上,并且是 br2
的尖端br3
.
Git 允许您添加新的分支名称标签,任意跳转现有标签,以及完全删除分支名称标签。但是,名称移动有一个 "normal pattern",而且是 "forward-only" 方向。即使不添加任何新的提交,我也可以将 br1
向前移动到 C
到 F
中的任何一个,并且 Git 会认为这是正常的并且只是这样做。我可以将 br2
向前移动到 F
。我无法向前移动 br3
,因为没有超出 F
.
的提交
不过,假设我添加了一个新提交 G
:
...--A--B----------G <-- br1
\
C--D--E <-- br2
\
F <-- br3
因为G
的父级是B
,我可以向前移动br1
指向G
。 G
指向 B
,正如 C
指向 B
,因此将 br1
移动到 C
或 G
可以。
不过,一旦我做了这个动作,Git 拒绝让 br1
以任何方式后退。
假设我将 G
复制到一个新的提交 G'
并添加到 F
:
的末尾
...--A--B----------G <-- br1
\
C--D--E <-- br2
\
F <-- br3
\
G'
如果我现在要求 Git 将 br1
移动到指向 G'
,G
会怎样?
没有指向 G
的内容,我们将 "lose" 它。 Git 将无法找到它,如果我没有将它的哈希值保存在某处(在我的 reflogs 中,或在我的屏幕上),我也会找到它。1 因此,将 br1
从 G
移动到 G'
的请求是 非快进 。2
这里的基本假设是,当您推送到裸存储库时,如果您请求的分支标签更改不是 "fast forward",您可能不知道提交 G
甚至 exists 在裸存储库上,因为它可能是由其他人发送到那里的,并行工作,只是比你先到 git push
步骤。在这种情况下,您需要从裸存储库 git fetch
到 pick up commit G
,然后弄清楚如何将您自己的工作提交到 附加 到现有提交,而不是删除 G
。 (这通常是通过变基或合并。)
要告诉 Git 服务器它应该移动一个分支,即使该动作会丢失一些提交,您也必须应用各种 "force" 标志之一。比较容易申请的是 --force
或 -f
,它只是告诉服务器:"I know what I'm doing, lose some commits already." 稍微长一点的,更安全的是 --force-with-lease
:你有你的 Git 告诉他们 Git "I believe the branch points to commit G
, and if so, make it point to G'
instead."
基本假设是错误的,G
是你的提交。您确实知道它在那里,并且您打算将其删除。所以,既然你的 Git 知道它,你可以使用 --force-with-lease
检查他们的(裸回购的)BitworksDevelopment
是否仍然指向同一个提交,如果是这样,用你的覆盖它新的替代品。或者,如果您知道您是唯一一个对裸存储库执行操作的人,您可以只使用普通的旧 --force
.
当然,如脚注 2 所示,完全删除名称实际上更简单,更典型的 squash-merge 模式也是如此。在这种情况下,因为图形看起来更像这样:
...--A--B--C <-- master
\
... [the old BitworksDevelopment]
您将通过删除分支名称而丢失的提交是您已压缩合并为提交的提交 C
。名称 master
足以容纳提交 C
;您不需要 两个 名称。至少,现在还没有:你 将 想要 C
的另一个名称,一旦你去进行新的提交,它将在 C
之后出现,但是你没有不想通过名称 master
.
查找
请注意,Git 对裸存储库的保护仅适用于非快进分支名称更新。删除一个分支,丢失提交,完全没问题!不过,您必须使用 git push --delete origin BitworksDevelopment
将删除请求发送到服务器,所以这不会是偶然发生的。这与正常的开发推送完全不同,两个开发人员之间的竞争,都推送到同一个分支,导致非快进,是一个正常的日常事故,值得防护。
1裸存储库通常没有 reflog,并且 运行 在推送后立即进行垃圾收集,因此 G
可能真的-删除得很快。
2快进分支名称移动的技术定义是名称当前指向的提交是一个您建议指向的提交的祖先。由于常规合并提交指向两个或多个提交,因此将分支名称移动到一个新的合并提交,该合并提交只是将该分支与另一个分支合并,是一种快进。对于大多数 squash "merges" 也是如此:我们在主分支上添加一个提交,代表在另一个分支上的多个提交中完成的所有工作(然后我们完全丢弃另一个分支)。您的情况的不同之处在于,您是故意 而没有 丢弃另一个分支;相反,您正试图以非快进方式改变另一个分支。
我制作了我的 Git 工作存储库的裸存储库克隆。远程裸仓库位于网络驱动器上,我一直在推送它,所以我在不同的物理媒体上有备份。我现在在尝试推送到裸存储库时遇到错误,因为我的本地存储库 落后于 远程存储库。对远程存储库的所有修改都是通过从我的工作存储库推送的。如果没有对远程仓库进行其他更改,我的本地仓库怎么会落后于远程仓库? 这是我在尝试推送到远程仓库时遇到的错误
git -c diff.mnemonicprefix=false -c core.quotepath=false push -v --tags --set-upstream AlcatrazVehicleBW1 BitworksDevelopment:BitworksDevelopment FixSetOsDateTime:FixSetOsDateTime HeapUseBy3rdPartyLibBugFix:HeapUseBy3rdPartyLibBugFix M_Bitworks20161226CLOSED:M_Bitworks20161226CLOSED Orig_Port_to_Vx7_Review_changes_by_jdn:Orig_Port_to_Vx7_Review_changes_by_jdn ReSquashM_BitworksIntoMaster:ReSquashM_BitworksIntoMaster master:master
Pushing to //bw1/Public/Bitworks/Projects/Alcatraz/Vehicle.git
To //bw1/Public/Bitworks/Projects/Alcatraz/Vehicle.git
= [up to date] FixSetOsDateTime -> FixSetOsDateTime
= [up to date] HeapUseBy3rdPartyLibBugFix -> HeapUseBy3rdPartyLibBugFix
= [up to date] Orig_Port_to_Vx7_Review_changes_by_jdn -> Orig_Port_to_Vx7_Review_changes_by_jdn
= [up to date] master -> master
* [new branch] M_Bitworks20161226CLOSED -> M_Bitworks20161226CLOSED
* [new branch] ReSquashM_BitworksIntoMaster -> ReSquashM_BitworksIntoMaster
! [rejected] BitworksDevelopment -> BitworksDevelopment (non-fast-forward)
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/FixSetOsDateTime'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/HeapUseBy3rdPartyLibBugFix'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/Orig_Port_to_Vx7_Review_changes_by_jdn'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/master'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/M_Bitworks20161226CLOSED'
updating local tracking ref 'refs/remotes/AlcatrazVehicleBW1/ReSquashM_BitworksIntoMaster'
error: failed to push some refs to '//bw1/Public/Bitworks/Projects/Alcatraz/Vehicle.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
它拒绝的分支 BitworksDevelopment 已在本地存储库中移动以指向 master 分支的头部,以试图丢弃旧的 BitworksDevelopment 被 squash 合并到 master 的分支。目的是从当前的 master head 开始新的开发分支。我的理解是推送会覆盖远程 AlcatrazVehicleBW1 裸存储库上的跟踪分支指针。看来又出现了一个我不明白的 Git 概念。
The branch it is rejecting BitworksDevelopment was moved in the local repository to point to the head of the master branch in an attempt to discard the old BitworksDevelopment branch which was squash merged into master.
嗯,那就是问题所在。请注意,这里最简单的事情就是 删除 这个分支名称。
... because my local repository is behind the remote repository
那是来自Git的抱怨,但是抱怨是……好吧,"wrong"是个错误的词;也许更好的词是 "presumptive".
请记住,在 Git 中,分支 names 仅指向 一个特定的提交 。该提交是 "tip of the branch":
...--A--B <-- br1
\
C--D--E <-- br2
\
F <-- br3
此处,提交 A
和 B
在 所有三个分支 上,分支名称 br1
指向 B
,因此 B
是 br1
上的 提示提交 。 C
到 E
的提交在两个分支上,E
是 br2
的尖端,而 F
仅在一个分支上,并且是 br2
的尖端br3
.
Git 允许您添加新的分支名称标签,任意跳转现有标签,以及完全删除分支名称标签。但是,名称移动有一个 "normal pattern",而且是 "forward-only" 方向。即使不添加任何新的提交,我也可以将 br1
向前移动到 C
到 F
中的任何一个,并且 Git 会认为这是正常的并且只是这样做。我可以将 br2
向前移动到 F
。我无法向前移动 br3
,因为没有超出 F
.
不过,假设我添加了一个新提交 G
:
...--A--B----------G <-- br1
\
C--D--E <-- br2
\
F <-- br3
因为G
的父级是B
,我可以向前移动br1
指向G
。 G
指向 B
,正如 C
指向 B
,因此将 br1
移动到 C
或 G
可以。
不过,一旦我做了这个动作,Git 拒绝让 br1
以任何方式后退。
假设我将 G
复制到一个新的提交 G'
并添加到 F
:
...--A--B----------G <-- br1
\
C--D--E <-- br2
\
F <-- br3
\
G'
如果我现在要求 Git 将 br1
移动到指向 G'
,G
会怎样?
没有指向 G
的内容,我们将 "lose" 它。 Git 将无法找到它,如果我没有将它的哈希值保存在某处(在我的 reflogs 中,或在我的屏幕上),我也会找到它。1 因此,将 br1
从 G
移动到 G'
的请求是 非快进 。2
这里的基本假设是,当您推送到裸存储库时,如果您请求的分支标签更改不是 "fast forward",您可能不知道提交 G
甚至 exists 在裸存储库上,因为它可能是由其他人发送到那里的,并行工作,只是比你先到 git push
步骤。在这种情况下,您需要从裸存储库 git fetch
到 pick up commit G
,然后弄清楚如何将您自己的工作提交到 附加 到现有提交,而不是删除 G
。 (这通常是通过变基或合并。)
要告诉 Git 服务器它应该移动一个分支,即使该动作会丢失一些提交,您也必须应用各种 "force" 标志之一。比较容易申请的是 --force
或 -f
,它只是告诉服务器:"I know what I'm doing, lose some commits already." 稍微长一点的,更安全的是 --force-with-lease
:你有你的 Git 告诉他们 Git "I believe the branch points to commit G
, and if so, make it point to G'
instead."
基本假设是错误的,G
是你的提交。您确实知道它在那里,并且您打算将其删除。所以,既然你的 Git 知道它,你可以使用 --force-with-lease
检查他们的(裸回购的)BitworksDevelopment
是否仍然指向同一个提交,如果是这样,用你的覆盖它新的替代品。或者,如果您知道您是唯一一个对裸存储库执行操作的人,您可以只使用普通的旧 --force
.
当然,如脚注 2 所示,完全删除名称实际上更简单,更典型的 squash-merge 模式也是如此。在这种情况下,因为图形看起来更像这样:
...--A--B--C <-- master
\
... [the old BitworksDevelopment]
您将通过删除分支名称而丢失的提交是您已压缩合并为提交的提交 C
。名称 master
足以容纳提交 C
;您不需要 两个 名称。至少,现在还没有:你 将 想要 C
的另一个名称,一旦你去进行新的提交,它将在 C
之后出现,但是你没有不想通过名称 master
.
请注意,Git 对裸存储库的保护仅适用于非快进分支名称更新。删除一个分支,丢失提交,完全没问题!不过,您必须使用 git push --delete origin BitworksDevelopment
将删除请求发送到服务器,所以这不会是偶然发生的。这与正常的开发推送完全不同,两个开发人员之间的竞争,都推送到同一个分支,导致非快进,是一个正常的日常事故,值得防护。
1裸存储库通常没有 reflog,并且 运行 在推送后立即进行垃圾收集,因此 G
可能真的-删除得很快。
2快进分支名称移动的技术定义是名称当前指向的提交是一个您建议指向的提交的祖先。由于常规合并提交指向两个或多个提交,因此将分支名称移动到一个新的合并提交,该合并提交只是将该分支与另一个分支合并,是一种快进。对于大多数 squash "merges" 也是如此:我们在主分支上添加一个提交,代表在另一个分支上的多个提交中完成的所有工作(然后我们完全丢弃另一个分支)。您的情况的不同之处在于,您是故意 而没有 丢弃另一个分支;相反,您正试图以非快进方式改变另一个分支。