Изменить коммит, отправленный на GitHub... удаление файлов

Git крутит мой мозг. Но я думаю, что я на полпути с этой проблемой.

Я зафиксировал (дважды) и отправил на GitHub, но первый коммит содержал два файла, которые не должны были быть включены. Итак, я сделал следующее...

git reset --hard HEAD~2

Это вернуло HEAD к первому коммиту с дополнительными файлами.

HEAD is now at 1979096c2

Теперь, если я исправлю, снова зафиксирую (и принудительно нажму) ТОЛЬКО два необходимых файла, исправит ли это фиксацию на GitHub?

Чтобы быть более понятным... первоначальный (неправильный) коммит содержал 4 файла. Я хочу изменить это, чтобы иметь только 2 файла. Я на правильном пути?

3 ответа

Решение

Вместо того, чтобы делать полный сброс, вы также можете сделать git revert.

git revert <commit_id>

Используйте git log, чтобы обратиться к идентификатору коммита, который вы хотите вернуть.

Вы правы, и это все исправит. Будьте осторожны с принудительным толчком, поскольку вы в основном переписываете историю. Любой, кто вытащил те коммиты, которые вы собираетесь удалить, будет отклоняться от удаленного. Если вы единственный человек, работающий в репо или филиале, это не имеет значения.

Нет.

Прежде всего, когда вы говорите "изменить, совершить (и принудительный толчок)", вы имеете в виду git commit --amend команда? Наименование amend Вариант может быть немного запутанным. Хотя он и отражает цель команды, он предполагает, что она редактирует существующий коммит, чего не делает, потому что это невозможно.

Что у вас после сброса примерно так

O <--(master)
 \
  A -- B <--(origin/master)

Так ты совершил дважды (A а также B), но A содержит файлы, которые вы не хотите в репо, поэтому вы сбрасываете обратно 2 коммитов (до A). Тогда первое, что нужно понять, если вы делаете commit --amend отсюда будет вноситься поправка O - не совершать A,

Но также, что значит "изменить" коммит, учитывая, что - как я уже говорил выше - вы не можете изменить существующий коммит? Что ж, это означает, что вы создаете новый коммит - у которого есть новый идентификатор - и "заменяете" старый коммит им. Это звучит как раскалывание волос, но это важно, потому что "замена" коммита не делает все то, что вы могли бы предположить, что он будет делать.

Давайте предположим, что вы сбросили для принятия A, В вашем примере, как описано, это было бы git reset --hard master^ (1 коммит перед веткой - так что вы проверили коммит, который был "неправильным"). Теперь у вас есть

O -- A <--(master)
      \
       B <--(origin/master)

Теперь вы можете редактировать рабочее дерево (т.е. удалять ненужные файлы), а затем вы можете сказать git "изменить" коммит A, Но то, что вы получите, это

O -- A -- B <--(origin/master)
 \
  C <--(master)

C это новый коммит с новым идентификатором. Если вы сделали только небольшие изменения до commit --amendто это касается в основном тех же изменений, относительно O, как A - но это все еще совершенно отдельный коммит. В истории вашего местного отделения, C заменяет A - но только в вашем местном филиале - не во всем хранилище. B все еще видит A как его родитель, и origin/master еще указывает на B,

Если вы затем нажмете, вы будете двигаться origin/master в C, Это редактирование истории, которое имеет последствия, если хранилище используется совместно с другими. Увидеть git rebase документы в разделе "восстановление после перебазирования вверх по течению"; этот раздел применим к любому переписыванию, независимо от того, включает ли оно rebase команда. Также обратите внимание, что если вы не правильно координируете принудительный толчок с другими пользователями репо, возможно, что любой из них сделает неправильную вещь при восстановлении и отменит сделанные вами изменения.

Так что в дополнение к замене A с Cэта процедура удаляет B из ветки истории, потому что "замена" A с C не является заменой на месте во всем хранилище.

Вы можете это исправить, перебрав B от A в C, Есть несколько способов сделать это, например:

git checkout origin/master
git rebase --onto master HEAD^

Это дает вам

O -- A -- B <--(origin/master)
 \
  C -- B' <--(master)

Здесь я использовал обозначение, которое указывает, что новый коммит (B') применяет те же изменения, что и старый коммит (B) относительно новой базы - но это все еще совершенно новый коммит. Опять же, это переписывание истории, и вам придется координировать действия с любыми другими пользователями и принудительно нажимать.

В зависимости от того, почему эти файлы должны быть исключены из репо, также может быть важно знать, что это (пока) физически не удаляет исходную историю (включая файлы, которые вы удалили). Ваш локальный репо будет удерживать их, по крайней мере, до тех пор, пока старая история остается в рефлоге. Есть шаги, которые вы можете предпринять, чтобы выполнить более раннюю очистку локально; но пульт (в зависимости от того, как он размещен) может иметь или не иметь удобных процедур для удаления файлов оттуда. И ничто из того, что вы можете сделать, не гарантирует, что файлы будут удалены из любых других клонов, которые могут существовать.

Таким образом, если файлы содержали конфиденциальную информацию (и если кто-то еще имел доступ к удаленному устройству), вам придется обращаться с этой информацией как скомпрометированной. Если файлы просто большие, вы можете искать существующие вопросы и ответы, подробно описывающие, как удалить их из истории, чтобы освободить место

Другие вопросы по тегам