11#include " ../subcommand/push_subcommand.hpp"
22
33#include < iostream>
4+ #include < unordered_map>
45
56#include < git2/remote.h>
67
8+ #include " ../utils/ansi_code.hpp"
79#include " ../utils/credentials.hpp"
810#include " ../utils/progress.hpp"
911#include " ../wasm/scope.hpp"
@@ -14,8 +16,14 @@ push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app)
1416 auto * sub = app.add_subcommand (" push" , " Update remote refs along with associated objects" );
1517
1618 sub->add_option (" <remote>" , m_remote_name, " The remote to push to" )->default_val (" origin" );
17-
18- sub->add_option (" <refspec>" , m_refspecs, " The refspec(s) to push" );
19+ sub->add_option (" <refspec>" , m_refspecs, " The refspec(s) to push" )
20+ ->expected (0 ,-1 );
21+ sub->add_flag (
22+ " --all,--branches" ,
23+ m_branches_flag,
24+ " Push all branches (i.e. refs under " + ansi_code::bold + " refs/heads/" + ansi_code::reset
25+ + " ); cannot be used with other <refspec>."
26+ );
1927
2028 sub->callback (
2129 [this ]()
@@ -25,6 +33,15 @@ push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app)
2533 );
2634}
2735
36+ // TODO: put in common
37+ static std::string oid_to_hex (const git_oid& oid)
38+ {
39+ char oid_str[GIT_OID_SHA1_HEXSIZE + 1 ];
40+ git_oid_fmt (oid_str, &oid);
41+ oid_str[GIT_OID_SHA1_HEXSIZE] = ' \0 ' ;
42+ return std::string (oid_str);
43+ }
44+
2845void push_subcommand::run ()
2946{
3047 wasm_http_transport_scope transport; // Enables wasm http(s) transport.
@@ -40,25 +57,133 @@ void push_subcommand::run()
4057 push_opts.callbacks .push_transfer_progress = push_transfer_progress;
4158 push_opts.callbacks .push_update_reference = push_update_reference;
4259
43- if (m_refspecs.empty ())
60+ if (m_branches_flag)
61+ {
62+ auto iter = repo.iterate_branches (GIT_BRANCH_LOCAL);
63+ auto br = iter.next ();
64+ while (br)
65+ {
66+ std::string refspec = " refs/heads/" + std::string (br->name ());
67+ m_refspecs.push_back (refspec);
68+ br = iter.next ();
69+ }
70+ }
71+ else if (m_refspecs.empty ())
4472 {
73+ std::string branch;
4574 try
4675 {
4776 auto head_ref = repo.head ();
48- std::string short_name = head_ref.short_name ();
49- std::string refspec = " refs/heads/" + short_name;
50- m_refspecs.push_back (refspec);
77+ branch = head_ref.short_name ();
5178 }
5279 catch (...)
5380 {
5481 std::cerr << " Could not determine current branch to push." << std::endl;
5582 return ;
5683 }
84+ std::string refspec = " refs/heads/" + branch;
85+ m_refspecs.push_back (refspec);
86+ }
87+ else
88+ {
89+ for (auto & r : m_refspecs)
90+ {
91+ if (r.rfind (" refs/" , 0 ) == 0 )
92+ {
93+ continue ;
94+ }
95+
96+ r = " refs/heads/" + r;
97+ }
5798 }
5899 git_strarray_wrapper refspecs_wrapper (m_refspecs);
59- git_strarray* refspecs_ptr = nullptr ;
60- refspecs_ptr = refspecs_wrapper;
100+ git_strarray* refspecs_ptr = refspecs_wrapper;
101+
102+ // Take a snapshot of repo's references to check which ones are new after push
103+ auto repo_refs = repo.reference_list ();
104+ std::unordered_map<std::string, git_oid> remote_refs_before_oids;
105+ const std::string prefix = std::string (" refs/remotes/" ) + remote_name + " /" ;
106+ for (const auto &r : repo_refs)
107+ {
108+ if (r.size () > prefix.size () && r.compare (0 , prefix.size (), prefix) == 0 )
109+ {
110+ // r is like "refs/remotes/origin/main"
111+ std::string short_name = r.substr (prefix.size ()); // "main" or "feature/x"
112+ std::string canonical_remote_ref = std::string (" refs/heads/" ) + short_name;
113+
114+ git_oid oid = repo.ref_name_to_id (r);
115+ remote_refs_before_oids.emplace (std::move (canonical_remote_ref), oid);
116+ }
117+ }
61118
62119 remote.push (refspecs_ptr, &push_opts);
63- std::cout << " Pushed to " << remote_name << std::endl;
120+
121+ std::cout << " To " << remote.url () << std::endl;
122+ for (const auto & refspec : m_refspecs)
123+ {
124+ std::string_view ref_view (refspec);
125+ std::string_view prefix_local = " refs/heads/" ;
126+ std::string local_short_name;
127+ if (ref_view.size () >= prefix_local.size () && ref_view.substr (0 , prefix_local.size ()) == prefix_local)
128+ {
129+ local_short_name = std::string (ref_view.substr (prefix_local.size ()));
130+ }
131+ else
132+ {
133+ local_short_name = std::string (refspec);
134+ }
135+
136+ std::optional<std::string> upstream_opt = repo.branch_upstream_name (local_short_name);
137+
138+ std::string remote_branch = local_short_name;
139+ std::string canonical_remote_ref = " refs/heads/" + local_short_name;
140+ if (upstream_opt.has_value ())
141+ {
142+ const std::string up_name = upstream_opt.value ();
143+ auto pos = up_name.find (' /' );
144+ if (pos != std::string::npos && pos + 1 < up_name.size ())
145+ {
146+ std::string up_remote = up_name.substr (0 , pos);
147+ std::string up_branch = up_name.substr (pos + 1 );
148+ if (up_remote == remote_name)
149+ {
150+ remote_branch = up_branch;
151+ canonical_remote_ref = " refs/heads/" + remote_branch;
152+ }
153+ }
154+ }
155+
156+ auto it = remote_refs_before_oids.find (canonical_remote_ref);
157+ if (it == remote_refs_before_oids.end ())
158+ {
159+ std::cout << " * [new branch] " << local_short_name << " -> " << remote_branch << std::endl;
160+ continue ;
161+ }
162+
163+ git_oid remote_oid = it->second ;
164+
165+ std::optional<git_oid> local_oid_opt;
166+ if (auto ref_opt = repo.find_reference_dwim ((" refs/heads/" + local_short_name)))
167+ {
168+ const git_oid* target = ref_opt->target ();
169+ local_oid_opt = *target; // TODO: pas comprenu pourquoi je ne peux pas faire local_oid_opt =
170+ // ref_opt->target();
171+ }
172+
173+ if (!local_oid_opt)
174+ {
175+ std::cout << " " << local_short_name << " -> " << remote_branch << std::endl;
176+ continue ;
177+ }
178+ git_oid local_oid = local_oid_opt.value ();
179+
180+ if (!git_oid_equal (&remote_oid, &local_oid))
181+ {
182+ std::string old_hex = oid_to_hex (remote_oid);
183+ std::string new_hex = oid_to_hex (local_oid);
184+ // TODO: check order of hex codes
185+ std::cout << " " << old_hex.substr (0 , 7 ) << " .." << new_hex.substr (0 , 7 ) << " "
186+ << local_short_name << " -> " << local_short_name << std::endl;
187+ }
188+ }
64189}
0 commit comments