Как удалить большое количество файлов без удаления контента

454

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

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

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

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

Также было бы полезно, если бы кто-то мог объяснить, как работает эта конвейерная операция.

Сарат
источник
8
rm -fне является командой git и не имеет --cachedопции. Ваши локальные файлы были удалены до того, как вы их выполнили, git rmпоэтому я не думаю, что вы можете на законных основаниях обвинять git rmчто-либо.
CB Bailey
8
@sarat, рассмотрите возможность изменения правильного ответа на ответ с большим количеством голосов Яна Мэддокса , так как git reset --hardон не является правильным и фактически удалит содержимое. Это запутает пользователей - как и меня.
Марко Пашков
2
@ Сарат, как говорит Марко, продолжай. Эта страница получает много трафика.
Росс
@MarcoPashkov & Ross спасибо, ребята. Выполнено.
сарат

Ответы:

986

git reset

Если все, что вам нужно, это отменить слишком усердный «git add»:

git reset

Ваши изменения будут без изменений и готовы для повторного добавления по вашему усмотрению.


НЕ ПРОПУСТИТЕ git reset --hard.

Он не только удалит добавленные вами файлы, но и отменит все изменения, внесенные в ваш рабочий каталог. Если вы создали какие-либо новые файлы в рабочем каталоге, они не будут удалены.

Ян Мэддокс
источник
15
Я должен вам пинту Йен
DasBooten
1
Я часто нахожу , что я должен выполнить git checkout -- *, а
Den-Jason
1
Вы сэкономили много усилий. Благодаря человеку
RajnikantDixit
35

Если у вас нетронутый репо (или HEAD не установлен) [1], вы можете просто

rm .git/index

Конечно, это потребует от вас повторно добавить файлы , которые вы же хотите добавить.


[1] Обратите внимание (как поясняется в комментариях), это обычно происходит только в том случае, если репо является новым («нетронутым») или если не было совершено никаких коммитов. С технической точки зрения, когда нет проверки или рабочего дерева.

Просто делая это более понятным :)

sehe
источник
Да, это больше похоже на удаление самого созданного индекса. Хорошо, что мне не нужно повторно инициализировать git. Спасибо!
сарат
Вы уверены, что это безопасная операция? Я просто сделал это (на самом деле переместил индекс), и все остальные файлы были подготовлены для удаления.
Звоните
@inger "Если у вас нетронутый репо". У тебя явно не было этого.
Сех
На самом деле, мне было интересно, что вы имели в виду под "нетронутым репо" (мне тоже не повезло с Google) .. То есть вы имели в виду пустой репо?
Звоните
1
@inger Согласен. Я должен был предположить, что у ОП была именно такая ситуация - он не уточняет ее, но его описание оставляет возможность. В любом случае, я просто делюсь информацией и не могу повлиять на голосование :(.
Добавил
15

Используйте git reset HEADдля сброса индекса без удаления файлов. (Если вы хотите сбросить только определенный файл в индексе, вы можете использовать git reset HEAD -- /path/to/fileдля этого.)

Трубный оператор в оболочке принимает stdoutпроцесс слева и передает его stdinпроцессу справа. По сути это эквивалент:

$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out

но вместо этого $ proc1 | proc2второй процесс может начать получать данные до того, как первый завершит их вывод, и в действительности не будет задействовано никакого файла.

янтарный
источник
но как использовать его с несколькими файлами. Я никогда не передавал эти файлы раньше.
сарат
3
Просто введите git reset HEADбез указания чего-либо еще, и он сбросит весь индекс. Затем вы можете просто повторно добавить только те файлы, которые вы хотите.
Янтарная
Я получил следующую ошибку. Я никогда не совершал эти вещи раньше. $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
сарат
1
Попробуйте только git resetтогда, без HEAD.
Янтарная
Я уже пробовал, что я оказался в следующей ошибке. $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
сарат
9
git stash && git stash pop
Bijan
источник
2
Я бы сделал 'git stash && git stash pop', чтобы тайник также был удален. 'apply' оставил бы тайник в списке тайников.
Читти
8

Если HEAD не установлен (т.е. у вас еще нет коммитов, но вы не хотите просто сдуть, .gitпотому что вы уже настроили другую конфигурацию репо, которую хотите сохранить), вы также можете сделать

git rm -rf --cached .

расстегнуть все По сути, это то же самое, что и решение Sehe, но позволяет избежать взлома внутренних компонентов Git.

jjlin
источник
это фактически говорит Git об удалении всего в кэшированной области.
Visionary Software Solutions
1
Кеш также известен как промежуточная область, поэтому я не уверен, к чему вы клоните.
Jjlin
Из sehe, rm .git / index очень опасен - обязательно прочитайте ПРИМЕЧАНИЕ, которое он имеет о новом репо! Это гораздо безопаснее для остальных 99,999% случаев. Я не читал внимательно, и мне пришлось выбросить мою рабочую копию и выполнить повторное клонирование после выполнения команды rm .git / index для моей рабочей копии.
phpguru
НЕ используйте эту команду! Это изменит ВЕСЬ проект на неотслеживаемое состояние (включая те, которые не были поставлены). Это не решение исходного вопроса. Правильное решение с помощью команды 'git rm' - это ТОЛЬКО указывать файлы, которые вы хотите удалить без меток: git rm -rf --cached <файлы, которые вы хотите удалить из архива>.
Монте Креасор
Эту команду следует использовать только тогда, когда у вас есть новый репо без коммитов (это означает, что «HEAD not set»), но вы не хотите просто сдувать, .gitпотому что вы настроили другую конфигурацию репо, которую вы хочу сохранить. Я редактировал, чтобы уточнить это.
Jjlin
5

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

Использование git resetбыло объяснено, но вы также запросили объяснение переданных команд, так что вот так:

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

Команда git ls-filesвыводит список всех файлов, о которых знает git. Опция -zнакладывает на них определенный формат, ожидаемый формат xargs -0, который затем вызывает rm -fих, что означает удаление их без проверки вашего одобрения.

Другими словами, «перечислите все файлы, которые знает git и удалите вашу локальную копию».

Затем мы git diffпереходим к тому , что показывает изменения между различными версиями элементов, о которых знает git. Это могут быть изменения между разными деревьями, различия между локальными и удаленными копиями и т. Д.
Как здесь используется, он показывает неустановленные изменения; файлы, которые вы изменили, но еще не зафиксировали. Опция --name-onlyозначает, что вам нужны только (полные) имена файлов, и --diff-filter=Dозначает, что вы заинтересованы только в удаленных файлах. (Эй, разве мы не просто удалили кучу вещей?) Затем они попадают в канал xargs -0, который мы видели ранее, что вызывает git rm --cachedих, то есть они удаляются из кэша, в то время как рабочее дерево должно быть оставлено в покое - за исключением того, что Вы только что удалили все файлы из вашего рабочего дерева. Теперь они также удалены из вашего индекса.

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


TL; DR: вы только что все надули; начать заново и использовать git resetс этого момента.

SQB
источник
2

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

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

git reset --hard

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

Обновление: из ваших комментариев к ответу Амбер звучит, что вы еще не создали никаких коммитов (поскольку HEAD не может быть решена), так что, боюсь, это не поможет.

Что касается того, как работают эти каналы: git ls-files -zи git diff --name-only --diff-filter=D -zоба выводят список имен файлов, разделенных байтом 0. (Это полезно, поскольку, в отличие от новых строк, 0байты гарантированно не встречаются в именах файлов в Unix-подобных системах.) Программа по xargsсуществу строит командные строки из своего стандартного ввода, по умолчанию беря строки из стандартного ввода и добавляя их в конец командной строки. -0Вариант говорит ожидать стандартный ввод пути разделенных 0байт. xargsможет вызвать команду несколько раз, чтобы использовать все параметры из стандартного ввода, убедившись, что командная строка никогда не становится слишком длинной.

В качестве простого примера, если у вас есть файл с именем test.txt, со следующим содержанием:

hello
goodbye
hello again

... тогда команда xargs echo whatever < test.txtвызовет команду:

echo whatever hello goodbye hello again
Марк Лонгэйр
источник
Я никогда не делал никаких коммитов, поэтому он скажет, что не может решить HEAD. Что мы делаем в таких ситуациях. Большое спасибо за подробное объяснение трубы.
сарат
8
Если вы только что изменили свой git ignore и включили git add --all для включения большого количества файлов, НЕ запускайте git reset --hard для их удаления. ОНИ БУДУТ УДАЛЕНЫ !!
Наслаждайтесь
5
Uwaaahh !! Может быть, вам нужно выделить слово «осторожно» . Я только что увидел эти три слова "git reset --hard", и все мои неподготовленные файлы ... fufff !! ушел!!!!!
Вайнет Читтети
1

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

git reset --soft HEAD

В случае, если вы хотите отменить изменения и вернуть их из рабочего каталога,

git reset --hard HEAD
027
источник