Как навсегда удалить несколько коммитов из удаленной ветки

490

Я знаю, что это переписывание истории, что плохо, яда, яда.

Но как навсегда удалить несколько коммитов из удаленной ветки?

Арнис Лапса
источник
96
Да, это действительно плохо, яда, яда, но по какой-то причине мне это нужно.
Джеймс Моррис
44
Я знаю, что это глупо, но иногда случается дерьмо - например, тестирование логинов и использование простых текстовых паролей в коде, которые являются настоящими учетными данными для входа. И возгласы ...
frhd
6
реальные учетные данные для входа в систему .. Да, напоминает мне о некоторых возгласах
Привет Вселенная
1
Возможный дубликат
коммитов
2
Я так устал от этой академической болтовни о том, насколько это опасно и как это никогда не должно быть сделано Яда Яда. Временами гораздо лучше удалять вещи из истории git и справляться с конфликтами / взломом других разработчиков. Это действительно так просто. Люди, которые игнорируют это, вероятно, никогда не работали вне классной комнаты.
раздавить

Ответы:

369

Вы git reset --hardВаше местное отделение , чтобы удалить изменения из рабочего дерева и индекса, и вы git push --forceисправленное местное отделение на пульт дистанционного управления. ( другое решение здесь , включающее удаление удаленной ветви и повторное ее нажатие)

Этот SO-ответ иллюстрирует опасность такой команды, особенно если люди зависят от удаленной истории для своих локальных репозиториев.
Вы должны быть готовы указывать на людей в разделе « ВОССТАНОВЛЕНИЕ ОТ UPSTREAM REBASE » на git rebaseстранице руководства.


В Git 2.23 (август 2019 года, девять лет спустя) вы будете использовать новую команду git switch.
То есть: (заменитьgit switch -C mybranch origin/mybranch~n
n на количество коммитов для удаления)

Это восстановит индекс и рабочее дерево, как если git reset --hardбы.

VonC
источник
Странный. Кажется, я уже пробовал это. Вместе с некоторым перебазированием - работает как шарм. Спасибо.
Арнис Лапса
7
@Arnis: отлично тогда;) push --forceпрочь
VonC
Я использовал BFG Repo-Cleaner, чтобы избавиться от некоторых конфиденциальных данных, в результате чего у меня осталась «неназванная» ветвь с исходным файлом, после сброса до последнего требуемого коммита и жесткого нажатия на источник все прошло нормально (:
Rodrirokr
Обратите внимание, что URL коммита еще жив (по крайней мере, в течение некоторого времени), поэтому, если у кого-то есть URL коммита (вы дали его богу знает почему), он сможет получить доступ к коду.
Mosh Feu
1
@MoshFeu True: git gcне всегда запускается достаточно часто на удаленной стороне. Например, на GitHub: twitter.com/githubhelp/status/387926738161774592?lang=es
VonC
248

Просто обратите внимание, чтобы использовать last_working_commit_id, при отмене нерабочего коммита

git reset --hard <last_working_commit_id>

Поэтому мы не должны возвращаться к commit_id чего мы не хотим.

Тогда обязательно, мы должны нажать на удаленную ветку:

git push --force
hd84335
источник
10
Идеальный, элегантный, самый простой ответ. Я только что вернулся к последнему фиксированному
lauWM
2
Это заставило меня потерять свои локальные изменения тоже. Я не ожидал этого. Но лучше, чем вводить свой личный пароль для работы репо.
Airwavezx
3
Вы можете сохранить свои локальные изменения с помощью git stash .... сделать некоторые вещи .... и git stash pop (ваши локальные изменения вернулись)
MonTea
Это дает мне ошибку как «remote: error: запрещение не-ускоренных
пересылок
@Airwavezx это то, что git reset --hardдолжен делать.
Лука
146

Важно: Убедитесь, что вы указали, какие ветки в git push -f, или вы можете случайно изменить другие ветки! [*]

В этом уроке показаны три варианта . В случае разрыва ссылки я оставлю здесь основные шаги.

  1. Отменить полный коммит
  2. Удалить последний коммит
  3. Удалить коммит из списка

1 Отменить полный коммит

git revert dd61ab23

2 Удалить последний коммит

git push <<remote>> +dd61ab23^:<<BRANCH_NAME_HERE>>

или, если филиал доступен локально

git reset HEAD^ --hard
git push <<remote>> -f

где + dd61 ... ваш хеш коммита, а git интерпретирует x ^ как родительский элемент x, а + как принудительный небыстрый push.

3 Удалить коммит из списка

git rebase -i dd61ab23^

Это откроет и редактор, показывающий список всех коммитов. Удалите тот, от которого вы хотите избавиться. Завершите ребаз и подтолкните силу, чтобы сделать репо.

git rebase --continue
git push <remote_repo> <remote_branch> -f
reefaktor
источник
5
Убедитесь, что вы указали, какие ветви в «git push <remote_repo> <remote_branch> -f», или вы можете случайно изменить другие ветви!
Найджел Шеридан-Смит
Только шаги 1 и 2 сделали работу и ответили на оригинальный вопрос. (Не выполняйте шаг 3)
Саад Бенбузид
Это варианты для разных сценариев, а не шаги, которые нужно предпринять. В моем случае интерактивная перебазировка (вариант 3) сделала то, что я искал.
Стив Блэквелл
Я должен был сделать шаг 3, хотя. Почему бы тебе не запустить этот @Saad? К счастью, мой «remote» был просто «origin» по умолчанию, а <remote_branch> «master» по умолчанию
Bart
30

Если вы хотите удалить, например, последние 3коммиты, выполните следующую команду, чтобы удалить изменения из файловой системы (рабочего дерева) и истории коммитов (индекса) в вашей локальной ветке:

git reset --hard HEAD~3

Затем выполните следующую команду (на локальном компьютере), чтобы заставить удаленную ветвь переписать свою историю:

git push --force

Поздравляем! Все сделано!

Некоторые заметки:

Вы можете получить нужный идентификатор фиксации, запустив

git log

После этого вы можете заменить HEAD~Nс <desired-commit-id>следующим образом:

git reset --hard <desired-commit-id>

Если вы хотите сохранить изменения в файловой системе и просто изменить индекс (историю фиксации), используйте --softфлаг вроде git reset --soft HEAD~3. Тогда у вас есть шанс проверить свои последние изменения и сохранить или удалить все или их часть. В последнем случае runnig git statusпоказывает файлы, измененные с тех пор <desired-commit-id>. Если вы используете --hardопцию, git statusвам сообщат, что ваша локальная ветка точно такая же, как и удаленная. Если вы не используете --hardни --soft, используется режим по умолчанию --mixed. В этом режиме git help resetговорит:

Сбрасывает индекс, но не рабочее дерево (т. Е. Измененные файлы сохраняются, но не помечаются для фиксации) и сообщает, что не было обновлено.

Абдолла
источник
10

Это может быть слишком поздно и слишком поздно, но что мне помогло, так это круто звучащий «ядерный» вариант. В основном с помощью командыfilter-branch вы можете удалять файлы или изменять что-либо в большом количестве файлов на протяжении всей вашей истории git.

Это лучше всего объяснить здесь .

jansmolders86
источник
9
Еще не поздно Может стать полезным для странников с похожими проблемами :)
Арнис Лапса
9

Упрощение от ответа pctroll, аналогично основанному на этом сообщении в блоге .

# look up the commit id in git log or on github, e.g. 42480f3, then do
git checkout master
git checkout your_branch
git revert 42480f3
# a text editor will open, close it with ctrl+x (editor dependent)
git push origin your_branch
# or replace origin with your remote
ted.strauss
источник
2
Работает на меня, спасибо. И я хочу навсегда удалить один коммит (например, содержит pwd) из истории удаленных веток, как это сделать?
улыбается
1
У меня тоже работает, но у меня тот же вопрос, что и у Smiles, я не хочу, чтобы кто-нибудь видел мой коммит / ревер в истории ... как мне это убрать?
Роберто Родригес
4

Иногда самый простой способ решить эту проблему - создать новую ветку из того места, где вы знаете, что код хорош. Затем вы можете оставить историю ошибочных веток в одиночку на тот случай, если позже вам понадобится выбрать другие коммиты из нее. Это также гарантирует, что вы не потеряли историю коммитов.

В вашем местном филиале:

git log

скопируйте хеш коммита, в котором вы хотели видеть ветку, и выйдите из журнала git

git checkout theHashYouJustCopied
git checkout -b your_new_awesome_branch

Теперь у вас есть новая ветка именно так, как вы этого хотите.

Если вам также необходимо сохранить конкретный коммит из ветки с ошибками, которой нет в новой ветке, вы можете просто выбрать нужный коммит:

git checkout the_errant_branch
git log

Скопируйте хэш коммита одного коммита, который вам нужен для добавления в хорошую ветку, и выйдите из журнала git.

git checkout your_new_awesome_branch
git cherry-pick theHashYouJustCopied

Погладить себя по спине.

Douglas.Sesar
источник
очень легко, а кого это волнует, если у вас ветка с мертвыми ногами? сделать новую ветку и покончить с этим!
Эндрю Фокс
Это действительно отличный ответ. Я рад, что я сделал это вместо коммитных сборов или манипулирования удаленной веткой.
Magnilex
0
 git reset --soft commit_id
 git stash save "message"
 git reset --hard commit_id
 git stash apply stash stash@{0}
 git push --force
pandorago
источник