Git не хранит файлов . Git сохраняет фиксирует .
В ветвях нет файлов; ветви имеют коммитов .
Когда вы извлекаете sh из одного Git в другой, вы не извлекаете файлы sh. Ты пу sh совершает .
Это может показаться многократным повторением, но в этом суть: вам нужно помнить, что Git совершает коммиты . Итак: что именно является коммитом?
Что ж, внутри он состоит из двух частей:
Есть снимок . Это имеет файлы! Да, наконец-то у нас есть несколько файлов. 10
В этих файлах есть что-то особенное. Это не обычные файлы. Вы не можете работать с ними. Они заморожены навсегда, сжаты и превращены в формат, который может прочитать только Git. Вы не можете получить к ним доступ или изменить их. Они не годятся ни для чего, кроме архивирования. Таким образом, нам понадобится способ получить их из из Git, что мы получим через мгновение.
И есть некоторые метаданные в каждом коммите, такие как имя и адрес электронной почты пользователя, который делает коммит.
Это то, для чего предназначен ваш git config --global user.name
. Вы не должны устанавливать это в пустую строку, и вы также не должны устанавливать свой адрес электронной почты в пустую строку. Git на самом деле не подтверждает, что то, что вы здесь установили, является действительным, но в качестве хорошей практики рекомендуется использовать что-то реальное.
Каждый коммит получает уникальный га sh ID в момент его создания. С тех пор этот ha sh ID означает , что совершает, и никакие другие; этот идентификатор ha sh всегда зарезервирован для , которые передают . Как правило, вы не будете иметь дело напрямую с идентификаторами ha sh, за исключением некоторых случаев, когда вы можете использовать git log
, а затем вырезать и вставить один из них в команду git revert
или git reset
, как только доберетесь до этой точки. , Но помните, что идентификатор ha sh - это то, как Git знает, какой коммит есть какой. Имена ветвей, такие как master
или testbranch
, служат для запоминания одного идентификатора ha sh (идентификатор ha sh, имя которого запоминается с течением времени).
Чтобы создать новую ветку, вы спрашиваете Git, чтобы создать новую ветвь, используя существующий коммит ha sh ID. Идентификатор ha sh по умолчанию - это текущий коммит. Всегда есть текущий коммит, 1 и почти всегда текущее имя ветки. 2 Когда вы используете git checkout master
, вы просите Git выбрать ветку master
и, следовательно, последний коммит в этой ветви.
Когда вы просите Git создать имя новой ветви testbranch
, используя git checkout -b testbranch
, вы просите Git сделать новое имя содержит такой же идентификатор коммитов ha sh и выбирает это имя в качестве текущей ветви, и, следовательно, этот коммит имеет идентификатор * sh в качестве текущего коммита. Поэтому Git не меняет фиксирует , но меняет имена ветвей . Оба имени ветви определяют один и тот же коммит.
Теперь давайте перейдем к работе с файлами вместо целого коммита.
1 Существует одно или два исключения из этого правила, в том числе в новом полностью пустом хранилище, где нет коммитов, но мы не будем здесь с этим разбираться.
2 Случай, когда нет текущей ветви , - это то, что Git называет отсоединенным HEAD . Здесь мы также не будем заниматься этим.
Работа с файлами
По сути, каждый Git коммит доступен только для чтения и абсолютно неизменен, а его файлы находятся в бесполезном формате , * * * * * * * * * * * * * * * * * * * * * * * * * * * 143 ”* * * * * * * * * * * * * * * * * 110 *
* * * * * * * * * * * * * * * * * * * * * * то, что
* * * * * * * * * * * * 2.23 и более поздних версий): вы выбираете имя ветви, например
master
, и тем самым задаете c commit ha sh ID, и вы просите Git, пожалуйста
скопировать файлы коммита в работу район .
Эта рабочая область, где файлы имеют свою обычную повседневную форму, - ваше рабочее дерево или рабочее дерево . Два имени относятся к одной и той же вещи. Обратите внимание, что Git само по себе не использует это рабочее дерево, кроме как для его заполнения из коммита. Это рабочее дерево для использования .
Теперь вы используете его. Одна из вещей, которую вы можете сделать с этим, - создавать новые файлы. Еще одна вещь, которую вы можете сделать, это открыть существующий файл в редакторе, отредактировать его и записать обратно. Наконец, вы можете удалить файлы полностью. Все эти действия происходят только в вашем рабочем дереве . Изменения, которые вы внесли в свое рабочее дерево, не включены ни в один коммит .
В конечном итоге вам придется поместить их в некоторые коммиты. Для этого вам нужно будет использовать команду git commit
. Вы можете предположить, что это будет смотреть на ваше рабочее дерево и использовать файлы, которые там находятся, чтобы сделать новый коммит. Это было бы разумно, но это не то, что делает Git.
Вместо этого Git создает новый коммит из третьей копии каждого файл. Эта третья копия находится в Git index . 3 Если вы изменили файл в рабочем дереве или добавили новый, вы должны использовать git add
скопировать обновленный или новый файл рабочего дерева в индекс.
3 Технически, индекс содержит ссылку на содержимое файла, а не на фактическую копию. Однако до тех пор, пока вы не начнете исследовать git ls-files --stage
и git update-index
, вы можете просто думать об индексе как о сохранении копии файла.
Создание нового коммита из индекса
Чтобы сделать новый коммит, вы запускаете:
git commit
(или, возможно, git commit -m <message>
: если вы пропустите -m
, ваш Git откроет редактор для вас, чтобы напечатать сообщение ). Это создает новый снимок с метаданными на основе ваших настроек git config
и того, что вы указали в качестве сообщения журнала, объясняя , почему вы сделали этот коммит.
Git делает этот новый коммит из файлы, которые находятся в индексе, с какими бы данными они не хранили в индексе. Таким образом, новый коммит, который вы только что сделали, теперь будет соответствовать индексу. Новый коммит теперь является текущим коммитом, а Git записывает идентификатор нового коммита ha sh - уникальный для этого коммита - в текущее имя ветви.
Обратите внимание, как начальный git checkout
заполнил индекс Git из проверяемого коммита, и как этот новый git commit
сделал коммит из того, что было в Git ' индекс s. Таким образом, как своего рода общее правило - за исключением, опять же, - индекс стремится соответствовать фиксации сразу после git checkout
или git switch
, а также соответствовать фиксации сразу после git commit
. 4
Так что ваши изменения в вашем рабочем дереве между ними делают вещи, но как только вы изменили свое рабочее дерево, вы должны использовать git add
в скопировать обновленные файлы обратно в индекс. Любые новые файлы должны быть git add
-ed, что кажется достаточно ясным для новых пользователей Git, но меняет на существующие файлы должны быть git add
-ed как ну, это немного удивительно. 5
4 Исключения из этого правила становятся очень сложными. См. Извлечение другой ветви, если в текущей ветви есть незафиксированные изменения .
5 Git предлагает git commit -a
, что говорит Git: для всех файлов, которые уже есть в индексе, выполните git add
для них при необходимости, затем выполните git commit
. Это почти эквивалентно выполнению git add -u
перед фиксацией, за исключением некоторых странных угловых случаев это можно объяснить только тем, что Git также допускает дополнительные временные индексные файлы, и этот тип git commit
использует их.
Индекс также называется промежуточной областью : о git status
Термины index и staging area оба означают одно и то же. Хотя вы не можете видеть индекс напрямую, 6 вы можете Git сообщить вам о области индекса / промежуточной области.
Помните, что есть три активные копии каждого файла: одна в текущем коммите - эта заморожена на все времена - плюс одна в индексе плюс одна в вашем рабочем дереве. Команда git status
помогает вам с этими тремя копиями, выполняя два отдельных сравнения.
Первое сравнение сравнивает каждый файл в текущем коммите с каждым файлом в индексе. Когда эти два файла соответствуют , git status
говорит ничего . Когда они отличаются , git status
говорит, что этот файл подготовлен для фиксации .
При втором сравнении каждый файл в индексе сравнивается с каждым файлом в вашей работе. -tree. Когда эти два файла соответствуют , git status
говорит ничего . Когда они отличаются , git status
говорит, что этот файл не подготовлен для фиксации .
Так что, если файл F в вашей работе -tree is not staged for commit
, запуск git add
скопирует содержимое файла F в индексную копию файла F . Теперь индексная копия F не будет соответствовать принятой копии, а файл F будет теперь staged for commit
. Если вы измените копию рабочего дерева снова , файл будет оба: , он не будет подготовлен и подготовлен одновременно. Это возможно, потому что есть три копии F .
6 Технически, вы можете: использовать git ls-files --stage
, чтобы увидеть его. Обратите внимание, что эта команда является многословной и не удобной для пользователя даже по Git стандартам.
неотслеживаемые файлы
Поскольку ваше рабочее дерево ваше , вы может помещать в него файлы, которые не включены в индекс Git. Когда вы сделаете это, git status
заметит, что индексная копия файла отсутствует. Он скажет, что этот файл неотслеживаемый .
Это все, что является неотслеживаемым файлом: это файл, который существует в вашем рабочем дереве, но не в индексе Git , Поскольку его нет в индексе Git, он не будет в следующем коммите. 7 Вам нужно будет использовать git add
, чтобы скопировать его в индекс Git, чтобы он теперь staged for commit
: индексная копия, которая теперь существует, отличается от (несуществующей) копии с текущей фиксацией.
7 Обратите внимание, что git commit -a
не будет добавьте этот файл: он запускает git add
только для файлов, которые имеют в индексе.
Игнорируемые файлы
Команда git status
равна очень полезно. Используйте это часто. Обратите внимание, однако, что каждый раз, когда вы используете его, он жалуется на ваши неотслеживаемые файлы. Если у вас много неотслеживаемых файлов, вы получите множество жалоб от git status
.
Вы можете перечислить неотслеживаемые файлы в файле с именем .gitignore
. Если вы сделаете это, git status
перестанет ныть о них. Команда git add
также прекратит добавлять их в индекс Git. Таким образом, перечисляя файлы, которые в настоящее время не отслежены, и , которые вы не хотите отслеживать , вы можете получить Git, чтобы автоматически не фиксировать их и перестать ныть о них.
Перечисление отслеживаемого файла в .gitignore
не имеет никакого эффекта. Так что .gitignore
на самом деле не файлы для игнорировать; вместо этого, это файлы к не жалуются на то, что не отслеживаются и не добавляются автоматически с помощью операции добавления всех файлов например, git add *
. Но вызывать этот файл .git-do-not-complain-about-these-untracked-files-and-do-not-add-them-when-I-use-an-en-masse-add-command
было бы неудобно, поэтому он называется .gitignore
.
Почему клонирование дает вам рабочее дерево
Когда вы запускаете:
git clone <url>
ваш Git будет:
- создать новый пустой каталог;
- внутри этого каталога запустить
git init
, чтобы создать пустой репозиторий: один без коммитов вообще; - используйте
git remote add
, чтобы добавить remote в этот пустой репозиторий: этот пульт обычно называется origin
; - выполнить любую другую конфигурацию, необходимую в этом новом пустом репозитории ;
- запустите
git fetch origin
, чтобы получить коммитов от других Git, а затем переименовать их ветви, такие как master
, в свои собственные Git имена для удаленного отслеживания , такие как origin/master
; - , наконец, запустите
git checkout
для некоторого имени ветви, обычно здесь используется значение по умолчанию master
.
Этот последний шаг, git checkout master
, создает вашу ветвь master
из вашего имени для удаленного слежения origin/master
- который содержит фиксацию ha sh ID, точно так же, как имя ветки, поскольку он скопирован из их master
ответвления *1397*, а затем выбирает его в качестве текущей ветви и текущего коммита. Именно этот шаг оформления заказа заполняет индекс Git и ваше рабочее дерево. Вот почему вы видите реальные файлы: ваш Git извлек их из коммита, который является последним коммитом в вашей ветке master
. Ваша Git просто создала вашу master
ветвь для соответствия другой Git master
ветви, которую ваша Git теперь помнит как ваша origin/master
.