Скотт Чакон - Pro Git
- Название:Pro Git
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Скотт Чакон - Pro Git краткое содержание
В книге рассматриваются следующие темы: основы Git;
ветвление в Git;
Git на сервере;
распределённый Git;
GitHub;
инструменты Git;
настройка Git;
Git и другие системы контроля версий.
Pro Git - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Рисунок 4. Объекты в директории .git, а также указатели на вершины веток.
Когда выполняется команда git branch (имя ветки), Git, по сути, выполняет update-ref для добавления хеша последнего коммита текущей ветки под указанным именем в виде новой ссылки.
HEAD
Как же Git получает хеш последнего коммита при выполнении git branch (имя ветки)? Ответ кроется в файле HEAD.
Файл HEAD — это символическая ссылка (не в терминах файловой системы) на текущую ветку. Символическая ссылка отличается от обычной тем, что она содержит не сам хеш SHA-1, а указатель на другую ссылку. Если вы заглянете внутрь HEAD, то увидите следующее:
$cat .git/HEAD
ref: refs/heads/master
Если выполнить git checkout test, Git обновит содержимое файла:
$cat .git/HEAD
ref: refs/heads/test
При выполнении git commit Git создаёт коммит, указывая его родителем объект, SHA-1 которого содержится в файле, на который ссылается HEAD.
При желании, можно вручную редактировать этот файл, но лучше использовать команду symbolic-ref. Получить значение HEAD этой командой можно так:
$git symbolic-ref HEAD
refs/heads/master
Изменить значение HEAD можно так:
$git symbolic-ref HEAD refs/heads/test
$cat .git/HEAD
ref: refs/heads/test
Символическую ссылку на файл вне .git/refs поставить нельзя:
$git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
Метки
Мы рассмотрели три основных типа объектов Git, но есть ещё один. Метка очень похожа на коммит: она содержит имя автора метки, дату, сообщение и указатель. Разница же в том, что метка указывает на коммит, а не на дерево. Она похожа на ветку, которая никогда не перемещается: она всегда указывает на один и тот же коммит, просто давая ему понятное имя.
Как мы знаем из главы Основы Git, метки бывают двух типов: аннотированные и легковесные. Легковесную метку можно создать следующей командой:
$git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
Вот и всё! Легковесная метка — это ветка, которая никогда не перемещается. Аннотированная метка имеет более сложную структуру. При создании аннотированной метки Git создаёт специальный объект, на который будет указывать ссылка, а не просто указатель на коммит. Мы можем увидеть это, создав аннотированную метку (-a задаёт аннотированные метки):
$git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
Вот значение SHA-1 созданного объекта:
$cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
Теперь выполним cat-file для этого хеша:
$git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon Sat May 23 16:48:58 2009 -0700
test tag
Обратите внимание, в поле object записан SHA-1 помеченного коммита. Также стоит отметить, что это поле не обязательно должно указывать на коммит; вы можете пометить любой объект в Git. Например, в исходниках Git мейнтейнер добавил свой публичный GPG-ключ в блоб и пометил его. Увидеть этот ключ можно, выполнив команду:
$git cat-file blob junio-gpg-pub
В репозитории ядра Linux также есть метка, указывающая не на коммит: самая первая метка указывает на дерево первичного импорта.
Ссылки на удалённые ветки
Третий тип ссылок, который мы рассмотрим — ссылки на удалённые ветки. Если вы добавили удалённый репозиторий и отправили в него какие-нибудь изменения, Git сохранит последнее отправленное значение SHA-1 в директории refs/remotes для каждой отправленной ветки. Например, можно добавить удалённый репозиторий origin и отправить туда ветку master:
$git remote add origin git@github.com:schacon/simplegit-progit.git
$git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
Позже вы сможете посмотреть, где находилась ветка master с сервера origin во время последней синхронизации с ним, заглянув в файл refs/remotes/origin/master:
$cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Ссылки на удалённые ветки отличаются от веток (ссылки в refs/heads) тем, что они считаются неизменяемыми. Это означает, что вы можете переключится на любую из таких ссылок с помощью git checkout, но Git не установит HEAD на такую ссылку, а значит вы не сможете фиксировать свои изменения с помощью git commit Git поддерживает удалённые ветки в качестве закладок на определённые состояния в удалённом репозитории во время последнего контакта с сервером.
Pack-файлы
Рассмотрим объекты, хранящиеся в базе данных тестового Git репозитория. К этому моменту их должно быть 11 штук: 4 блоба, 3 дерева, 3 коммита и одна метка:
$find .git/objects -type f
.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
Git использует zlib для сжатия содержимого этих файлов; к тому же у нас не так уж и много данных, поэтому все эти файлы вместе занимают всего 925 байт. Для того, чтобы продемонстрировать одну интересную особенность Git, добавим файл побольше. Добавим файл repo.rb из библиотеки Grit — он занимает примерно 22 Кб:
$curl https://raw.githubusercontent.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb
$git add repo.rb
$git commit -m 'added repo.rb'
[master 484a592] added repo.rb
3 files changed, 709 insertions(+), 2 deletions(-)
delete mode 100644 bak/test.txt
create mode 100644 repo.rb
rewrite test.txt (100%)
Если мы посмотрим на полученное дерево, мы увидим значение SHA-1 блоба для файла repo.rb:
$git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 repo.rb
100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
Посмотрим, сколько этот объект занимает места на диске, используя git cat-file:
$git cat-file -s 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5
22044
Теперь немного изменим этот файл и посмотрим на результат:
$echo '# testing' >> repo.rb
$git commit -am 'modified repo a bit'
[master 2431da6] modified repo.rb a bit
1 file changed, 1 insertion(+)
Взглянув на дерево, полученное в результате коммита, мы увидим любопытную вещь:
$git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob b042a60ef7dff760008df33cee372b945b6e884e repo.rb
100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
Теперь файлу repo.rb соответствует совершенно другой блоб. Это означает, что всего одна единственная строка, добавленная в конец 400-строчного файла, требует создания абсолютно нового объекта:
$git cat-file -s b042a60ef7dff760008df33cee372b945b6e884e
22054
Итак, мы имеем два почти одинаковых объекта занимающих по 22 Кб на диске. Было бы здорово, если бы Git сохранял только один объект целиком, а другой как разницу между ним и первым объектом.
Читать дальшеИнтервал:
Закладка: