Skip to content

Commit ea1b738

Browse files
committed
Add --abbrev-commit, --pretty and --oneline to the log subcommand
1 parent e0f7ab9 commit ea1b738

File tree

9 files changed

+309
-32
lines changed

9 files changed

+309
-32
lines changed

src/subcommand/log_subcommand.cpp

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@
1111

1212
#include "log_subcommand.hpp"
1313
#include "../utils/terminal_pager.hpp"
14-
#include "../wrapper/repository_wrapper.hpp"
15-
#include "../wrapper/commit_wrapper.hpp"
1614

1715
log_subcommand::log_subcommand(const libgit2_object&, CLI::App& app)
1816
{
1917
auto *sub = app.add_subcommand("log", "Shows commit logs");
2018

21-
sub->add_flag("--format", m_format_flag, "Pretty-print the contents of the commit logs in a given format, where <format> can be one of full and fuller");
19+
sub->add_option("--format", m_format_flag, "Pretty-print the contents of the commit logs in a given format, where <format> can be one of full and fuller");
2220
sub->add_option("-n,--max-count", m_max_count_flag, "Limit the output to <number> commits.");
23-
// sub->add_flag("--oneline", m_oneline_flag, "This is a shorthand for --pretty=oneline --abbrev-commit used together.");
21+
sub->add_flag("--abbrev-commit", m_abbrev_commit_flag, "Instead of showing the full 40-byte hexadecimal commit object name, show a prefix that names the object uniquely. --abbrev=<n> (which also modifies diff output, if it is displayed) option can be used to specify the minimum length of the prefix.");
22+
sub->add_option("--abbrev", m_abbrev, "Instead of showing the full 40-byte hexadecimal object name in diff-raw format output and diff-tree header lines, show the shortest prefix that is at least <n> hexdigits long that uniquely refers the object.");
23+
sub->add_flag("--no-abbrev-commit", m_no_abbrev_commit_flag, "Show the full 40-byte hexadecimal commit object name. This negates --abbrev-commit, either explicit or implied by other options such as --oneline.");
24+
sub->add_flag("--oneline", m_oneline_flag, "This is a shorthand for --format=oneline --abbrev-commit used together.");
2425

2526
sub->callback([this]() { this->run(); });
2627
};
@@ -166,6 +167,7 @@ void print_refs(const commit_refs& refs)
166167
return;
167168
}
168169

170+
std::cout << termcolor::yellow;
169171
std::cout << " (";
170172

171173
bool first = true;
@@ -179,7 +181,7 @@ void print_refs(const commit_refs& refs)
179181
first = false;
180182
}
181183

182-
for (const auto& tag :refs.tags)
184+
for (const auto& tag : refs.tags)
183185
{
184186
if (!first)
185187
{
@@ -212,17 +214,47 @@ void print_refs(const commit_refs& refs)
212214
std::cout << ")" << termcolor::reset;
213215
}
214216

215-
void print_commit(repository_wrapper& repo, const commit_wrapper& commit, std::string m_format_flag)
217+
void log_subcommand::print_commit(repository_wrapper& repo, const commit_wrapper& commit)
216218
{
217-
std::string buf = commit.commit_oid_tostr();
219+
const bool abbrev_commit = (m_abbrev_commit_flag || m_oneline_flag) && !m_no_abbrev_commit_flag;
220+
const bool oneline = (m_format_flag == "oneline") || m_oneline_flag;
221+
222+
std::string sha = commit.commit_oid_tostr();
223+
224+
if (abbrev_commit && m_abbrev <= sha.size())
225+
{
226+
sha = sha.substr(0, m_abbrev);
227+
}
228+
229+
commit_refs refs = get_refs_for_commit(repo, commit.oid());
230+
231+
std::string message = commit.message();
232+
while (!message.empty() && message.back() == '\n')
233+
message.pop_back();
234+
235+
if (oneline)
236+
{
237+
std::string subject;
238+
{
239+
std::istringstream s(message);
240+
std::getline(s, subject);
241+
}
242+
243+
std::cout << termcolor::yellow << sha << termcolor::reset;
244+
print_refs(refs);
245+
if (!subject.empty())
246+
{
247+
std::cout << " " << subject;
248+
}
249+
return;
250+
}
218251

219252
signature_wrapper author = signature_wrapper::get_commit_author(commit);
220253
signature_wrapper committer = signature_wrapper::get_commit_committer(commit);
221254

222255
stream_colour_fn colour = termcolor::yellow;
223-
std::cout << colour << "commit " << buf;
256+
std::cout << colour << "commit " << sha << termcolor::reset;
224257

225-
commit_refs refs = get_refs_for_commit(repo, commit.oid());
226258
print_refs(refs);
227259

228260
std::cout << termcolor::reset << std::endl;
@@ -247,11 +279,6 @@ void print_commit(repository_wrapper& repo, const commit_wrapper& commit, std::s
247279
}
248280
}
249281

250-
std::string message = commit.message();
251-
while (!message.empty() && message.back() == '\n')
252-
{
253-
message.pop_back();
254-
}
255282
std::istringstream message_stream(message);
256283
std::string line;
257284
while (std::getline(message_stream, line))
@@ -287,7 +314,7 @@ void log_subcommand::run()
287314
std::cout << std::endl;
288315
}
289316
commit_wrapper commit = repo.find_commit(commit_oid);
290-
print_commit(repo, commit, m_format_flag);
317+
print_commit(repo, commit);
291318
++i;
292319
}
293320

src/subcommand/log_subcommand.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <limits>
55

66
#include "../utils/common.hpp"
7+
#include "../wrapper/commit_wrapper.hpp"
8+
#include "../wrapper/repository_wrapper.hpp"
79

810

911
class log_subcommand
@@ -14,7 +16,13 @@ class log_subcommand
1416
void run();
1517

1618
private:
19+
20+
void print_commit(repository_wrapper& repo, const commit_wrapper& commit);
21+
1722
std::string m_format_flag;
1823
int m_max_count_flag=std::numeric_limits<int>::max();
19-
// bool m_oneline_flag = false;
24+
size_t m_abbrev = 7;
25+
bool m_abbrev_commit_flag = false;
26+
bool m_no_abbrev_commit_flag = false;
27+
bool m_oneline_flag = false;
2028
};
Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
11
#include "revparse_subcommand.hpp"
2+
#include "../utils/git_exception.hpp"
23
#include "../wrapper/repository_wrapper.hpp"
3-
#include <ios>
4-
#include <stdexcept>
54

65
revparse_subcommand::revparse_subcommand(const libgit2_object&, CLI::App& app)
76
{
87
auto* sub = app.add_subcommand("rev-parse", "Pick out and message parameters");
98

10-
sub->add_flag("--is-bare-repository", m_is_bare_repository_flag);
11-
sub->add_flag("--is-shallow-repository", m_is_shallow_repository_flag);
9+
auto* bare_opt = sub->add_flag("--is-bare-repository", m_is_bare_repository_flag, "When the repository is bare print \"true\", otherwise \"false\".");
10+
auto* shallow_opt = sub->add_flag("--is-shallow-repository", m_is_shallow_repository_flag, "When the repository is shallow print \"true\", otherwise \"false\".");
11+
12+
sub->add_option("<rev>", m_revisions, "Revision(s) to parse (e.g. HEAD, main, HEAD~1, dae86e, ...)");
13+
14+
sub->parse_complete_callback([this, sub, bare_opt, shallow_opt]() {
15+
for (CLI::Option* opt : sub->parse_order())
16+
{
17+
if (opt == bare_opt)
18+
{
19+
m_queries_in_order.push_back("is_bare");
20+
}
21+
else if (opt == shallow_opt)
22+
{
23+
m_queries_in_order.push_back("is_shallow");
24+
}
25+
}
26+
});
1227

1328
sub->callback([this]() { this->run(); });
1429
}
@@ -18,16 +33,39 @@ void revparse_subcommand::run()
1833
auto directory = get_current_git_path();
1934
auto repo = repository_wrapper::open(directory);
2035

21-
if (m_is_bare_repository_flag)
22-
{
23-
std::cout << std::boolalpha << repo.is_bare() << std::endl;
24-
}
25-
else if (m_is_shallow_repository_flag)
36+
if (!m_queries_in_order.empty())
2637
{
27-
std::cout << std::boolalpha << repo.is_shallow() << std::endl;
38+
for (const auto& q : m_queries_in_order)
39+
{
40+
if (q == "is_bare")
41+
{
42+
std::cout << std::boolalpha << repo.is_bare() << std::endl;
43+
}
44+
if (q == "is_shallow")
45+
{
46+
std::cout << std::boolalpha << repo.is_shallow() << std::endl;
47+
}
48+
}
49+
return;
2850
}
29-
else
51+
52+
if (!m_revisions.empty())
3053
{
31-
std::cout << "revparse only supports --is-bare-repository and --is-shallow-repository for now" << std::endl;
54+
for (const auto& rev : m_revisions)
55+
{
56+
auto obj = repo.revparse_single(rev.c_str());
57+
58+
if (!obj.has_value())
59+
{
60+
throw git_exception("bad revision '" + rev + "'", git2cpp_error_code::BAD_ARGUMENT);
61+
return;
62+
}
63+
64+
auto oid = obj.value().oid();
65+
std::cout << git_oid_tostr_s(&oid) << std::endl;
66+
}
67+
return;
3268
}
69+
70+
std::cout << "revparse only supports --is-bare-repository, --is-shallow-repository and parsing revisions for now" << std::endl;
3371
}

src/subcommand/revparse_subcommand.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#pragma once
22

3+
#include <string>
4+
#include <vector>
5+
36
#include <CLI/CLI.hpp>
47

58
#include "../utils/common.hpp"
@@ -13,6 +16,8 @@ class revparse_subcommand
1316

1417
private:
1518

19+
std::vector<std::string> m_revisions;
20+
std::vector<std::string> m_queries_in_order;
1621
bool m_is_bare_repository_flag = false;
1722
bool m_is_shallow_repository_flag = false;
1823
};

src/subcommand/tag_subcommand.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include <git2.h>
22

33
#include "../subcommand/tag_subcommand.hpp"
4-
#include "../wrapper/commit_wrapper.hpp"
5-
#include "../wrapper/tag_wrapper.hpp"
64

75
tag_subcommand::tag_subcommand(const libgit2_object&, CLI::App& app)
86
{
@@ -12,6 +10,7 @@ tag_subcommand::tag_subcommand(const libgit2_object&, CLI::App& app)
1210
sub->add_flag("-f,--force", m_force_flag, "Replace an existing tag with the given name (instead of failing)");
1311
sub->add_option("-d,--delete", m_delete, "Delete existing tags with the given names.");
1412
sub->add_option("-n", m_num_lines, "<num> specifies how many lines from the annotation, if any, are printed when using -l. Implies --list.");
13+
sub->add_flag("-a,--annotate", m_annotate_flag, "Make an annotated tag.");
1514
sub->add_option("-m,--message", m_message, "Tag message for annotated tags");
1615
sub->add_option("<tagname>", m_tag_name, "Tag name");
1716
sub->add_option("<commit>", m_target, "Target commit (defaults to HEAD)");
@@ -217,10 +216,18 @@ void tag_subcommand::run()
217216
{
218217
delete_tag(repo);
219218
}
220-
else if (m_list_flag || (m_tag_name.empty() && m_message.empty()))
219+
else if (m_list_flag || (m_tag_name.empty() && m_message.empty() && !m_annotate_flag))
221220
{
222221
list_tags(repo);
223222
}
223+
else if (m_annotate_flag)
224+
{
225+
if (m_message.empty())
226+
{
227+
throw git_exception("error: -a/--annotate requires -m/--message", git2cpp_error_code::BAD_ARGUMENT);
228+
}
229+
create_tag(repo);
230+
}
224231
else if (!m_message.empty())
225232
{
226233
create_tag(repo);

src/subcommand/tag_subcommand.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ class tag_subcommand
2828
std::string m_target;
2929
bool m_list_flag = false;
3030
bool m_force_flag = false;
31+
bool m_annotate_flag = false;
3132
int m_num_lines = 0;
3233
};

0 commit comments

Comments
 (0)