Короткий ответ: ты не можешь.Все, что git rm --cached
делает, это удаляет запись (или несколько записей) из вашего индекса.Что-то еще всегда может вернуть такую запись.
Это TL; DR, и вы можете остановиться здесь, если хотите.Но если вы хотите знать, что вы должны делать с этими файлами, читайте дальше ...
Это, однако, не очень хороший способ сформулировать эффект удаления записи изindex:
... когда я выполняю git rm - кэшированное имя файла над моим файлом, чтобы получить изменения , исключенные из подготовки git и репозитория область
(выделено мной), потому что индекс не хранит изменения .Здесь есть несколько важных терминологических вопросов, которые, если вы не очень точны, могут привести к некоторой степени страдания в будущем.Итак, давайте проясним ситуацию здесь, поскольку Git уже ужасно запутан (я работаю с ним уже более десяти лет, и у него все еще есть темные углы).
Об индексе
Итак, давайте поговорим об индексе.Эта вещь - этот индекс - очень важна в Git, потому что именно так вы делаете следующий коммит.По этой причине некоторые части Git называют это областью подготовки .Некоторые части Git, такие как git rm --cached
, называют его cache .Это всего лишь три термина для одной и той же вещи: для структуры данных, которую Git переносит, слабо привязанной к вашему рабочему дереву, которую Git будет использовать при создании new commit.
Сам индекс представляет собой сложного маленького зверя и играет расширенную роль во время слияний, но в основном он удерживает копий файлов .Чтобы понять, как работает эта часть, полезно взглянуть на commitits и work-tree (или рабочее дерево, или рабочий каталог, или любое количество похожих терминов).Под коммитом или, точнее, подразумевается полный снимок всех файлов .Здесь нет изменений , есть только файлы.Если файл main.py
находится в коммите, в коммите есть полная копия из main.py
с содержимым, которое было у вас, когда вы - или кто-либо еще - запускали git commit
.
.файлы внутри коммитов преднамеренно замораживаются и сжимаются - иногда очень сильно сжаты - и Git-ified в форму, которую действительно может использовать только Git.Это отлично подходит для архивации коммитов навсегда, но не подходит для выполнения какой-либо работы.Чтобы завершить работу, Git должен разморозить, распаковать и де-Git-ify ваши файлы в форму, которую вы обычно используете.Так вот откуда исходит ваше дерево работы: это место, где вы можете выполнять свою работу.
Тогда вы можете подумать, что Git остановится здесь: у вас будут коммиты, которые заморожены навсегда, итвое рабочее дерево;и вы изменяете файлы в своем рабочем дереве и говорите Git о фиксации, и он снова замораживает файлы рабочего дерева.Но на самом деле это не то, что происходит.
Вместо этого, когда вы извлекаете коммит, используя, например, git checkout <em>branch</em>
, Git копирует замороженный, Git-ifiedфайлы из коммита в индекс.Здесь файлы все еще Git-ified и готовы заморозить в следующий коммит.Но они на самом деле не заморожены сейчас. Теперь вы можете перезаписать их.Они по-прежнему Git-only!
Итак, скопировав файлы в указатель, Git теперь продолжает распаковывать и де-Git-ify файлы и помещатьнормальные файлы в вашем рабочем дереве.Это означает, что когда вы делаете и делаете следующий коммит, Git может - и делает - игнорировать ваше рабочее дерево.Он просто берет все, что есть в вашем индексе прямо сейчас , полные копии всех файлов, и замораживает их в новом коммите.
Вот почему выВы должны продолжать работать git add
, даже если у вас был git add
-данный файл ранее.git add
копирует файл work-tree в копию index .Если раньше в индексе была копия, ну, теперь она перезаписывается новой (и недавно Git-ified) версией.Если нет, то теперь это в индексе.В любом случае, теперь он готов перейти к следующему коммиту.
Наличие файла в индекса - это именно то, что определяет файл как отслеживаемый .Если он в индексе, он отслеживается.Если нет, то это не так.
Так что git rm --cached somefile
удаляет Git-ified копию somefile
из индекса.Без --cached
это также приведет к удалению обычного формата somefile
из рабочего дерева.С --cached
он оставляет файл рабочего дерева позади:
$ git checkout master
... bunch of files exist ...
$ git rm --cached main.py # main.py is now untracked
$ git add main.py # main.py is now tracked
Нет коммиты произошли между ними, поэтому мы изменили файл с отслеженного на неотслеживаемый, затем обратно с неотслеживаемого наотслеживаются.Копия в индексе теперь совпадает с копией, которая была в индексе ранее - эта более ранняя копия вышла из коммита, но так как версия рабочего дерева является версией de-Git-ified, и мы повторно вставили ее в Git-ifiedиндекс, теперь он такой же, каким был до того, как мы его удалили.
Если мы не допустим файл вне индекса (снова git rm --cached
), а затем git commit
. новый коммит, который мы делаем, теперь не имеет файла в нем.(Новый коммит также становится верхним коммитом ветви.) Так что если мы git checkout
этот новый коммит позже, этот файл не будет в коммите, поэтому он не в индексе.Если в рабочем дереве есть неотслеживаемый файл с таким именем, этот неотслеживаемый файл не будет поврежден.
Но как только мы проверяем любой более старый коммит, который имеет , этот файл, хорошо, он находится в коммите, поэтому Git копирует его в индекс, а затем и в рабочее дерево.Теперь он снова отслеживается, потому что теперь он в индексе.Если мы закончили с просмотром старого коммита, и у нас git checkout
нового, у которого нет файла, Git:
- увидит, что файлв коммите и индексе и рабочем дереве
- видит, что файл не в новом коммите, чтобы перейти к
- , удаляет файл из индекса и рабочийдерево при переключении на новый коммит
О .gitignore
файлах
При перечислении имени файла или шаблона, соответствующего имени файла, в файле .gitignore
не сообщаетсяGit для игнорировать файл, точно.Он воздействует на неотслеживаемых файлов.
Не отслеживаемый файл - это, как мы уже отмечали, файл, который находится в рабочем дереве, но не в индексе.Неважно, входит ли он в какой-либо конкретный коммит или нет, важно то, находится ли он в индексе прямо сейчас .Если вы добавляете файл в индекс, используя git add
, чтобы скопировать его (и сжать и Git-ify) из рабочего дерева в индекс, ну, теперь он там и, следовательно, отслеживается.Если вы git rm --cached
файл из индекса, ну, теперь он не там и, следовательно, не отслеживается.Меняйте местами столько, сколько хотите!Ничего действительно важного пока не происходит: вы просто вводите файл в индекс или удаляете его из индекса.
Отсутствие отслеживания имеет два основных эффекта:
- Он не входит в следующий коммит, если и когда вы запустите
git commit
.Это потому, что Git создает новые коммиты из того, что есть в индексе. - И это заставляет Git скулить на вас: Эй, файл
somefile
не отслежен, разве вы не хотите, чтобы он был в ваших коммитах?
Перечисление имени файла в .gitignore
заставляет Git замолчать из-за отсутствия отслеживания, и делает git add --all
или git add .
not скопировать этот файл в индекс, если его там еще нет.Таким образом, мы могли бы сказать, что вместо .gitignore
этот файл должен называться .git-stop-whining-about-these-files-and-do-not-automatically-add-them-with-mass-add-operations
.
Это не очень приятное имя, поэтому Git использует .gitignore
.
* 118.7 * Впрочем, при перечислении файла в
.gitignore
есть нежелательный побочный эффект.Git обычно очень осторожен с неотслеживаемыми файлами.Предположим, что файл не отслежен, и какая-то операция приведет к его засорению.Например, предположим, что
somefile
сейчас не отслеживается и не входит в
текущий коммит .Но это в коммите tip ветки
dev
, и вы говорите Git:
git checkout dev
или
git merge dev
.(Случай слияния более сложен, но имеет те же проблемы.)
Поскольку файл равен в коммите в конце dev
, Git потребуется скопировать somefile
от этого коммита до индекса и рабочего дерева.Это будет перезаписать somefile
.Git скажет вам: Нет, я не буду задевать ваш файл somefile
.Это не отслеживается и мешает.Пожалуйста, зафиксируйте его или уберите с пути.
Но если вы укажете somefile
в своем .gitignore
, Git будет не стесняться его затушевывать после всех ,по крайней мере, в некоторых случаях (включая git checkout dev
один).Итак, этот .gitignore
файл должен иметь имя .git-stop-whining-about-these-files-and-do-not-automatically-add-them-with-mass-add-operations-but-do-feel-free-to-clobber-them-in-some-cases
.
Вывод: идеального ответа не существует
Нет существующий коммит может быть когда-либо изменено , поэтому, если какой-то файл попал в некоторые коммиты, где он не должен был существовать, вы довольно хорошо застряли.Вы можете делать то, что некоторые называют «переписыванием истории» (используя, например, git filter-branch
или BFG ).Это дает новые и улучшенные коммиты с разными хэш-идентификаторами, у которых нет файлов, которые вы должны затем убедить всех использовать вместо старых плохих коммитов, в которых был файл.
Или вы можете git rm --cached
файл и выбрать, включать его или нет в .gitignore
.Если это что-то, что безопасно для клобера, перечисление этого здесь - вероятно путь.Таким образом, файл не будет в вашем индексе в new коммитах, которые вы делаете отсюда.Конечно, если вы вернетесь к старым коммитам и будете использовать их - используйте то, что вставлено в ваш индекс - для создания новых коммитов, забыв снова git rm --cached
, это не поможет, потому что когда файл равен в вашем индексе вы фактически должны удалить его, либо переключившись обратно на коммит, у которого его нет, либо запустив на нем git rm --cached
.Но git add .
не будет добавлять его случайно.Вы просто должны быть осторожны, чтобы не clobber файл выйти из вашего рабочего дерева, когда возвращаетесь к более старым коммитам, которые его имеют.
Или, конечно, вы можетеgit rm --cached
файл и мириться с любым нытьем.