Как я могу редактировать старое сообщение 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-сервер, но не нужно беспокоиться о повторной синхронизации проекта другими людьми.
4 ответа
Причина, по которой вы не можете просто "изменить" произвольный коммит, заключается в том, что коммиты являются неизменяемыми. Когда вы изменяете коммит, он фактически заменяет текущий коммит другим и перемещает вашу ветку в новый коммит. Коммит со старым сообщением, именем автора и т. Д. Остается в истории, пока вы его не очистите:
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
Это в значительной степени именно то, что делает интерактивная перебазировка, когда вы, между прочим, изменяете только один коммит, кроме как без явной временной ветки.
Если вы просто меняете несколько коммитов, используйте git rebase -i
и вариант "перефразировать". Например...
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'"
Поскольку вы хотите внести изменения программно, интерактивная перебазировка (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
Вместо перебазирования и принудительной отправки измененной ветки можно заменить коммит другим сообщением, не затрагивая существующие хэши коммита:
git checkout <commit>
git commit --amend -m "New message"
git replace <commit> $(git rev-parse HEAD)
Это также можно сделать в интерактивном режиме с помощью:
git replace --edit <commit>
Обратите внимание, что измененные ссылки затем придется отправлять и получать явно с помощью:
git push origin 'refs/replace/*'
git fetch origin 'refs/replace/*:refs/replace/*'