Skip to content

Commit 81992bd

Browse files
committed
Add tracking info
1 parent c460fce commit 81992bd

File tree

2 files changed

+372
-5
lines changed

2 files changed

+372
-5
lines changed

src/subcommand/log_subcommand.cpp

Lines changed: 178 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
#include <exception>
12
#include <format>
23
#include <git2.h>
3-
#include <git2/revwalk.h>
4+
#include <git2/oid.h>
5+
#include <git2/refs.h>
46
#include <git2/types.h>
57
#include <string_view>
8+
#include <vector>
69

710
#include <termcolor/termcolor.hpp>
811

@@ -50,15 +53,181 @@ void print_time(git_time intime, std::string prefix)
5053
std::cout << prefix << out << " " << sign << std::format("{:02d}", hours) << std::format("{:02d}", minutes) <<std::endl;
5154
}
5255

53-
void print_commit(const commit_wrapper& commit, std::string m_format_flag)
56+
std::vector<std::string> get_tags_for_commit(repository_wrapper& repo, const git_oid* commit_oid)
57+
{
58+
std::vector<std::string> tags;
59+
git_strarray tag_names = {0};
60+
61+
if (git_tag_list(&tag_names, repo) != 0)
62+
{
63+
return tags;
64+
}
65+
66+
for (size_t i = 0; i < tag_names.count; i++)
67+
{
68+
std::string tag_name = tag_names.strings[i];
69+
std::string ref_name = "refs/tags/" + std::string(tag_name);
70+
71+
reference_wrapper tag_ref = repo.find_reference(ref_name);
72+
object_wrapper peeled = tag_ref.peel<object_wrapper>();
73+
74+
if (git_oid_equal(&peeled.oid(), commit_oid))
75+
{
76+
tags.push_back(std::string(tag_name));
77+
}
78+
}
79+
80+
git_strarray_dispose(&tag_names);
81+
return tags;
82+
}
83+
84+
std::vector<std::string> get_branches_for_commit(repository_wrapper& repo, git_branch_t type, const git_oid* commit_oid, const std::string exclude_branch)
85+
{
86+
std::vector<std::string> branches;
87+
88+
auto branch_iter = repo.iterate_branches(type);
89+
while (auto branch = branch_iter.next())
90+
{
91+
const git_oid* branch_target = nullptr;
92+
git_reference* ref = branch.value();
93+
94+
if (git_reference_type(ref) == GIT_REFERENCE_DIRECT)
95+
{
96+
branch_target = git_reference_target(ref);
97+
}
98+
else if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC)
99+
{
100+
git_reference* resolved = nullptr;
101+
if (git_reference_resolve(&resolved, ref) == 0)
102+
{
103+
branch_target = git_reference_target(resolved);
104+
git_reference_free(resolved);
105+
}
106+
}
107+
108+
if (branch_target && git_oid_equal(branch_target, commit_oid))
109+
{
110+
std::string branch_name;
111+
branch_name = branch->name();
112+
if (type == GIT_BRANCH_LOCAL)
113+
{
114+
if (branch_name != exclude_branch)
115+
{
116+
branches.push_back(branch_name);
117+
}
118+
}
119+
else
120+
{
121+
branches.push_back(branch_name);
122+
}
123+
}
124+
}
125+
126+
return branches;
127+
}
128+
129+
struct commit_refs
130+
{
131+
std::string head_branch;
132+
std::vector<std::string> tags;
133+
std::vector<std::string> local_branches;
134+
std::vector<std::string> remote_branches;
135+
136+
bool has_refs() const {
137+
return !head_branch.empty() || !tags.empty() ||
138+
!local_branches.empty() || !remote_branches.empty();
139+
}
140+
};
141+
142+
commit_refs get_refs_for_commit(repository_wrapper& repo, const git_oid* commit_oid)
143+
{
144+
commit_refs refs;
145+
146+
if (!repo.is_head_unborn())
147+
{
148+
auto head = repo.head();
149+
auto head_taget = head.target();
150+
if (git_oid_equal(head_taget, commit_oid))
151+
{
152+
refs.head_branch = head.short_name();
153+
}
154+
}
155+
156+
refs.tags = get_tags_for_commit(repo, commit_oid);
157+
refs.local_branches = get_branches_for_commit(repo, GIT_BRANCH_LOCAL, commit_oid, refs.head_branch);
158+
refs.remote_branches = get_branches_for_commit(repo, GIT_BRANCH_REMOTE, commit_oid, "");
159+
160+
return refs;
161+
}
162+
163+
void print_refs(commit_refs refs)
164+
{
165+
if (!refs.has_refs())
166+
{
167+
return;
168+
}
169+
170+
std::cout << " (";
171+
172+
bool first = true;
173+
174+
if (!refs.head_branch.empty())
175+
{
176+
std::cout << termcolor::bold << termcolor::cyan << "HEAD" << termcolor::reset
177+
<< termcolor::yellow << " -> " << termcolor::reset
178+
<< termcolor::bold << termcolor::green << refs.head_branch << termcolor::reset
179+
<< termcolor::yellow;
180+
first = false;
181+
}
182+
183+
for (const auto& tag :refs.tags)
184+
{
185+
if (!first)
186+
{
187+
std::cout << ", ";
188+
}
189+
std::cout << termcolor::bold << "tag: " << tag << termcolor::reset << termcolor::yellow;
190+
first = false;
191+
}
192+
193+
for (const auto& remote : refs.remote_branches)
194+
{
195+
if (!first)
196+
{
197+
std::cout << ", ";
198+
}
199+
std::cout << termcolor::bold << termcolor::red << remote << termcolor::reset << termcolor::yellow;
200+
first = false;
201+
}
202+
203+
for (const auto& local : refs.local_branches)
204+
{
205+
if (!first)
206+
{
207+
std::cout << ", ";
208+
}
209+
std::cout << termcolor::bold << termcolor::green << local << termcolor::reset << termcolor::yellow;
210+
first = false;
211+
}
212+
213+
std::cout << ")" << termcolor::reset;
214+
}
215+
216+
void print_commit(repository_wrapper& repo, const commit_wrapper& commit, std::string m_format_flag)
54217
{
55218
std::string buf = commit.commit_oid_tostr();
56219

57220
signature_wrapper author = signature_wrapper::get_commit_author(commit);
58221
signature_wrapper committer = signature_wrapper::get_commit_committer(commit);
59222

60223
stream_colour_fn colour = termcolor::yellow;
61-
std::cout << colour << "commit " << buf << termcolor::reset << std::endl;
224+
std::cout << colour << "commit " << buf;
225+
226+
commit_refs refs = get_refs_for_commit(repo, &commit.oid());
227+
print_refs(refs);
228+
229+
std::cout << termcolor::reset << std::endl;
230+
62231
if (m_format_flag=="fuller")
63232
{
64233
std::cout << "Author:\t " << author.name() << " " << author.email() << std::endl;
@@ -78,7 +247,7 @@ void print_commit(const commit_wrapper& commit, std::string m_format_flag)
78247
print_time(author.when(), "Date:\t");
79248
}
80249
}
81-
std::cout << "\n " << commit.message() << "\n" << std::endl;
250+
std::cout << "\n " << commit.message();
82251
}
83252

84253
void log_subcommand::run()
@@ -102,8 +271,12 @@ void log_subcommand::run()
102271
git_oid commit_oid;
103272
while (!walker.next(commit_oid) && i<m_max_count_flag)
104273
{
274+
if (i != 0)
275+
{
276+
std::cout << std::endl;
277+
}
105278
commit_wrapper commit = repo.find_commit(commit_oid);
106-
print_commit(commit, m_format_flag);
279+
print_commit(repo, commit, m_format_flag);
107280
++i;
108281
}
109282

0 commit comments

Comments
 (0)