libgit2 не извлекает изменения, но всегда все

Я пытаюсь использовать libgit2, чтобы сначала клонировать голый репозиторий, а затем обновить его с изменениями из источника github. Клонирование работает нормально:

git_repository *_repository
git_clone_bare(&_repository, REPOSITORY_URL, path, &transferProgressCallback, NULL);
git_repository_free(_repository);

Но когда я пытаюсь обновить репозиторий из источника, libgit2 всегда снова загружает весь репозиторий. Он просто не получает только изменения. Я использую этот код:

git_remote *remote;
git_repository *_repository;

git_repository_open(&_repository, path);
git_remote_load(&remote, _repository, "origin");
git_remote_connect(remote, GIT_DIR_FETCH);
git_remote_download(remote, &transferProgressCallback, NULL);

git_remote_disconnect(remote);
git_remote_update_tips(remote);
git_remote_free(remote);

(Я удалил обработку ошибок.) Я использую такой обратный вызов, чтобы сообщить о ходе выполнения:

void transferProgressCallback(const git_transfer_progress *stats, void *payload) {
    float receivedMegaBytes = (float)stats->received_bytes/(1024*1024.0);
    float progress = ((float)stats->received_objects / (float)stats->total_objects) * 100.0;
    printf("Loading: %.1f (%.1f)\n", progress, receivedMegaBytes);
}

По обратному вызову скачивается все (то же количество байт, что и при git_clone_bare). Должно быть, я что-то упускаю или делаю что-то не так, верно? Но я не вижу, где. Все, что я хочу, это чтобы код извлекал только изменения (это то, что не присутствует локально). Но вместо этого он продолжает извлекать весь репозиторий.

Пожалуйста, в чем тут может быть проблема? Заранее большое спасибо!


person aus    schedule 24.11.2012    source источник
comment
Как вы диагностировали, что весь репозиторий был снова загружен?   -  person nulltoken    schedule 24.11.2012
comment
Я использую обратный вызов, который показывает количество переданных байтов. Я только что отредактировал сообщение соответствующим образом. (Хотя обратный вызов на самом деле не использует printf, а устанавливает метку и индикатор выполнения, но это много кода, не связанного с libgit2, поэтому я его пропустил.)   -  person aus    schedule 24.11.2012


Ответы (1)


Это очень странно. Я не могу воспроизвести проблему.

С какой версией libgit2 вы работаете?

Я локально добавил тест в пакет выборки libgit2, который воспроизводит вашу проблему и... он соответствует текущим последний совет по разработке libgit2. Следующие URL были успешно проверены:

static void transferProgressCallback(const git_transfer_progress *stats, void *payload)
{
    bool *invoked = (bool *)payload;
    *invoked = true;
}

void test_network_fetch__doesnt_retreive_a_pack_when_the_repository_is_up_to_date(void)
{
    git_repository *_repository;
    git_remote *remote;
    bool invoked = false;

    cl_git_pass(git_clone_bare(&_repository, "https://github.com/libgit2/TestGitRepository.git", "./fetch/lg2", NULL, NULL));
    git_repository_free(_repository);

    cl_git_pass(git_repository_open(&_repository, "./fetch/lg2"));

    cl_git_pass(git_remote_load(&remote, _repository, "origin"));
    cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH));

    cl_assert_equal_i(false, invoked);

    cl_git_pass(git_remote_download(remote, &transferProgressCallback, &invoked));

    cl_assert_equal_i(false, invoked);

    cl_git_pass(git_remote_update_tips(remote));
    git_remote_disconnect(remote);

    git_remote_free(remote);
    git_repository_free(_repository);
}

ОБНОВИТЬ:

Я отправил запрос на включение в проект libgit2, чтобы убедиться, что тест также проходит на Трэвисе, сервере CI.

ОБНОВЛЕНИЕ 2:

Хорошо, я выполнил еще несколько действий по устранению неполадок, и я все еще не могу воспроизвести проблему.

  • Я создал новый репозиторий на GitHub через веб-интерфейс
  • Через сеанс bash я создал коммит, а затем отправил его вверх по течению.
  • Затем я клонировал его через libgit2 в новую временную папку. было загружено 3 объекта
  • Потом еще раз скачал, ничего не скачалось.
  • Вернемся к сеансу bash, я создал еще один коммит и отправил его вверх по течению.
  • Вернемся к коду libgit2, повторная загрузка загружает 3 новых объекта из второго коммита.

Приведенный ниже код, даже если это не настоящий тест (поскольку он требует некоторого взаимодействия со стороны пользователя), демонстрирует то, что было объяснено выше.

void test_network_fetch__retrieve_a_pack_when_the_remote_repository_has_been_updated(void)
{
    git_repository *_repository;
    git_remote *remote;
    bool invoked = false;

    /*
     * $ mkdir /tmp/so-check/ && cd /tmp/so-check/
     * 
     * $ touch README.md
     * 
     * $ git init
     * Initialized empty Git repository in d:/temp/so-check/.git/
     * 
     * $ git add README.md
     * 
     * $ git commit -m "first commit"
     * [master (root-commit) e3454be] first commit
     *  0 files changed
     *  create mode 100644 README.md
     * 
     * $ git remote add origin https://github.com/nulltoken/so-check.git
     * 
     * $ git push -u origin master
     * Username for 'https://github.com': nulltoken
     * Password for 'https://[email protected]':
     * Counting objects: 3, done.
     * Writing objects: 100% (3/3), 212 bytes, done.
     * Total 3 (delta 0), reused 0 (delta 0)
     * To https://github.com/nulltoken/so-check.git
     *  * [new branch]      master -> master
     * Branch master set up to track remote branch master from origin.
     * 
     * $
     */

    cl_git_pass(git_clone_bare(&_repository, "https://github.com/nulltoken/so-check.git", "./fetch/soc", NULL, NULL));
    git_repository_free(_repository);

    cl_git_pass(git_repository_open(&_repository, "./fetch/soc"));

    cl_git_pass(git_remote_load(&remote, _repository, "origin"));
    cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH));

    cl_assert_equal_i(false, invoked);

    cl_git_pass(git_remote_download(remote, &transferProgressCallback, &invoked));

    cl_assert_equal_i(false, invoked);

    cl_git_pass(git_remote_update_tips(remote));
    git_remote_disconnect(remote);

    git_remote_free(remote);
    git_repository_free(_repository);

    /*
     * $ mkdir /tmp/so-check2 && cd /tmp/so-check2
     * 
     * $ git clone https://github.com/nulltoken/so-check.git .
     * Cloning into '.'...
     * remote: Counting objects: 3, done.
     * remote: Total 3 (delta 0), reused 3 (delta 0)
     * Unpacking objects: 100% (3/3), done.
     *
     * $ echo "Test" > README.md
     * 
     * $ git add README.md
     * 
     * $ git commit -m "Now with a meaningful content"
     * [master 9c6c300] Now with a meaningful content
     *  1 file changed, 1 insertion(+)
     *
     $ git push
     * Username for 'https://github.com': nulltoken
     * Password for 'https://[email protected]':
     * Counting objects: 5, done.
     * Writing objects: 100% (3/3), 262 bytes, done.
     * Total 3 (delta 0), reused 0 (delta 0)
     * To https://github.com/nulltoken/so-check.git
     *    e3454be..9794f71  master -> master
     * $
     */

    /* Set a breakpoint below in order to push the additional commit.
     * Once it's done, let the code run again.
     */
    cl_git_pass(git_repository_open(&_repository, "./fetch/soc"));

    cl_git_pass(git_remote_load(&remote, _repository, "origin"));
    cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH));

    cl_assert_equal_i(false, invoked);

    cl_git_pass(git_remote_download(remote, &transferProgressCallback, &invoked));

    cl_assert_equal_i(true, invoked);

    cl_git_pass(git_remote_update_tips(remote));
    git_remote_disconnect(remote);

    git_remote_free(remote);
    git_repository_free(_repository);
}

Ниже вывод консоли, результат второй загрузки. Можно заметить, что извлекаются только 3 объекта:

Fetching: (0/3)
Fetching: (1/3)
Fetching: (2/3)
Fetching: (3/3)
Fetching: (3/3)

А в репозитории 6 объектов (3 из первого коммита, 3 из второго):

$ git count-objects --verbose
count: 6
size: 0
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0

С моей точки зрения, похоже, что libgit2 действительно может загрузить дифференциальный пакет.

person nulltoken    schedule 24.11.2012
comment
Вау, это потрясающий ответ. Большое спасибо! Так что мое использование API правильное, и libgit2 тоже работает нормально. Это действительно помогает, потому что теперь я знаю, что проблема должна быть где-то еще. Еще раз большое спасибо! - person aus; 25.11.2012