Git:用一个分支修复回购及其在不同分支上的远程
Git: Fix repo with a branch and its remote on different branches
我不知道这是怎么发生的,但我有一个 git 存储库处于以下状态:
A--B--C--D master
\
E--F origin/master
提交 E
和 F
此时已过时;他们在 B
上所做的更改无关紧要,如有必要,可以将其删除。
我只保留 origin
远程作为我的代码的备份,没有其他人克隆它,所以我可以使用我需要的任何暴力破解。
清理它的最干净的方法是什么?
I only keep the origin remote as a backup for my code, and nobody else has cloned it, so I can use whatever brute force I need.
在这种情况下,git push --force origin master
就足够了。 非常确定 你可以在你的存储库中使用 origin/master
,并且 origin
上的(单独的)Git 存储库中的 master
], no-longer-able 找到提交 F
.
(您自己的存储库会在 reflog 名称 [=235 下记住提交 <code>E
和 F
一段时间=]@{number},因此只要您保持自己的存储库完好无损,如果它们毕竟没有过时,您仍然可以取回它们。然而,在某些时候它们真的会被删除。server 可能根本没有 reflogs 并且它的提交副本 E
和 F
可能会相对快速地消失—例如,以秒、小时或几天为单位。)
这是如何工作的以及为什么工作
每个 Git 存储库都有 自己的 分支名称,semi-private 到特定的 Git 存储库。在您调用 origin
的机器上有一个存储库,它有一个分支名称 master
.
你的remote-tracking名字,1如origin/master
,是你的Git'这是记住某些 other Git 的 branch 名称的方法。在这种情况下,您的 origin/master
是您的 Git 对 origin
的 master
的记忆。
当你的 Git 通过 git fetch
或 git push
呼叫他们的 Git 时,两个 Git 开始对话。 fetch 和 push 略有不同,但是你可以使用 git ls-remote
来观察 git fetch
本身的观察者。只需 运行 git ls-remote origin
(或保留 origin
,因为默认值通常是 origin
):您的 Git 会溢出 other Git 的分支、标签和它列出的其他名称。这是 git fetch
的第一部分:您的 Git 打电话给他们的 Git 并获得此列表。
当您使用 git fetch
时,您的 Git 使用此列表询问他们的 Git 任何提交和他们拥有的其他内部 Git objects ,你没有,你的 Git 想要。例如,如果您还没有提交 F
,而您的 origin/master
记住了提交 B
或 E
,并且他们将提交 F
作为他们的master
,你的 Git 会说:我想提交 F
please 他们会将其添加到提交列表中发送。然后他们会提供提交 E
——一个 Git 必须 提供每个提交的 parent——你的 Git 要么说 不,谢谢,我已经有了 或 是的 (在这种情况下,他们会提供 B
,E
' s parent,等等)。
然后,他们的获取过程会捆绑将这些提交提交给您的 Git 所需的任何内容——这是您将看到 counting objects
和 compressing objects
的地方——并将其发送过来。您的 Git 扩展了这些,以便您拥有一组适当的提交及其数据,然后根据存储在 their 中的哈希 ID 创建或更新您的 origin/master
master
:现在您肯定已经提交了 F
,您的 Git 可以让您的 origin/master
指向它。
因此,如果您 运行:
git fetch origin
在任何时候——这是命令的 "get me everything" 形式——你的 Git 将调用他们的 Git 并获得初步的 "everything" 列表。两个 Git 会从那里弄清楚你的 Git 需要什么,然后把它交给你的 Git。然后,您的 Git 将根据 all 分支名称创建或更新 all 您的 remote-tracking 名称。
当你使用 git push
时,它与 Git 接近 fetch
的对立面——这对是 push
和 fetch
而不是比 push
和 pull
由于历史错误2——发生类似的过程,但有两个关键区别:
您的 Git 发送,而不是接收。 (您的 Git 仍然选择要发送的内容,并且 "must offer parent if sending commit" 仍然有效,依此类推,但是对于 git fetch
,他们的 Git 已发送而您的 Git 已收到.)
最后,您的 Git 不是 Git 更新某种 "remote-tracking name",而是询问(礼貌地)或命令(强制地)他们的 Git 到 设置 它的一些 分支 名称。3
如果您要求或命令他们设置他们的 master
,并且他们服从,您的 Git 现在知道他们的 master
已设置为您提供的哈希 ID,因此您的Git 现在更新您的 origin/master
remote-tracking 姓名。
当您使用 ask-type git push origin master
时,您的 Git 会发送您拥有而他们没有的提交——例如 C
和 D
——然后礼貌地问他们:拜托,如果没问题,请将你的 master
设置为指向提交 D
? 他们会说 不!如果我这样做,我会忘记提交 F
! 这个错误作为 Git 行话 rejected 和 non-fast-forward,但这只是意味着他们拒绝了,因为那样会丢失提交 F
,因此也会丢失 E
。
但这正是您希望他们做的。所以哟只需要向他们发送一个强有力的命令:设置你的 master
! 他们仍然可以拒绝——例如,如果你没有权限——但你当然有权限所以在这种情况下,他们会服从,并失去提交 F
.
git push
有两种强制模式:git push --force
是古版本,git push --force-with-lease
是more-modern(因为Git1.9左右)变体。它们之间的区别是 --force
只是说 set,但是 --force-with-lease
说: I think your master
is _____.如果是这样,请将其设置为 _____ 并告诉我您做到了;如果不是,告诉我我错了,毕竟不要设置你的 master
。 第一个空白填入你的 Git 的 origin/master
值:你的Git 对他们 Git 的 master
的记忆。这样一来,您就可以确保让他们扔掉的正是您认为他们会扔掉的东西。
如果您是其他 Git 中唯一的 用户,则无需 --force-with-lease
添加的注意事项:您的想法是正确的, 是 正确的,根据定义。但如果您担心自己可能会健忘(例如,如果您使用两台不同的笔记本电脑并且不记得哪一台是最新的),您可以使用更高级的 check-first-then-force --force-with-lease
。使用 --force-with-lease
永远不会 错误 ,除了旧的 --force
是历史默认值之外,--force-with-lease
确实应该是默认值。
1Git 调用这些 remote-tracking 分支名称 但几年前我决定 branch 在这里是无用的混乱,会造成一些额外的混乱,所以我现在只称它们为 remote-tracking names.
2通常,在获取提交之后,您希望整合那些提交。这就是 git pull
所做的:它 运行s git fetch
到 get 提交,然后 运行s 第二个 Git 命令到整合 那些提交。在早期,这似乎是正确的自然粒度,所以 git pull
是与 git push
相反的 user-facing 命令。
不过,事实证明,将获取操作与集成操作分开通常很重要,例如,在两者之间插入某种 inspect 操作,以便选择正确的积分形式。 Mercurial 做对了,Git 做错了:在 Mercurial 中,hg pull
的意思是 Git 对 git fetch
的意思,你必须添加一个单独的操作,或者一个额外的标志, hg pull
使其也执行集成步骤。
3您可以选择您要求他们设置的名称,这样您就可以让您的 Git 请求或命令设置标签名称,或其他类型的名字,但一般来说,这里通常的情况是 "branch name".
我不知道这是怎么发生的,但我有一个 git 存储库处于以下状态:
A--B--C--D master
\
E--F origin/master
提交 E
和 F
此时已过时;他们在 B
上所做的更改无关紧要,如有必要,可以将其删除。
我只保留 origin
远程作为我的代码的备份,没有其他人克隆它,所以我可以使用我需要的任何暴力破解。
清理它的最干净的方法是什么?
I only keep the origin remote as a backup for my code, and nobody else has cloned it, so I can use whatever brute force I need.
在这种情况下,git push --force origin master
就足够了。 非常确定 你可以在你的存储库中使用 origin/master
,并且 origin
上的(单独的)Git 存储库中的 master
], no-longer-able 找到提交 F
.
(您自己的存储库会在 reflog 名称 [=235 下记住提交 <code>E
和 F
一段时间=]@{number},因此只要您保持自己的存储库完好无损,如果它们毕竟没有过时,您仍然可以取回它们。然而,在某些时候它们真的会被删除。server 可能根本没有 reflogs 并且它的提交副本 E
和 F
可能会相对快速地消失—例如,以秒、小时或几天为单位。)
这是如何工作的以及为什么工作
每个 Git 存储库都有 自己的 分支名称,semi-private 到特定的 Git 存储库。在您调用 origin
的机器上有一个存储库,它有一个分支名称 master
.
你的remote-tracking名字,1如origin/master
,是你的Git'这是记住某些 other Git 的 branch 名称的方法。在这种情况下,您的 origin/master
是您的 Git 对 origin
的 master
的记忆。
当你的 Git 通过 git fetch
或 git push
呼叫他们的 Git 时,两个 Git 开始对话。 fetch 和 push 略有不同,但是你可以使用 git ls-remote
来观察 git fetch
本身的观察者。只需 运行 git ls-remote origin
(或保留 origin
,因为默认值通常是 origin
):您的 Git 会溢出 other Git 的分支、标签和它列出的其他名称。这是 git fetch
的第一部分:您的 Git 打电话给他们的 Git 并获得此列表。
当您使用 git fetch
时,您的 Git 使用此列表询问他们的 Git 任何提交和他们拥有的其他内部 Git objects ,你没有,你的 Git 想要。例如,如果您还没有提交 F
,而您的 origin/master
记住了提交 B
或 E
,并且他们将提交 F
作为他们的master
,你的 Git 会说:我想提交 F
please 他们会将其添加到提交列表中发送。然后他们会提供提交 E
——一个 Git 必须 提供每个提交的 parent——你的 Git 要么说 不,谢谢,我已经有了 或 是的 (在这种情况下,他们会提供 B
,E
' s parent,等等)。
然后,他们的获取过程会捆绑将这些提交提交给您的 Git 所需的任何内容——这是您将看到 counting objects
和 compressing objects
的地方——并将其发送过来。您的 Git 扩展了这些,以便您拥有一组适当的提交及其数据,然后根据存储在 their 中的哈希 ID 创建或更新您的 origin/master
master
:现在您肯定已经提交了 F
,您的 Git 可以让您的 origin/master
指向它。
因此,如果您 运行:
git fetch origin
在任何时候——这是命令的 "get me everything" 形式——你的 Git 将调用他们的 Git 并获得初步的 "everything" 列表。两个 Git 会从那里弄清楚你的 Git 需要什么,然后把它交给你的 Git。然后,您的 Git 将根据 all 分支名称创建或更新 all 您的 remote-tracking 名称。
当你使用 git push
时,它与 Git 接近 fetch
的对立面——这对是 push
和 fetch
而不是比 push
和 pull
由于历史错误2——发生类似的过程,但有两个关键区别:
您的 Git 发送,而不是接收。 (您的 Git 仍然选择要发送的内容,并且 "must offer parent if sending commit" 仍然有效,依此类推,但是对于
git fetch
,他们的 Git 已发送而您的 Git 已收到.)最后,您的 Git 不是 Git 更新某种 "remote-tracking name",而是询问(礼貌地)或命令(强制地)他们的 Git 到 设置 它的一些 分支 名称。3
如果您要求或命令他们设置他们的 master
,并且他们服从,您的 Git 现在知道他们的 master
已设置为您提供的哈希 ID,因此您的Git 现在更新您的 origin/master
remote-tracking 姓名。
当您使用 ask-type git push origin master
时,您的 Git 会发送您拥有而他们没有的提交——例如 C
和 D
——然后礼貌地问他们:拜托,如果没问题,请将你的 master
设置为指向提交 D
? 他们会说 不!如果我这样做,我会忘记提交 F
! 这个错误作为 Git 行话 rejected 和 non-fast-forward,但这只是意味着他们拒绝了,因为那样会丢失提交 F
,因此也会丢失 E
。
但这正是您希望他们做的。所以哟只需要向他们发送一个强有力的命令:设置你的 master
! 他们仍然可以拒绝——例如,如果你没有权限——但你当然有权限所以在这种情况下,他们会服从,并失去提交 F
.
git push
有两种强制模式:git push --force
是古版本,git push --force-with-lease
是more-modern(因为Git1.9左右)变体。它们之间的区别是 --force
只是说 set,但是 --force-with-lease
说: I think your master
is _____.如果是这样,请将其设置为 _____ 并告诉我您做到了;如果不是,告诉我我错了,毕竟不要设置你的 master
。 第一个空白填入你的 Git 的 origin/master
值:你的Git 对他们 Git 的 master
的记忆。这样一来,您就可以确保让他们扔掉的正是您认为他们会扔掉的东西。
如果您是其他 Git 中唯一的 用户,则无需 --force-with-lease
添加的注意事项:您的想法是正确的, 是 正确的,根据定义。但如果您担心自己可能会健忘(例如,如果您使用两台不同的笔记本电脑并且不记得哪一台是最新的),您可以使用更高级的 check-first-then-force --force-with-lease
。使用 --force-with-lease
永远不会 错误 ,除了旧的 --force
是历史默认值之外,--force-with-lease
确实应该是默认值。
1Git 调用这些 remote-tracking 分支名称 但几年前我决定 branch 在这里是无用的混乱,会造成一些额外的混乱,所以我现在只称它们为 remote-tracking names.
2通常,在获取提交之后,您希望整合那些提交。这就是 git pull
所做的:它 运行s git fetch
到 get 提交,然后 运行s 第二个 Git 命令到整合 那些提交。在早期,这似乎是正确的自然粒度,所以 git pull
是与 git push
相反的 user-facing 命令。
不过,事实证明,将获取操作与集成操作分开通常很重要,例如,在两者之间插入某种 inspect 操作,以便选择正确的积分形式。 Mercurial 做对了,Git 做错了:在 Mercurial 中,hg pull
的意思是 Git 对 git fetch
的意思,你必须添加一个单独的操作,或者一个额外的标志, hg pull
使其也执行集成步骤。
3您可以选择您要求他们设置的名称,这样您就可以让您的 Git 请求或命令设置标签名称,或其他类型的名字,但一般来说,这里通常的情况是 "branch name".