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
84253void 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