Я обычно представляю список коммитов на рассмотрение. Если у меня есть следующие коммиты:
HEAD
Commit3
Commit2
Commit1
... Я знаю, что могу изменить коммит с головой git commit --amend
. Но как я могу изменить Commit1
, учитывая, что это не HEAD
коммит?
git
git-rewrite-history
Сэм Ляо
источник
источник
Ответы:
Вы можете использовать git rebase . Например, если вы хотите изменить коммит
bbc643cd
, запуститеПожалуйста, обратите внимание на знак вставки
^
в конце команды, потому что на самом деле вам нужно перебазировать обратно в коммит, прежде чем тот, который вы хотите изменить .В редакторе по умолчанию измените
pick
наedit
в строке упоминание 'bbc643cd'.Сохраните файл и выйдите: git будет интерпретировать и автоматически выполнять команды в файле. Вы окажетесь в предыдущей ситуации, в которой вы только что создали commit
bbc643cd
.На данный момент
bbc643cd
это ваш последний коммит, и вы можете легко изменить его : внести изменения, а затем зафиксировать их с помощью команды:После этого введите:
вернуться к предыдущему коммиту HEAD.
ВНИМАНИЕ : обратите внимание, что это изменит SHA-1 этого коммита, а также всех дочерних элементов - другими словами, это переписывает историю с этого момента. Делая это , вы можете сломать репо, если нажмете команду
git push --force
источник
reword
действиеgit rebase -i
вместоedit
(оно автоматически открывает редактор и выполняет остальные шаги перебазирования; это исключает использованиеgit commit --ammend
иgit rebase --continue
когда вам нужно только изменить сообщение фиксации, а не содержимое ).git stash
доgit rebase
иgit stash pop
после, если у вас есть ожидающие изменения.git commit --all --amend --no-edit
здесь. Все, что я должен был сделать после этого,git rebase -i ...
- этоgit commit --amend
нормальноgit rebase --continue
.Используйте удивительный интерактивный ребаз:
Найдите нужный коммит, измените
pick
наe
(edit
), сохраните и закройте файл. Git перемотает на этот коммит, что позволит вам:git commit --amend
для внесения изменений, илиgit reset @~
для отмены последнего коммита, но не для изменений в файлах (т. е. перенесите вас в тот момент, когда вы редактировали файлы, но еще не зафиксировали).Последнее полезно для выполнения более сложных вещей, таких как разбиение на несколько коммитов.
Затем запустите
git rebase --continue
, и Git воспроизведет последующие изменения поверх вашего измененного коммита. Вас могут попросить исправить некоторые конфликты слияния.Примечание:
@
является сокращением дляHEAD
и~
является коммитом перед указанным коммитом.Узнайте больше о переписывании истории в Git docs.
Не бойся перебазировать
ProTip ™: не бойтесь экспериментировать с «опасными» командами, которые переписывают историю * - Git по умолчанию не удаляет ваши коммиты в течение 90 дней; вы можете найти их в reflog:
* Остерегайтесь опций, как
--hard
и--force
хотя - они могут отказаться от данных.* Кроме того, не переписывайте историю ни в каких ветвях, над которыми вы сотрудничаете.
Во многих системах
git rebase -i
откроется Vim по умолчанию. Vim не работает, как большинство современных текстовых редакторов, поэтому взгляните на то, как сделать перебаз с помощью Vim . Если вы предпочитаете использовать другой редактор, измените его с помощьюgit config --global core.editor your-favorite-text-editor
.источник
@
как сокращение дляHEAD
. Спасибо за публикацию этого.git reset @~
именно то, что я хотел сделать после выбора коммитаgit rebase ...
. Ты мой герой)Интерактивные перебазироваться с
--autosquash
то , что я часто использую , когда мне нужно FixUp предыдущих коммитов глубже в истории. Это существенно ускоряет процесс, который иллюстрирует ответ ZelluX, и особенно удобно, когда вам нужно отредактировать более одного коммита.Из документации:
Предположим, у вас есть история, которая выглядит так:
и у вас есть изменения, которые вы хотите внести в Commit2, а затем зафиксируйте изменения, используя
в качестве альтернативы вы можете использовать commit-sha вместо сообщения фиксации,
"fixup! e8adec4
или даже просто префикс сообщения фиксации.Затем инициируйте интерактивную перебазировку коммита до
ваш редактор откроется с коммитами, уже правильно упорядоченными
все, что вам нужно сделать, это сохранить и выйти
источник
git commit --fixup=@~
вместоgit commit -m "fixup! Commit2"
. Это особенно полезно, когда ваши сообщения фиксации длиннее, и было бы неудобно печатать все это.Запустить:
$ git rebase --interactive commit_hash^
каждый
^
указывает, сколько коммитов вы хотите отредактировать, если он только один (указанный вами хэш, то вы просто добавляете один)^
.Использование Vim изменить слова ,
pick
чтобыreword
для фиксаций вы хотите изменить, сохранить и выйти (:wq
). Затем git предложит вам каждый коммит, который вы пометили как reword, чтобы вы могли изменить сообщение коммита.Каждое сообщение коммита вы должны сохранить и выйти (
:wq
), чтобы перейти к следующему сообщению коммитаЕсли вы хотите выйти без применения изменений, нажмите
:q!
РЕДАКТИРОВАТЬ : для навигации
vim
используйтеj
для перехода вверх,k
вниз,h
влево иl
вправо (все это вNORMAL
режиме, нажмитеESC
для перехода вNORMAL
режим). Чтобы редактировать текст, нажмите,i
чтобы войти вINSERT
режим, в который вы вставляете текст. Нажмите,ESC
чтобы вернуться вNORMAL
режим :)ОБНОВЛЕНИЕ : Вот отличная ссылка из списка GitHub Как отменить (почти) все, что с Git
источник
git push --force
?git push --force
перезаписывает удаленные коммиты с вашими локальными коммитами. Это не относится к этой теме :)Если по какой-то причине вам не нравятся интерактивные редакторы, вы можете использовать
git rebase --onto
.Скажи, что хочешь изменить
Commit1
. Во-первых, ветвь из ранееCommit1
:Во-вторых, возьмите
Commit1
с собойcherry-pick
:Теперь внесите изменения, создав
Commit1'
:И, наконец, после того, как вы спрятали любые другие изменения, перенесите остальные ваши коммиты
master
на верх вашего нового коммита:Читайте: «перебазировать на ветку
amending
все коммиты междуCommit1
(не включительно) иmaster
(включительно)». То есть, Commit2 и Commit3, полностью исключая старый Commit1. Вы можете просто выбрать их, но так проще.Не забудьте убирать свои ветви!
источник
git checkout -b amending Commit1~1
чтобы получить предыдущий коммитgit checkout -b amending Commit1
?На основании документации
Поправка к сообщению старых или нескольких сообщений коммита
Выше показан список последних 3 коммитов в текущей ветви, замените 3 на что-то другое, если хотите больше. Список будет выглядеть примерно так:
Замените pick на reword перед каждым коммит-сообщением, которое вы хотите изменить. Допустим, вы изменили второй коммит в списке, ваш файл будет выглядеть следующим образом:
Сохраните и закройте файл списка коммитов, появится новый редактор, в котором вы сможете изменить сообщение о коммите, изменить сообщение о коммите и сохранить.
Окончательно Force-push исправленных коммитов.
источник
Полностью неинтерактивная команда (1)
Я просто думал, что поделюсь псевдонимом, который я использую для этого. Он основан на неинтерактивном интерактивном ребазе. Чтобы добавить его в свой git, выполните эту команду (объяснение приведено ниже):
Самым большим преимуществом этой команды является тот факт, что она не vim .
(1) учитывая, что нет никаких конфликтов во время перебазирования, конечно
Применение
Название
amend-to
кажется подходящим ИМХО. Сравните поток с--amend
:объяснение
git config --global alias.<NAME> '!<COMMAND>'
- создает глобальный псевдоним git,<NAME>
который будет выполнять не-git команду<COMMAND>
f() { <BODY> }; f
- анонимная функция bash.SHA=`git rev-parse "$1"`;
- преобразует аргумент в git revision и присваивает результат переменнойSHA
git commit --fixup "$SHA"
Fixup-коммит дляSHA
. Смgit-commit
документыGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
часть была покрыта другими ответами.--autosquash
это то, что используется в сочетании сgit commit --fixup
, см.git-rebase
документы для получения дополнительной информацииGIT_SEQUENCE_EDITOR=true
это то, что делает все это неинтерактивным. Этот взлом я узнал из этого поста в блоге .источник
amend-to
обрабатывать неподготовленные файлы:git config --global alias.amend-to '!f() { SHA=
git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Автоматическое интерактивное редактирование ребазирования с последующим коммитом, готовым к повторному выполнению
Я обнаружил, что исправляю прошлый коммит достаточно часто, поэтому я написал для него скрипт.
Вот рабочий процесс:
Это приведет вас к коммиту, который вы хотите отредактировать.
Фиксируйте и ставьте коммит так, как вам хотелось бы.
(Вы можете использовать
git stash save
любые файлы, которые вы не делаете)Повторите коммит
--amend
, например:Завершите перебазирование:
Чтобы вышеперечисленное сработало, поместите приведенный ниже скрипт в исполняемый файл, который называется
git-commit-edit
где-то в вашем$PATH
:источник
Пришел к такому подходу (и он, вероятно, точно такой же, как с использованием интерактивного ребазинга), но для меня это довольно просто.
Примечание: я представляю этот подход для иллюстрации того, что вы можете сделать, а не для повседневной альтернативы. Так как в нем много шагов (и, возможно, несколько предостережений).
Скажем, вы хотите изменить коммит,
0
и вы в настоящее время наfeature-branch
Оформить заказ на эту фиксацию и создать
quick-branch
. Вы также можете клонировать свою функциональную ветвь как точку восстановления (перед запуском).Теперь у вас будет что-то вроде этого:
Сценические изменения, прятать все остальное.
Зафиксируйте изменения и вернитесь к
feature-branch
Теперь у вас будет что-то вроде этого:
Перебазировать
feature-branch
наquick-branch
(разрешить любые конфликты по пути). Примените тайник и удалитеquick-branch
.И вы в конечном итоге:
Git не будет дублировать (хотя я не могу точно сказать, в какой степени) коммит 0 при ребазинге.
Примечание: все хеши коммитов меняются, начиная с коммита, который мы изначально намеревались изменить.
источник
Чтобы получить неинтерактивную команду, поместите скрипт с этим содержимым в ваш PATH:
Используйте его, поставив свои изменения (с
git add
), а затем запуститеgit fixup <commit-to-modify>
. Конечно, он все равно будет интерактивным, если у вас возникнут конфликты.источник
git stash
+rebase
автоматизацияКогда мне нужно много раз модифицировать старый коммит для обзоров Геррита, я делаю:
GitHub вверх по течению .
Применение:
git add
если уже в репоgit-amend-old $old_sha
Мне это нравится,
--autosquash
потому что это не раздавливает другие несвязанные исправления.источник
git amend
чтобы применить изменения к конкретному коммиту с использованием текущего тайника, очень умно!Я решил это,
1) путем создания нового коммита с изменениями, которые я хочу ..
2) я знаю, какой коммит мне нужно слить с ним. который совершает 3.
Итак,
git rebase -i HEAD~4
# 4 представляет последние 4 коммита (здесь коммит 3 находится на 4-м месте)3) в интерактивном ребазе недавний коммит будет расположен внизу это будет выглядеть одинаково,
4) здесь нам нужно изменить коммит, если вы хотите объединить с конкретным. это должно быть как,
после перестановки необходимо заменить
p
pick
наf
( исправление объединится без сообщения фиксации) илиs
( объединение сквоша с сообщением фиксации может измениться во время выполнения)а затем сохранить свое дерево.
Теперь слияние сделано с существующим коммитом.
источник
Наилучшим вариантом является использование «Интерактивной команды rebase» .
Теперь, как использовать эту команду?
-i
стенд для "интерактивного" . Обратите внимание, что вы можете выполнить ребаз в неинтерактивном режиме. например:HEAD
указывает ваше текущее местоположение (может быть также именем филиала или коммитом SHA).~n
Означает «п beforeé, такHEAD~n
будет список„п“фиксаций до того, вы в данный момент.git rebase
имеет другую команду, как:p
илиpick
сохранить коммит как есть.r
илиreword
: сохранить содержимое фиксации, но изменить сообщение фиксации.s
илиsquash
: объединить изменения этого коммита в предыдущий коммит (коммит над ним в списке).... так далее.
Примечание: лучше сделать так, чтобы Git работал с вашим редактором кода, чтобы все было проще. Например, если вы используете визуальный код, вы можете добавить вот так
git config --global core.editor "code --wait"
. Или вы можете найти в Google, как связать предпочитаемый вами редактор кода с GIT.Пример
git rebase
Я хотел изменить последние 2 коммита, которые я сделал, поэтому я обрабатываю так:
Теперь я использую
git rebase
для изменения 2 последних сообщения о коммитах:$git rebase -i HEAD~2
он открывает редактор кода и показывает это:Так как я хочу изменить сообщение коммита для этих 2 коммитов. Так что я буду печатать
r
илиreword
вместоpick
. Затем сохраните файл и закройте вкладку. Обратите внимание, чтоrebase
выполняется в многошаговом процессе, поэтому следующим шагом является обновление сообщений. Также обратите внимание, что коммиты отображаются в обратном хронологическом порядке, поэтому последний коммит отображается в том же, а первый коммит в первой строке и т. Д.Обновите сообщения: обновите первое сообщение:
сохранить и закрыть Редактировать второе сообщение
сохранить и закрыть.
К концу перебазирования вы получите такое сообщение:
Successfully rebased and updated refs/heads/documentation
это означает, что вы добились успеха. Вы можете отобразить изменения:Желаю, чтобы это могло помочь новым пользователям :).
источник
Для меня это было для удаления некоторых учетных данных из репо. Я попытался перебазировать и столкнулся с кучей, казалось бы, не связанных между собой конфликтов, когда пытался перебазировать - продолжай. Не пытайтесь перебазировать себя, используйте инструмент под названием BFG (brew install bfg) на Mac.
источник
Если вы еще не выдвинули коммиты, вы можете вернуться к предыдущему коммиту, используя
git reset HEAD^[1,2,3,4...]
Например
Ой, забыл добавить file2 в первый коммит ...
Это добавит file2 к первому коммиту.
источник
Ну, это решение может показаться очень глупым, но может спасти вас в определенных условиях.
Мой друг просто случайно натолкнулся на очень большие файлы (четыре автоматически сгенерированных файла размером от 3 до 5 ГБ каждый), а затем сделал еще несколько коммитов кода, прежде чем осознал проблему, которая больше
git push
не работала!Файлы были перечислены в списке,
.gitignore
но после переименования папки контейнера они были открыты и зафиксированы! И теперь было еще несколько коммитов кода поверх этого, ноpush
он работал вечно (пытаясь загрузить ГБ данных!) И в конечном итоге потерпел неудачу из-за ограничений размера файлов Github .Проблема с интерактивным перебазированием или чем-то подобным заключалась в том, что им приходилось ковыряться в этих огромных файлах, и им потребовалось бы целую вечность, чтобы что-то сделать. Тем не менее, проведя почти час в CLI, мы не были уверены, действительно ли файлы (и дельты) удалены из истории или просто не включены в текущие коммиты. Толчок тоже не работал, и мой друг действительно застрял.
Итак, решение, которое я придумал, было:
~/Project-old
.~/Project
).cp -r
файлы из~/Project-old
папки в~/Project
.mv
отредактированы и.gitignore
правильно включены ..git
папку в недавно клонированной~/Project
старой. Вот где живут журналы проблемной истории!push
изданы.Самая большая проблема этого решения заключается в том, что оно имеет дело с ручным копированием некоторых файлов, а также объединяет все последние коммиты в один (очевидно, с новым хешем коммитов.) B
Большим преимуществом является то, что он очень понятен на каждом этапе, отлично работает с большими файлами (а также с чувствительными) и не оставляет следов в истории!
источник