Skip to content

Commit 171dc28

Browse files
authored
Minimal command for branches (#19)
* Minimal command for branches * copilot revision * Displays current branch when listing * Better arguments names * Fixed typo in embeded_git
1 parent c038e3f commit 171dc28

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+311
-16
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ find_package(libgit2)
4141
set(GIT2CPP_SRC
4242
${GIT2CPP_SOURCE_DIR}/subcommand/add_subcommand.cpp
4343
${GIT2CPP_SOURCE_DIR}/subcommand/add_subcommand.hpp
44+
${GIT2CPP_SOURCE_DIR}/subcommand/branch_subcommand.cpp
45+
${GIT2CPP_SOURCE_DIR}/subcommand/branch_subcommand.hpp
4446
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.cpp
4547
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.hpp
4648
${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.cpp
@@ -49,6 +51,8 @@ set(GIT2CPP_SRC
4951
${GIT2CPP_SOURCE_DIR}/utils/common.hpp
5052
${GIT2CPP_SOURCE_DIR}/utils/git_exception.cpp
5153
${GIT2CPP_SOURCE_DIR}/utils/git_exception.hpp
54+
${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.cpp
55+
${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.hpp
5256
${GIT2CPP_SOURCE_DIR}/wrapper/commit_wrapper.cpp
5357
${GIT2CPP_SOURCE_DIR}/wrapper/commit_wrapper.hpp
5458
${GIT2CPP_SOURCE_DIR}/wrapper/index_wrapper.cpp

src/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "utils/git_exception.hpp"
66
#include "version.hpp"
77
#include "subcommand/add_subcommand.hpp"
8+
#include "subcommand/branch_subcommand.hpp"
89
#include "subcommand/init_subcommand.hpp"
910
#include "subcommand/status_subcommand.hpp"
1011

@@ -23,6 +24,7 @@ int main(int argc, char** argv)
2324
init_subcommand init(lg2_obj, app);
2425
status_subcommand status(lg2_obj, app);
2526
add_subcommand add(lg2_obj, app);
27+
branch_subcommand(lg2_obj, app);
2628

2729
app.parse(argc, argv);
2830

src/subcommand/branch_subcommand.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <iostream>
2+
3+
#include "../subcommand/branch_subcommand.hpp"
4+
#include "../wrapper/repository_wrapper.hpp"
5+
6+
branch_subcommand::branch_subcommand(const libgit2_object&, CLI::App& app)
7+
{
8+
auto* sub = app.add_subcommand("branch", "List, create or delete branches");
9+
10+
sub->add_option("<branchname>", m_branch_name, "The name of the branch to create or delete");
11+
12+
sub->add_flag("-d,--delete", m_deletion_flag, "Delete a branch");
13+
sub->add_flag("-a,--all", m_all_flag, "List both remote-tracking branches and local branches");
14+
sub->add_flag("-r,--remotes", m_remote_flag, "List or delete (if used with -d) the remote-tracking branches");
15+
sub->add_flag("-l,--list", m_list_flag, "List branches");
16+
sub->add_flag("-f,--force", m_force_flag, "Skips confirmation");
17+
18+
sub->callback([this]() { this->run(); });
19+
}
20+
21+
void branch_subcommand::run()
22+
{
23+
auto directory = get_current_git_path();
24+
auto repo = repository_wrapper::open(directory);
25+
26+
if (m_list_flag || m_branch_name.empty())
27+
{
28+
auto head_name = repo.head().short_name();
29+
std::cout << "* " << head_name << std::endl;
30+
git_branch_t type = m_all_flag ? GIT_BRANCH_ALL : (m_remote_flag ? GIT_BRANCH_REMOTE : GIT_BRANCH_LOCAL);
31+
auto iter = repo.iterate_branches(type);
32+
auto br = iter.next();
33+
while (br)
34+
{
35+
if (br->name() != head_name)
36+
{
37+
std::cout << " " << br->name() << std::endl;
38+
}
39+
br = iter.next();
40+
}
41+
}
42+
else if (m_deletion_flag)
43+
{
44+
run_deletion(repo);
45+
}
46+
else
47+
{
48+
run_creation(repo);
49+
}
50+
}
51+
52+
void branch_subcommand::run_deletion(repository_wrapper& repo)
53+
{
54+
auto branch = repo.find_branch(m_branch_name);
55+
// TODO: handle unmerged stated once we handle upstream repos
56+
delete_branch(std::move(branch));
57+
}
58+
59+
60+
void branch_subcommand::run_creation(repository_wrapper& repo)
61+
{
62+
// TODO: handle specification of starting commit
63+
repo.create_branch(m_branch_name, m_force_flag);
64+
}

src/subcommand/branch_subcommand.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
#include <CLI/CLI.hpp>
6+
7+
#include "../utils/common.hpp"
8+
#include "../wrapper/repository_wrapper.hpp"
9+
10+
class branch_subcommand
11+
{
12+
public:
13+
14+
explicit branch_subcommand(const libgit2_object&, CLI::App& app);
15+
void run();
16+
17+
private:
18+
19+
void run_deletion(repository_wrapper& repo);
20+
void run_creation(repository_wrapper& repo);
21+
22+
std::string m_branch_name = {};
23+
bool m_deletion_flag = false;
24+
bool m_all_flag = false;
25+
bool m_remote_flag = false;
26+
bool m_list_flag = false;
27+
bool m_force_flag = false;
28+
};

src/subcommand/status_subcommand.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ void status_subcommand::run()
186186
auto bare = false;
187187
auto repo = repository_wrapper::init(directory, bare);
188188
auto sl = status_list_wrapper::status_list(repo);
189-
auto branch_name = reference_wrapper::get_ref_name(repo);
189+
auto branch_name = repo.head().short_name();
190190

191191
std::set<std::string> tracked_dir_set{};
192192
std::set<std::string> untracked_dir_set{};

src/wrapper/branch_wrapper.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include "../utils/git_exception.hpp"
2+
#include "../wrapper/branch_wrapper.hpp"
3+
#include "../wrapper/commit_wrapper.hpp"
4+
#include "../wrapper/repository_wrapper.hpp"
5+
6+
#include <iostream>
7+
8+
branch_wrapper::branch_wrapper(git_reference* ref)
9+
: base_type(ref)
10+
{
11+
}
12+
13+
branch_wrapper::~branch_wrapper()
14+
{
15+
git_reference_free(p_resource);
16+
p_resource = nullptr;
17+
}
18+
19+
std::string_view branch_wrapper::name() const
20+
{
21+
const char* out = nullptr;
22+
throwIfError(git_branch_name(&out, p_resource));
23+
return std::string_view(out);
24+
}
25+
26+
void delete_branch(branch_wrapper&& branch)
27+
{
28+
throwIfError(git_branch_delete(branch));
29+
}
30+
31+
branch_iterator::branch_iterator(git_branch_iterator* iter)
32+
: base_type(iter)
33+
{
34+
}
35+
36+
branch_iterator::~branch_iterator()
37+
{
38+
git_branch_iterator_free(p_resource);
39+
p_resource = nullptr;
40+
}
41+
42+
43+
std::optional<branch_wrapper> branch_iterator::next()
44+
{
45+
git_reference* ref = nullptr;
46+
git_branch_t type;
47+
int res = git_branch_next(&ref, &type, p_resource);
48+
if (res == 0)
49+
{
50+
return branch_wrapper(ref);
51+
}
52+
else
53+
{
54+
return std::nullopt;
55+
}
56+
}

src/wrapper/branch_wrapper.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#pragma once
2+
3+
#include <optional>
4+
#include <string_view>
5+
6+
#include <git2.h>
7+
8+
#include "../wrapper/wrapper_base.hpp"
9+
10+
class commit_wrapper;
11+
12+
class branch_wrapper : public wrapper_base<git_reference>
13+
{
14+
public:
15+
16+
using base_type = wrapper_base<git_reference>;
17+
18+
~branch_wrapper();
19+
20+
branch_wrapper(branch_wrapper&&) = default;
21+
branch_wrapper& operator=(branch_wrapper&&) = default;
22+
23+
std::string_view name() const;
24+
25+
private:
26+
27+
explicit branch_wrapper(git_reference* ref);
28+
29+
friend class repository_wrapper;
30+
friend class branch_iterator;
31+
};
32+
33+
void delete_branch(branch_wrapper&& br);
34+
35+
// Rust / Python-like iterator instead of regular C++ iterator,
36+
// because of the libgit2 API. Implementing the postfix increment
37+
// operator of an input iterator would be overcomplicated.
38+
class branch_iterator : public wrapper_base<git_branch_iterator>
39+
{
40+
public:
41+
42+
using base_type = wrapper_base<git_branch_iterator>;
43+
44+
~branch_iterator();
45+
46+
branch_iterator(branch_iterator&&) = default;
47+
branch_iterator& operator=(branch_iterator&&) = default;
48+
49+
std::optional<branch_wrapper> next();
50+
51+
private:
52+
53+
explicit branch_iterator(git_branch_iterator* iter);
54+
55+
friend class repository_wrapper;
56+
};

src/wrapper/commit_wrapper.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
#include "commit_wrapper.hpp"
21
#include "../utils/git_exception.hpp"
2+
#include "../wrapper/commit_wrapper.hpp"
3+
#include "../wrapper/repository_wrapper.hpp"
34

45
commit_wrapper::~commit_wrapper()
56
{
@@ -8,7 +9,7 @@ commit_wrapper::~commit_wrapper()
89
}
910

1011

11-
commit_wrapper commit_wrapper::last_commit(const repository_wrapper& repo, const std::string& ref_name)
12+
commit_wrapper commit_wrapper::from_reference_name(const repository_wrapper& repo, const std::string& ref_name)
1213
{
1314
git_oid oid_parent_commit;
1415
throwIfError(git_reference_name_to_id(&oid_parent_commit, repo, ref_name.c_str()));

src/wrapper/commit_wrapper.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
#include <git2.h>
66

7-
#include "../wrapper/repository_wrapper.hpp"
87
#include "../wrapper/wrapper_base.hpp"
98

9+
class repository_wrapper;
10+
1011
class commit_wrapper : public wrapper_base<git_commit>
1112
{
1213
public:
@@ -17,7 +18,7 @@ class commit_wrapper : public wrapper_base<git_commit>
1718
commit_wrapper& operator=(commit_wrapper&&) noexcept = default;
1819

1920
static commit_wrapper
20-
last_commit(const repository_wrapper& repo, const std::string& ref_name = "HEAD");
21+
from_reference_name(const repository_wrapper& repo, const std::string& ref_name = "HEAD");
2122

2223
private:
2324

src/wrapper/refs_wrapper.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
#include "../utils/git_exception.hpp"
22
#include "../wrapper/refs_wrapper.hpp"
33

4+
reference_wrapper::reference_wrapper(git_reference* ref)
5+
: base_type(ref)
6+
{
7+
}
48

59
reference_wrapper::~reference_wrapper()
610
{
711
git_reference_free(p_resource);
812
p_resource=nullptr;
913
}
1014

11-
std::string reference_wrapper::get_ref_name(const repository_wrapper& rw)
15+
std::string reference_wrapper::short_name() const
1216
{
13-
reference_wrapper ref;
14-
throwIfError(git_repository_head(&(ref.p_resource), rw));
15-
return git_reference_shorthand(ref.p_resource);
17+
return git_reference_shorthand(p_resource);
1618
}

0 commit comments

Comments
 (0)