Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,18 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/subcommand/clone_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/commit_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/commit_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/fetch_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/fetch_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/log_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/log_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/merge_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/merge_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/push_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/push_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/remote_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/remote_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/reset_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/reset_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.cpp
Expand All @@ -82,6 +88,8 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/wrapper/object_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/refs_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/refs_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/remote_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/remote_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/repository_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/repository_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/signature_wrapper.cpp
Expand Down
6 changes: 6 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
#include "subcommand/checkout_subcommand.hpp"
#include "subcommand/clone_subcommand.hpp"
#include "subcommand/commit_subcommand.hpp"
#include "subcommand/fetch_subcommand.hpp"
#include "subcommand/init_subcommand.hpp"
#include "subcommand/log_subcommand.hpp"
#include "subcommand/merge_subcommand.hpp"
#include "subcommand/push_subcommand.hpp"
#include "subcommand/remote_subcommand.hpp"
#include "subcommand/reset_subcommand.hpp"
#include "subcommand/status_subcommand.hpp"

Expand All @@ -35,9 +38,12 @@ int main(int argc, char** argv)
checkout_subcommand checkout(lg2_obj, app);
clone_subcommand clone(lg2_obj, app);
commit_subcommand commit(lg2_obj, app);
fetch_subcommand fetch(lg2_obj, app);
reset_subcommand reset(lg2_obj, app);
log_subcommand log(lg2_obj, app);
merge_subcommand merge(lg2_obj, app);
push_subcommand push(lg2_obj, app);
remote_subcommand remote(lg2_obj, app);

app.require_subcommand(/* min */ 0, /* max */ 1);

Expand Down
128 changes: 128 additions & 0 deletions src/subcommand/fetch_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include <iostream>
#include <iomanip>

#include <git2/remote.h>

#include "../subcommand/fetch_subcommand.hpp"
#include "../wrapper/repository_wrapper.hpp"
#include "../wrapper/remote_wrapper.hpp"
#include "../utils/output.hpp"
#include "../utils/git_exception.hpp"

namespace
{
int sideband_progress(const char* str, int len, void*)
{
std::cout << "remote: " << std::string(str, static_cast<std::size_t>(len));
std::cout.flush();
return 0;
}

int fetch_progress(const git_indexer_progress* stats, void* payload)
{
bool done = false;

auto* pr = reinterpret_cast<git_indexer_progress*>(payload);
*pr = *stats;

if (done)
{
return 0;
}

int network_percent = pr->total_objects > 0 ?
(100 * pr->received_objects / pr->total_objects)
: 0;
size_t mbytes = pr->received_bytes / (1024*1024);

std::cout << "Receiving objects: " << std::setw(4) << network_percent
<< "% (" << pr->received_objects << "/" << pr->total_objects << "), "
<< mbytes << " MiB";

if (pr->received_objects == pr->total_objects)
{
std::cout << ", done." << std::endl;
done = true;
}
else
{
std::cout << '\r';
}
return 0;
}

int update_refs(const char* refname, const git_oid* a, const git_oid* b, git_refspec*, void*)
{
char a_str[GIT_OID_SHA1_HEXSIZE+1], b_str[GIT_OID_SHA1_HEXSIZE+1];

git_oid_fmt(b_str, b);
b_str[GIT_OID_SHA1_HEXSIZE] = '\0';

if (git_oid_is_zero(a))
{
std::cout << "[new] "
<< std::string(b_str, 20)
<< " " << refname << std::endl;
}
else
{
git_oid_fmt(a_str, a);
a_str[GIT_OID_SHA1_HEXSIZE] = '\0';

std::cout << "[updated] "
<< std::string(a_str, 10)
<< ".."
<< std::string(b_str, 10)
<< " " << refname << std::endl;
}

return 0;
}
}

fetch_subcommand::fetch_subcommand(const libgit2_object&, CLI::App& app)
{
auto* sub = app.add_subcommand("fetch", "Download objects and refs from another repository");

sub->add_option("<remote>", m_remote_name, "The remote to fetch from")
->default_val("origin");

sub->callback([this]() { this->run(); });
}

void fetch_subcommand::run()
{
auto directory = get_current_git_path();
auto repo = repository_wrapper::open(directory);

// Find the remote (default to origin if not specified)
std::string remote_name = m_remote_name.empty() ? "origin" : m_remote_name;
auto remote = repo.find_remote(remote_name);

git_indexer_progress pd = {0};
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
fetch_opts.callbacks.sideband_progress = sideband_progress;
fetch_opts.callbacks.transfer_progress = fetch_progress;
fetch_opts.callbacks.payload = &pd;
fetch_opts.callbacks.update_refs = update_refs;

cursor_hider ch;

// Perform the fetch
throw_if_error(git_remote_fetch(remote, nullptr, &fetch_opts, "fetch"));

// Show statistics
const git_indexer_progress* stats = git_remote_stats(remote);
if (stats->local_objects > 0)
{
std::cout << "\rReceived " << stats->indexed_objects << "/" << stats->total_objects
<< " objects in " << stats->received_bytes << " bytes (used "
<< stats->local_objects << " local objects)" << std::endl;
}
else
{
std::cout << "\rReceived " << stats->indexed_objects << "/" << stats->total_objects
<< " objects in " << stats->received_bytes << " bytes" << std::endl;
}
}

23 changes: 23 additions & 0 deletions src/subcommand/fetch_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <string>

#include <CLI/CLI.hpp>

#include "../utils/common.hpp"
#include "../wrapper/repository_wrapper.hpp"

class fetch_subcommand
{
public:

explicit fetch_subcommand(const libgit2_object&, CLI::App& app);
void run();

private:

std::string m_remote_name;
};



72 changes: 72 additions & 0 deletions src/subcommand/push_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <iostream>

#include <git2/remote.h>

#include "../subcommand/push_subcommand.hpp"
#include "../wrapper/repository_wrapper.hpp"
#include "../wrapper/remote_wrapper.hpp"
#include "../utils/git_exception.hpp"
#include "../utils/common.hpp"

namespace
{
int push_transfer_progress(unsigned int current, unsigned int total, size_t bytes, void*)
{
if (total > 0)
{
int percent = (100 * current) / total;
std::cout << "Writing objects: " << percent << "% (" << current
<< "/" << total << "), " << bytes << " bytes\r";
}
return 0;
}

int push_update_reference(const char* refname, const char* status, void*)
{
if (status)
{
std::cout << " " << refname << " " << status << std::endl;
}
else
{
std::cout << " " << refname << std::endl;
}
return 0;
}
}

push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app)
{
auto* sub = app.add_subcommand("push", "Update remote refs along with associated objects");

sub->add_option("<remote>", m_remote_name, "The remote to push to")
->default_val("origin");

sub->add_option("<refspec>", m_refspecs, "The refspec(s) to push");

sub->callback([this]() { this->run(); });
}

void push_subcommand::run()
{
auto directory = get_current_git_path();
auto repo = repository_wrapper::open(directory);

std::string remote_name = m_remote_name.empty() ? "origin" : m_remote_name;
auto remote = repo.find_remote(remote_name);

git_push_options push_opts = GIT_PUSH_OPTIONS_INIT;
push_opts.callbacks.push_transfer_progress = push_transfer_progress;
push_opts.callbacks.push_update_reference = push_update_reference;

git_strarray_wrapper refspecs_wrapper(m_refspecs);
git_strarray* refspecs_ptr = nullptr;
if (!m_refspecs.empty())
{
refspecs_ptr = refspecs_wrapper;
}

throw_if_error(git_remote_push(remote, refspecs_ptr, &push_opts));
std::cout << "Pushed to " << remote_name << std::endl;
}

25 changes: 25 additions & 0 deletions src/subcommand/push_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <string>
#include <vector>

#include <CLI/CLI.hpp>

#include "../utils/common.hpp"
#include "../wrapper/repository_wrapper.hpp"

class push_subcommand
{
public:

explicit push_subcommand(const libgit2_object&, CLI::App& app);
void run();

private:

std::string m_remote_name;
std::vector<std::string> m_refspecs;
};



Loading