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