Удалить файлы из Git commit


1613

Я использую Git, и я зафиксировал несколько файлов, используя

git commit -a

Позже я обнаружил, что файл был ошибочно добавлен в коммит.

Как я могу удалить файл из последнего коммита?


2
Эта ссылка идеально подходит для вашего вопроса: stackoverflow.com/questions/307828/…
b3h3m0th

@CharlesB: да, это мой последний коммит
Lolly

8
Вы выдвинули коммит на сервер?
Паритош Сингх,

4
Я просто делаю это, используя:git reset filepath
felipekm

Ответы:


3090

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

git reset --soft HEAD^ 

или

git reset --soft HEAD~1

Затем сбросьте ненужные файлы, чтобы исключить их из коммита:

git reset HEAD path/to/unwanted_file

Теперь совершите коммит снова, вы даже можете повторно использовать то же самое сообщение коммита:

git commit -c ORIG_HEAD  

86
Спасибо за это. Стоит добавить, что если вы уже выдвинули свой предыдущий (неправильный) коммит, а теперь попытаетесь git pushисправить его до репо, он будет жаловаться Updates were rejected because the tip of your current branch is behind its remote counterpart.. Если вы уверены, что хотите подтолкнуть их (например, это ваша вилка), то вы можете использовать -fопцию для принудительного толчка, например git push origin master -f. (Не делайте этого с
репозиторием в восходящем направлении, из которого извлекаются

57
git reset --soft HEAD^моя самая распространенная операция отмены
funroll

2
@PabloFernandez, во-первых, принятый ответ мог быть тем, что искал ОП (также, он был опубликован несколькими месяцами ранее). Во-вторых, принятые ответы всегда на вершине, независимо от количества голосов.
MITjanitor

4
@PabloFernandez вверху всех ответов находятся три вкладки, которые позволяют вам управлять порядком ответов: активными , самыми старыми и голосами . Я думаю, твое настроено на самое старое . Переключите его на голосование, хотя принятый ответ все еще будет наверху, этот ответ будет вторым.
13

15
Я знал об этом много, git resetно хотел, чтобы способ повлиять на существующий коммит "на месте". Я только что узнал о git commit -C. Так что для меня то, что я хочу, это ваш точный рецепт с еще одним шагом, «новый коммит снова» прописан как git commit -C [hash of original HEAD commit from first step].
metamatt

323

ВНИМАНИЕ ! Если вы хотите только удалить файл из предыдущего коммита и сохранить его на диске , прочитайте ответ Джуззлина чуть выше.

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

  1. удалить файл git rm <file>
  2. совершить с изменением флага: git commit --amend

Флаг изменения указывает git выполнить коммит снова, но «объединить» (не в смысле слияния двух веток) этот коммит с последним коммитом.

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


121
Вы также можете использовать git rm --cachedдля хранения файлов на диске
Аркадий Кукаркин

14
Предупреждение тем, кто просматривает этот ответ: убедитесь, что вы хотите УДАЛИТЬ файл (как ушел, ушел, ушел!), А не просто удалите его из списка фиксации.
Скотт Биггс

8
Для того, чтобы добавить к тому , что говорят другие (и сделать его легче запомнить , чтобы не делать этого , если вы действительно хотите): в команде будет делать то , что само по себе делает! rmgitrm
лет

@CharlesB Можете ли вы добавить примечание из комментария Аркадия Кукаркина к своему ответу, чтобы сделать его более заметным?
mopo922

2
Обратите внимание, что файлы все еще можно восстановить, в случае, если вы передумали, фиксация ранее git commit --amendвсе еще существует и может быть найдена, например, с помощью git reflog. Так что это не так плохо, как предлагают другие комментарии.
Steohan

165

Все существующие ответы говорят об удалении ненужных файлов из последнего коммита.

Если вы хотите удалить ненужные файлы из старого коммита (даже отправленного) и не хотите создавать новый коммит, который не нужен из-за действия:

1.

Найдите коммит, которому вы хотите, чтобы файл соответствовал.

git checkout <commit_id> <path_to_file>

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

2.

git commit -am "remove unwanted files"

3.

Найдите commit_id коммита, по которому файлы были добавлены по ошибке , скажем "35c23c2" здесь

git rebase 35c23c2~1 -i  // notice: "~1" is necessary

Эта команда открывает редактор в соответствии с вашими настройками. По умолчанию используется vim.

Переместите последний коммит, который должен быть «удалить ненужные файлы», на следующую строку некорректного коммита (в нашем случае «35c23c2») и установите команду как fixup:

pick 35c23c2 the first commit
fixup 0d78b28 remove unwanted files

Вы должны быть хороши после сохранения файла.

Заканчивать :

git push -f

Если вы, к сожалению, получаете конфликты, вы должны решить их вручную.


2
Делать это с нано - это невероятно! Ctrl + K, Ctrl + U, поставить 'f', Ctrl + X, поставить 'y' и вуаля!
sequielo

6
Если вы действительно хотите удалить файлы из репозитория (а не из файловой системы), а не просто вернуть их к предыдущей версии, то вместо шага 1 сделайте git rm --cached <file(s)>.
Waldyrious

2
Подождите, вы можете просто перемещать коммиты по файлу Interactive-ReBase по желанию?
Дэн Розенстарк

2
Вы можете полностью, но вы можете (или не можете) получить конфликты.
Брайан,

6
Этот процесс можно сделать немного проще, добавив --fixup=35c23c2в git commitкоманду. Это автоматически настроит коммит как исправление требуемого коммита, поэтому вам не нужно будет указывать его в ребазе. Кроме того, если добавить --autosquashк git rebaseкоманде, мерзавец будет автоматически перемещать вашу фиксацию в нужном месте, так что вам не нужно ничего делать в интерактивном перебазировании - просто сохранить результат (а это означает , что вам даже не нужно -iфлаг, хотя мне все равно нравится использовать его, чтобы убедиться, что все выглядит так, как я ожидаю).
Гусс

144

Как показывает принятый ответ, вы можете сделать это, сбросив весь коммит. Но это довольно тяжелый подход.
Более чистый способ сделать это - сохранить коммит и просто удалить из него измененные файлы.

git reset HEAD^ -- path/to/file
git commit --amend --no-edit

Команда git resetпримет файл, как это было в предыдущем коммите, и поместит его в индекс. Файл в рабочем каталоге остается нетронутым.
Затем git commitбудет зафиксировать и сжать индекс в текущий коммит.

По сути, это берет версию файла, которая была в предыдущем коммите, и добавляет ее к текущему коммиту. Это не приводит к чистым изменениям, и поэтому файл эффективно удаляется из коммита.


5
Это гораздо лучший ответ для удаления всего одного файла, без изменения всей фиксации.
nimish

Это точно так же, как этот ответ: D stackoverflow.com/a/27340569/1623984
ThatsAMorais

@ThatsAMorais действительно :-). Мне интересно, слился ли этот вопрос с другим, и поэтому я его не видел. Или, может быть, я просто слепой. В любом случае, я думаю, что я склонен оставить его, так как по результатам голосования он кажется более популярным (возможно, люди предпочитают короткий и прямой ответ).
Патрик

Во что бы то ни стало оставьте это! :) У нас явно была правильная идея, и цель - помочь. Я думаю, что слияние это хорошая теория.
ТоМорайс

Как это сделать, если вы уже нажали на ветку на github? Я попытался нажать после выполнения этого исправления и получил сообщение «Обновления были отклонены, потому что подсказка вашей текущей ветки находится за подсказкой: ее удаленный аналог».
Олли Уильямс,

41

Если вы не отправили изменения на сервер, вы можете использовать

git reset --soft HEAD~1

Это сбросит все изменения и вернется к одному коммиту обратно

Если вы отправили изменения, следуйте инструкциям @CharlesB.


2
-1 git reset удаляет произошедшие изменения файла из области подготовки, здесь изменение было зафиксировано
CharlesB

Хорошо, но я буду сдерживать голосование, так как это не то, чего хочет ОП :) извините
CharlesB

хорошо, это хорошо для меня, но почему противник не хочет этого. В чем проблема?
Паритош Сингх,

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

3
@Aris используйте <git diff --cached>, чтобы увидеть изменения
Paritosh Singh

37

Удаление файла с помощью rm удалит его!

Вы всегда добавляете коммит в git, а не удаляете, поэтому в этом случае верните файл в состояние, в котором он находился до первого коммита (это может быть действие удаления 'rm', если файл новый), а затем повторно зафиксировать, и файл будет идти.

Чтобы вернуть файл в предыдущее состояние:

    git checkout <commit_id> <path_to_file>

или вернуть его в состояние на удаленной ГОЛОВКЕ:

    git checkout origin/master <path_to_file>

затем измените коммит, и вы обнаружите, что файл исчез из списка (и не удален с вашего диска!)


36
git checkout HEAD~ path/to/file
git commit --amend

1
Это лучший способ изменить последний коммит, который не был передан. Это сбросит изменения в одном файле, фактически удалив этот файл из последнего коммита.
Алекс Браво

Это также изменило файл. Как сохранить локальные изменения в файле?
theonlygusti

29

Следующее действие приведет к удалению только того файла, который вы намеревались, что и было задано OP.

git reset HEAD^ /path/to/file

Вы увидите что-то вроде следующего ...

Изменения, которые необходимо зафиксировать: (используйте «git reset HEAD ...» для удаления)

изменено: / путь / к / файлу

Изменения, не подготовленные для фиксации: (используйте «git add ...» для обновления того, что будет зафиксировано) (используйте «git checkout - ...» для отмены изменений в рабочем каталоге)

изменено: / путь / к / файлу

  • «Изменения должны быть зафиксированы» - это предыдущая версия файла перед фиксацией. Это будет выглядеть как удаление, если файл никогда не существовал. Если вы передадите это изменение, будет исправление, которое вернет изменение в файл в вашей ветви.
  • «Изменения, не подготовленные для фиксации» - это зафиксированное вами изменение и текущее состояние файла.

На этом этапе вы можете делать с файлом все, что захотите, например, сбросить версию.

Когда вы будете готовы совершить:

git commit --amend -a

или (если у вас есть другие изменения, которые вы не хотите совершать, пока)

git commit add /path/to/file
git commit --amend

3
Ответ Джуззлина великолепен, но он чрезмерен, чтобы расстегнуть весь коммит, когда вы только хотите расстаться с ним. Невыполнение всего коммита может вызвать проблемы, если в данный момент вы внесете в файл фиксированные изменения в этом коммите, которые вы не хотите потерять.
ThatsAMorais

27

Я объясню вам с примером.
Пусть A, B, C - 3 последовательных коммита. Коммит B содержит файл, который не должен был быть зафиксирован.

git log  # take A commit_id
git rebase -i "A_commit_ID" # do an interactive rebase
change commit to 'e' in rebase vim # means commit will be edited
git rm unwanted_file
git rebase --continue
git push --force-with-lease <branchName>    

Если конкретный файл не находится в последнем или предыдущем коммите, это самый элегантный способ. Я бы даже сказал, что это самый элегантный способ в целом. Мне нравится интерактивный перебазирование.
bvgheluwe

Для одного коммита измените noopна edit [A_commit_ID]илиe [A_commit_ID]
TamusJRoyce

23

Вы можете просто попробовать.

git reset --soft HEAD~1

и создать новый коммит.

Тем не менее, есть потрясающее программное обеспечение "Gitkraken". что облегчает работу с git.


1
И просто обратите внимание: после этого вам нужно git commit --amendбудет обновить удаление файла при последнем коммите; и после этого вы можете проверить, действительно ли он был удален с помощьюgit log -1 --stat
sdbbs

13
git rm --cached <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit -m "removed unwanted file from git"

оставит вам локальный файл еще. Если вам также не нужен локальный файл, вы можете пропустить параметр --cached.

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

git rm --cached <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit --squash <commit_id>
git add <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit -m "brand new file!"
git rebase --interactive <commit_id>^

и затем вы можете с легкостью завершить ребазинг, не запоминая более сложные команды, не фиксируя сообщение или не набирая столько текста.


Это работает для меня. Я предполагаю, что если вы хотите добавить файлы обратно в микс, просто используйте git add -A или git add. и они вернулись.
Александр Миллс

11

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

Предполагая, что это не общая ветка, и вы не против переписать историю , запустите:

git gui citool --amend

Вы можете отменить проверку файла, который был ошибочно зафиксирован, а затем нажать «Подтвердить».

введите описание изображения здесь

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


2
В Ubuntu вы можете установить git gui с помощьюsudo apt-get install git-gui
JDiMatteo

Спасибо! Я застрял с проблемой (ошибка?), Где была добавлена ​​папка с репозиторием .git, и все обычные команды удаления не работали. Это однако помогло. Это было несколько коммитов назад, я сначала использовал, git rebase -i HEAD~4а затем выполнил вашу команду, чтобы открыть редактор. Еще одно примечание: «Unstaging» можно найти в меню «Commit».
Джонни Сковдал

Самое простое решение из всех. Проще всего запомнить. И гораздо менее подвержен ошибкам, чем использование git reset --soft HEAD^(помня --soft arg), за которым следует git commit -c ORIG_HEAD(вместо --amend, который все испортил).
Брент Фауст

9

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

git checkout origin/<remote-branch> <filename>
git commit --amend

6

Выполните последовательность следующих команд:

//to remove the last commit, but preserve changes  
git reset --soft HEAD~1

//to remove unneded file from the staging area  
git reset HEAD `<your file>` 

//finally make a new commit  
git commit -m 'Your message'

Я попытался выполнить эти шаги, и я вижу эту ошибку: не удалось отправить некоторые ссылки в «git ....». Чтобы предотвратить потерю истории, обновления без ускоренной пересылки были отклонены. Объедините удаленные изменения (например, 'git pull'), прежде чем нажать снова. Подробности смотрите в разделе «Примечание о быстрой перемотке» в «git push --help». (после git pull у меня такие же изменения)
Dezigo

Это означает, что состояние вашего удаленного репо изменилось, когда вы выполняли свою локальную работу. И после 'git pull' ваши локальные изменения должны быть объединены с удаленными, вот и все. Конечно, ваши изменения должны остаться.
Сергей Онищенко

Другими словами, если вы получаете эту ошибку @Dezigo, добавьте флаг -f для принудительного обновления.
jungledev

5

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

git reset --soft HEAD^
git checkout origin/master <filepath>

Ура!


Добро пожаловать. Этот ответ был бы лучше, если бы вы объяснили, что на самом деле делают команды.
Марк Чорли

3

Что-то, что сработало для меня, но все же думаю, что должно быть лучшее решение:

$ git revert <commit_id>
$ git reset HEAD~1 --hard

Просто оставьте изменения, которые вы хотите отменить, в другом коммите, проверьте другие

$ git commit --amend // or stash and rebase to <commit_id> to amend changes

3

git reset --soft HEAD^откатывает ваш коммит, и когда вы печатаете git status, он говорит вам, что делать:

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

2

На самом деле, я думаю, что более быстрый и простой способ - использовать интерактивный режим git rebase.

git rebase -i head~1  

(или голова ~ 4, как далеко ты хочешь пойти)

а затем вместо «выбрать», используйте «редактировать». Я не понимал, насколько мощным является «редактирование».

https://www.youtube.com/watch?v=2dQosJaLN18

Надеюсь, вы найдете это полезным.


видео длится 10 минут и не очень полезно
MolbOrg

2

Была такая же проблема, где у меня есть изменения в локальной ветке, где я хотел вернуть только один файл. То, что работало для меня, было -

( функция / target_branch ниже содержит все мои изменения, в том числе те, которые я хотел отменить для определенного файла)

( origin / feature / target_branch - это удаленная ветка, в которую я хочу отправить свои изменения)

( Feature / Staging - это моя временная промежуточная ветвь, в которую я буду выталкивать все мои разыскиваемые изменения, за исключением изменения в этом одном файле).

  1. Создайте локальную ветку из моего источника / feature / target_branch - она ​​называется feature / staging

  2. Объединенной мой рабочий местное отделение функции / target_branch к функции / постановка филиала

  3. Отмеченная функция / постановка, затем git reset --soft ORIG_HEAD (Теперь все изменения из функции / постановки 'будут поставлены, но не зафиксированы.)

  4. Unstaged файл, который я ранее проверил с ненужными изменениями

  5. Изменена ветвь вверх по течению для объекта / размещения на источник / функция / target_branch

  6. Подтвердил остальные поэтапные изменения и отправил вверх по течению к моему удаленному источнику / feature / target_branch


1

Если вам больше не нужен этот файл, вы можете сделать

git rm file
git commit --amend
git push origin branch

1

Если вы используете GitHub и еще не отправили коммит, GitHub Desktop легко решает эту проблему:

  1. Выберите Репозиторий -> Отменить самый последний коммит
  2. Отмените выбор файла, который вы ошибочно добавили. Ваше предыдущее сообщение будет уже в диалоговом окне.
  3. Нажмите кнопку фиксации!

1

Если вы хотите удалить файлы из предыдущих коммитов, используйте фильтры

git filter-branch --prune-empty --index-filter 'git rm --ignore-unmatch --cached "file_to_be_removed.dmg"'

Если вы видите эту ошибку:

Невозможно создать новую резервную копию. Предыдущая резервная копия уже существует в refs / original / Force для перезаписи резервной копии с -f

Просто удалите резервные копии в вашем локальном репо

$ rm -rf .git/refs/original/refs

1

если вы еще не добавили свои изменения в git

git reset --soft HEAD~1

Это сбросит все изменения и вернется к одному коммиту обратно

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

git rm <file>
 git commit --amend

или даже лучше:

сбросить в первую очередь

git reset --soft HEAD~1

сбросить ненужный файл

git reset HEAD path/to/unwanted_file

совершить снова

git commit -c ORIG_HEAD  

это так же, как и выше, но даже очень помогло проверить
Решма

0

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

git checkout origin/develop <path-to-file>
git add <path-to-file>
git commit -m "Message"
git push

0

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

git reset --hard @{u}

Тогда скопируйте вещи обратно. Подтвердите, нажмите.


0

Вы можете просто использовать эту команду:

git restore --staged <file>

0
Here is the step to remove files from Git Commit.

>git reset --soft HEAD^1(either commitid ) -- now files moved to the staging area.
>git rm --cached filename(it will removed the file from staging area)
>git commit -m 'meaningfull message'(Now commit the required files)

-1

Ни один из ответов на этот раз не является разумным. Похоже, что существует достаточное требование, чтобы было предложено реальное решение: https://github.com/git/git/blob/master/Documentation/SubmittingPatches

git --uncommit <имя файла>

было бы здорово. Я понял, что мы не хотим изменять историю, но если я локально и случайно добавил локальный «хакерский» файл и хочу удалить его из коммита, это было бы очень полезно.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.