Skip to content
Merged
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
10 changes: 10 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 @@ -68,6 +74,8 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/utils/git_exception.hpp
${GIT2CPP_SOURCE_DIR}/utils/output.cpp
${GIT2CPP_SOURCE_DIR}/utils/output.hpp
${GIT2CPP_SOURCE_DIR}/utils/progress.cpp
${GIT2CPP_SOURCE_DIR}/utils/progress.hpp
${GIT2CPP_SOURCE_DIR}/utils/terminal_pager.cpp
${GIT2CPP_SOURCE_DIR}/utils/terminal_pager.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/annotated_commit_wrapper.cpp
Expand All @@ -82,6 +90,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
80 changes: 6 additions & 74 deletions src/subcommand/clone_subcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "../subcommand/clone_subcommand.hpp"
#include "../utils/output.hpp"
#include "../utils/progress.hpp"
#include "../wrapper/repository_wrapper.hpp"

clone_subcommand::clone_subcommand(const libgit2_object&, CLI::App& app)
Expand All @@ -10,81 +11,11 @@ clone_subcommand::clone_subcommand(const libgit2_object&, CLI::App& app)

sub->add_option("<repository>", m_repository, "The (possibly remote) repository to clone from.")->required();
sub->add_option("<directory>", m_directory, "The name of a new directory to clone into.");
sub->add_flag("--bare", m_bare, "Create a bare Git repository.");

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

namespace
{
int sideband_progress(const char* str, int len, void*)
{
printf("remote: %.*s", len, str);
fflush(stdout);
return 0;
}

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

// We need to copy stats into payload even if the fetch is done,
// because the checkout_progress callback will be called with the
// same payload and needs the data to be up do date.
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;
}

void checkout_progress(const char* path, size_t cur, size_t tot, void* payload)
{
static bool done = false;
if (done)
{
return;
}
auto* pr = reinterpret_cast<git_indexer_progress*>(payload);
int deltas_percent = pr->total_deltas > 0 ?
(100 * pr->indexed_deltas / pr->total_deltas)
: 0;

std::cout << "Resolving deltas: " << std::setw(4) << deltas_percent
<< "% (" << pr->indexed_deltas << "/" << pr->total_deltas << ")";
if (pr->indexed_deltas == pr->total_deltas)
{
std::cout << ", done." << std::endl;
done = true;
}
else
{
std::cout << '\r';
}
}
}

void clone_subcommand::run()
{
git_indexer_progress pd;
Expand All @@ -94,9 +25,10 @@ void clone_subcommand::run()
checkout_opts.progress_cb = checkout_progress;
checkout_opts.progress_payload = &pd;
clone_opts.checkout_opts = checkout_opts;
clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress;
clone_opts.fetch_opts.callbacks.transfer_progress = fetch_progress;
clone_opts.fetch_opts.callbacks.payload = &pd;
clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress;
clone_opts.fetch_opts.callbacks.transfer_progress = fetch_progress;
clone_opts.fetch_opts.callbacks.payload = &pd;
clone_opts.bare = m_bare ? 1 : 0;

std::string short_name = m_directory;
if (m_directory.empty())
Expand Down
1 change: 1 addition & 0 deletions src/subcommand/clone_subcommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ class clone_subcommand

std::string m_repository = {};
std::string m_directory = {};
bool m_bare = false;
};
54 changes: 54 additions & 0 deletions src/subcommand/fetch_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <iostream>

#include <git2/remote.h>

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

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
remote.fetch(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;
}
}
19 changes: 19 additions & 0 deletions src/subcommand/fetch_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <string>

#include <CLI/CLI.hpp>

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

class fetch_subcommand
{
public:

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

private:

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

#include <git2/remote.h>

#include "../subcommand/push_subcommand.hpp"
#include "../utils/progress.hpp"
#include "../wrapper/repository_wrapper.hpp"

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;

if (m_refspecs.empty())
{
try
{
auto head_ref = repo.head();
std::string short_name = head_ref.short_name();
std::string refspec = "refs/heads/" + short_name;
m_refspecs.push_back(refspec);
}
catch (...)
{
std::cerr << "Could not determine current branch to push." << std::endl;
return;
}
}
git_strarray_wrapper refspecs_wrapper(m_refspecs);
git_strarray* refspecs_ptr = nullptr;
refspecs_ptr = refspecs_wrapper;

remote.push(refspecs_ptr, &push_opts);
std::cout << "Pushed to " << remote_name << std::endl;
}
21 changes: 21 additions & 0 deletions src/subcommand/push_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <string>
#include <vector>

#include <CLI/CLI.hpp>

#include "../utils/common.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