Как добавить измененный файл в более старый (не последний) коммит в Git
За последний час я изменил несколько вещей и сделал их шаг за шагом, но я только что понял, что забыл добавить измененный файл несколько коммитов назад.
Журнал выглядит так:
GIT TidyUpRequests u:1 d:0> git log
commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce
Author: David Klein <>
Date: Tue Apr 27 09:43:55 2010 +0200
The Main program now tests both Webservices at once
commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463
Author: David Klein <>
Date: Tue Apr 27 09:43:27 2010 +0200
ISBNDBQueryHandler now uses the XPath functions from XPath.fs too
commit 06a504e277fd98d97eed4dad22dfa5933d81451f
Author: David Klein <>
Date: Tue Apr 27 09:30:34 2010 +0200
AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs
commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
Author: David Klein <>
Date: Tue Apr 27 09:29:53 2010 +0200
Factored out some common XPath Operations
Есть идеи?
7 ответов
Использование git rebase
, В частности:
- использование
git stash
сохранить изменения, которые вы хотите добавить. - использование
git rebase -i HEAD~10
(или сколько коммитов вы хотите увидеть). - Отметить коммит в вопросе (
a0865...
) для редактирования, изменив словоpick
в начале строки вedit
, Не удаляйте другие строки, так как это приведет к удалению коммитов.[^ Vimnote] - Сохраните файл rebase, и git вернется в оболочку и будет ждать, пока вы исправите этот коммит.
- Вставьте тайник с помощью
git stash pop
- Добавьте свой файл с
git add <file>
, - Изменить коммит с
git commit --amend --no-edit
, - Сделать
git rebase --continue
который перезапишет остальные ваши коммиты против нового. - Повторите, начиная с шага 2, если вы пометили более одного коммита для редактирования.
[^ vimnote]: если вы используете vim
затем вам нужно будет нажать клавишу Вставить, чтобы отредактировать, затем нажмите Esc и введите :wq
чтобы сохранить файл, выйдите из редактора и примените изменения. Кроме того, вы можете настроить удобный редактор git commit с помощью git config --global core.editor "nano"
,
"Исправить" старый коммит с небольшим изменением, не изменяя сообщение коммита старого коммита, где OLDCOMMIT
это что-то вроде 091b73a
:
git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^
Вы также можете использовать git commit --squash=OLDCOMMIT
отредактировать старое сообщение коммита во время перебазирования.
git rebase --interactive
вызовет текстовый редактор (который можно настроить) для подтверждения (или редактирования) последовательности команд rebase. В файле есть информация об изменениях инструкции rebase; просто сохраните и выйдите из редактора (:wq
вvim
) продолжить с ребазом.--autosquash
автоматически поставит любой--fixup=OLDCOMMIT
фиксирует в желаемом порядке. Обратите внимание, что--autosquash
действует только тогда, когда--interactive
опция используется.^
вOLDCOMMIT^
означает, что это ссылка на коммит непосредственно передOLDCOMMIT
,
Вышеуказанные шаги полезны для проверки и / или изменения последовательности команд rebase, но также можно пропустить / автоматизировать интерактивный текстовый редактор rebase:
- настройка
GIT_SEQUENCE_EDITOR
к сценарию. - Создание псевдонима git для автоматического автоматического удаления всех исправлений в очереди.
- Создание псевдонима git для автоматической фиксации одного коммита.
Смотрите git commit и git rebase. Как всегда, при переписывании истории git вы должны фиксировать или фиксировать коммиты, которые вы еще никому не публиковали (включая случайных пользователей интернета и серверы сборки).
С git 1.7 есть действительно простой способ git rebase
:
подготовить ваши файлы:
git add $files
создать новый коммит и повторно использовать сообщение коммита вашего "битого" коммита
git commit -c master~4
перед именем fixup!
в теме (или squash!
если вы хотите редактировать коммит (сообщение):
fixup! Factored out some common XPath Operations
использование git rebase -i --autosquash
чтобы исправить ваш коммит
Вы можете попробовать rebase --interactive
сеанс для изменения вашего старого коммита (при условии, что вы еще не передали эти коммиты в другое репо).
Иногда вещь исправлена в п.2. нельзя исправить до не совсем совершенного коммита, который он исправляет, потому что этот коммит глубоко скрыт в серии патчей.
Это именно то, для чего нужен интерактивный ребаз: используйте его после множества "а" и "б", переставляя и редактируя коммиты, и складывая несколько коммитов в один.Начните с последнего коммита, который вы хотите сохранить как есть:
git rebase -i <after-this-commit>
Редактор будет запущен со всеми коммитами в вашей текущей ветке (игнорируя коммиты слияния), которые идут после данного коммита.
Вы можете переупорядочить коммиты в этом списке на свое усмотрение, и вы можете удалить их. Список выглядит примерно так:
pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...
Онлайновые описания предназначены исключительно для вашего удовольствия; git rebase будет смотреть не на них, а на имена коммитов (в этом примере "deadbee" и "fa1afe1"), поэтому не удаляйте и не редактируйте имена.
Заменив команду "pick" на команду "edit", вы можете указать git rebase прекратить работу после применения этого коммита, чтобы вы могли редактировать файлы и / или сообщение о коммите, вносить изменения и продолжать перебазирование.
Вот функция, которая реализует ответ @Greg:
function gitamendoldcommit() {
printf "\n\nPress any key if you have no changes other than those you want to add to $1."
printf "(You can commit your unwanted changes and undo later.):\n\n"
read foo
printf "\n\nChange 'pick' to 'edit' in front of $1 (top one), save, close the editor & press any key..."
printf "Resolve any possible conflicts, if any. then: git add .; git rebase --continue\n\n"
git rebase -i $1^
git stash pop
git add .
git commit --amend --no-edit
git rebase --continue
}
Использование: (при наличии только предполагаемых изменений в постановке)
gitamendoldcommit $OLDCOMMIT
Кроме того, если вы используете
git rebase -i
и хотите перейти к первой фиксации вашей текущей ветки, которую вы можете использовать
git rebase -i --root
. Теперь вы можете легко изменить свою первую фиксацию.
В 2023 году есть инструменты, которые это делают: в частности, git Absorb . Это отличный инструмент, способный изменить множество пыльных рабочих процессов git.