wake-up-neo.net

Wie kann ich eine alte Git-Commit-Nachricht programmgesteuert bearbeiten?

Sie können nur die letzte Commit-Nachricht programmgesteuert bearbeiten:

git commit --amend -m 'xxxxxxx'

Oder ein zufälliges Commit interaktiv:

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

Wie kombiniere ich beides? Ich möchte eine Nachricht programmgesteuert ändern, aber zu einem vorherigen Commit, nicht nur zum letzten.

Das Commit, das ich ändern möchte, wurde bereits an einen Git-Server weitergeleitet, aber wenn andere Personen das Git-Projekt erneut synchronisieren, ist dies kein Problem. 

7
Jesus H

Wenn Sie nur ein paar Commits ändern, verwenden Sie git rebase -i und die Option "reword". Zum Beispiel...

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

Wenn Sie pick auf reword setzen, wird Ihnen ein Editor zum Umschreiben der Festschreibungsnachricht angeboten.


Wenn Sie für viele Commits dasselbe tun müssen, verwenden Sie git filter-branch mit einem --msg-filter. Die ursprüngliche Commit-Nachricht befindet sich in stdin, die neue Commit-Nachricht in stdout. Hier ist eine, um "Farbe" in "Farbe" in allen Commits im aktuellen Zweig zu ändern.

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

Der Grund, warum Sie ein beliebiges Commit nicht einfach "ändern" können, ist, dass Commits unveränderlich sind. Wenn Sie ein Commit ändern, wird das aktuelle Commit durch ein anderes Commit ersetzt und Ihr Zweig wird zum neuen Commit verschoben. Das Commit mit der alten Nachricht, dem Namen des Autors usw. ist noch in der Historie vorhanden, bis Sie es bereinigen:

Before:

        master
          |
          v
A -- B -- C

After:

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

Um "willkürliche Änderungen" eines simulierten Commits zu simulieren, müssten Sie nicht nur dieses Commit neu schreiben, sondern die gesamte Historie danach, da ein Commit seine Eltern als Teil seiner unveränderlichen Daten enthält:

Before:

        master
          |
          v
A -- B -- C

After:

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

Sie können dies tun, indem Sie in dem Commit, an dem Sie interessiert sind, einen Zweig erstellen, ihn ändern und den Bereich des Commits, der dem Original folgt, an der Spitze des ursprünglichen Zweigs auf den neuen Zweig umstellen. Hier ist ein Beispiel, das zeigt, was Sie suchen:

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

Dies ist so ziemlich genau das, was interaktive Rebase macht, wenn Sie übrigens nur einen einzelnen Commit ändern, außer ohne den expliziten temporären Zweig.

4
Mad Physicist

Da Sie die Änderung programmgesteuert vornehmen möchten, ist interaktives Rebase (git rebase -i) keine Option.

Das Bearbeiten eines alten Commits, aus welchem ​​Grund auch immer, wird alle Commits darüber hinaus effektiv widerlegen. Wenn Sie nur die Festschreibungsnachricht ändern, müssen Sie sich nicht um Zusammenführungskonflikte kümmern.

Sie erstellen einen neuen temporären Zweig mit dem Ziel-Commit als HEAD, bearbeiten die Commit-Nachricht, führen den alten Zweig mit dem neuen zusammen und löschen dann den alten temporären Zweig.

In einem Shell-Skript:

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
0
Timur Tabi