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

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

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

git reset --hard HEAD~2

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

HEAD is now at 1979096c2

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

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

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

Romain Valeri 07.02.2019 15:01

да. Но будьте осторожны с принудительным нажатием, поскольку вы переписываете историю, и любой, кто вытащил эти коммиты, теперь расходится.

tayfun 07.02.2019 15:01

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

edcincy 07.02.2019 15:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
276
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Нет, не будет. После того, что он изменил, есть коммит, который будет потерян при этой процедуре.

Mark Adelsberger 07.02.2019 17:37
Ответ принят как подходящий

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

git revert <commit_id>

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

Да... Я на самом деле сделал это один раз раньше. Можно ли сказать, что я новичок в Git? Но на этот раз он сообщил мне, что файлы необходимо «переместить или удалить», прежде чем произойдет слияние. Когда я попытался использовать «--cache/path/to/file», git сказал, что не может найти файл! Поэтому я решил использовать метод исправления.

edcincy 07.02.2019 15:21

ЭТО РАБОТАЛО. Ну наконец то. Поскольку я не мог удалить файлы из командной строки bash, я нашел их в файловой системе и удалил их таким образом. Реверт в любом случае заменит их. После использования revert я снова зафиксировал только два нужных мне файла. Изменить (как отмечено в другом комментарии) не работает, как я подозревал.

edcincy 08.02.2019 13:29

Нет.

Прежде всего, когда вы говорите «изменить, зафиксировать (и принудительно отправить)», вы имеете в виду команду 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) относительно новой базы, но это все еще совершенно новая фиксация. Опять же, это переписывание истории, и вам придется координировать свои действия с любыми другими пользователями и принудительно нажимать.

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

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

И теперь я знаю, почему Git меня смущает. Я получаю множество ответов на одну и ту же проблему. Я исправляю фиксацию ветки в своем собственном репо, а затем открою запрос на включение. Разве я не в безопасности, используя исправление, как я его описал?

edcincy 07.02.2019 15:32

@edcincy - вы получаете несколько ответов, потому что некоторые люди сосредоточены на том, как они подошли бы к исходной проблеме (а не на вопросе, который вы задали), а другие либо ошибаются в своем собственном понимании git, либо не поняли вопрос. Вот почему мой ответ структурирован так, чтобы дать вам достаточно информации, чтобы понять, ПОЧЕМУ то, что вы делаете, не будет делать то, что, как я понимаю, вы просите. Если вы предпочитаете «более простые для восприятия» ответы, это нормально, но они могут ввести вас в заблуждение, и если вы не потратите время на то, чтобы понять git в его терминах, он будет по-прежнему сбивать с толку.

Mark Adelsberger 07.02.2019 17:36

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