【问题标题】:How can I edit an old git commit message programmatically?如何以编程方式编辑旧的 git 提交消息?
【发布时间】:2018-11-10 23:08:10
【问题描述】:

您可以通过编程方式仅编辑最后一条提交消息:

git commit --amend -m 'xxxxxxx'

或者以交互方式随机提交:

git rebase -i HEAD~n
# Vim opens up, select the commit you want to modify, and change the word "pick" for "edit"
git commit --amend -m "Changing an old commit message!"
git rebase --continue

如何将两者结合起来?我想以编程方式更改消息,但要更改为先前的提交,而不仅仅是最后一个。

我要修改的提交已经被推送到 git 服务器,但让其他人重新同步 git 项目不是问题。

【问题讨论】:

标签: git git-rebase git-commit git-amend


【解决方案1】:

您不能简单地“修改”任意提交的原因是提交是不可变的。当您修改提交时,它实际上会用另一个提交替换当前提交并将您的分支移动到新提交。在您清理之前,包含旧消息、作者姓名等的提交仍然存在于历史记录中:

Before:

        master
          |
          v
A -- B -- C

After:

        master
          |
          v
A -- B -- C'
      \
       \- C

要模拟“修改”任意提交,您不仅必须重写该提交,还必须重写其之后的整个历史记录,因为提交将其父级作为其不可变数据的一部分:

Before:

        master
          |
          v
A -- B -- C

After:

         master
           |
           v
A -- B' -- C'
 \ 
  \- B --- C

您可以通过在您感兴趣的提交上创建一个分支、修改它并将原始分支的提交范围重新定位到原始分支的尖端到新分支上来做到这一点。这是一个显示您所追求的示例:

Start:

             master
               |
               v
A -- B -- C -- D

New Branch:

             master
               |
               v
A -- B -- C -- D
     ^
     |
    temp

Amend:

             master
               |
               v
A -- B -- C -- D
 \
  \- B'
     ^
     |
    temp

Rebase:

A -- B  -- C  -- D
 \
  \- B' -- C' -- D'
     ^           ^
     |           |
    temp       master

Cleanup:

A -- B  -- C  -- D
 \
  \- B' -- C' -- D'
                 ^
                 |
               master

顺便说一句,这与交互式 rebase 几乎完全相同,当你只修改一个提交时,除了没有显式的临时分支。

【讨论】:

    【解决方案2】:

    如果您只是更改一些提交,请使用git rebase -i 和“reword”选项。比如……

    pick 6256642 mv file1 file2
    pick 20c2e82 Add another line to file2
    
    # Rebase 8236784..20c2e82 onto 8236784 (2 commands)
    #
    # Commands:
    # p, pick = use commit
    # r, reword = use commit, but edit the commit message
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    # f, fixup = like "squash", but discard this commit's log message
    # x, exec = run command (the rest of the line) using shell
    # d, drop = remove commit
    

    pick 切换为reword,您将获得一个编辑器来重写提交消息。


    如果您需要对大量提交执行相同的操作,请使用 git filter-branch--msg-filter。原始提交消息在标准输入上,新提交消息在标准输出上。这是在当前分支的所有提交中将“颜色”更改为“颜色”的方法。

    git filter-branch --msg-filter "perl -ple 's{color}{colour}g'"
    

    【讨论】:

    • filter-branch 应用于所有提交。是否可以将过滤器应用于特定的提交?我尝试在最后传递一个提交哈希,但过滤器分支需要一个哈希..ref。如果我通过 hash..HEAD,它将应用于指定哈希之后的所有提交。如果不可能,我想我可以使用提供的解决方案(通过解析标准输入消息)。谢谢!
    • @JesusH git filter-branch 采用与git rev-list 相同的修订参数,因此您可以设计一种方法来指定一个提交。例如,git rev-list HEAD^..HEAD 只做HEAD。如果您只想进行一次提交,请使用git rebase -i。我不明白你为什么要编写一个程序来更改一次提交的消息。这是非常不寻常的。如果您解释说我们可以提供更好的帮助。
    【解决方案3】:

    由于您想以编程方式进行更改,因此不能选择交互式 rebase (git rebase -i)。

    无论出于何种原因,编辑旧的提交都会有效地将所有提交重新设置在此之上。如果您只更改提交消息,则无需担心合并冲突。

    您创建一个新的临时分支,将目标提交作为其 HEAD,编辑提交消息,将旧分支合并到新分支上,然后删除旧的临时分支。

    在 shell 脚本中:

    CURBRANCH=`git rev-parse --abbrev-ref HEAD`
    TMPBRANCH=tmp$$
    git checkout $SHA -b $TMPBRANCH
    MSG=`tempfile`
    git log --format=%B -n 1 HEAD > $MSG
    ... edit the $MSG file
    git commit --amend -F $MSG
    SHA=`git rev-list -n 1 HEAD`   # Commit has change, so SHA has also changed
    rm $MSG
    git rebase --onto $TMPBRANCH HEAD $CURBRANCH
    git branch -d $TMPBRANCH
    

    【讨论】:

      猜你喜欢
      • 2012-05-05
      • 2011-11-27
      • 2011-11-08
      • 1970-01-01
      • 2011-04-25
      • 2014-12-25
      • 1970-01-01
      • 2020-08-13
      • 2011-11-30
      相关资源
      最近更新 更多