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
26 changes: 13 additions & 13 deletions src/subcommand/diff_subcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ diff_subcommand::diff_subcommand(const libgit2_object&, CLI::App& app)
sub->callback([this]() { this->run(); });
}

void diff_subcommand::print_stats(const diff_wrapper& diff, bool use_colour)
void print_stats(const diff_wrapper& diff, bool use_colour, bool stat_flag, bool shortstat_flag, bool numstat_flag, bool summary_flag)
{
git_diff_stats_format_t format;
if (m_stat_flag)
if (stat_flag)
{
if (m_shortstat_flag || m_numstat_flag || m_summary_flag)
if (shortstat_flag || numstat_flag || summary_flag)
{
throw git_exception("Only one of --stat, --shortstat, --numstat and --summary should be provided.", git2cpp_error_code::BAD_ARGUMENT);
}
Expand All @@ -68,9 +68,9 @@ void diff_subcommand::print_stats(const diff_wrapper& diff, bool use_colour)
format = GIT_DIFF_STATS_FULL;
}
}
else if (m_shortstat_flag)
else if (shortstat_flag)
{
if (m_numstat_flag || m_summary_flag)
if (numstat_flag || summary_flag)
{
throw git_exception("Only one of --stat, --shortstat, --numstat and --summary should be provided.", git2cpp_error_code::BAD_ARGUMENT);
}
Expand All @@ -79,9 +79,9 @@ void diff_subcommand::print_stats(const diff_wrapper& diff, bool use_colour)
format = GIT_DIFF_STATS_SHORT;
}
}
else if (m_numstat_flag)
else if (numstat_flag)
{
if (m_summary_flag)
if (summary_flag)
{
throw git_exception("Only one of --stat, --shortstat, --numstat and --summary should be provided.", git2cpp_error_code::BAD_ARGUMENT);
}
Expand All @@ -90,15 +90,15 @@ void diff_subcommand::print_stats(const diff_wrapper& diff, bool use_colour)
format = GIT_DIFF_STATS_NUMBER;
}
}
else if (m_summary_flag)
else if (summary_flag)
{
format = GIT_DIFF_STATS_INCLUDE_SUMMARY;
}

auto stats = diff.get_stats();
auto buf = stats.to_buf(format, 80);

if (use_colour && m_stat_flag)
if (use_colour && stat_flag)
{
// Add colors to + and - characters
std::string output(buf.ptr);
Expand Down Expand Up @@ -179,7 +179,7 @@ void diff_subcommand::print_diff(diff_wrapper& diff, bool use_colour)
{
if (m_stat_flag || m_shortstat_flag || m_numstat_flag || m_summary_flag)
{
print_stats(diff, use_colour);
print_stats(diff, use_colour, m_stat_flag, m_shortstat_flag, m_numstat_flag, m_summary_flag);
return;
}

Expand Down Expand Up @@ -320,19 +320,19 @@ void diff_subcommand::run()
{
if (tree1.has_value() && tree2.has_value())
{
return repo.diff_tree_to_tree(std::move(tree1.value()), std::move(tree2.value()), &diffopts);
return repo.diff_tree_to_tree(tree1.value(), tree2.value(), &diffopts);
}
else if (m_cached_flag)
{
if (m_cached_flag || !tree1)
{
tree1 = repo.treeish_to_tree("HEAD");
}
return repo.diff_tree_to_index(std::move(tree1.value()), std::nullopt, &diffopts);
return repo.diff_tree_to_index(tree1.value(), std::nullopt, &diffopts);
}
else if (tree1)
{
return repo.diff_tree_to_workdir_with_index(std::move(tree1.value()), &diffopts);
return repo.diff_tree_to_workdir_with_index(tree1.value(), &diffopts);
}
else
{
Expand Down
3 changes: 2 additions & 1 deletion src/subcommand/diff_subcommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class diff_subcommand
public:

explicit diff_subcommand(const libgit2_object&, CLI::App& app);
void print_stats(const diff_wrapper& diff, bool use_colour);
void print_diff(diff_wrapper& diff, bool use_colour);
void run();

Expand Down Expand Up @@ -53,3 +52,5 @@ class diff_subcommand
bool m_colour_flag = true;
bool m_no_colour_flag = false;
};

void print_stats(const diff_wrapper& diff, bool use_colour, bool stat_flag, bool shortstat_flag, bool numstat_flag, bool summary_flag);
52 changes: 47 additions & 5 deletions src/subcommand/stash_subcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

#include <git2/remote.h>

#include "../subcommand/diff_subcommand.hpp"
#include "../subcommand/stash_subcommand.hpp"
#include "../subcommand/status_subcommand.hpp"
#include "../wrapper/repository_wrapper.hpp"

bool has_subcommand(CLI::App* cmd)
{
std::vector<std::string> subs = { "push", "pop", "list", "apply" };
std::vector<std::string> subs = { "push", "pop", "list", "apply", "show" };
return std::any_of(subs.begin(), subs.end(), [cmd](const std::string& s) { return cmd->got_subcommand(s); });
}

Expand All @@ -22,10 +22,15 @@ stash_subcommand::stash_subcommand(const libgit2_object&, CLI::App& app)
auto* list = stash->add_subcommand("list", "");
auto* pop = stash->add_subcommand("pop", "");
auto* apply = stash->add_subcommand("apply", "");
auto* show = stash->add_subcommand("show", "Show the changes recorded in the stash as a diff");

push->add_option("-m,--message", m_message, "");
pop->add_option("--index", m_index, "");
apply->add_option("--index", m_index, "");
show->add_flag("--stat", m_stat_flag, "Generate a diffstat");
show->add_flag("--shortstat", m_shortstat_flag, "Output only the last line of --stat");
show->add_flag("--numstat", m_numstat_flag, "Machine-friendly --stat");
show->add_flag("--summary", m_summary_flag, "Output a condensed summary");

stash->callback([this,stash]()
{
Expand All @@ -38,6 +43,7 @@ stash_subcommand::stash_subcommand(const libgit2_object&, CLI::App& app)
list->callback([this]() { this->run_list(); });
pop->callback([this]() { this->run_pop(); });
apply->callback([this]() { this->run_apply(); });
show->callback([this]() { this->run_show(); });
}

void stash_subcommand::run_push()
Expand Down Expand Up @@ -66,14 +72,20 @@ void stash_subcommand::run_list()
throw_if_error(git_stash_foreach(repo, list_stash_cb, NULL));
}

git_oid stash_subcommand::resolve_stash_commit(repository_wrapper& repo)
{
std::string stash_spec = "stash@{" + std::to_string(m_index) + "}";
auto stash_obj = repo.revparse_single(stash_spec);
git_oid stash_id = stash_obj->oid();
return stash_id;
}

void stash_subcommand::run_pop()
{
auto directory = get_current_git_path();
auto repo = repository_wrapper::open(directory);

std::string stash_spec = "stash@{" + std::to_string(m_index) + "}";
auto stash_obj = repo.revparse_single(stash_spec);
git_oid stash_id = stash_obj->oid();
git_oid stash_id = resolve_stash_commit(repo);
char id_string[GIT_OID_HEXSZ + 1];
git_oid_tostr(id_string, sizeof(id_string), &stash_id);

Expand All @@ -90,3 +102,33 @@ void stash_subcommand::run_apply()
throw_if_error(git_stash_apply(repo, m_index, NULL));
status_run();
}

void stash_subcommand::run_show()
{
auto directory = get_current_git_path();
auto repo = repository_wrapper::open(directory);

git_oid stash_id = resolve_stash_commit(repo);
commit_wrapper stash_commit = repo.find_commit(stash_id);

if (git_commit_parentcount(stash_commit) < 1)
{
throw std::runtime_error("stash show: stash commit has no parents");
}

commit_wrapper parent_commit = stash_commit.get_parent(0);

tree_wrapper stash_tree = stash_commit.tree();
tree_wrapper parent_tree = parent_commit.tree();

git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;

diff_wrapper diff = repo.diff_tree_to_tree(parent_tree, stash_tree, &diff_opts);

bool use_colour = true;
if (!m_shortstat_flag && !m_numstat_flag && !m_summary_flag)
{
m_stat_flag = true;
}
print_stats(diff, use_colour, m_stat_flag, m_shortstat_flag, m_numstat_flag, m_summary_flag);
}
10 changes: 10 additions & 0 deletions src/subcommand/stash_subcommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,28 @@
#include <CLI/CLI.hpp>

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

class stash_subcommand
{
public:

explicit stash_subcommand(const libgit2_object&, CLI::App& app);
git_oid resolve_stash_commit(repository_wrapper& repo);
void run_push();
void run_list();
void run_pop();
void run_apply();
void run_show();

private:

std::vector<std::string> m_options;
std::string m_message = "";
size_t m_index = 0;

bool m_stat_flag = false;
bool m_shortstat_flag = false;
bool m_numstat_flag = false;
bool m_summary_flag = false;
};
19 changes: 18 additions & 1 deletion src/wrapper/commit_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "../wrapper/commit_wrapper.hpp"
#include <git2/commit.h>

#include "../utils/git_exception.hpp"
#include "tree_wrapper.hpp"
#include "../wrapper/commit_wrapper.hpp"

commit_wrapper::commit_wrapper(git_commit* commit)
: base_type(commit)
{
Expand Down Expand Up @@ -38,6 +41,13 @@ std::string commit_wrapper::summary() const
return git_commit_summary(*this);
}

commit_wrapper commit_wrapper::get_parent(size_t i) const
{
git_commit* parent;
throw_if_error(git_commit_parent(&parent, *this, i));
return commit_wrapper(parent);
}

commit_list_wrapper commit_wrapper::get_parents_list() const
{
size_t parent_count = git_commit_parentcount(*this);
Expand All @@ -52,3 +62,10 @@ commit_list_wrapper commit_wrapper::get_parents_list() const
}
return commit_list_wrapper(std::move(parents_list));
}

tree_wrapper commit_wrapper::tree() const
{
git_tree* tree;
throw_if_error(git_commit_tree(&tree, *this));
return tree_wrapper(tree);
}
4 changes: 4 additions & 0 deletions src/wrapper/commit_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string>

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

class commit_wrapper;
using commit_list_wrapper = list_wrapper<commit_wrapper>;
Expand All @@ -27,8 +28,11 @@ class commit_wrapper : public wrapper_base<git_commit>
std::string message() const;
std::string summary() const;

commit_wrapper get_parent(size_t i) const;
commit_list_wrapper get_parents_list() const;

tree_wrapper tree() const;

private:

commit_wrapper(git_commit* commit);
Expand Down
8 changes: 4 additions & 4 deletions src/wrapper/repository_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ config_wrapper repository_wrapper::get_config()

// Diff

diff_wrapper repository_wrapper::diff_tree_to_index(tree_wrapper old_tree, std::optional<index_wrapper> index, git_diff_options* diffopts)
diff_wrapper repository_wrapper::diff_tree_to_index(const tree_wrapper& old_tree, std::optional<index_wrapper> index, git_diff_options* diffopts)
{
git_diff* diff;
git_index* idx = nullptr;
Expand All @@ -519,21 +519,21 @@ diff_wrapper repository_wrapper::diff_tree_to_index(tree_wrapper old_tree, std::
return diff_wrapper(diff);
}

diff_wrapper repository_wrapper::diff_tree_to_tree(tree_wrapper old_tree, tree_wrapper new_tree, git_diff_options* diffopts)
diff_wrapper repository_wrapper::diff_tree_to_tree(const tree_wrapper& old_tree, const tree_wrapper& new_tree, git_diff_options* diffopts)
{
git_diff* diff;
throw_if_error(git_diff_tree_to_tree(&diff, *this, old_tree, new_tree, diffopts));
return diff_wrapper(diff);
}

diff_wrapper repository_wrapper::diff_tree_to_workdir(tree_wrapper old_tree, git_diff_options* diffopts)
diff_wrapper repository_wrapper::diff_tree_to_workdir(const tree_wrapper& old_tree, git_diff_options* diffopts)
{
git_diff* diff;
throw_if_error(git_diff_tree_to_workdir(&diff, *this, old_tree, diffopts));
return diff_wrapper(diff);
}

diff_wrapper repository_wrapper::diff_tree_to_workdir_with_index(tree_wrapper old_tree, git_diff_options* diffopts)
diff_wrapper repository_wrapper::diff_tree_to_workdir_with_index(const tree_wrapper& old_tree, git_diff_options* diffopts)
{
git_diff* diff;
throw_if_error(git_diff_tree_to_workdir_with_index(&diff, *this, old_tree, diffopts));
Expand Down
8 changes: 4 additions & 4 deletions src/wrapper/repository_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ class repository_wrapper : public wrapper_base<git_repository>
config_wrapper get_config();

// Diff
diff_wrapper diff_tree_to_index(tree_wrapper old_tree, std::optional<index_wrapper> index, git_diff_options* diffopts);
diff_wrapper diff_tree_to_tree(tree_wrapper old_tree, tree_wrapper new_tree, git_diff_options* diffopts);
diff_wrapper diff_tree_to_workdir(tree_wrapper old_tree, git_diff_options* diffopts);
diff_wrapper diff_tree_to_workdir_with_index(tree_wrapper old_tree, git_diff_options* diffopts);
diff_wrapper diff_tree_to_index(const tree_wrapper& old_tree, std::optional<index_wrapper> index, git_diff_options* diffopts);
diff_wrapper diff_tree_to_tree(const tree_wrapper& old_tree, const tree_wrapper& new_tree, git_diff_options* diffopts);
diff_wrapper diff_tree_to_workdir(const tree_wrapper& old_tree, git_diff_options* diffopts);
diff_wrapper diff_tree_to_workdir_with_index(const tree_wrapper& old_tree, git_diff_options* diffopts);
diff_wrapper diff_index_to_workdir(std::optional<index_wrapper> index, git_diff_options* diffopts);

//Tags
Expand Down
1 change: 1 addition & 0 deletions src/wrapper/tree_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ class tree_wrapper : public wrapper_base<git_tree>

tree_wrapper(git_tree* tree);

friend class commit_wrapper;
friend class repository_wrapper;
};
25 changes: 25 additions & 0 deletions test/test_stash.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,28 @@ def test_stash_apply(xtl_clone, commit_env_config, git2cpp_path, tmp_path, index
assert "stash@{0}" in p_list.stdout
if index_flag != "":
assert "stash@{1}" in p_list.stdout


def test_stash_show(xtl_clone, commit_env_config, git2cpp_path, tmp_path):
assert (tmp_path / "xtl").exists()
xtl_path = tmp_path / "xtl"

filename = "mook_show.txt"
p = xtl_path / filename
p.write_text("Hello")

cmd_add = [git2cpp_path, "add", filename]
p_add = subprocess.run(cmd_add, cwd=xtl_path, text=True)
assert p_add.returncode == 0

cmd_stash = [git2cpp_path, "stash"]
p_stash = subprocess.run(cmd_stash, capture_output=True, cwd=xtl_path, text=True)
assert p_stash.returncode == 0

cmd_show = [git2cpp_path, "stash", "show", "--stat"]
p_show = subprocess.run(cmd_show, capture_output=True, cwd=xtl_path, text=True)
assert p_show.returncode == 0

# A diffstat should mention the file and summary "file changed"
assert filename in p_show.stdout
assert "1 file changed" in p_show.stdout