web-dev-qa-db-ja.com

プログラムで古いgit commitメッセージを編集するにはどうすればよいですか?

プログラムで編集できるのは、最後のコミットメッセージのみです。

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プロジェクトを再同期させることは問題ではありません。

7
Jesus H

いくつかのコミットを変更するだけの場合は、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

pickrewordに切り替えると、コミットメッセージを書き換えるためのエディターが提供されます。


たくさんのコミットに対して同じことをする必要がある場合は、 git filter-branch--msg-filter。元のコミットメッセージは標準入力にあり、新しいコミットメッセージは標準出力にあります。これは、現在のブランチのすべてのコミットで「色」を「色」に変更するものです。

git filter-branch --msg-filter "Perl -ple 's{color}{colour}g'"
7
Schwern

任意のコミットを単に「修正」できないのは、コミットが不変であるためです。コミットを修正すると、実際には現在のコミットが別のコミットに置き換えられ、ブランチが新しいコミットに移動します。古いメッセージ、作成者名などのコミットは、クリーンアップするまで履歴に残っています。

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

ちなみにこれは、明示的な一時ブランチがない場合を除いて、1つのコミットのみを変更した場合の対話型リベースの動作とほぼ同じです。

5
Mad Physicist

プログラムで変更を加えたいので、インタラクティブなリベース(git rebase -i)はオプションではありません。

何らかの理由で古いコミットを編集すると、その上にすべてのコミットが効果的にリベースされます。コミットメッセージのみを変更する場合は、マージの競合を心配する必要はありません。

ターゲットコミットをHEADとして新しい一時ブランチを作成し、コミットメッセージを編集して、古いブランチを新しいブランチにマージしてから、古い一時ブランチを削除します。

シェルスクリプトで:

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
1
user5613277