Что именно делает «git ls-files» и как мы можем удалить из него файл? - PullRequest
2 голосов
/ 21 мая 2019

Показывает ли он файлы из локального хранилища, промежуточного хранилища, удаленного хранилища или откуда-то еще?

Я постоянно вижу файл, который присутствует в «git ls-files».Этот файл был удален из удаленного хранилища.После чего я попытался сделать git pull.Однако этот файл все еще отображается в этом списке команд.Он не должен присутствовать здесь, потому что он также отсутствует в удаленном хранилище.

Ответы [ 4 ]

2 голосов
/ 21 мая 2019

Резюме

Вам нужно понять, что Git хранит не менее трех, а иногда до пяти активных копий каждого файла: одна в текущем коммите , одна ( или два или три!) в index и один - единственный, который вы можете видеть и работать - в вашем рабочем дереве . Команда git ls-files просматривает эти копии, а затем сообщает вам о некоторых из них, в зависимости от флагов, которые вы указываете для git ls-files.

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

Long

Я думаю, здесь есть две проблемы. Один требует некоторой терминологии, а затем другой должен встать на свои места:

Показывает ли [git ls-files] файлы из локального репозитория,

Вроде, но:

промежуточное хранилище,

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

удаленный репозиторий

Определенно нет: не должно быть никаких удаленных репозиториев - то есть других Git с собственными репозиториями - вообще, и если они есть, только у git fetch и git push ваш Git вызывает Git и обменивается данными с их. (Ну, git ls-remote выполняет первый маленький бит git fetch, а git pull запускает git fetch, поэтому эти два также обмениваются данными с удаленным. Но git ls-files нет.)

или откуда-то еще?

Да, вроде. Это возвращает нас к первой части. Итак, давайте возьмем эти три бита терминологии, как определено в глоссарии Git . Текст, выделенный курсивом (включая полужирный курсив) ниже, непосредственно из связанной документации:

  • Репозиторий

    Коллекция ссылок вместе с объектной базой данных , содержащей все объекты, которые достижимы из ссылок, возможно сопровождаемые метаданными одного или больше фарфор . Хранилище может совместно использовать базу данных объектов с другими хранилищами с помощью альтернативного механизма . (все их ссылки)

    Это, конечно, полно еще большей терминологии. Чтобы попытаться немного де-мистифицировать его, они говорят, что собственно хранилище не включает в себя индекс и рабочее дерево: оно в основном состоит из commitits (и их содержание). Конечно, для этого необходимо определить «индекс» и «рабочее дерево», поэтому давайте перейдем к:

  • Индекс

    Коллекция файлов со статистической информацией, содержимое которых хранится в виде объектов. Индекс является сохраненной версией вашего рабочего дерева . По правде говоря, он также может содержать вторую и даже третью версию рабочего дерева, которые используются при слиянии .

  • рабочее дерево (я обычно называю это рабочее дерево):

    Дерево актуальных извлеченных файлов. Рабочее дерево обычно содержит содержимое дерева фиксации HEAD , а также любые локальные изменения, которые вы внесли, но еще не зафиксировали.

Коммиты заморожены навсегда

Когда тебевы запускаете git commit, Git делает снимок всех ваших файлов - ну, в любом случае, всех ваших отслеженных файлов - и сохраняет их, а также некоторые метаданные, такие как ваше имя и адрес электронной почты, в коммите. Этот коммит в основном постоянный - вы можете избавиться от коммитов, обычно с небольшим трудом, но просто для удобства представьте их как постоянные - и полностью, полностью, только для чтения на 100%. Это специально предназначено только для чтения, так как это позволяет другим коммитам совместно использовать идентичные копии файлов, так что если вы фиксируете один и тот же файл один раз, десять раз или даже миллион раз, на самом деле только одна копия этого файла в хранилище. Только когда вы изменяете файл на новую версию, Git должен зафиксировать новую отдельную копию.

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

... <-C4 <-C5 <-C6 ...

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

Так что коммиты навсегда заморожены. Файлы внутри них также заморожены и сжаты в специальном формате Git-only. Мне нравится называть эти файлы "высушенными". это означает, что они отлично подходят для архивирования, но они совершенно бесполезны для выполнения любой новой работы ... и , что означает что Git должен предоставить какой-то способ взять эти файлы, высушенные вымораживанием, и перевести их в полезную форму.

Рабочее дерево предоставляет копии полезных форм

На самом деле все не так просто: у рабочего дерева есть регидратированные копии ваших файлов в полезной форме. Поскольку они представляют собой обычные повседневные файлы на вашем компьютере, вы можете просматривать их, использовать их, изменять их по своему усмотрению и работать с ними. Технически они вовсе не в хранилище - они скорее рядом с ним. В типичной настройке сам репозиторий находится в папке / 1177 * каталога / верхнего уровня вашего рабочего дерева.

Очевидно, что если есть коммит, который вы извлекли в , сделайте рабочим деревом, то теперь должно быть две копии каждого файла: фиксированный с фиксацией, плюс обычный рабочий. Git может остановиться здесь. Mercurial останавливается здесь: если вы используете Mercurial вместо Git, вам не нужно беспокоиться о третьей копии, потому что третьей копии нет. Но Git продолжает хранить еще больше копий файлов.

Индекс / промежуточная область находится между коммитом и рабочим деревом

Что Git делает здесь, так это вставляет третью копию каждого файла между зафиксированной копией и копией рабочего дерева. Эта третья копия находится в формате зафиксированного файла, т. Е. Предварительно обезвожена, но, будучи не в commit , на самом деле она не полностью заморожена: ее можно заменить в любое время , Вот что делает git add: git add берет обычную копию файла из рабочего дерева, сжимает ее в формат сублимации и заменяет копию в индексе. Или, если файл вообще не был в индексе, он помещает копию в индекс.

Вот почемуВы должны git add файлы все время.В Mercurial вы только hg add файл один раз .После этого вы просто запускаете hg commit, и Mercurial просматривает все файлы, о которых знает, и фиксирует их в новом коммите.Это может занять много времени в большом хранилище.Git, напротив, уже имеет всех файлов, о которых он должен знать, и уже обезвожен, в индексе, поэтому git commit может просто упаковать эти обезвоженные файлы в новый замороженный коммит.Стоимость этой скорости составляет git add, но если вы начнете играть хитрые трюки с индексными копиями, например, используя git add -p, вы получите больше преимуществ, чем , просто ускорение.

Как и глоссарий Git , упомянутый в описании индекса, индекс играет расширенную роль во время конфликтующего слияния.Когда вы выполняете операцию слияния - будь то из git merge, или из git revert, или git cherry-pick, или из любой другой команды Git, использующей механизм слияния, - и она не проходит гладко, Git включает все три входа длякаждый файл в индекс, так что вместо одной копии file.ext вы получите три.Но пока вы не находитесь в середине слияния, в индексе есть только одна копия.

Обычно индексная копия соответствует замороженной копии HEAD или совпадает с копией рабочего дерева, илии то и другое.Например, после нового git checkout все три копии совпадают.Затем вы изменяете file.ext в рабочем дереве: теперь фиксация и индекс совпадают, но они не совпадают с копией рабочего дерева.Тогда вы git add file.ext, а теперь индекс и рабочее дерево совпадают, но они отличаются от замороженной копии.Затем вы git commit делаете новый коммит, который становится текущим коммитом, и все три копии снова совпадают.

Обратите внимание, что вы можете изменить копию рабочего дерева:

vim file.ext

затем скопируйте обновленный в индекс:

git add file.ext

, затем отредактируйте его еще раз:

vim file.ext

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

Рабочее дерево может содержать файлы, которых вообще нет в индексе

Индекс изначально простокопия текущего коммита.Затем Git также копирует эти файлы в рабочее дерево, чтобы вы могли их использовать.Но вы можете создавать файлы в рабочем дереве и не запускать git add на них.Этих файлов сейчас нет в индексе, и если вы запустите git commit, они также не будут включены в новый коммит, потому что Git создает новый коммит из индекса.

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

git rm --cached file.ext

удаляет копию индекса.Конечно, он не может коснуться текущей замороженной копии коммита, но если вы сейчас сделаете новый коммит, новый коммит вообще не будет содержать file.ext.(Конечно, предыдущий коммит все еще работает.)

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

Теперь мы можем ясно увидеть, что git ls-files делает

Что делает git ls-files, так это читает все: коммит, индекс, и рабочее дерево.В зависимости от того, какие аргументы вы вводите git ls-files, он затем печатает имена некоторых или всех файлов, которые есть в индексе и / или в рабочем дереве:

git ls-files --stage

литийsts файлы, которые находятся в области index / staging, вместе с номерами их промежуточных слотов. (Он ничего не говорит о копиях в HEAD коммите и рабочем дереве.) Или:

git ls-files --others

перечисляет (имена) файлов, которые находятся в рабочем дереве, но отсутствуют в индексе. (Это ничего не говорит о копиях в HEAD коммите.) Или:

git ls-files --modified

перечисляет (имена) файлов, которые находятся в индексе и , отличаются от их копий в коммите HEAD (или вообще не в коммите HEAD). Без вариантов:

git ls-files

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

1 голос
/ 21 мая 2019

git ls-files правильно работает в вашем случае. Поскольку ваш git status показывает, что X-файл удален из рабочего каталога, это означает, что файл все еще существует в индексе. Вот почему git ls-files показывает X, потому что команда показывает содержимое индекса.

Теперь вам нужно удалить этот файл из индекса, просто запустите:

git rm --cached <pathToXFile>
0 голосов
/ 21 мая 2019

Я постоянно вижу файл, который присутствует в "git ls-files".Этот файл был удален из удаленного хранилища.После чего я попытался сделать git pull.

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

Если вы нене хочу это в своем индексе, удалите это.Обычно это git rm --cached или, если вы также хотите, чтобы оно ушло из вашего рабочего дерева, просто git rm.

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

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

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

0 голосов
/ 21 мая 2019

git ls-files объединяет список файлов в индексе кэша каталогов с фактическим списком рабочих каталогов и показывает различные комбинации этих двух.

для информации можно найти здесь

Редактировать:

Фактическая директория - это ваша текущая ветка на вашем локальном компьютере (только для отслеживаемых файлов), и вы можете удалить файл из наличных, например, git rm --cached fileName

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...