From 656b242987bdc27900008ef9baaae891eff4320e Mon Sep 17 00:00:00 2001 From: Dexter Morganov Date: Thu, 19 Mar 2020 10:05:20 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D1=82=D0=BE=D1=87=D0=BD=D1=91=D0=BD=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=D0=B4,=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=B8=20=D0=BF=D1=80=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D1=80=D1=8B=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- book/B-embedding-git/sections/jgit.asc | 17 ++--- book/B-embedding-git/sections/libgit2.asc | 83 +++++++++++------------ 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/book/B-embedding-git/sections/jgit.asc b/book/B-embedding-git/sections/jgit.asc index fa82c7b3..d5d99266 100644 --- a/book/B-embedding-git/sections/jgit.asc +++ b/book/B-embedding-git/sections/jgit.asc @@ -2,15 +2,13 @@ (((jgit)))(((java))) Если вы хотите использовать Git из Java-программ, существует библиотека для работы с Git, называемая JGit. -Она достаточно полно реализует функциональность Git и написана полностью на Java. -Эта библиотека получила широкое распространение в Java-мире. +Она достаточно полно реализует функциональность Git, написана на чистом Java и широко используется Java сообществом. Проект JGit находится под опекой Eclipse и расположен по адресу http://www.eclipse.org/jgit[]. ==== Приступая к работе Существует несколько способов добавить JGit в проект и начать писать код с использованием предоставляемого API. -Возможно, самый простой путь -- использование Maven. -Подключение библиотеки происходит путём добавления следующих строк в секцию `` в вашем pom.xml: +Возможно, самый простой путь -- использование Maven: подключение библиотеки происходит путём добавления следующих строк в секцию `` в вашем pom.xml: [source,xml] ---- @@ -46,6 +44,7 @@ java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App // Создание нового репозитория; директория должна существовать Repository newlyCreatedRepo = FileRepositoryBuilder.create( new File("/tmp/new_repo/.git")); +newlyCreatedRepo.create(); // Открыть существующий репозиторий Repository existingRepo = new FileRepositoryBuilder() @@ -129,7 +128,7 @@ Git git = new Git(repo); ---- В классе Git можно найти отличный набор высокоуровневых "текучих" методов (builder-style / fluent interface). -Давайте взглянем на пример -- результат выполнения этого кода смахивает на `git ls-remote`: +Давайте взглянем на пример -- результат выполнения этого кода напоминает `git ls-remote`: [source,java] ---- @@ -145,9 +144,8 @@ for (Ref ref : remoteRefs) { } ---- -Тут показан частый случай использования класса Git: методы возвращают тот же объект, на котором вызваны, что позволяет чередовать их друг за другом, устанавливая параметры. -Финальный аккорд -- непосредственное выполнение команды с помощью метода `.call()`. -В этом примере мы запрашиваем список тегов (но не "головы" веток) с удалённого репозитория `origin`. +Тут показан частый случай использования класса Git: методы возвращают тот же объект, на котором вызваны, что позволяет чередовать их друг за другом, устанавливая параметры, а выполнение происходит при вызове `.call()`. +В этом примере мы запрашиваем с удалённого репозитория `origin` список тегов, исключая ветки. Обратите внимание на использование класса `CredentialsProvider` для аутентификации. Множество команд доступно в классе Git, включая такие как `add`, `blame`, `commit`, `clean`, `push`, `rebase`, `revert`, `reset` и другие. @@ -159,5 +157,4 @@ for (Ref ref : remoteRefs) { * Официальная документация по JGit API доступна в Интернете на http://download.eclipse.org/jgit/docs/latest/apidocs[]. Это обыкновенный Javadoc, так что ваша любимая IDE может скачать её и использовать оффлайн. -* "Поваренная книга" JGit, расположенная по адресу https://github.com/centic9/jgit-cookbook[] включает в себя много готовых "рецептов" использования JGit для решения тех или иных задач. -* Вопрос на StackOverflow http://stackoverflow.com/questions/6861881[] содержит несколько полезных ссылок. +* "Поваренная книга" JGit, расположенная по адресу https://github.com/centic9/jgit-cookbook[], включает в себя много готовых "рецептов" использования JGit для решения тех или иных задач. diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index 31fdb824..ad9edb20 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -2,7 +2,7 @@ (((libgit2)))(((C))) Другой доступный вам вариант -- это использование библиотеки Libgit2. -Libgit2 -- это свободная от внешних зависимостей реализация Git, фокусирующаяся на предоставлении приятного API другим программам. +Libgit2 -- это свободная от внешних зависимостей реализация Git, ориентирующаяся на предоставление отличного API другим программам. Вы можете найти её на http://libgit2.github.com[]. Для начала, давайте посмотрим на что похож C API. @@ -33,30 +33,28 @@ git_repository_free(repo); Первая пара строк открывают Git репозиторий. Тип `git_repository` представляет собой ссылку на репозиторий с кешем в памяти. Это самый простой метод, его можно использовать если вы знаете точный путь к рабочей директории репозитория или к `.git` директории. -Существует расширенный вариант -- `git_repository_open_ext` -- который принимает набор параметров для поиска репозитория. -Функция `git_clone` с компаньонами используется для клонирования удалённого репозитория. -И, наконец, `git_repository_init` используется для создания нового репозитория с нуля. +Кроме этого, существуют методы `git_repository_open_ext`, который принимает набор параметров для поиска репозитория, `git_clone` и сопуствующие -- для создания локальной копии удалённого репозитория и `git_repository_init` -- для создания нового репозитория с нуля. -Следующий кусок кода использует `rev-parse` синтаксис (см. <>) чтобы получить коммит на который указывает HEAD. -Возвращаемый тип -- это указатель на структуру `git_object`, которая представляет любой объект, хранящийся во внутренней БД Git. -`git_object` -- родительский тип для нескольких других; внутренняя структура всех этих типов одинаковая, так что вы можете относительно безопасно преобразовывать типы друг в друга. -В нашем случае `git_object_type(head_commit)` вернёт `GIT_OBJ_COMMIT`, так что мы вправе привести типы для `git_commit`. +Следующий блок кода использует `rev-parse` синтаксис (см. <>), чтобы получить коммит, на который указывает HEAD. +Возвращаемый тип является указателем на структуру `git_object`, которая представляет любой объект, хранящийся во внутренней базе данных Git. +`git_object` является ``родительским'' для некоторых других типов; внутренняя структура всех этих типов одинаковая и соответствует `git_object`, так что вы можете относительно безопасно преобразовывать типы друг в друга. +В нашем случае `git_object_type(head_commit)` вернёт `GIT_OBJ_COMMIT`, так что мы вправе привести тип к `git_commit`. -Затем мы получаем некоторые свойства коммита. +Следующий блока кода показывает как получить доступ к свойствам коммита. Последняя строчка в этом фрагменте кода использует тип `git_oid` -- это внутреннее представление SHA-1 в Libgit2. Глядя на этот пример, можно сделать несколько выводов: -* Если вы объявили указатель и передали его в одну из функций Libgit2, она, возможно, вернёт целочисленный код ошибки. +* Если вы объявили указатель и передали его в одну из функций Libgit2, то она, скорее всего, вернёт целочисленный код ошибки. Значение `0` означает успешное выполнение операции, всё что меньше -- означает ошибку. -* Если Libgit2 возвращает вам указатель, вы ответственны за очистку ресурсов +* Если Libgit2 возвращает вам указатель, вы ответственны за очистку ресурсов. * Если Libgit2 возвращает `const`-указатель, вам не нужно заботится о его очистке, но он может оказаться невалидным, если объект на который он ссылается будет уничтожен. -* Писать на C -- сложно. +* Писать на C -- несколько сложновато. (((Ruby))) Последний пункт намекает на маловероятность использования C при работе с Libgit2. К счастью, существует ряд обёрток над Libgit2 для различных языков, которые позволяют довольно удобно работать с Git репозиториями, используя ваш язык программирования и среду исполнения. -Давайте взглянем на пример ниже, написанный с использованием Ruby и обёртки над Libgit2 для него под названием Rugged, которую можно найти на https://github.com/libgit2/rugged[]. +Давайте взглянем на тот же пример, только написанный с использованием Ruby и обёртки над Libgit2 под названием Rugged, которую можно найти на https://github.com/libgit2/rugged[]. [source,ruby] ---- @@ -69,7 +67,7 @@ tree = commit.tree Как видите, код гораздо менее загромождён. Во-первых, Rugged использует исключения: он может кинуть ошибку типа `ConfigError` или `ObjectError` чтобы просигнализировать о сбое. -Во-вторых, нет необходимости явно подчищать ресурсы, потому что в Ruby есть сборщик мусора. +Во-вторых, нет необходимости явно освобождать ресурсы, потому что в Ruby есть встроенный сборщик мусора. Давайте посмотрим на более сложный пример -- создание коммита с нуля: [source,ruby] @@ -97,29 +95,28 @@ commit_id = Rugged::Commit.create(repo, commit = repo.lookup(commit_id) # <8> ---- -<1> Создание нового blob'а, содержащего файл. +<1> Создание нового blob'а, включающего содержимое нового файла. <2> Заполнение индекса содержимым дерева HEAD и добавление нового файла `newfile.txt`. -<3> Создание нового дерева в ODB и использование его для нового коммита. -<4> Мы используем одну и ту же сигнатуру для автора и коммиттера. -<5> Сообщение в коммите. +<3> Создание нового дерева в базе данных объектов и использование его для нового коммита. +<4> Мы используем одну и ту же подпись для автора и коммиттера. +<5> Сообщение коммита. <6> При создании коммита нужно указать его предков. Для этих целей мы используем HEAD как единственного родителя. -<7> Rugged (как и Libgit2) дополнительно могут обновить HEAD-указатель. -<8> Результирующее значение -- это SHA-1 хэш нового коммита, по которому его можно вычитать из репозитория для получения объекта типа `Commit`. +<7> Rugged (как и Libgit2) дополнительно могут обновить HEAD при создании комита. +<8> Используя полученное значение SHA-1 хеша нового коммита, можно получить объект типа `Commit`. Код на Ruby приятен и чист, а благодаря тому что Libgit2 делает основную работу ещё и выполняется довольно быстро. На случай если вы пишете не на Ruby, мы рассмотрим другие обёртки над Libgit2 в <>. - ==== Расширенная функциональность -У Libgit2 есть несколько фич, выходящих за рамки стандартного Git. -Одна из таких фич -- расширяемость: Libgit2 позволяет использовать нестандартные "бэкэнды" для некоторых операций; таким образом вы можете хранить объекты по-иному, нежели это делает Git из коробки. +Libgit2 обладает рядом возможностей, выходящих за рамки стандартного Git. +Одна из таких возможностей -- расширяемость: Libgit2 позволяет использовать нестандартные интерфейсы для ряда операций, таким образом вы можете хранить объекты по-иному, нежели это делает стандартный Git. Например, Libgit2 позволяет использовать нестандартные хранилища для конфигурации, ссылок и внутренней базы данных объектов. Давайте взглянем, как это работает. Код ниже заимствован из примеров, написанных командой разработчиков Libgit2, вы можете ознакомиться с ними на https://github.com/libgit2/libgit2-backends[]. -Вот как можно использовать нестандартное хранилище объектов: +Вот как можно использовать нестандартное хранилище для базы данных объектов: [source,c] ---- @@ -133,18 +130,18 @@ error = git_odb_add_backend(odb, my_backend, 1); // <3> git_repository *repo; error = git_repository_open(&repo, "some-path"); -error = git_repository_set_odb(odb); // <4> +error = git_repository_set_odb(repo, odb); // <4> ---- _(Заметьте, ошибки перехватываются, но не обрабатываются. Мы надеемся, ваш код лучше нашего.)_ -<1> Инициализация "фронтэнда" для пустого хранилища объектов (ODB), используемого в качестве контейнера "бэкэндов", которые будут выполнять работу. -<2> Инициализация произвольного ODB бэкэнда. -<3> Добавление "бэкэнда" к "фронтэнду" -<4> Открытие репозитория и указание ему использовать ODB созданный на предыдущем этапе. +<1> Инициализация интерфейса для пустой базы данных объектов, который будет использоваться как контейнер для внутренних интерфейсов, которые будут выполнять работу. +<2> Инициализация произвольного внутреннего интерфейса базы данных объектов. +<3> Добавление внутреннего интерфейса к внешнему. +<4> Открытие репозитория и настройка на использование собственной базы для поиска объектов. Что же скрыто внутри `git_odb_backend_mine`? -Это ваша собственная реализаация ODB, и вы можете делать что угодно, лишь убедитесь в правильности заполнения полей структуры `git_odb_backend`. +Это ваша собственная реализация базы данных объектов, где вы можете делать что угодно, лишь бы поля структуры `git_odb_backend` были заполнены верно. Например, внутри _может_ быть следующий код: [source,c] @@ -152,7 +149,7 @@ _(Заметьте, ошибки перехватываются, но не об typedef struct { git_odb_backend parent; - // Другие поля + // Дополнительные поля void *custom_context; } my_backend_struct; @@ -174,8 +171,9 @@ int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/) return GIT_SUCCESS; } ---- -Важный момент: первое поле структуры `my_backend_struct` имеет тип `git_odb_backend` -- это обеспечивает расположение полей в памяти в формате, ожидаемом Libgit2. -Оставшиеся поля можно располагать произвольно; сама структура может быть любого нужного вам размера. + +Важный момент: в `my_backend_struct` первое поле должно быть структурой `git_odb_backend`, что обеспечит расположение полей в памяти в формате, ожидаемом Libgit2. +Оставшиеся поля можно располагать произвольно, а сама структура может быть любого нужного вам размера. Функция инициализации выделяет память под структуру, устанавливает произвольный контекст и заполняет поля структуры `parent`, которые необходимо поддерживать. Взгляните на файл `include/git2/sys/odb_backend.h` в исходном коде Libgit2 чтобы узнать полный список сигнатур доступных методов; в вашем конкретном случае вы сами решаете, какие из них необходимо имплементировать. @@ -186,13 +184,12 @@ int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/) У Libgit2 есть привязки для многих языков. Здесь мы приведём лишь парочку небольших примеров; полный список поддерживаемых языков гораздо шире и включает в себя, среди прочего, C++, Go, Node.js, Erlang и JVM, на разных стадиях зрелости. Официальный список обёрток можно найти на https://github.com/libgit2[]. -Примеры кода ниже показывают как получить сообщение HEAD-коммита (что-то типа `git log -l`). - +Примеры кода ниже показывают как получить сообщение HEAD-коммита (что-то типа `git log -1`). ===== LibGit2Sharp (((.NET)))(((C#)))(((Mono))) -Если вы пишете под платформы .NET / Mono, LibGit2Sharp (https://github.com/libgit2/libgit2sharp[]) -- то, что прописал вам доктор. +Если вы пишете под платформы .NET / Mono, LibGit2Sharp (https://github.com/libgit2/libgit2sharp[]) -- то, что вы искали. Эта библиотека написана на C# и все прямые вызовы методов Libgit2 тщательно обёрнуты в управляемый CLR код. Вот как будет выглядеть наш пример: @@ -219,26 +216,22 @@ NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message]; Objective-git полностью интероперабелен с новым языком Swift, так что не бойтесь переходить на него с Objective-C. - ===== pygit2 (((Python))) Обёртка над Libgit2 для Python называется Pygit2, её можно найти на http://www.pygit2.org/[]. И наш пример будет выглядеть так: + [source,python] ---- -pygit2.Repository("/path/to/repo") # открыть репозиторий - .head.resolve() # получить прямую ссылку - .get_object().message # получить коммит, прочитать сообщение pygit2.Repository("/path/to/repo") # открыть репозиторий .head # получить текущую ветку - .peel(pygit2.Commit) # получить последний коммит ветки + .peel(pygit2.Commit) # получить коммит .message # прочитать сообщение ---- - ==== Дополнительные материалы -Конечно же, покрыть полностью все возможности Libgit2 не в силах этой книги. -Если вы хотите подробнее ознакомиться с Libgit2, можете начать с документации к API по адресу https://libgit2.github.com/libgit2[] и с руководства на https://libgit2.github.com/docs[]. -Для привязок к другим языкам, загляните в README и тестовые исходники, довольно часто в них встречаются ссылки на полезные материалы по теме. +Конечно же, полное описание возможностей Libgit2 выходит далеко за пределы этой книги. +Если вы хотите подробнее ознакомиться с Libgit2, можете начать с документации к API https://libgit2.github.com/libgit2[] и набора руководств https://libgit2.github.com/docs[]. +Для привязок к другим языкам, загляните в README и исходники тестов, довольно часто в них встречаются ссылки на полезные материалы по теме.