A path - это просто имя файла. Например:
README.md
- это имя файла, а также путь. Путь не содержит папкообразных частей. src/main.py
- это имя файла, а также путь. Путь содержит часть, похожую на папку, src
, и часть, похожую на файл, main.py
, и ваш компьютер, вероятно, требует, чтобы Git фактически создал папку / каталог с именем src
, прежде чем Git сможет создать файл с именем main.py
. Для Git это в основном просто файл с именем src/main.py
, но Git будет учитывать причуду вашего компьютера, требующую такого странного разделения "файлов" и "папок", или как вы хотите их называть.
Обратите внимание, что Git не хранит папки. Файлы - это просто файлы в области index / staging, даже если в их именах есть части folder-i sh. Git builds new фиксирует коммит из того, что находится в индексе во время выполнения git commit
, 1 , поэтому коммиты не могут хранить пустые папки, потому что индекс не может хранить имя, заканчивающееся на a sla sh. 2
Сам индекс, который также называется промежуточной областью , или (редко в наши дни) кеш , странная, но важная вещь Git застревает между текущим коммитом и вашим рабочим деревом . Ваше рабочее дерево - это то место, где у вас есть файлы в их обычной повседневной форме, с которыми вы можете работать, но GIt не использует их для новых коммитов; Git использует индекс. Таким образом, индекс можно довольно точно описать как 3 , как ваш предложенный следующий коммит . Запуск git add
копирует файл из вашего рабочего дерева в индекс. 4 Это делает файл готовым к фиксации, если, конечно, вы его не измените: тогда вам придется снова скопировать его в индекс.
Файл, который существует в вашем рабочем дереве, принадлежит вам, как и вы. Git не будет перезаписывать его, кроме:
- , когда вы извлекаете коммит, в котором есть файл с этим именем (после создания любых папок, необходимых для достижения этой точки, как отмечено выше), или
- , когда вы делаете
git merge
, который требует от Git наилучших усилий при объединении в файл, или - , когда вы специально просите Git перезаписать его.
Если в index указан один и тот же путь, т. Е. Все части папки-y плюс окончательное имя файла, этот файл рабочего дерева будет отслежен . Если нет, файл рабочего дерева не отслеживается .
Поскольку Git делает следующий коммит из того, что находится в индексе, каждый отслеживается * Файл 1064 * включается в следующий коммит (в той форме, в которой он находится в индексе, поэтому вы должны оставить его git add
). Если файл не в индексе, следующий коммит не будет иметь этот файл.
1 Если вы используйте git commit -a
или некоторые другие формы git commit
, они эффективно запускают git add
для вас непосредственно перед фактическим принятием. Но это всего лишь сокращенная версия git add <those files>; git commit
: Git по-прежнему создает коммит из области index / staging-area.
2 Это не совсем так. Git может поместить такой путь в индекс. Но части Git продолжают настаивать на том, что эта вещь Git вызывает gitlink , что является частью того, как Git отслеживает то, что Git называет подмодулями . Поэтому они не работают должным образом для хранения пустых папок / каталогов: эти вещи превращаются в сломанные подмодули, то есть в gitlinks без необходимой информации, чтобы заставить остальную часть этого работать.
3 У index есть несколько дополнительных ролей, особенно во время конфликтующих слияний, которые делают это не совсем правильным. Но это разумная ментальная модель: вы можете думать об индексе как о копиях всех файлов, которые go войдут в следующий коммит. Они начинают быть копиями файлов с текущего коммита. См. Также сноску 4.
4 Технически, индекс содержит ссылку на внутренний Git объект BLOB , а не на копию файла. Но это техническое различие действительно проявляется только в том случае, если вы начинаете искать в индексе, например, с git ls-files --stage
, или начинаете использовать git update-index
для помещения в него идентификаторов объекта ha sh. Если вы просто думаете об индексе как о Git -определенной копии каждого файла, который будет go в следующем коммите, эта ментальная модель работает довольно хорошо.
Когда rm --cached
получает tricky
Если мы находимся в обычном повседневном хранилище, мы можем добавить совершенно новый файл:
$ git checkout -b feature master
<make all-new file>
$ git add newfile.ext
$ git commit
У нового коммита есть новый файл, которого нет в старом коммите , Новая ветвь feature
содержит файл в своем коммите-коммите, а master
не имеет файла.
Неудивительно, если мы сейчас:
$ git checkout master
файл newfile.ext
исчезает из рабочего дерева.
В общем, предположим, что вы переходите от коммита, который имеет , к файлу, который не . То есть вы запускаете git checkout
для коммита (в конце некоторой ветви), в котором нет файла newfile.ext
. Но newfile.ext
есть сейчас и в вашем рабочем дереве, и в индексе. Так что Git должен вытащить копию из индекса. Он также удаляет копию из вашего рабочего дерева. Это то, что мы только что сделали, переключившись с develop
(у которого есть новый файл) на master
(у которого нет файла).
Теперь давайте go вернемся к develop
:
$ git checkout develop
В коммите на кончике develop
есть файл newfile.ext
. В данный момент у вас его нет в индексе или в рабочем дереве, поэтому для Git безопасно скопировать newfile.ext
из коммита подсказки develop
в индекс, а затем скопировать его в ваше рабочее дерево. И теперь у вас действительно есть файл, и жизнь прекрасна.
Но: о-о, мы не должны были совершать newfile.ext
в конце концов. Это файл конфигурации, или база данных живых пользователей, или что-то еще. Мы не хотим этого в feature
. Поэтому мы удалили его:
$ git rm newfile.ext
$ git commit
Но, о-о, мы потеряли нашу конфигурацию (или базу данных, или что бы то ни было)! Так что вместо git rm
давайте не будем выполнять две вышеуказанные команды. Вместо этого давайте сделаем:
$ git rm --cached newfile.ext
$ git commit
На этот раз Git удаляет newfile.ext
из index , но не из нашего рабочего дерева . Файл все еще находится в нашем рабочем дереве. Оно ушло из индекса, поэтому его нет в новом коммите на feature
.
Но теперь, если мы возьмем старый коммит на feature
например, по его sh ID, что происходит? Ну, этот коммит содержит newfile.ext
. Git хочет поместить этот файл в индекс и скопировать его в рабочее дерево.
Обычно мы получаем жалобу, что этот git checkout
перезапишет newfile.ext
. Иногда - это немного сложно, именно тогда, когда Git перезапишет newfile.ext
в любом случае! И если мы заставим оформить заказ, Git перезапишет newfile.ext
, как мы и просили. И теперь этот файл находится как в индексе, как видно из коммита, в котором мы его сохранили, так и в обычной (не Git -идентифицированной) форме в нашем рабочем дереве.
Так как он находится в обоих индексах и рабочее дерево, если мы теперь git checkout feature
или git checkout master
- оба из которых идентифицируют коммиты, которые не имеют файл - Git теперь удалит файл, из индекса и рабочего дерева. Наша драгоценная конфигурация или база данных или что бы то ни было, снова исчезли!
Итак, знайте, что делает git rm --cached
, но помните, что он также устанавливает эти ловушки: коммиты, в которых файл делает существуют и могут перезаписать что-нибудь ценное, когда вы их проверите. Вы не можете изменить эти существующие коммиты: у них будет этот файл навсегда. Лучшее, что вы можете сделать, это избежать их или вообще прекратить их использование, если это проблема.