Git commit --amend 合并了两个提交

Git commit --amend merged two commits

我有一个远程 'dev' 分支,正在本地处理它。

我在 'dev' 上使用提交消息 "my_feature" 进行了第一次提交,将我的本地分支领先于远程 1 次提交。

然后我开发了一些新东西并制作了 git add -u,准备提交。 然后我意识到我想将以前的提交消息重写为 "my_feature (1/2)" 以使我当前的提交消息成为 "my_feature (2/2)",将我的本地分支提前 2 次提交。

所以我做了一个 git commit --amend(认为它只会编辑之前提交的消息),将 "my_feature" 提交消息编辑为 "my_feature (1/2)" 并且... 最终只有一个标记为 "my_feature (1/2)" 的提交 包含我所有的更改(第一次提交 + 暂存文件差异)——我的索引现在是干净的。

所以如果我做对了,我的命令实际上做了一个提交,还提交了暂存文件,这产生了一个(合并的?)提交?

我没想到 Git 会做这样的事情。 我只是想编辑我的旧提交消息,而不是将旧的与我当前的暂存合并文件。 (现在想想 rebase 本来可以更好。)

虽然我能理解为什么 git commit --amend 可以提交(即使我只想编辑提交消息),我很难理解 Git 如何合并我的两个提交使用 commit 命令合二为一。

谁能给我解释一下?

$ git --version
git version 1.7.10.4

如果您有暂存文件并执行

git commit --amend

您将创建一个新的提交,其中包含之前提交中的所有内容加上暂存的所有内容,并且这个新提交将替换 之前的提交作为您已签出的分支的提示。

git commit --amend 没有任何暂存文件可用于更改提交消息,但请注意,即使在没有暂存文件的情况下,您也会得到一个新的 sha1,换句话说,一个新的提交。

来自documentation

Used to amend the tip of the current branch. Prepare the tree object you would want to replace the latest commit as usual (this includes the usual -i/-o and explicit paths), and the commit log editor is seeded with the commit message from the tip of the current branch. The commit you create replaces the current tip — if it was a merge, it will have the parents of the current tip as parents — so the current top commit is discarded.

git commit --amend 将阶段性更改添加到最近的提交中。因为它合并你的两个我怀疑有不是两个提交而是一个。

man page 对此进行了解释:

--amend
    Replace the tip of the current branch by creating a new commit. The
    recorded tree is prepared as usual (including the effect of the -i and
    -o options and explicit pathspec), and the message from the original
    commit is used as the starting point, instead of an empty message, when
    no other message is specified from the command line via options such as
    -m, -F, -c, etc. The new commit has the same parents and author as the
    current one (the --reset-author option can countermand this).

    It is a rough equivalent for:

        $ git reset --soft HEAD^
        $ ... do something else to come up with the right tree ...
        $ git commit -c ORIG_HEAD

    but can be used to amend a merge commit.

    You should understand the implications of rewriting history if you
    amend a commit that has already been published. (See the "RECOVERING
    FROM UPSTREAM REBASE" section in git-rebase[1].)

因为您描述了处理多个提交,所以我将解释上面描述的工作流程如何代替:

A--B (origin/dev) (dev)

编辑文件,并添加暂存 (git add -u) 然后:

$ git commit # edit a good message (see below)

A--B (origin/dev)
    \
     C (dev)

现在重复:

$ git commit # edit another awesome message (see below)

A--B (origin/dev)
    \
     C--D (dev)

但现在您意识到提交 C 有错误的提交消息。所以我们做一个变基:

$ git rebase -i origin/dev

在编辑器中,您会看到提交 C 和 D 及其主题行和关键字 pick。找到您要修复的提交并将 pick 更改为 reword 然后保存文件。

git 将打开另一个编辑器并让您修复提交消息。保存并继续。

关于提交消息的注释(因为我想传播这个词):

https://thoughtbot.com/blog/5-useful-tips-for-a-better-commit-message

Capitalized, short (50 chars or less) summary

More detailed explanatory text, if necessary.  Wrap it to about 72
characters or so.  In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body.  The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.

Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug."  This convention matches up with commit messages generated
by commands like git merge and git revert.

Further paragraphs come after blank lines.

- Bullet points are okay, too

- Typically a hyphen or asterisk is used for the bullet, followed by a
  single space, with blank lines in between, but conventions vary here

- Use a hanging indent

这是预期的行为。来自 git commit documentation.

--amend

Replace the tip of the current branch by creating a new commit. The recorded tree is prepared as usual (including the effect of the -i and -o options and explicit pathspec), and the message from the original commit is used as the starting point, instead of an empty message, when no other message is specified from the command line via options such as -m, -F, -c, etc. The new commit has the same parents and author as the current one (the --reset-author option can countermand this).

It is a rough equivalent for:

$ git reset --soft HEAD^
$ ... do something else to come up with the right tree ...
$ git commit -c ORIG_HEAD

but can be used to amend a merge commit.

You should understand the implications of rewriting history if you amend a commit that has already been published. (See the "RECOVERING FROM UPSTREAM REBASE" section in git-rebase[1].)


要理解的重要部分是 git reset --soft HEAD^。这将 "remove" 从您的历史记录中提交,但不会更改您的工作树或索引。

看看documentation of git reset。强调我的。

--soft

Does not touch the index file or the working tree at all (but resets the head to , just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.