Удалить файл, зафиксированный в старом коммите

У меня есть 6 коммитов, и в каждом из них зафиксировано несколько файлов. Моя проблема в том, что я закоммитил файл, который не должен фиксировать, и я хочу, чтобы он исчез из этого старого коммита, поэтому я его не вижу:

last commit
  file8
  file7

commit 3
  file6
  file5

commit 2
  file4
  file3

first commit
  file2
  file1

Как я могу удалить файл4 из коммита 2, чтобы он исчез?

...
commit 3
  file6
  file5

commit 2
  file3

...

person rodriciru    schedule 14.07.2021    source источник


Ответы (2)


Вы не можете. Ни один коммит не может быть изменен. Таким образом, вы не можете удалить файл из старого коммита.

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

Если коммит № 1 в порядке, вы можете оставить его как есть. Однако коммит № 2, который следует за № 1, не подходит. Вы должны выбросить это. Вы не можете отказаться или удалить его напрямую, но вы можете прекратить его использование. Как только вы это сделаете, Git в конечном итоге удалит его.1 Однако вам понадобится новая и улучшенная версия коммита №2, которую вы будете использовать вместо старой коммит-#2.

Коммит № 3 может быть частично в порядке, если он не содержит файла, который вы не хотите содержать ни в одном из коммитов.2 Но даже если в таком случае все в порядке, это определенно в конце концов, это не так, потому что это относится к неправильному коммиту № 2. Каждый коммит Git ссылается на своего непосредственного предшественника, поэтому, чтобы заменить коммит № 2, вы также должны удалить коммит № 3. Это означает, что вам нужно будет заменить № 3.

Коммит № 4 может быть отчасти исправен, как и № 3, но, как и № 3, он ссылается на плохой коммит: в данном случае, на сам № 3! № 3 плохой, потому что он напрямую ссылается на № 2, и это также делает № 4 плохим. Так что вам придется сделать новую и улучшенную версию коммита № 4.

Это повторяется с коммитами № 5 и № 6. Если фиксация № 2 неверна, вы должны заменить ее новой и улучшенной версией, а это также требует замены каждой последующей фиксации.

Итак: как вы собираетесь заменять эти коммиты? Вот тут-то и появляется git rebase. Что делает git rebase — в чем его суть — берет некоторые существующие коммиты, которые в основном в порядке в том или ином отношении, но не в каком-то другом смысле, — и заменяет их с новыми и улучшенными коммитами.

Команда git rebase делает это с помощью git cherry-pick внутри. Это хорошая идея, чтобы понять это и знать, как все это работает. Это довольно хорошо освещено в других публикациях StackOverflow, хотя, так что см. те.


1По умолчанию неиспользуемые коммиты хранятся не менее 30 дней на случай, если вы передумаете и захотите их вернуть. Когда они такие, их трудно найти, и вряд ли стоит пытаться ускорить стандартное устаревание не менее 30 дней, которое делает с ними Git, но если у вас есть странная ситуация, можно ускорить процесс.

2Каждая фиксация содержит каждый файл, а не только файлы, измененные с момента предыдущей фиксации. Поэтому, если фиксация № 3 не удаляет файл по сравнению с фиксацией № 2, в конце концов, это не нормально. Но это побочный момент из-за того, как мы будем создавать новые и улучшенные коммиты.

person torek    schedule 14.07.2021
comment
Насколько я знаю, это возможно с помощью следующей команды: git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch path_to_file" HEAD -> посмотри мой ответ. Или я ошибаюсь? - person SwissCodeMen; 14.07.2021
comment
@SwissCodeMen: filter-branch также копирует коммиты в новые и улучшенные коммиты. Однако это не очень удобная для пользователя команда. - person torek; 14.07.2021
comment
Да, я согласен с вами, что git filter branch не очень полезная команда. Но я попробовал это сейчас, и файл был удален в коммите X без создания/копирования другого коммита... Так что я думаю, что это возможно, но использовать/выполнять с осторожностью. - person SwissCodeMen; 14.07.2021
comment
@SwissCodeMen: Но он сделал (создал новую фиксацию, а затем еще кучу новых коммитов). Сравните хэш-идентификаторы до и после ветки фильтра. Не просто подсчитывайте коммиты! Кроме того, после этого запустите git log --all --decorate --graph, чтобы увидеть исходные коммиты под именами refs/original/refs/heads/. - person torek; 14.07.2021

Вы можете сделать это с помощью следующей команды. Но сначала узнайте путь к файлу в вашем репозитории, который вы хотите удалить (file4).

git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch <path_to_file>" HEAD

После этого выполните git push -f и файл будет удален из commit2 и из репозитория.

НО БУДЬТЕ ОСТОРОЖНЫ git filter-branch. Документацию вы можете посмотреть здесь

person SwissCodeMen    schedule 14.07.2021