Комментарий eftshift0 содержит ответ: файл, о котором Git писал, который был перезаписан git mv --force
, был копией рабочего дерева .Здесь происходит то, что Git имеет много копий файлов!
Коммиты являются постоянными (ну, в основном) и доступны только для чтения, и замораживают файлы навсегда
Когда вы используете Git длясовершать новые коммиты, важно запомнить несколько вещей.Во-первых, фиксирует себя - это постоянные записи.Каждый коммит имеет или имеет:
- снимок всех файлов, которые вы сказали Git заморозить в этом коммите;
- ваше имя (как автора и коммиттера) или имяавтор / коммиттер, если коммит был сделан кем-то другим;
- ваше (или чужое) сообщение журнала о том, почему вы сделали коммит;и - эта часть крайне важна, но мы не будем ее здесь рассматривать, потому что нас пока не интересует, как работает история Git - хэш-идентификатор родителя или родителей коммита.
Фактическое имя каждого коммита - это большой уродливый хэш-идентификатор, который Git составляет на месте, когда вы (или кто-либо другой) делает коммит.Git гарантирует, что каждый большой уродливый хэш-идентификатор будет уникальным, поэтому каждый коммит будет иметь свой хэш-идентификатор.Однажды сделанный, никто - ни вы, ни Git - не могут изменить коммит: если вы попытаетесь это сделать, и действительно что-то измените и сделаете коммит снова, то вы получите другой коммит, с новым и другим идентификатором хэша.Старый коммит также остается в репозитории.
В некоторых случаях вы можете сказать Git забыть о коммите (на самом деле, целую цепочку коммитов), так что вы никогда не сможете найти ихснова;в конце концов Git очистит их и удалит их.Но в основном то, что мы делаем с репозиторием Git, это добавление новых коммитов , сохраняя при этом все существующие коммиты без изменений.Мы не можем изменить какой-либо существующий коммит вообще, поэтому после его создания у него есть замороженная копия всех файлов, сохраненная навсегда на тот случай, если они понадобятся вам из глубокой заморозки.
Замороженные файлысжатые и только для Git, поэтому у нас должно быть рабочее дерево
Поскольку Git сохраняет, навсегда (в основном), каждую версию каждый файл, который вы (или кто-либо еще)) когда-либо говорили, что для сохранения эти файлы быстро займут все ваше хранилище, если Git сохранит их как есть.Таким образом, замороженные файлы сжимаются, иногда очень сжимаются, в специальном формате Git-only, разделяется среди всех коммитов.Новые заморозки - новые коммиты - просто по возможности повторно используйте старые заморозки из старых коммитов.Все это происходит автоматически и негласно, но имеет серьезные последствия.
Если бы у Git не было способа восстановить / повторно гидрировать ваши файлы, высушенные вымораживанием, вы никогда бы не смогли получить любых из них назад!Там не будет git checkout
.Одним словом, это было бы плохо.Таким образом, Git предоставляет вам пространство, в котором он извлекает (и размораживает) ваши файлы, превращая их обратно в полезные файлы.Это пространство - ваше рабочее дерево или рабочее дерево .
В общем, вы используете git checkout
, чтобы сообщить Git: Мне бы здесь хотелосьКоммит, пожалуйста. Вы используете имя , как master
, но вы действительно выбираете коммит по его уникальному хэш-идентификатору.Git восстанавливает файлы и помещает их в ваше рабочее дерево, чтобы вы могли получить к ним доступ и работать с ними.
Git запоминает, какой коммит вы выбрали (и его имя ветки): это ваш текущий коммит.Git делает это, прикрепляя имя HEAD
к имени ветви. 1 Он остается вашим текущим коммитом, пока вы не сделаете что-то, чтобы изменить то, что является вашим текущим коммитом - включая git checkout
, но также включая создание новый коммит, который затем становится текущим коммитом.В любом случае, очевидно, что на данный момент у нас есть две копии каждого файла.Если у вас есть файл с именем README.txt
, мы можем назвать один из них HEAD:README.txt
, а другой просто README.txt
.Копия HEAD
только для Git и заморожена на все времена, а копия рабочего дерева нормальная.
Git coulОстановимся на этом - на нем могут храниться замороженные Git-файлы, сохраненные навсегда в коммитах, плюс одна копия рабочего дерева, с которой вы работаете или с которой работаете.Но Git добавляет третью копию в смесь.
1 Присоединение HEAD
к какому-либо имени ветви достаточно, чтобы запомнить как текущую ветку , так и вашутекущий коммит, потому что имя ветки запоминает коммит.Вы можете спросить Git: Как называется ветка для HEAD
? , и вы получите ветку;или вы можете спросить Git: Что такое хеш-код коммита для HEAD
? , и Git использует имя ветви для поиска коммита.
Индекс
Git использует трюк здесь, частично для скорости, частично для различных других целей.Вместо того, чтобы вынимать файлы из глубокой заморозки, восстанавливать их и забывать о том, что они сделали, Git по существу копирует файлы из морозильника в более удобное место.Здесь они все еще находятся в сильно сжатой форме Git, но теперь они не заморожены .
Эта третья область - действительно средняя область между commit и work-tree - по-разному называются index , staging area или cache , в зависимости от того, кто / какой бит Git являетсязвонитьПервое, что делает этот индекс, это то, что он делает git commit
быстрым .Поскольку файлы в индексе (или промежуточной области) всегда уже находятся в правильной форме , все, что нужно сделать git commit
- это заморозить их.Другие системы управления версиями вынуждены изучать все ваше рабочее дерево, тщательно изучая каждый файл, чтобы увидеть, не изменился ли он, что может даже потребовать повторного сжатия файла в замороженном виде.Это занимает много времени.Git не обязан этого делать.
Но это означает, что когда вы работаете, у вас есть третья версия каждого файла.Мало того, что HEAD:README.txt
должно идти с вашим рабочим деревом README.txt
, есть также index копия README.txt
, которую мы можем назвать :README.txt
.
Когда вызапустите git add
для файла, Git сжимает версию этого файла в рабочем дереве и заменяет ту, которая была в индексе ранее.Или, если раньше его вообще не было в индексе, теперь это так.В любом случае, новая версия файла теперь готова к работе - все, что git commit
должен сделать, это заморозить предварительно сжатый файл!
Вот где git rm
приходит. Если у вас есть файлэто в вашем рабочем дереве, потому что оно было в коммите, у вас - или Git в любом случае - прямо сейчас у вас есть три копии файла: HEAD:file
в текущем коммите, :file
виндекс и file
в рабочем дереве.Запуск git rm file
удаляет две копии: одну в индексе и одну в рабочем дереве.(Он не может коснуться замороженного, потому что, ну, он заморожен!) Теперь, когда файл отсутствует в индексе, он не будет находиться в следующем коммите васmake.
Однако, если вы запускаете git rm --cached
, Git удаляет only индексную копию.Теперь у вас есть HEAD:file
и file
, но нет :file
.Это означает, что сделанный вами следующий коммит не будет содержать файл file
.Хотя немного трудно понять, что вы сделали, потому что индексная копия каждого файла обычно невидима.Если вы используете свои обычные компьютерные инструменты, чтобы увидеть, какие файлы у вас есть, это покажет вам файлы work-tree .
Копия HEAD
каждого файла также обычно невидима, которая имеетта же проблема - но поскольку зафиксированные файлы заморожены, нам, как правило, все равно.Мы просто используем git checkout
, чтобы переключиться на другой коммит, если мы хотим увидеть файлы.Это обновляет индекс и рабочее дерево, чтобы соответствовать другому коммиту.Тогда мы можем просто посмотреть на рабочее дерево, потому что все три копии всех файлов совпадают.
git status
говорит вам все, в сокращенной и, таким образом, полезной форме
Git makes новые коммиты из индекса.Таким образом, индекс определяет, что вы будете совершать.Вот почему мы можем описать это как , что будет в следующем коммите, который вы сделаете. Но индекс по существу невидим.Как вы узнаете, что будет в следующем коммите, который вы делаете?
Запуск git status
- это то, как вы узнаете, что происходит с вашим индексом.
Первое, что делает git status
, эторасскажет вам о вашей текущей ветке, т.е. она смотрит, к какому имени ветки добавлено специальное имя HEAD
.Это говорит вам, куда пойдет ваш следующий коммит.
Остальные выходные данные git status
сообщают вам о файлах, подготовленных для фиксации и файлах, не подготовленных к фиксации ,Вместо перечисления каждого файла в индексе, который в большом проекте будет состоять из целого ряда файлов, git status
делает сначала сравнивает индексные копии каждого файлачтобы увидеть, что изменилось в авторе с копий HEAD
.Точная разница не нужна, просто быстрое сканирование для - это индексная копия , то же самое или другое ? (Это то, что может сделать Gitочень быстро из-за его внутреннего замороженного формата.)
Если файл в индексе - копия :file
- отличается от копии HEAD:file
, Git сообщает вам, что этот файл для коммита .Вы знаете, что это будет в следующем коммите, но более полезно, что вы также знаете, что это будет другой в новом снимке.Сравнивая старый (текущий HEAD
) и предложенный новый коммит, file
будет иметь измененный .
Между тем, git status
также сравнивает индексную копию :file
с работойкопия дерева, file
.Если эти два значения разные, Git сообщает вам, что этот файл не подготовлен для фиксации .Это говорит о том, что вы можете запустить git add
прямо сейчас, чтобы скопировать file
в :file
.
Обратите внимание, что все три версии file
могут быть разными!В данном случае это и staged for commit
и not staged for commit
.И, конечно, у вас могут быть новые файлы - файлы, которые не находятся в HEAD
, но находятся в в индексе и рабочем дереве сейчас.Вы можете удалить файлы - файлы, которые имеют в HEAD
, но теперь не в индексе и рабочем дереве.
Присутствие в индексе - это то, что делает файл отслеженным
Индекс и копии файла рабочего дерева - это разные вещи.Это означает, что вы можете иметь файл, который находится в рабочем дереве, но не в индексе.Такой файл является неотслеживаемым .Обратите внимание, что не имеет значения, находится ли файл в HEAD
коммите!(Если это равно в коммите HEAD
, то должно быть так, что было в индексе, и вы удалили его из индекса и просто еще не зафиксировали.) Запуск git status
сообщит вам о таких файлах, и будет жаловаться, что они не отслежены.
Вы также можете иметь файл, который находится в индексе, но отсутствует в рабочем дереве.Это несколько странное положение вещей, но происходит, если вы используете не-Git команду для удаления файла.Git не особо заботится о том, что вы сделали это - он все равно будет использовать индексную копию для новых коммитов - но git status
скажет вам об этом: файл будет удален при сравнении index-vs-work-tree.
Вы можете заставить Git замолчать насчет неотслеживаемых файлов, перечислив их имена (или шаблоны глобуса , как *.tmp
) в ваших .gitignore
файлах.Это не делает файл неотслеженным!Это заставляет Гита замолчать из-за них.У него есть и другие эффекты, но главный из них - закрыть Git.Это полезно, потому что делает git status
вывод короче .
Когда git status
сообщает вам только то, что вам нужно знать - некоторые файлы отличаются, когда Git запускает git diff
из HEAD
для индексации, а некоторые файлы отличаются, когда Git запускает git diff
из индекса врабочее дерево - тогда git status
становится настолько полезным, насколько это возможно.Вам не нужно выборочно выбирать выходные данные, чтобы найти полезные вещи, потому что файлы X и Y находятся в стадии подготовки, а Z не находятся в стадии размещения это именно то, что нужно.Два файла будут разными в следующем коммите, если вы сделаете это прямо сейчас;файл Z может также отличаться, если вы git add
его.
Если вы выборочно удаляете файлы только из индекса или только из рабочего дерева, вы попадаете в эти довольно необычныеугловые чехлы.Некоторые из них до имеют смысл;Git не помешает ни одному из них.Git обычно старается быть осторожным, чтобы не заглушить неотслеживаемые файлы, потому что они не будут навсегда заморожены в новые коммиты, в отличие от отслеживаемых файлов.