Skip to content

Add commit and reset subcommand #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 31, 2025
Merged
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/subcommand/checkout_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/clone_subcommand.cpp
${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/init_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/reset_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/reset_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/utils/common.cpp
Expand All @@ -69,6 +73,8 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/wrapper/refs_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/repository_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/repository_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/signature_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/signature_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/status_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/status_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/wrapper_base.hpp
Expand Down
4 changes: 4 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include "subcommand/branch_subcommand.hpp"
#include "subcommand/checkout_subcommand.hpp"
#include "subcommand/clone_subcommand.hpp"
#include "subcommand/commit_subcommand.hpp"
#include "subcommand/init_subcommand.hpp"
#include "subcommand/reset_subcommand.hpp"
#include "subcommand/status_subcommand.hpp"

int main(int argc, char** argv)
Expand All @@ -29,6 +31,8 @@ int main(int argc, char** argv)
branch_subcommand branch(lg2_obj, app);
checkout_subcommand checkout(lg2_obj, app);
clone_subcommand clone(lg2_obj, app);
commit_subcommand commit(lg2_obj, app);
reset_subcommand reset(lg2_obj, app);

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

Expand Down
2 changes: 2 additions & 0 deletions src/subcommand/add_subcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ void add_subcommand::run()
if (m_all_flag)
{
index.add_all();
index.write();
}
else
{
index.add_entries(m_add_files);
index.write();
}
}
37 changes: 37 additions & 0 deletions src/subcommand/commit_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <git2.h>
#include <unistd.h>

#include "commit_subcommand.hpp"
#include "../wrapper/index_wrapper.hpp"
#include "../wrapper/repository_wrapper.hpp"


commit_subcommand::commit_subcommand(const libgit2_object&, CLI::App& app)
{
auto *sub = app.add_subcommand("commit", "Record changes to the repository");

sub->add_option("-m,--message", m_commit_message, "Commit message");

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


void commit_subcommand::run()
{
auto directory = get_current_git_path();
auto bare = false;
auto repo = repository_wrapper::init(directory, bare);
auto author_committer_signatures = signature_wrapper::get_default_signature_from_env(repo);

if (m_commit_message.empty())
{
std::cout << "Please enter a commit message:" << std::endl;
std::getline(std::cin, m_commit_message);
if (m_commit_message.empty())
{
throw std::runtime_error("Aborting, no commit message specified.");
}
}

repo.create_commit(author_committer_signatures, m_commit_message);
}
16 changes: 16 additions & 0 deletions src/subcommand/commit_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <CLI/CLI.hpp>

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

class commit_subcommand
{
public:

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

private:
std::string m_commit_message;
};
61 changes: 61 additions & 0 deletions src/subcommand/reset_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "reset_subcommand.hpp"
// #include "../wrapper/index_wrapper.hpp"
#include "../wrapper/repository_wrapper.hpp"
#include <stdexcept>

enum class reset_type
{
GIT_RESET_SOFT = 1,
GIT_RESET_MIXED = 2,
GIT_RESET_HARD = 3
};

reset_subcommand::reset_subcommand(const libgit2_object&, CLI::App& app)
{
auto *sub = app.add_subcommand("reset", "Reset current HEAD to the specified state");

sub->add_option("<commit>", m_commit, "The ID of the commit that will become HEAD");

sub->add_flag("--soft", m_soft_flag, "");
sub->add_flag("--mixed", m_mixed_flag, "");
sub->add_flag("--hard", m_hard_flag, "");

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


void reset_subcommand::run()
{
auto directory = get_current_git_path();
auto bare = false;
auto repo = repository_wrapper::init(directory, bare);

auto target = repo.revparse_single(m_commit);
if (!target)
{
throw std::runtime_error("Target revision not found.");
}

git_checkout_options options;
git_checkout_options_init(&options, GIT_CHECKOUT_OPTIONS_VERSION);

git_reset_t reset_type;
if (m_soft_flag)
{
reset_type = GIT_RESET_SOFT;
}
if (m_mixed_flag)
{
reset_type = GIT_RESET_MIXED;
}
if (m_hard_flag)
{
reset_type = GIT_RESET_HARD;
if (m_commit.empty())
{
m_commit = "HEAD";
}
}

repo.reset(target.value(), reset_type, options);
}
19 changes: 19 additions & 0 deletions src/subcommand/reset_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <CLI/CLI.hpp>

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

class reset_subcommand
{
public:

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

private:
std::string m_commit;
bool m_soft_flag = false;
bool m_mixed_flag = false;
bool m_hard_flag = false;
};
1 change: 0 additions & 1 deletion src/wrapper/commit_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ const git_oid& commit_wrapper::oid() const
{
return *git_commit_id(p_resource);
}

1 change: 1 addition & 0 deletions src/wrapper/commit_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <git2.h>

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

class commit_wrapper : public wrapper_base<git_commit>
Expand Down
12 changes: 12 additions & 0 deletions src/wrapper/index_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,17 @@ void index_wrapper::add_impl(std::vector<std::string> patterns)
{
git_strarray_wrapper array{patterns};
throw_if_error(git_index_add_all(*this, array, 0, NULL, NULL));
// throw_if_error(git_index_write(*this));
}

void index_wrapper::write()
{
throw_if_error(git_index_write(*this));
}

git_oid index_wrapper::write_tree()
{
git_oid tree_id;
throw_if_error(git_index_write_tree(&tree_id, *this));
return tree_id;
}
3 changes: 3 additions & 0 deletions src/wrapper/index_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class index_wrapper : public wrapper_base<git_index>

static index_wrapper init(repository_wrapper& rw);

void write();
git_oid write_tree();

void add_entries(std::vector<std::string> patterns);
void add_all();

Expand Down
5 changes: 5 additions & 0 deletions src/wrapper/object_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ const git_oid& object_wrapper::oid() const
{
return *git_object_id(*this);
}

object_wrapper::operator git_commit*() const noexcept
{
return reinterpret_cast<git_commit*>(p_resource);
}
2 changes: 2 additions & 0 deletions src/wrapper/object_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class object_wrapper : public wrapper_base<git_object>

const git_oid& oid() const;

operator git_commit*() const noexcept;

private:

object_wrapper(git_object* obj);
Expand Down
38 changes: 38 additions & 0 deletions src/wrapper/repository_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "../utils/git_exception.hpp"
#include "../wrapper/index_wrapper.hpp"
#include "../wrapper/object_wrapper.hpp"
#include "../wrapper/repository_wrapper.hpp"

repository_wrapper::~repository_wrapper()
Expand Down Expand Up @@ -107,6 +109,35 @@ commit_wrapper repository_wrapper::find_commit(const git_oid& id) const
return commit_wrapper(commit);
}

void repository_wrapper::create_commit(const signature_wrapper::author_committer_signatures& author_committer_signatures,
const std::string& message)
{
const char* message_encoding = "UTF-8";
git_oid commit_id;

std::string update_ref = "HEAD";
auto parent = revparse_single(update_ref);
std::size_t parent_count = 0;
const git_commit* parents[1] = {nullptr};
if (parent)
{
parent_count = 1;
parents[0] = *parent;
}

git_tree* tree;
index_wrapper index = this->make_index();
git_oid tree_id = index.write_tree();
index.write();

throw_if_error(git_tree_lookup(&tree, *this, &tree_id));

throw_if_error(git_commit_create(&commit_id, *this, update_ref.c_str(), author_committer_signatures.first, author_committer_signatures.second,
message_encoding, message.c_str(), tree, parent_count, parents));

git_tree_free(tree);
}

annotated_commit_wrapper repository_wrapper::find_annotated_commit(const git_oid& id) const
{
git_annotated_commit* commit;
Expand All @@ -130,3 +161,10 @@ void repository_wrapper::set_head_detached(const annotated_commit_wrapper& commi
{
throw_if_error(git_repository_set_head_detached_from_annotated(*this, commit));
}

void repository_wrapper::reset(const object_wrapper& target, git_reset_t reset_type, const git_checkout_options& checkout_options)
{
// TODO: gerer l'index

throw_if_error(git_reset(*this, target, reset_type, &checkout_options));
}
5 changes: 4 additions & 1 deletion src/wrapper/repository_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "../wrapper/index_wrapper.hpp"
#include "../wrapper/object_wrapper.hpp"
#include "../wrapper/refs_wrapper.hpp"
#include "../wrapper/signature_wrapper.hpp"
#include "../wrapper/wrapper_base.hpp"

class repository_wrapper : public wrapper_base<git_repository>
Expand Down Expand Up @@ -50,6 +51,7 @@ class repository_wrapper : public wrapper_base<git_repository>
// Commits
commit_wrapper find_commit(std::string_view ref_name = "HEAD") const;
commit_wrapper find_commit(const git_oid& id) const;
void create_commit(const signature_wrapper::author_committer_signatures&, const std::string&);

// Annotated commits
annotated_commit_wrapper find_annotated_commit(const git_oid& id) const;
Expand All @@ -60,9 +62,10 @@ class repository_wrapper : public wrapper_base<git_repository>
// Objects
std::optional<object_wrapper> revparse_single(std::string_view spec) const;

// Set head
// Head manipulations
void set_head(std::string_view ref_name);
void set_head_detached(const annotated_commit_wrapper& commit);
void reset(const object_wrapper& target, git_reset_t reset_type, const git_checkout_options& checkout_options);

private:

Expand Down
17 changes: 17 additions & 0 deletions src/wrapper/signature_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "../wrapper/repository_wrapper.hpp"
#include "../wrapper/signature_wrapper.hpp"
#include "../utils/git_exception.hpp"

signature_wrapper::~signature_wrapper()
{
git_signature_free(p_resource);
p_resource=nullptr;
}

signature_wrapper::author_committer_signatures signature_wrapper::get_default_signature_from_env(repository_wrapper& rw)
{
signature_wrapper author;
signature_wrapper committer;
throw_if_error(git_signature_default_from_env(&(author.p_resource), &(committer.p_resource), rw));
return {std::move(author), std::move(committer)};
}
26 changes: 26 additions & 0 deletions src/wrapper/signature_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <utility>

#include <git2.h>

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

class repository_wrapper;

class signature_wrapper : public wrapper_base<git_signature>
{
public:
using author_committer_signatures = std::pair<signature_wrapper, signature_wrapper>;

~signature_wrapper();

signature_wrapper(signature_wrapper&&) = default;
signature_wrapper& operator=(signature_wrapper&&) = default;

static author_committer_signatures get_default_signature_from_env(repository_wrapper&);

private:

signature_wrapper() = default;
};
2 changes: 1 addition & 1 deletion test/data/status_data/embedded_git/HEAD
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ref: refs/heads/main
ref: refs/heads/commit_test_branch
Binary file modified test/data/status_data/embedded_git/index
Binary file not shown.
16 changes: 16 additions & 0 deletions test/data/status_data/embedded_git/logs/HEAD
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
0000000000000000000000000000000000000000 75743dcbd85064226c77a0b862af817838ae0b2e Sandrine Pataut <pataut.sandrine@gmail.com> 1750769952 +0200 commit (initial): first commit
75743dcbd85064226c77a0b862af817838ae0b2e ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1750771272 +0200 commit: Second commit
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from main to bla
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from bla to main
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from main to bla
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from bla to main
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from main to bla
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from bla to main
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from main to bla
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887403 +0200 checkout: moving from bla to main
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887505 +0200 checkout: moving from main to commit_test_branch
ee8c4cf874c4f1e3ba755f929fe7811018adee3d cba545ef5cc4ddf12a9744b6a49b20dda1ef1d5c Sandrine Pataut <pataut.sandrine@gmail.com> 1753887505 +0200 commit: test commit
cba545ef5cc4ddf12a9744b6a49b20dda1ef1d5c ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887505 +0200 reset: moving to ee8c4cf874c4f1e3ba755f929fe7811018adee3d
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887505 +0200 checkout: moving from commit_test_branch to main
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753887505 +0200 checkout: moving from main to commit_test_branch
ee8c4cf874c4f1e3ba755f929fe7811018adee3d 75743dcbd85064226c77a0b862af817838ae0b2e Sandrine Pataut <pataut.sandrine@gmail.com> 1753888486 +0200 reset: moving to 75743dcbd85064226c77a0b862af817838ae0b2e
75743dcbd85064226c77a0b862af817838ae0b2e ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753888486 +0200 checkout: moving from commit_test_branch to main
ee8c4cf874c4f1e3ba755f929fe7811018adee3d ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753888486 +0200 checkout: moving from main to commit_test_branch
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0000000000000000000000000000000000000000 ee8c4cf874c4f1e3ba755f929fe7811018adee3d Sandrine Pataut <pataut.sandrine@gmail.com> 1753888486 +0200 branch: Created from ee8c4cf874c4f1e3ba755f929fe7811018adee3d
Binary file not shown.
Binary file not shown.
Loading
Loading