Git
git commit

git commit命令: 信息修改、删除、取消、推送、选项

这篇文章将涵盖几乎所有与git commit命令有关的内容。我们将介绍如何编辑、删除和中止提交信息,推送后中止,以及其他有用的选项。

1. 仔细看看git commit命令

在用git init命令创建了一个新的 repo,并用git add命令暂存了需要修改的内容之后,就该提交了。 git commit命令负责将所有当前被暂存的变更登记为当前 repo 的新历史。 既然这是Git系统的一个核心部分,那么就值得更具体一点了。

让我们一步一步地详细了解一下吧

  1. 当你输入 git commit命令时,Git 会检查在 repo 中是否有任何阶段性的修改。如果没有阶段性变化,它将打印以下信息。
$ git commit
On branch main
nothing to commit, working tree clean
  1. 在确认变更的存在后,Git 会创建一个新的提交对象,并为该提交分配一个 SHA-1 哈希值。正如我们在git add post中看到的,这个对象负责存储与单个提交相关的所有数据。

  2. 元数据值,如作者、提交者和提交消息,都被添加到提交对象中。

  3. 提交对象还存储了对一个树形对象的引用,该对象代表了提交时的文件系统。树对象指向Blob对象,Blob对象持有实际的文件内容。 这样一来,提交对象就有了一个已知的当前状态的快照。

  4. 当前工作分支中的最新提交被存储为新提交对象的父提交值。这样可以确保新创建的提交在当前分支上被注册。

  5. 最后,之前指向最新提交的HEAD被改为指向新添加的提交,使其成为当前分支的最后一个提交。

这样一来,所有对阶段性状态的改变都被记录为该 repo 历史的一部分。这是个简单的命令,但里面有很多东西要做。

接下来,我们来看看如何修改已经提交的提交信息。

2. 如何编辑一个提交信息

Git是一个非常重视提交的系统,一旦提交了,就会有很多人关注。 对于已经完成推送的提交,更是如此。 这是因为一次提交会破坏与许多团队成员的同步。

尽管如此,我们都是人,都会犯错。 如果你在提交信息中犯了一个错,你可以迅速修复它并通知你的团队。让我们来看看如何做到这一点。

首先,编辑当前分支中最后一次提交的命令。

$ git commit --amend -m "new commit message"

让我们看看实际的执行结果

git commit --amend execution result

提交信息 2.md created 已经改为 2.md created!!

但这里有一点你需要知道。 同一位置的两个提交的哈希值是不同的。 在修改之前,它是7d16880,而在修改之后,它是ff55e3d。 虽然它看起来像一个修复,但Git在内部删除了旧的提交,并注册了一个新的提交,其中有相同的修改和新的信息。

这有可能导致与使用旧提交开始新工作的团队成员产生冲突。 为了避免这种情况,如果你改变了提交信息,你应该按照新提交的方式通知团队。

2.1. 如果你已经提交了一个现有的提交,怎么办?

如果你用--amend选项在本地编辑一个现有的提交,而该提交在编辑之前已经被推送了,那么本地 repo 和远程 repo 之间会有差异。 在这种情况下,你将无法在当时推送本地的版本。这样做的目的是为了防止远程 repo 提前搞乱你的提交。

在这种情况下,你会得到一个类似下面的错误信息。

$ git push origin main
! [rejected]        your-branch -> your-branch (non-fast-forward)
error: failed to push some refs to 'your-remote-repository-url'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.

有两种方法来解决这种情况。

2.2. 强制推送解决方案

第一种方法是覆盖远程 repo 的拒绝,强制当前本地 repo 推送。I 如果你正在运行一个单独的项目,或者你的团队中的每个人都知道当前的问题,这可能很容易。

它只需要一个命令

$ git push -f

$ git push --force

然而,在所有其他情况下,例如当一个新的提交被注册到一个远程 repo,或者当一个团队成员正在处理一个现有的提交时,它有可能弄乱提交历史,这可能是相当烦人的。

所以只有在真正安全的情况下才使用这种方法。

2.3. 拉取和合并的解决方法

第二种方法在某种程度上更安全。它涉及到从远程 repo 拉取现有的提交历史,然后将其与你的本地提交历史合并或重新发布。然后你可以推回,就像普通的合并一样。

这种方法是安全的,但它确实需要一些额外的工作。如果你还在协作,第二种方法才是最合适的。

关于pullmergerebase命令的更多信息,见相应的文章。

3. 如何撤销一个提交

下面介绍如何撤销一个提交,这将使现有的提交消失,但现有提交中登记的修改会回来,并被修改和解除缓存。

命令如下

$ git reset HEAD~1

让我们看看它的运行情况

运行git commit的结果

首先我们用新文本替换了2.md的内容,然后是add,然后是commit

git reset HEAD~1 execution result

完成提交后,我用git status命令检查了一下,没有更多的改动(nothing to commit)。

然后我运行了git reset HEAD~1来撤销提交,2.md文件中的改动恢复到了未缓存状态。(unstaged changes after reset)

你也可以在撤销提交后检查的状态中看到,2.md文件处于未暂存状态。

git log after reverting commit

最后,运行 git log{:shell}:,你会看到我们上面记录的 1ac689b 提交已经消失。

这就是如何在不丢失所有修改的情况下撤销一个提交。

4.如何删除一个提交

下面是删除一个提交的方法,它可以删除现有的提交以及针对它注册的修改。如果不需要这些修改,可以用它来代替第3节中的取消方法。

命令如下

$ git reset --hard HEAD~1

让我们看看它的运行情况

git reset --hard HEAD~1 experimental settings

如果你用git status检查,目前没有任何阶段性变化。使用 git add 命令将其分阶段,然后完成提交。如果你检查日志,你会发现新哈希值c2072b8的提交已经被注册了。

git reset --hard HEAD~1 执行结果

现在发出 git reset ---hard HEAD~1 来删除最后一次提交。没有修改回来,看历史记录,c2072b8的提交被成功删除。

5. 撤销推送完成的提交

我们之前在第2.1节中看到过这个问题,但要用git reset命令撤消或删除你推送到远程 repo 的提交并不容易。 这是因为本地 repo 和远程 repo 的提交历史是不同的,而远程 repo 会拒绝推送。

解决这个问题的一个方法是第2.2节中的强制推送方法,但我提到不推荐这样做。 取而代之的是,Git 提供了一个命令来明确撤销旧的提交并注册一个新的。

这些命令是

$ git revert HEAD --no-edit

这条命令创建了一个新的提交,恢复了上一次提交的所有修改。这可以由开发者手动完成,但开发者也是人,他们有可能会漏掉某一行。 因此,我们建议使用上述命令来代劳。

我们来看看实际的执行情况

git commit status

这是当前新提交的状态。

让我们注册一个新的提交,明确地恢复我们刚刚注册的那个。

运行 git revert HEAD --no-edit 的结果

一个新的提交已经创建,并且自动写了一条消息,说我们已经恢复了一个现有的提交。如果你没有指定 --no-edit 选项、 它将打开一个纯文本编辑器,比如`vi',你可以在那里写出你想要的提交信息。

6. 使开发更容易的其他选项

到目前为止,git commit命令的-m--amend选项已经在示例代码中有所涉及。这里有一些其他选项可以考虑。

6.1. 不使用git add -u命令的-a选项

git commit -a选项会自动分阶段提交所有修改,而不使用git add命令。

注意,这不包括处于未跟踪状态的文件。像这样使用它

$ git commit -a -m "commit without add command"

6.2. 针对空提交的 --allow-empty 选项

有时你想留下一堆没有新改动的提交。这个选项允许你在没有改动的情况下留下提交。

像这样使用它

$ git commit --allow-empty -m "No changes"

6.3. 使用 --no-verify 选项来覆盖 pre-commit 和 commit-msg 钩子

Git 钩子是事件触发器,当某一事件发生时执行定义的脚本。当一个新的提交被注册时,"pre-commit钩 "和 "commit-msg钩 "被触发。

--no-verify选项是一种忽略这些钩子并创建新提交的方法。使用方法如下

$ git commit --no-verify -m "This Commit ignore hooks"

7. 总结

在这篇文章中,我们几乎涵盖了关于git commit命令的所有知识。 我相信,知道如何提交与知道如何修改和删除提交同样重要。 我将就本篇文章中涉及的git resetgit revert命令写出更深入的文章。

copyright for git commit

© 2023 All rights reserved.