1. 概述
在这篇文章中,我们将探讨修改Git(/git-guide)提交的不同方法。
2. 使用amend
我们可以通过简单的amend
选项来修改最新的Git提交。它会替换最近的提交。我们可以修改提交消息并更新包含在提交中的文件。Git将考虑修改后的提交作为一个新的提交。
让我们通过一个例子尝试amend
选项。为了简单起见,我们先更新一个文件,然后使用消息“Commit 1”进行提交。现在,让我们尝试使用amend
选项更新提交:
git commit --amend
执行上述命令后,会打开一个编辑器以包含更改。我们更新提交消息并保存更改。关闭编辑器后,可以看到更新后的提交如下:
[master c0bc5d3] Amended Commit 1
Date: Wed Jun 29 22:41:08 2022 +0530
1 file changed, 1 insertion(+), 1 deletion(-)
我们也可以在提交时包含暂存区的更改。让我们添加额外的更改,并使用amend
选项将它们包含在最新提交中,同时更改提交消息:
[master 0a1d571] Amended Commit 1 - Added new file
Date: Wed Jun 29 22:41:08 2022 +0530
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 README2
如果我们只想添加暂存区的更改而不更新提交消息,可以使用no-edit
选项:
git commit --amend --no-edit
因此,我们可以看到amend
选项是向最近的提交添加更改的便捷方式。接下来,我们将探讨更新Git历史中较旧提交的不同方法。
3. 使用rebase
(/git-merge-vs-rebase#git-rebase)
我们可以使用rebase
命令将一系列提交移动到新的基线上。Git在内部为每个旧提交创建一个新的提交,并将其移动到指定的新基线上。
使用rebase
命令的-i
选项启动交互式会话。在这个会话中,我们可以根据需要对每个提交进行修改,使用以下命令:
-
pick
(p) -> 包含特定提交 -
squash
(s) -> 将提交与前一个提交合并 -
drop
(d) -> 删除特定提交 -
reword
(r) -> 包括提交并更新提交消息 -
edit
(e) -> 包含提交,同时可以选择更新包含的文件
让我们在我们的示例中使用上述命令来更新提交历史。此时,git log
显示以下提交:
commit 5742fcbe1cb14a9c4f1425eea9032ffb4c6191e5 (HEAD -> master)
Author: #####
Date: Fri Jul 1 08:11:52 2022 +0530
commit 5
commit e9ed266b84dd29095577ddd8f6dc7fcf5cf9db0d
Author: #####
Date: Fri Jul 1 08:11:37 2022 +0530
commit 4
commit 080e3ecc041b7be1757af67bf03db982135b9093
Author: #####
Date: Fri Jul 1 08:11:18 2022 +0530
commit 3
commit d5923e0ced1caff5874d8d41f39d197b5e1e2468
Author: #####
Date: Fri Jul 1 08:10:58 2022 +0530
commit 2
commit 1376dc1182a798b16dc85239ec7382e8340d5267
Author: #####
Date: Wed Jun 29 22:41:08 2022 +0530
Amended Commit 1 - Added new file
假设我们要改变“Amended Commit 1 - Added new file" 之后提交的修改。
让我们将上述提交设置为新基线:
git rebase -i 1376dc1182a798b16dc85239ec7382e8340d5267
这将打开一个编辑器,我们可以根据需要进行更改:
pick d5923e0 commit 2
pick 080e3ec commit 3
pick e9ed266 commit 4
pick 5742fcb commit 5
# Rebase #####..### onto #### (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
现在,让我们尝试一些命令来更新Git历史:
reword d5923e0 commit 2-updated
edit 080e3ec commit 3
squash e9ed266 commit 4
drop 5742fcb commit 5
在第一条命令后,我们会看到以下输出:
[detached HEAD 178e8eb] commit 2-alter
Date: Fri Jul 1 08:10:58 2022 +0530
1 file changed, 1 insertion(+)
Stopped at ######... commit 3
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
现在,按照Git输出指定的,我们执行git commit –amend
命令并进行一些更改:
commit 3
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Fri Jul 1 08:11:18 2022 +0530
#
# interactive rebase in progress; onto 1376dc1
# Last commands done (2 commands done):
# reword d5923e0 commit 2-updated
# edit 080e3ec commit 3
# Next commands to do (2 remaining commands):
# squash e9ed266 commit 4
# drop 5742fcb commit 5
# You are currently splitting a commit while rebasing branch 'master' on '1376dc1'.
#
# Changes to be committed:
# modified: README
# modified: README2
关闭编辑器后,我们得到以下输出:
[detached HEAD 9433120] commit 3 - updated
Date: Fri Jul 1 08:11:18 2022 +0530
2 files changed, 3 insertions(+), 1 deletion(-)
在这里,我们不仅更新了提交消息,还把一个额外的文件包含在了提交中。
接下来,我们需要执行git rebase –continue
命令继续下一个更新。
我们的下一步是将commit 4
与commit 3
合并,它会打开以下编辑器:
# This is a combination of 2 commits.
# This is the 1st commit message:
commit 3 - updated
# This is the commit message #2:
commit 4
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Date: Fri Jul 1 08:11:18 2022 +0530
# interactive rebase in progress; onto 1376dc1
# Last commands done (3 commands done):
# edit 080e3ec commit 3
# squash e9ed266 commit 4
# Next command to do (1 remaining command):
# drop 5742fcb commit 5
# You are currently rebasing branch 'master' on '1376dc1'.
#
# Changes to be committed:
# modified: README
# modified: README2
在上述编辑器中添加修改后,我们得到以下输出:
[detached HEAD 917c583] commit 3 - squashed with commit 4
Date: Fri Jul 1 08:11:18 2022 +0530
2 files changed, 3 insertions(+), 1 deletion(-)
Successfully rebased and updated refs/heads/master.
最后,我们请求删除commit 5
,这不需要我们进一步操作。
4. 查看日志分析
完成上述步骤后,我们可以看到git log
的输出:
commit 917c583d5bb02803ee43cf87a2143f201c97bbe8 (HEAD -> master)
Author: #######
Date: Fri Jul 1 08:11:18 2022 +0530
commit 3 - squashed with commit 4
commit 4
commit 178e8ebec178c166d1c9def2d680f41933eba29b
Author: #######
Date: Fri Jul 1 08:10:58 2022 +0530
commit 2-alter
commit 1376dc1182a798b16dc85239ec7382e8340d5267
Author: #######
Date: Wed Jun 29 22:41:08 2022 +0530
Amended Commit 1 - Added new file
这里我们可以观察到几点:
-
commit 5
已被删除 -
commit 4
与commit 3
合并 -
commit 2
的消息已更新
在最终的日志中,我们可以看到提交的ID已经改变。这是因为Git已经替换了之前的提交,并用带有修改的新提交取代了它们。
我们可以使用reflog
命令查看与当前HEAD
相关的引用日志。它包括所有与Git提交相关的更新历史。
让我们使用reflog
命令来观察我们示例的Git历史:
917c583 (HEAD -> master) HEAD@{0}: rebase -i (finish): returning to refs/heads/master
917c583 (HEAD -> master) HEAD@{1}: rebase -i (squash): commit 3 - squashed with commit 4
9433120 HEAD@{2}: commit (amend): commit 3 - updated
f4e8340 HEAD@{3}: commit (amend): commit 3 - updated
fd048e1 HEAD@{4}: commit (amend): commit 3 - updated
39b2f1b HEAD@{5}: commit (amend): commit 3 - updated
f79cbfb HEAD@{6}: rebase -i (edit): commit 3
178e8eb HEAD@{7}: rebase -i (reword): commit 2-alter
d5923e0 HEAD@{8}: rebase -i: fast-forward
1376dc1 HEAD@{9}: rebase -i (start): checkout 1376dc1182a798b16dc85239ec7382e8340d5267
5742fcb HEAD@{10}: commit: commit 5
e9ed266 HEAD@{11}: commit: commit 4
080e3ec HEAD@{12}: commit: commit 3
d5923e0 HEAD@{13}: commit: commit 2
1376dc1 HEAD@{14}: commit (amend): Amended Commit 1 - Added new file
5. 总结
在这篇文章中,我们探讨了改变Git历史的不同方法。然而,在使用这些选项时,我们应该谨慎行事,因为这可能会导致内容丢失。