Я работал с другом над проектом, и он редактировал кучу файлов, которые не должны были редактироваться. Каким-то образом я слил его работу с моей, или когда вытащил ее, или когда я попытался просто выбрать конкретные файлы, которые я хотел. Я долго искал и играл, пытаясь выяснить, как удалить коммиты, которые содержат изменения в этих файлах, кажется, что это сложность между возвратом и перебазированием, и нет простых примеров, и Предполагается, что я знаю больше, чем знаю.
Итак, вот упрощенная версия вопроса:
Учитывая следующий сценарий, как мне удалить коммит 2?
$ mkdir git_revert_test && cd git_revert_test
$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/
$ echo "line 1" > myfile
$ git add -A
$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ echo "line 2" >> myfile
$ git commit -am "commit 2"
[master 342f9bb] commit 2
1 files changed, 1 insertions(+), 0 deletions(-)
$ echo "line 3" >> myfile
$ git commit -am "commit 3"
[master 1bcb872] commit 3
1 files changed, 1 insertions(+), 0 deletions(-)
Ожидаемый результат
$ cat myfile
line 1
line 3
Вот пример того, как я пытался вернуться
$ git revert 342f9bb
Automatic revert failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
git
commit
revert
cherry-pick
Джошуа Чик
источник
источник
Ответы:
Алгоритм, который Git использует при расчете различий, требует, чтобы
Определение «смежных» основано на количестве строк по умолчанию из контекста diff, которое равно 3. Так что если «myfile» был построен следующим образом:
Тогда все работает как положено.
Второй ответ был очень интересным. Существует функция, которая еще не была официально выпущена (хотя она доступна в Git v1.7.2-rc2), которая называется Revert Strategy. Вы можете вызвать git так:
и он должен лучше понять, что вы имели в виду. Я не знаю, каков список доступных стратегий, и при этом я не знаю определения любой стратегии.
источник
perl -p
полезен для написания очень коротких (в одну строку) программ, которые зацикливаются и передают свои данные на выход, подобно sed.perl -i
используется для редактирования файлов на месте .perl -e
как отправить код для оценки .Есть четыре способа сделать это:
Чистый путь, возвращаясь, но сохраняйте в журнале возврат:
Суровым образом удалите всего лишь последний коммит:
Примечание. Избегайте,
git reset --hard
поскольку при этом также будут отменены все изменения в файлах с момента последней фиксации. Если--soft
не работает, попробуйте--mixed
или--keep
.Перебазировать (показать журнал последних 5 коммитов и удалить ненужные строки, или переупорядочить, или сжать несколько коммитов в одном, или сделать что-то еще, что вы хотите, это очень универсальный инструмент):
И если допущена ошибка:
Быстрая перебазировка: удалить только определенный коммит, используя его идентификатор:
Альтернативы: вы также можете попробовать:
Еще одна альтернатива:
В крайнем случае, если вам нужна полная свобода редактирования истории (например, потому что git не позволяет вам редактировать то, что вы хотите), вы можете использовать это очень быстрое приложение с открытым исходным кодом: reposurgeon .
Примечание: конечно, все эти изменения выполняются локально,
git push
после чего вы должны применить изменения к удаленному. И в случае, если ваше хранилище не хочет удалять коммит («ускоренная пересылка не разрешена», что происходит, когда вы хотите удалить коммит, который вы уже выдвинули), вы можете использоватьgit push -f
для принудительной отправки изменений.Примечание 2: если вы работаете над веткой и вам нужно принудительно нажать, вам следует избегать
git push --force
этого, поскольку это может перезаписать другие ветви (если вы внесли изменения в них, даже если ваша текущая проверка находится в другой ветви). Предпочитает всегда указывать удаленный филиал , когда вы вынуждаете толчок :git push --force origin your_branch
.источник
git rebase -i HEAD~5
работал на меня. Затем я просто удалил коммиты, которые мне не нужны, и смог решить проблему менее чем за 30 секунд. Спасибо.Вот простое решение:
(Примечание:
x
это количество коммитов)после выполнения файл блокнота откроется. Введите
drop
помимо вашего коммита.Если вы не знаете Vim, просто нажмите на каждый выбор слов, который вы хотите отредактировать, а затем нажмите клавишу «I» (для режима вставки). Когда вы закончите ввод, нажмите клавишу «esc», чтобы выйти из режима вставки.
и все, готово ... Просто синхронизируйте панель инструментов git, и изменения будут перенесены на удаленный компьютер.
Если коммит, который вы сбросили, уже был на пульте, вам придется принудительно нажать. Так как --force считается вредным , используйте его
git push --force-with-lease
.источник
Ваш выбор между
Вы должны выбрать (1), если ошибочное изменение было обнаружено кем-либо еще, и (2), если ошибка ограничена частной ветвью без отправления.
Git revert - это автоматизированный инструмент для выполнения (1), он создает новый коммит, отменяя предыдущий коммит. Вы увидите ошибки и удаление в истории проекта, но люди, которые извлекают данные из вашего хранилища, не столкнутся с проблемами при обновлении. В вашем примере это не работает автоматически, поэтому вам нужно отредактировать 'myfile' (удалить строку 2), сделать
git add myfile
иgit commit
разобраться с конфликтом. После этого вы получите четыре коммита в своей истории с коммитом 4, возвращающим коммит 2.Если никто не заботится о том, что ваша история меняется, вы можете переписать ее и удалить коммит 2 (вариант 2). Самый простой способ сделать это - использовать
git rebase -i 8230fa3
. В результате вы попадете в редактор, и вы можете отказаться от ошибочной фиксации, удалив фиксацию (и оставив «выбор» рядом с другими сообщениями фиксации. Ознакомьтесь с последствиями этого действия) .источник
Подход 1
Сначала получите хеш коммита (например: 1406cd61), который вам нужно вернуть. простое исправление будет ниже команды,
Если после фиксации 1406cd61 вы произвели больше изменений, относящихся к файлам 1406cd61, простая команда «Выше» работать не будет. Затем вы должны сделать следующие шаги, которые являются сбор вишни.
Подход 2
Пожалуйста, следуйте приведенным ниже инструкциям, поскольку мы используем --force, чтобы сделать это, вам необходимы права администратора git-репо.
Шаг 1. Найдите коммит до коммита, который вы хотите удалить
git log
Шаг 2: Оформить заказ
git checkout <commit hash>
Шаг 3: Создайте новую ветку, используя свой текущий коммит проверки
git checkout -b <new branch>
Шаг 4: Теперь вам нужно добавить коммит после удаленного коммита
git cherry-pick <commit hash>
Шаг 5: Теперь повторите Шаг 4 для всех остальных коммитов, которые вы хотите сохранить.
Шаг 6: После того, как все коммиты были добавлены в вашу новую ветку и были зафиксированы. Убедитесь, что все в правильном состоянии и работает как задумано. Дважды проверьте все было совершено:
git status
Шаг 7: Переключитесь на сломанную ветку
git checkout <broken branch>
Шаг 8: Теперь выполните полную перезагрузку прерванной ветки для коммита до того, который вы хотите удалить.
git reset --hard <commit hash>
Шаг 9: объединить вашу фиксированную ветку с этой веткой
git merge <branch name>
Шаг 10: Верните объединенные изменения в исходное состояние. ВНИМАНИЕ: Это перезапишет удаленный репозиторий!
git push --force origin <branch name>
Вы можете выполнить этот процесс, не создавая новую ветку, заменив Шаг 2 и 3 на Шаг 8, а затем не выполняйте Шаг 7 и 9.
источник
Вы можете удалить нежелательные коммиты с
git rebase
. Скажем, вы включили некоторые коммиты из ветки темы коллеги в ветку темы, но позже решите, что вам не нужны эти коммиты.На этом этапе ваш текстовый редактор откроет интерактивное представление rebase. Например
Если перебазировка не удалась, удалите временную ветку и попробуйте другую стратегию. В противном случае продолжайте со следующими инструкциями.
Если вы перемещаете ветку своей темы на удаленный компьютер, вам может потребоваться принудительное нажатие, так как история изменений изменилась. Если другие работают над той же веткой, дайте им голову.
источник
Из других ответов, приведенных здесь, я был немного озадачен тем, как
git rebase -i
можно использовать удаление коммита, поэтому я надеюсь, что здесь можно записать мой тестовый пример (очень похожий на OP).Вот
bash
скрипт, который вы можете вставить, чтобы создать тестовое хранилище в/tmp
папке:На данный момент, у нас есть
file.txt
с этим содержанием:На этом этапе HEAD находится на 5-м коммите, HEAD ~ 1 будет 4-м - и HEAD ~ 4 будет 1-м коммитом (поэтому HEAD ~ 5 не будет существовать). Допустим, мы хотим удалить 3-й коммит - мы можем выполнить эту команду в
myrepo_git
каталоге:( Обратите внимание, что в
git rebase -i HEAD~5
результате получается «fatal: необходима одна ревизия; недопустимый верхний колонтитул ~ 5». ) Откроется текстовый редактор (см. Скриншот в ответе @Dennis ) со следующим содержимым:Таким образом, мы получаем все коммиты, так как (но не включая ) наш запрошенный HEAD ~ 4. Удалить строку
pick 448c212 3rd git commit
и сохранить файл; Вы получите этот ответ отgit rebase
:В этот момент откройте myrepo_git /
folder/file.txt
в текстовом редакторе; вы увидите, что он был изменен:По сути,
git
видит, что когда HEAD получил 2-й коммит, было содержимоеaaaa
+bbbb
; и затем у него есть патчcccc
+,dddd
который он не знает, как добавить к существующему контенту.Так что здесь
git
не может решить за вас - это вы должны принять решение: удаляя 3-й коммит, вы либо сохраняете внесенные им изменения (здесь, строкаcccc
) - либо нет. Если вы этого не сделаете, просто удалите лишние строки - в том числеcccc
- вfolder/file.txt
текстовом редакторе, чтобы он выглядел так:... а затем сохранить
folder/file.txt
. Теперь вы можете выполнить следующие команды вmyrepo_git
каталоге:Ах - так, чтобы отметить , что мы решили конфликт, мы должны , прежде чем делать :
git add
folder/file.txt
git rebase --continue
Здесь снова открывается текстовый редактор, показывающий строку
4th git commit
- здесь у нас есть шанс изменить сообщение коммита (которое в этом случае могло бы быть существенно изменено на4th (and removed 3rd) commit
или подобное). Допустим, вы не хотите - просто выйдите из текстового редактора без сохранения; как только вы это сделаете, вы получите:На данный момент, теперь у вас есть такая история (которую вы также можете проверить, скажем, с помощью
gitk .
других инструментов), например, содержимогоfolder/file.txt
(с, по-видимому, неизменными временными метками оригинальных коммитов):И если ранее мы решили сохранить строку
cccc
(содержимое 3-го git коммита, который мы удалили), мы бы имели:Ну, это было то чтение, которое я надеялся найти, чтобы начать понимать, как
git rebase
работает с точки зрения удаления коммитов / ревизий; так что надеюсь, что это может помочь и другим ...источник
Похоже, что в какой-то момент плохой коммит был включен в коммит слияния. Ваш коммит слияния уже отменен? Если да, то вы захотите использовать
git revert
; вам придется стиснуть зубы и работать через конфликты. Если нет, то вы можете либо перебазировать, либо вернуть, но вы можете сделать это раньше фиксации слияния, а затем повторить слияние.На самом деле, мы не можем помочь вам в первом случае. После попытки откатить и обнаружить, что автоматический сбой, вы должны изучить конфликты и исправить их соответствующим образом. Это точно такой же процесс, как и исправление конфликтов слияния; Вы можете использовать,
git status
чтобы увидеть, где находятся конфликты, отредактировать необработанные файлы, найти конфликтующие фрагменты, выяснить, как их разрешить, добавить конфликтующие файлы и, наконец, зафиксировать. Если вы используетеgit commit
само по себе (нет-m <message>
), сообщение, которое появляется в вашем редакторе, должно быть шаблоном сообщения, созданногоgit revert
; Вы можете добавить заметку о том, как вы исправили конфликты, затем сохранить и выйти для фиксации.Во втором случае, устраняющем проблему до слияния, есть два подслоя, в зависимости от того, проделали ли вы больше работы после слияния. Если у вас нет, вы можете просто
git reset --hard HEAD^
сбросить слияние, сделать возврат, а затем повторить слияние. Но я думаю, у вас есть. Итак, в итоге вы сделаете что-то вроде этого:git rebase -i <something before the bad commit> <temporary branch>
для удаления неверного коммита)git rebase --onto <temporary branch> <old merge commit> <real branch>
источник
Итак, вы проделали некоторую работу и выдвинули ее, давайте назовем их коммитами A и B. Ваш коллега также выполнил некоторую работу, коммиты C и D. Вы объединили работу ваших коллег с вашей (слияние коммит E), затем продолжили работу, зафиксировали это, тоже (коммит F) и обнаружил, что ваш коллега изменил некоторые вещи, которые он не должен был делать.
Итак, ваша история коммитов выглядит так:
Вы действительно хотите избавиться от C, D и D '. Так как вы говорите, что объединили ваши коллеги с вашими, эти коммиты уже «там», поэтому удаление коммитов с помощью, например, git rebase - нет-нет. Поверьте мне, я пытался.
Теперь я вижу два выхода:
если вы еще не добавили E и F своему коллеге или кому-либо еще (как правило, вашему серверу-источнику), вы все же можете на время удалить их из истории. Это ваша работа, которую вы хотите сохранить. Это можно сделать с помощью
(замените D 'фактическим хешем коммита, который вы можете получить из
git log
В этот момент коммиты E и F исчезли, и изменения снова стали незафиксированными изменениями в вашей локальной рабочей области. В этот момент я бы переместил их в ветку или превратил в патч и сохранил бы их на потом. Теперь верните работу вашего коллеги, автоматически с помощью
git revert
или вручную. Когда вы это сделаете, переиграйте свою работу поверх этого. У вас могут быть конфликты слияния, но, по крайней мере, они будут в написанном вами коде , а не в коде вашего коллеги.Если вы уже выполнили работу, проделанную после коммитов вашего коллеги, вы все равно можете попытаться получить «обратный патч» либо вручную, либо с помощью
git revert
, но поскольку ваша работа «в пути», так сказать, вы, вероятно, получите больше конфликтов слияния и более запутанных. Похоже, это то, что вы оказались в ...источник
git revert - стратегия принятия, если коммит является слиянием: используйте git revert --strategy resol -m 1
источник