Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ find_package(libgit2)
set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/subcommand/add_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/add_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/branch_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/branch_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.cpp
Expand All @@ -49,6 +51,8 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/utils/common.hpp
${GIT2CPP_SOURCE_DIR}/utils/git_exception.cpp
${GIT2CPP_SOURCE_DIR}/utils/git_exception.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/commit_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/commit_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/index_wrapper.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "utils/git_exception.hpp"
#include "version.hpp"
#include "subcommand/add_subcommand.hpp"
#include "subcommand/branch_subcommand.hpp"
#include "subcommand/init_subcommand.hpp"
#include "subcommand/status_subcommand.hpp"

Expand All @@ -23,6 +24,7 @@ int main(int argc, char** argv)
init_subcommand init(lg2_obj, app);
status_subcommand status(lg2_obj, app);
add_subcommand add(lg2_obj, app);
branch_subcommand(lg2_obj, app);

app.parse(argc, argv);

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

#include "../subcommand/branch_subcommand.hpp"
#include "../wrapper/repository_wrapper.hpp"

branch_subcommand::branch_subcommand(const libgit2_object&, CLI::App& app)
{
auto* sub = app.add_subcommand("branch", "List, create or delete branches");

sub->add_option("<branchname>", m_branch_name, "The name of the branch to create or delete");

sub->add_flag("-d,--delete", m_deletion_flag, "Delete a branch");
sub->add_flag("-a,--all", m_all_flag, "List both remote-tracking branches and local branches");
sub->add_flag("-r,--remotes", m_remote_flag, "List or delete (if used with -d) the remote-tracking branches");
sub->add_flag("-l,--list", m_list_flag, "List branches");
sub->add_flag("-f,--force", m_force_flag, "Skips confirmation");

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

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

if (m_list_flag || m_branch_name.empty())
{
auto head_name = repo.head().short_name();
std::cout << "* " << head_name << std::endl;
git_branch_t type = m_all_flag ? GIT_BRANCH_ALL : (m_remote_flag ? GIT_BRANCH_REMOTE : GIT_BRANCH_LOCAL);
auto iter = repo.iterate_branches(type);
auto br = iter.next();
while (br)
{
if (br->name() != head_name)
{
std::cout << " " << br->name() << std::endl;
}
br = iter.next();
}
}
else if (m_deletion_flag)
{
run_deletion(repo);
}
else
{
run_creation(repo);
}
}

void branch_subcommand::run_deletion(repository_wrapper& repo)
{
auto branch = repo.find_branch(m_branch_name);
// TODO: handle unmerged stated once we handle upstream repos
delete_branch(std::move(branch));
}


void branch_subcommand::run_creation(repository_wrapper& repo)
{
// TODO: handle specification of starting commit
repo.create_branch(m_branch_name, m_force_flag);
}
28 changes: 28 additions & 0 deletions src/subcommand/branch_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <string>

#include <CLI/CLI.hpp>

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

class branch_subcommand
{
public:

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

private:

void run_deletion(repository_wrapper& repo);
void run_creation(repository_wrapper& repo);

std::string m_branch_name = {};
bool m_deletion_flag = false;
bool m_all_flag = false;
bool m_remote_flag = false;
bool m_list_flag = false;
bool m_force_flag = false;
};
2 changes: 1 addition & 1 deletion src/subcommand/status_subcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ void status_subcommand::run()
auto bare = false;
auto repo = repository_wrapper::init(directory, bare);
auto sl = status_list_wrapper::status_list(repo);
auto branch_name = reference_wrapper::get_ref_name(repo);
auto branch_name = repo.head().short_name();

std::set<std::string> tracked_dir_set{};
std::set<std::string> untracked_dir_set{};
Expand Down
56 changes: 56 additions & 0 deletions src/wrapper/branch_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "../utils/git_exception.hpp"
#include "../wrapper/branch_wrapper.hpp"
#include "../wrapper/commit_wrapper.hpp"
#include "../wrapper/repository_wrapper.hpp"

#include <iostream>

branch_wrapper::branch_wrapper(git_reference* polna_ref)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a better name for the argument here? I'd be happy with just ref.

: base_type(polna_ref)
{
}

branch_wrapper::~branch_wrapper()
{
git_reference_free(p_resource);
p_resource = nullptr;
}

std::string_view branch_wrapper::name() const
{
const char* out = nullptr;
throwIfError(git_branch_name(&out, p_resource));
return std::string_view(out);
}

void delete_branch(branch_wrapper&& branch)
{
throwIfError(git_branch_delete(branch));
}

branch_iterator::branch_iterator(git_branch_iterator* iter)
: base_type(iter)
{
}

branch_iterator::~branch_iterator()
{
git_branch_iterator_free(p_resource);
p_resource = nullptr;
}


std::optional<branch_wrapper> branch_iterator::next()
{
git_reference* ref = nullptr;
git_branch_t type;
int res = git_branch_next(&ref, &type, p_resource);
if (res == 0)
{
return branch_wrapper(ref);
}
else
{
return std::nullopt;
}
}
56 changes: 56 additions & 0 deletions src/wrapper/branch_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <optional>
#include <string_view>

#include <git2.h>

#include "../wrapper/wrapper_base.hpp"

class commit_wrapper;

class branch_wrapper : public wrapper_base<git_reference>
{
public:

using base_type = wrapper_base<git_reference>;

~branch_wrapper();

branch_wrapper(branch_wrapper&&) = default;
branch_wrapper& operator=(branch_wrapper&&) = default;

std::string_view name() const;

private:

explicit branch_wrapper(git_reference* ref);

friend class repository_wrapper;
friend class branch_iterator;
};

void delete_branch(branch_wrapper&& br);

// Rust / Python-like iterator instead of regular C++ iterator,
// because of the libgit2 API. Implementing the postfix increment
// operator of an input iterator would be overcomplicated.
class branch_iterator : public wrapper_base<git_branch_iterator>
{
public:

using base_type = wrapper_base<git_branch_iterator>;

~branch_iterator();

branch_iterator(branch_iterator&&) = default;
branch_iterator& operator=(branch_iterator&&) = default;

std::optional<branch_wrapper> next();

private:

explicit branch_iterator(git_branch_iterator* iter);

friend class repository_wrapper;
};
5 changes: 3 additions & 2 deletions src/wrapper/commit_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "commit_wrapper.hpp"
#include "../utils/git_exception.hpp"
#include "../wrapper/commit_wrapper.hpp"
#include "../wrapper/repository_wrapper.hpp"

commit_wrapper::~commit_wrapper()
{
Expand All @@ -8,7 +9,7 @@ commit_wrapper::~commit_wrapper()
}


commit_wrapper commit_wrapper::last_commit(const repository_wrapper& repo, const std::string& ref_name)
commit_wrapper commit_wrapper::from_reference_name(const repository_wrapper& repo, const std::string& ref_name)
{
git_oid oid_parent_commit;
throwIfError(git_reference_name_to_id(&oid_parent_commit, repo, ref_name.c_str()));
Expand Down
5 changes: 3 additions & 2 deletions src/wrapper/commit_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include <git2.h>

#include "../wrapper/repository_wrapper.hpp"
#include "../wrapper/wrapper_base.hpp"

class repository_wrapper;

class commit_wrapper : public wrapper_base<git_commit>
{
public:
Expand All @@ -17,7 +18,7 @@ class commit_wrapper : public wrapper_base<git_commit>
commit_wrapper& operator=(commit_wrapper&&) noexcept = default;

static commit_wrapper
last_commit(const repository_wrapper& repo, const std::string& ref_name = "HEAD");
from_reference_name(const repository_wrapper& repo, const std::string& ref_name = "HEAD");

private:

Expand Down
10 changes: 6 additions & 4 deletions src/wrapper/refs_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#include "../utils/git_exception.hpp"
#include "../wrapper/refs_wrapper.hpp"

reference_wrapper::reference_wrapper(git_reference* jaila_ref)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better argument name again.

: base_type(jaila_ref)
{
}

reference_wrapper::~reference_wrapper()
{
git_reference_free(p_resource);
p_resource=nullptr;
}

std::string reference_wrapper::get_ref_name(const repository_wrapper& rw)
std::string reference_wrapper::short_name() const
{
reference_wrapper ref;
throwIfError(git_repository_head(&(ref.p_resource), rw));
return git_reference_shorthand(ref.p_resource);
return git_reference_shorthand(p_resource);
}
9 changes: 6 additions & 3 deletions src/wrapper/refs_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@

#include <git2.h>

#include "../wrapper/repository_wrapper.hpp"
#include "../wrapper/wrapper_base.hpp"

class reference_wrapper : public wrapper_base<git_reference>
{
public:

using base_type = wrapper_base<git_reference>;

~reference_wrapper();

reference_wrapper(reference_wrapper&&) noexcept = default;
reference_wrapper& operator=(reference_wrapper&&) noexcept = default;

static std::string get_ref_name(const repository_wrapper& repo);
std::string short_name() const;

private:

reference_wrapper() = default;
reference_wrapper(git_reference* ref);

friend class repository_wrapper;
};
35 changes: 34 additions & 1 deletion src/wrapper/repository_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "repository_wrapper.hpp"
#include "../utils/git_exception.hpp"
#include "../wrapper/repository_wrapper.hpp"

repository_wrapper::~repository_wrapper()
{
Expand All @@ -21,8 +21,41 @@ repository_wrapper repository_wrapper::init(const std::string& directory, bool b
return rw;
}

reference_wrapper repository_wrapper::head() const
{
git_reference* ref;
throwIfError(git_repository_head(&ref, *this));
return reference_wrapper(ref);
}

index_wrapper repository_wrapper::make_index()
{
index_wrapper index = index_wrapper::init(*this);
return index;
}

branch_wrapper repository_wrapper::create_branch(const std::string& name, bool force)
{
return create_branch(name, commit_wrapper::from_reference_name(*this), force);
}

branch_wrapper repository_wrapper::create_branch(const std::string& name, const commit_wrapper& commit, bool force)
{
git_reference* branch = nullptr;
throwIfError(git_branch_create(&branch, *this, name.c_str(), commit, force));
return branch_wrapper(branch);
}

branch_wrapper repository_wrapper::find_branch(const std::string& name)
{
git_reference* branch = nullptr;
throwIfError(git_branch_lookup(&branch, *this, name.c_str(), GIT_BRANCH_LOCAL));
return branch_wrapper(branch);
}

branch_iterator repository_wrapper::iterate_branches(git_branch_t type) const
{
git_branch_iterator* iter = nullptr;
throwIfError(git_branch_iterator_new(&iter, *this, type));
return branch_iterator(iter);
}
Loading