Введение
Я делаю эксперименты с использованием популярного libgit2
, написанного на C.
Я пытаюсь сделать clone
, но использую необычный способ. По порядку, команды git:
git init
git remote add origin https://repository.git
git fetch origin
git checkout master
Используя git bash
и следующие команды, я могу получить существующее хранилище со всей его историей.
Вопрос
Теперь давайте посмотрим мою текущую реализацию C ++. Следующий код пытается скопировать поведение предыдущих написанных команд git.
#define url "https://repository.git"
#define path "./"
#define user "user"
#define pass "pass"
/** credential callback **/
int credentials(git_cred **cred, const char *, const char *, unsigned int, void *) {
return git_cred_userpass_plaintext_new(cred, user, pass);
}
class Git {
public:
Git() {
git_libgit2_init();
}
~Git() {
git_repository_free(repository);
git_libgit2_shutdown();
}
void update() {
init();
fetch();
checkout();
}
private:
void init() {
assertSuccess(git_repository_init(&repository, path, GIT_CVAR_FALSE));
git_remote *remote = nullptr;
git_remote_callbacks options = GIT_REMOTE_CALLBACKS_INIT;
assertSuccess(git_remote_create(&remote, repository, "origin", url));
options.credentials = credentials;
git_remote_connect(remote, GIT_DIRECTION_FETCH, &options, nullptr, nullptr);
}
void fetch() {
git_remote* remote = nullptr;
assertSuccess(git_remote_lookup(&remote, repository, "origin"));
git_fetch_options options = GIT_FETCH_OPTIONS_INIT;
options.callbacks.credentials = credentials;
assertSuccess(git_remote_fetch(remote, nullptr, &options, nullptr));
}
void checkout() {
git_checkout_options options = GIT_CHECKOUT_OPTIONS_INIT;
options.checkout_strategy = GIT_CHECKOUT_FORCE;
assertSuccess(git_checkout_head(repository, &options));
assertSuccess(git_checkout_index(repository, nullptr, &options));
assertSuccess(git_repository_set_head(repository, "refs/heads/master"));
git_object *treeish = nullptr;
assertSuccess(git_revparse_single(&treeish, repository, "master"));
assertSuccess(git_checkout_tree(repository, treeish, &options));
}
void assertSuccess(int error) {
if (!error) return;
const git_error *e = giterr_last();
std::cout << "code: " << e->klass << " error: " << e->message << std::endl;
exit(1);
}
private:
git_repository *repository = nullptr;
};
int main() {
Git git;
git.update();
return 0;
}
Очевидно, это не работает. Запустив эту программу (вызывая Git().update()
), я получаю следующую ошибку на этапе проверки:
code: 4 error: reference 'refs/heads/master' not found
Репозиторий git создан, и я вижу удаленный источник, который был успешно установлен, хотя git bash
. Я могу сделать руководство git checkout master
из git bash
, поэтому я полагаю, что моя текущая реализация checkout
не удалась.
Может ли кто-нибудь рассказать мне об этой ошибке? Я не смог найти достаточно ресурсов или поддержки для всех найденных примеров в интернете.
* 1047 РЕДАКТИРОВАТЬ *
Поскольку тестирование моего кода может помочь, позвольте мне дать CMakeLists.txt
для компиляции libgit2
. (исходный код https://github.com/libgit2/libgit2)
cmake_minimum_required(VERSION 3.13)
project(test)
include_directories(libgit/include)
LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
add_subdirectory(libgit)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
add_executable(test src/Git.h)
target_link_libraries(test git2)