推送后修改提交
amending a commit after it has been pushed
在我最近对已推送的存储库的提交中,我注意到我在文件中拼错了一个单词,现在想更改它。但是,我不想创建一个全新的提交。有没有办法修改我的最新提交并将其推送到我的存储库中,而无需重置、删除和推送?
过去我做过:
git reset HEAD~1 --soft
git push -f
# correct the spelling
git add .
git commit -m "bug10 fix"
有没有办法更正文件的拼写,修改我最近的提交并推送而无需重置,强制删除,然后重新提交?
我试过了:
# fixed the file
git add .
git commit --amend --no-edit
git push
! [rejected] Nov21 -> Nov21 (non-fast-forward)
无法更改任何 提交。这包括 在它被推送之前 。知道这一点很重要的原因——你需要知道 git commit --amend
是一个谎言的原因——是 git commit --amend
在本地做的事情, 可以 在这里做将提交推送到另一个 Git 存储库。
git commit --amend
的(微小)谎言是它 根本没有 更改提交。它只是 似乎 那样做。它真正做的是新的和改进的替换提交。
您可以随时执行此操作。你只需要知道每个提交都是编号——每个提交都有一个唯一编号,这是它的哈希ID——并且 Git 发现 以一种向后的方式(甚至可能 backassward)提交,通过 b运行ch 名称 或其他名称为您找到 最近的 提交,然后从那里向后工作。
想象一个简单的提交链,以您最近的提交结束,其哈希是一些丑陋的 运行dom-looking 哈希 ID,我们将其称为 H
。以下是 Git 查看和发现这些提交的方式:
... <-F <-G <-H <--your-branch
您的 b运行ch 名称“指向”(包含哈希 ID)提交 H
。提交 H
本身包含早期提交 G
的哈希 ID。 (提交 H
还包含每个文件的完整快照,尽管我们在这里根本不会看这个。)
提交 G
,作为一个提交,由一些丑陋的 运行dom 外观的大哈希 ID 编号,并且具有快照和元数据,因此向后指向更早的提交 F
。这是一个提交,所以它被编号并且具有相同类型的东西并且再次向后指向,依此类推。
现在,如果您在提交 H
和 运行 git commit --amend
中有一个小错字,Git 所做的就是进行 新提交。新提交与 H
完全一样,除了两种方式:
- 它有一个不同的哈希ID,所以我们称它为
I
;和
- 已更正拼写错误。
提交 H
仍在您的存储库中。它只是不再使用了。 H
仍然指向 G
,但新提交也是如此 I
:
H ???
/
... <-F <-G <-I <--your-branch
Git 更新您的 b运行ch name 以指向新提交 I
。这有效地“从 b运行ch 开始 H
”,因为 Git finds 通过从末尾开始并向后工作来提交。
现在,如果您 运行 git push
,您所做的是 将提交 H
发送到另一个 Git 存储库 ,然后让他们更新其中一个 他们的 b运行ch 名称——可能与您在存储库中使用的名称相同——以指向现在共享的提交:
...--F--G--H <--their-branch
如果你做出新的提交 I
这是一个新的和改进的 替代 H
并且只需将它与常规 git push
,他们将提交并暂时将其放入他们的存储库:
H <--their-branch
/
...--F--G
\
I
然后你让你的 Git 要求他们的 Git 设置 他们的 b运行ch 名称指向 I
也是
问题出在这里,因为当您这样做时,他们会检查:如果我更新我的 b运行ch 名称以指向 I
,我是否会丢失任何commits off the end? 当然,他们 做: 他们在 b运行ch 的末尾失去了 commit H
。这就是你想要他们做的——这就是你的 Git对你的所做的git commit --amend
,毕竟 — 但 他们不知道 。此时他们所知道的是他们确实有 H
而你要求他们现在放弃它。
您可以使用:
git push --force
或:
git push --force-with-lease
向他们发送命令,而不是礼貌的请求,告诉他们绝对应该让他们的名字指向I
(常规 --force
),或者您认为他们的名字现在指向 H
,如果是这样,他们应该改为指向 I
(--force-with-lease
)。如果他们从你那里接受这样的命令——大多数托管站点,比如 GitHub 和 Bitbucket 以及 GitLab 都有他们在 Git 上添加的奇特配置来控制这些东西——那么这可以让你替换毕竟 H
和 I
。
为什么你可能会使用 --force-with-lease
请注意,如果托管站点接受来自 其他人 的 git push
请求,他们现在可能有:
H--J--K <--their-branch
/
...--F--G
\
I
因此你的命令他们将他们的 b运行ch 设置为指向 I
不仅会丢弃你的提交 H
,还会丢弃另外两个额外的提交 J-K
, 关闭他们的 b运行ch.
使用 git push --force-with-lease
向他们发送您的新提交 I
,同时向他们发送您认为他们拥有的哈希 ID H
作为他们在 b运行 上的最终提交通道如果你的信念是错误的,你的条件命令——他们必须更改他们的名字以指向 I
——会被拒绝,说你的 Git 现在已经过时了,你需要 运行git fetch
先.
如果这 不能 发生,则您不需要 --force-with-lease
。非常古老的 Git 版本也没有 --force-with-lease
,但所有现代版本都有,通常最好保持安全检查,即使没有必要,因为随着时间的推移,“习惯”可能会变成“坏习惯”。
在我最近对已推送的存储库的提交中,我注意到我在文件中拼错了一个单词,现在想更改它。但是,我不想创建一个全新的提交。有没有办法修改我的最新提交并将其推送到我的存储库中,而无需重置、删除和推送?
过去我做过:
git reset HEAD~1 --soft
git push -f
# correct the spelling
git add .
git commit -m "bug10 fix"
有没有办法更正文件的拼写,修改我最近的提交并推送而无需重置,强制删除,然后重新提交?
我试过了:
# fixed the file
git add .
git commit --amend --no-edit
git push
! [rejected] Nov21 -> Nov21 (non-fast-forward)
无法更改任何 提交。这包括 在它被推送之前 。知道这一点很重要的原因——你需要知道 git commit --amend
是一个谎言的原因——是 git commit --amend
在本地做的事情, 可以 在这里做将提交推送到另一个 Git 存储库。
git commit --amend
的(微小)谎言是它 根本没有 更改提交。它只是 似乎 那样做。它真正做的是新的和改进的替换提交。
您可以随时执行此操作。你只需要知道每个提交都是编号——每个提交都有一个唯一编号,这是它的哈希ID——并且 Git 发现 以一种向后的方式(甚至可能 backassward)提交,通过 b运行ch 名称 或其他名称为您找到 最近的 提交,然后从那里向后工作。
想象一个简单的提交链,以您最近的提交结束,其哈希是一些丑陋的 运行dom-looking 哈希 ID,我们将其称为 H
。以下是 Git 查看和发现这些提交的方式:
... <-F <-G <-H <--your-branch
您的 b运行ch 名称“指向”(包含哈希 ID)提交 H
。提交 H
本身包含早期提交 G
的哈希 ID。 (提交 H
还包含每个文件的完整快照,尽管我们在这里根本不会看这个。)
提交 G
,作为一个提交,由一些丑陋的 运行dom 外观的大哈希 ID 编号,并且具有快照和元数据,因此向后指向更早的提交 F
。这是一个提交,所以它被编号并且具有相同类型的东西并且再次向后指向,依此类推。
现在,如果您在提交 H
和 运行 git commit --amend
中有一个小错字,Git 所做的就是进行 新提交。新提交与 H
完全一样,除了两种方式:
- 它有一个不同的哈希ID,所以我们称它为
I
;和 - 已更正拼写错误。
提交 H
仍在您的存储库中。它只是不再使用了。 H
仍然指向 G
,但新提交也是如此 I
:
H ???
/
... <-F <-G <-I <--your-branch
Git 更新您的 b运行ch name 以指向新提交 I
。这有效地“从 b运行ch 开始 H
”,因为 Git finds 通过从末尾开始并向后工作来提交。
现在,如果您 运行 git push
,您所做的是 将提交 H
发送到另一个 Git 存储库 ,然后让他们更新其中一个 他们的 b运行ch 名称——可能与您在存储库中使用的名称相同——以指向现在共享的提交:
...--F--G--H <--their-branch
如果你做出新的提交 I
这是一个新的和改进的 替代 H
并且只需将它与常规 git push
,他们将提交并暂时将其放入他们的存储库:
H <--their-branch
/
...--F--G
\
I
然后你让你的 Git 要求他们的 Git 设置 他们的 b运行ch 名称指向 I
也是
问题出在这里,因为当您这样做时,他们会检查:如果我更新我的 b运行ch 名称以指向 I
,我是否会丢失任何commits off the end? 当然,他们 做: 他们在 b运行ch 的末尾失去了 commit H
。这就是你想要他们做的——这就是你的 Git对你的所做的git commit --amend
,毕竟 — 但 他们不知道 。此时他们所知道的是他们确实有 H
而你要求他们现在放弃它。
您可以使用:
git push --force
或:
git push --force-with-lease
向他们发送命令,而不是礼貌的请求,告诉他们绝对应该让他们的名字指向I
(常规 --force
),或者您认为他们的名字现在指向 H
,如果是这样,他们应该改为指向 I
(--force-with-lease
)。如果他们从你那里接受这样的命令——大多数托管站点,比如 GitHub 和 Bitbucket 以及 GitLab 都有他们在 Git 上添加的奇特配置来控制这些东西——那么这可以让你替换毕竟 H
和 I
。
为什么你可能会使用 --force-with-lease
请注意,如果托管站点接受来自 其他人 的 git push
请求,他们现在可能有:
H--J--K <--their-branch
/
...--F--G
\
I
因此你的命令他们将他们的 b运行ch 设置为指向 I
不仅会丢弃你的提交 H
,还会丢弃另外两个额外的提交 J-K
, 关闭他们的 b运行ch.
使用 git push --force-with-lease
向他们发送您的新提交 I
,同时向他们发送您认为他们拥有的哈希 ID H
作为他们在 b运行 上的最终提交通道如果你的信念是错误的,你的条件命令——他们必须更改他们的名字以指向 I
——会被拒绝,说你的 Git 现在已经过时了,你需要 运行git fetch
先.
如果这 不能 发生,则您不需要 --force-with-lease
。非常古老的 Git 版本也没有 --force-with-lease
,但所有现代版本都有,通常最好保持安全检查,即使没有必要,因为随着时间的推移,“习惯”可能会变成“坏习惯”。