From 66f629b3f144efdd39b8f171b7c7cca5ee309817 Mon Sep 17 00:00:00 2001 From: Sandrine Pataut Date: Tue, 24 Mar 2026 10:13:11 +0100 Subject: [PATCH 1/3] Add branches to push subcommand --- src/subcommand/push_subcommand.cpp | 144 ++++++++++++++++++++++++++--- src/subcommand/push_subcommand.hpp | 2 + src/utils/ansi_code.hpp | 3 + src/utils/credentials.cpp | 32 ++++++- src/utils/credentials.hpp | 9 ++ src/utils/progress.cpp | 8 +- src/utils/progress.hpp | 9 ++ src/wrapper/remote_wrapper.cpp | 40 +++++++- src/wrapper/remote_wrapper.hpp | 11 ++- src/wrapper/repository_wrapper.cpp | 20 +++- src/wrapper/repository_wrapper.hpp | 2 +- test/test_push.py | 99 +++++++++++++++++++- 12 files changed, 355 insertions(+), 24 deletions(-) diff --git a/src/subcommand/push_subcommand.cpp b/src/subcommand/push_subcommand.cpp index 9e2af17..c59e7e2 100644 --- a/src/subcommand/push_subcommand.cpp +++ b/src/subcommand/push_subcommand.cpp @@ -1,9 +1,13 @@ #include "../subcommand/push_subcommand.hpp" #include +#include +#include +#include -#include +#include +#include "../utils/ansi_code.hpp" #include "../utils/credentials.hpp" #include "../utils/progress.hpp" #include "../wrapper/repository_wrapper.hpp" @@ -13,8 +17,15 @@ push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app) auto* sub = app.add_subcommand("push", "Update remote refs along with associated objects"); sub->add_option("", m_remote_name, "The remote to push to")->default_val("origin"); - + sub->add_option("", m_branch_name, "The branch to push"); sub->add_option("", m_refspecs, "The refspec(s) to push"); + sub->add_flag( + "--all,--branches", + m_branches_flag, + "Push all branches (i.e. refs under " + ansi_code::bold + "refs/heads/" + ansi_code::reset + + "); cannot be used with other ." + ); + sub->callback( [this]() @@ -24,6 +35,15 @@ push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app) ); } +// TODO: put in common +static std::string oid_to_hex(const git_oid& oid) +{ + char oid_str[GIT_OID_SHA1_HEXSIZE + 1]; + git_oid_fmt(oid_str, &oid); + oid_str[GIT_OID_SHA1_HEXSIZE] = '\0'; + return std::string(oid_str); +} + void push_subcommand::run() { auto directory = get_current_git_path(); @@ -37,25 +57,127 @@ void push_subcommand::run() push_opts.callbacks.push_transfer_progress = push_transfer_progress; push_opts.callbacks.push_update_reference = push_update_reference; - if (m_refspecs.empty()) + if (m_branches_flag) { - try + auto iter = repo.iterate_branches(GIT_BRANCH_LOCAL); + auto br = iter.next(); + while (br) { - auto head_ref = repo.head(); - std::string short_name = head_ref.short_name(); - std::string refspec = "refs/heads/" + short_name; + std::string refspec = "refs/heads/" + std::string(br->name()); m_refspecs.push_back(refspec); + br = iter.next(); + } + } + else if (m_refspecs.empty()) + { + std::string branch; + if (!m_branch_name.empty()) + { + branch = m_branch_name; } - catch (...) + else { - std::cerr << "Could not determine current branch to push." << std::endl; - return; + try + { + auto head_ref = repo.head(); + branch = head_ref.short_name(); + } + catch (...) + { + std::cerr << "Could not determine current branch to push." << std::endl; + return; + } } + std::string refspec = "refs/heads/" + branch; + m_refspecs.push_back(refspec); } git_strarray_wrapper refspecs_wrapper(m_refspecs); git_strarray* refspecs_ptr = nullptr; refspecs_ptr = refspecs_wrapper; + // Take a snapshot of remote branches to check which ones are new after push + git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + callbacks.credentials = user_credentials; + credentials_payload creds_payload; + callbacks.payload = &creds_payload; + push_opts.callbacks.payload = &creds_payload; + + auto remote_heads = remote.list_heads(&callbacks); + + // Map with names of branches and their oids before push + std::unordered_map remote_heads_map; + for (const auto& h : remote_heads) + { + remote_heads_map.emplace(h.name, h.oid); + } + remote.push(refspecs_ptr, &push_opts); - std::cout << "Pushed to " << remote_name << std::endl; + + std::cout << "To " << remote.url() << std::endl; + for (const auto& refspec : m_refspecs) + { + std::string_view ref_view(refspec); + std::string_view prefix = "refs/heads/"; + std::string local_short_name; + if (ref_view.substr(0, prefix.size()) == prefix) + { + local_short_name = ref_view.substr(prefix.size()); + } + else + { + local_short_name = refspec; + } + + std::optional upstream_opt = repo.branch_upstream_name(local_short_name); + + std::string remote_branch = local_short_name; + std::string remote_ref = "refs/heads/" + local_short_name; + if (upstream_opt.has_value()) + { + const std::string up_name = upstream_opt.value(); + auto pos = up_name.find('/'); + if (pos != std::string::npos && pos + 1 < up_name.size()) + { + std::string up_remote = up_name.substr(0, pos); + std::string up_branch = up_name.substr(pos + 1); + if(up_remote == remote_name) + { + remote_branch = up_name.substr(pos + 1); + remote_ref = "refs/heads/" + remote_branch; + } + } + } + + auto iter = remote_heads_map.find(remote_ref); + if (iter == remote_heads_map.end()) + { + std::cout << " * [new branch] " << local_short_name << " -> " << remote_branch << std::endl; + continue; + } + + git_oid remote_oid = iter->second; + + std::optional local_oid_opt; + if (auto ref_opt = repo.find_reference_dwim(("refs/heads/" + local_short_name))) + { + const git_oid* target = ref_opt->target(); + local_oid_opt = *target; // TODO: pas comprenu pourquoi je ne peux pas faire local_oid_opt = ref_opt->target(); + } + + if (!local_oid_opt) + { + std::cout << " " << local_short_name << " -> " << remote_branch << std::endl; + continue; + } + git_oid local_oid = local_oid_opt.value(); + + if (!git_oid_equal(&remote_oid, &local_oid)) + { + std::string old_hex = oid_to_hex(remote_oid); + std::string new_hex = oid_to_hex(local_oid); + // TODO: check order of hex codes + std::cout << " " << old_hex.substr(0, 7) << ".." << new_hex.substr(0, 7) + << " " << local_short_name << " -> " << local_short_name << std::endl; + } + } } diff --git a/src/subcommand/push_subcommand.hpp b/src/subcommand/push_subcommand.hpp index 07c301e..c4450bf 100644 --- a/src/subcommand/push_subcommand.hpp +++ b/src/subcommand/push_subcommand.hpp @@ -17,5 +17,7 @@ class push_subcommand private: std::string m_remote_name; + std::string m_branch_name; std::vector m_refspecs; + bool m_branches_flag = false; }; diff --git a/src/utils/ansi_code.hpp b/src/utils/ansi_code.hpp index 90b1e25..becc5a9 100644 --- a/src/utils/ansi_code.hpp +++ b/src/utils/ansi_code.hpp @@ -19,6 +19,9 @@ namespace ansi_code const std::string hide_cursor = "\e[?25l"; const std::string show_cursor = "\e[?25h"; + const std::string bold = "\033[1m"; + const std::string reset = "\033[0m"; + // Functions. std::string cursor_to_row(size_t row); diff --git a/src/utils/credentials.cpp b/src/utils/credentials.cpp index c8d43e3..8c9ae74 100644 --- a/src/utils/credentials.cpp +++ b/src/utils/credentials.cpp @@ -15,6 +15,8 @@ int user_credentials( void* payload ) { + credentials_payload* cached = payload ? static_cast(payload) : nullptr; + // Check for cached credentials here, if desired. // It might be necessary to make this function stateful to avoid repeating unnecessary checks. @@ -22,11 +24,24 @@ int user_credentials( if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) { - std::string username = username_from_url ? username_from_url : ""; - if (username.empty()) + std::string username; + if (username_from_url && username_from_url[0] != '\0') + { + username = username_from_url; + } + else if (cached && cached->username.has_value()) + { + username = *cached->username; + } + else { username = prompt_input("Username: "); + if (cached && !username.empty()) + { + cached->username = username; + } } + if (username.empty()) { giterr_set_str(GIT_ERROR_HTTP, "No username specified"); @@ -34,6 +49,19 @@ int user_credentials( } std::string password = prompt_input("Password: ", false); + if (cached && cached->password.has_value()) + { + password = *cached->password; + } + else + { + password = prompt_input("Password: ", false); + if (cached && !password.empty()) + { + cached->password = password; + } + } + if (password.empty()) { giterr_set_str(GIT_ERROR_HTTP, "No password specified"); diff --git a/src/utils/credentials.hpp b/src/utils/credentials.hpp index ba970e6..f7a9fb8 100644 --- a/src/utils/credentials.hpp +++ b/src/utils/credentials.hpp @@ -1,7 +1,16 @@ #pragma once +#include +#include + #include +struct credentials_payload +{ + std::optional username; + std::optional password; +}; + // Libgit2 callback of type git_credential_acquire_cb to obtain user credentials // (username and password) to authenticate remote https access. int user_credentials( diff --git a/src/utils/progress.cpp b/src/utils/progress.cpp index 12b7c63..9af2d13 100644 --- a/src/utils/progress.cpp +++ b/src/utils/progress.cpp @@ -139,11 +139,9 @@ int push_update_reference(const char* refname, const char* status, void*) { if (status) { - std::cout << " " << refname << " " << status << std::endl; - } - else - { - std::cout << " " << refname << std::endl; + std::cout << " ! [remote rejected] " << refname << " (" << status << ")" << std::endl; + return -1; } + return 0; } diff --git a/src/utils/progress.hpp b/src/utils/progress.hpp index 861c8d9..fc70509 100644 --- a/src/utils/progress.hpp +++ b/src/utils/progress.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include int sideband_progress(const char* str, int len, void*); @@ -7,4 +9,11 @@ int fetch_progress(const git_indexer_progress* stats, void* payload); void checkout_progress(const char* path, size_t cur, size_t tot, void* payload); int update_refs(const char* refname, const git_oid* a, const git_oid* b, git_refspec*, void*); int push_transfer_progress(unsigned int current, unsigned int total, size_t bytes, void*); + +struct push_update_payload +{ + std::string url; + bool header_printed = false; +}; + int push_update_reference(const char* refname, const char* status, void*); diff --git a/src/wrapper/remote_wrapper.cpp b/src/wrapper/remote_wrapper.cpp index 3f603dd..7ec5d85 100644 --- a/src/wrapper/remote_wrapper.cpp +++ b/src/wrapper/remote_wrapper.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "../utils/git_exception.hpp" remote_wrapper::remote_wrapper(git_remote* remote) @@ -62,3 +60,41 @@ void remote_wrapper::push(const git_strarray* refspecs, const git_push_options* { throw_if_error(git_remote_push(*this, refspecs, opts)); } + +void remote_wrapper::connect(git_direction direction, const git_remote_callbacks* callbacks) const +{ + throw_if_error(git_remote_connect(*this, direction, callbacks, nullptr, nullptr)); +} + +std::vector remote_wrapper::list_heads(const git_remote_callbacks* callbacks = nullptr) const +{ + std::vector result; + + this->connect(GIT_DIRECTION_FETCH, callbacks); + + const git_remote_head** heads = nullptr; + size_t heads_len = 0; + int err = git_remote_ls(&heads, &heads_len, *this); + if (err != 0) + { + git_remote_disconnect(*this); + throw_if_error(err); + } + + for (size_t i = 0; i < heads_len; ++i) + { + const git_remote_head* h = heads[i]; + if (!h || !h->name) + { + continue; + } + + remote_head rh; + rh.name = std::string(h->name); + rh.oid = h->oid; + result.push_back(std::move(rh)); + } + + git_remote_disconnect(*this); + return result; +} diff --git a/src/wrapper/remote_wrapper.hpp b/src/wrapper/remote_wrapper.hpp index a933fb8..1337072 100644 --- a/src/wrapper/remote_wrapper.hpp +++ b/src/wrapper/remote_wrapper.hpp @@ -1,13 +1,19 @@ #pragma once +#include #include #include #include -#include #include "../wrapper/wrapper_base.hpp" +struct remote_head +{ + std::string name; + git_oid oid; +}; + class remote_wrapper : public wrapper_base { public: @@ -27,6 +33,9 @@ class remote_wrapper : public wrapper_base void fetch(const git_strarray* refspecs, const git_fetch_options* opts, const char* reflog_message); void push(const git_strarray* refspecs, const git_push_options* opts); + void connect(git_direction direction, const git_remote_callbacks* callbacks) const; + + std::vector list_heads(const git_remote_callbacks* callbacks) const; private: diff --git a/src/wrapper/repository_wrapper.cpp b/src/wrapper/repository_wrapper.cpp index ccc0408..81b8372 100644 --- a/src/wrapper/repository_wrapper.cpp +++ b/src/wrapper/repository_wrapper.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "../utils/git_exception.hpp" #include "../wrapper/commit_wrapper.hpp" @@ -194,6 +197,21 @@ std::optional repository_wrapper::upstream() const } } +std::optional repository_wrapper::branch_upstream_name(std::string local_branch) const +{ + git_buf buf = GIT_BUF_INIT; + int error = git_branch_upstream_name(&buf, *this, local_branch.c_str()); + if (error != 0) + { + git_buf_dispose(&buf); + return std::nullopt; + } + + std::string result(buf.ptr ? buf.ptr : ""); + git_buf_dispose(&buf); + return result; +} + branch_tracking_info repository_wrapper::get_tracking_info() const { branch_tracking_info info; @@ -426,7 +444,7 @@ size_t repository_wrapper::shallow_depth_from_head() const if (parent_list.size() > 0u) { has_parent = true; - for (size_t j = 0u; parent_list.size(); j++) + for (size_t j = 0u; j < parent_list.size(); ++j) { const commit_wrapper& c = parent_list[j]; temp_commits_list.push_back(std::move(const_cast(c))); diff --git a/src/wrapper/repository_wrapper.hpp b/src/wrapper/repository_wrapper.hpp index d630343..429617b 100644 --- a/src/wrapper/repository_wrapper.hpp +++ b/src/wrapper/repository_wrapper.hpp @@ -6,7 +6,6 @@ #include -#include "../utils/common.hpp" #include "../utils/git_exception.hpp" #include "../wrapper/annotated_commit_wrapper.hpp" #include "../wrapper/branch_wrapper.hpp" @@ -74,6 +73,7 @@ class repository_wrapper : public wrapper_base branch_wrapper find_branch(std::string_view name) const; branch_iterator iterate_branches(git_branch_t type) const; std::optional upstream() const; + std::optional branch_upstream_name(std::string local_branch) const; branch_tracking_info get_tracking_info() const; // Commits diff --git a/test/test_push.py b/test/test_push.py index 313f201..3d2177d 100644 --- a/test/test_push.py +++ b/test/test_push.py @@ -61,4 +61,101 @@ def test_push_private_repo( assert p_push.returncode == 0 assert p_push.stdout.count("Username:") == 2 assert p_push.stdout.count("Password:") == 2 - assert "Pushed to origin" in p_push.stdout + assert " * [new branch] test-" in p_push.stdout + print(p_push.stdout) + + +def test_push_branch_private_repo( + git2cpp_path, tmp_path, run_in_tmp_path, private_test_repo, commit_env_config +): + """Test push with an explicit branch name: git2cpp push .""" + branch_name = f"test-{uuid4()}" + + username = "abc" + password = private_test_repo["token"] + input = f"{username}\n{password}" + repo_path = tmp_path / private_test_repo["repo_name"] + url = private_test_repo["https_url"] + + # Clone the private repo. + clone_cmd = [git2cpp_path, "clone", url] + p_clone = subprocess.run(clone_cmd, capture_output=True, text=True, input=input) + assert p_clone.returncode == 0 + assert repo_path.exists() + + # Create a new branch and commit on it. + checkout_cmd = [git2cpp_path, "checkout", "-b", branch_name] + p_checkout = subprocess.run(checkout_cmd, cwd=repo_path, capture_output=True, text=True) + assert p_checkout.returncode == 0 + + (repo_path / "push_branch_file.txt").write_text("push branch test") + subprocess.run([git2cpp_path, "add", "push_branch_file.txt"], cwd=repo_path, check=True) + subprocess.run([git2cpp_path, "commit", "-m", "branch commit"], cwd=repo_path, check=True) + + # Switch back to main so HEAD is NOT on the branch we want to push. + subprocess.run( + [git2cpp_path, "checkout", "main"], capture_output=True, check=True, cwd=repo_path + ) + + status_cmd = [git2cpp_path, "status"] + p_status = subprocess.run(status_cmd, cwd=repo_path, capture_output=True, text=True) + assert p_status.returncode == 0 + assert "On branch main" in p_status.stdout + + # Push specifying the branch explicitly (HEAD is on main, not the test branch). + input = f"{username}\n{password}" + push_cmd = [git2cpp_path, "push", "origin", branch_name] + p_push = subprocess.run(push_cmd, cwd=repo_path, capture_output=True, text=True, input=input) + assert p_push.returncode == 0 + assert " * [new branch] test-" in p_push.stdout + print("\n\n", p_push.stdout) + + +def test_push_branches_flag_private_repo( + git2cpp_path, tmp_path, run_in_tmp_path, private_test_repo, commit_env_config +): + """Test push --branches pushes all local branches.""" + branch_a = f"test-a-{uuid4()}" + branch_b = f"test-b-{uuid4()}" + + username = "abc" + password = private_test_repo["token"] + input = f"{username}\n{password}" + repo_path = tmp_path / private_test_repo["repo_name"] + url = private_test_repo["https_url"] + + # Clone the private repo. + clone_cmd = [git2cpp_path, "clone", url] + p_clone = subprocess.run(clone_cmd, capture_output=True, text=True, input=input) + assert p_clone.returncode == 0 + assert repo_path.exists() + + # Create two extra branches with commits. + for branch_name in [branch_a, branch_b]: + subprocess.run( + [git2cpp_path, "checkout", "-b", branch_name], + capture_output=True, + check=True, + cwd=repo_path, + ) + (repo_path / f"{branch_name}.txt").write_text(f"content for {branch_name}") + subprocess.run([git2cpp_path, "add", f"{branch_name}.txt"], cwd=repo_path, check=True) + subprocess.run( + [git2cpp_path, "commit", "-m", f"commit on {branch_name}"], + cwd=repo_path, + check=True, + ) + + # Go back to main. + subprocess.run( + [git2cpp_path, "checkout", "main"], capture_output=True, check=True, cwd=repo_path + ) + + # Push all branches at once. + input = f"{username}\n{password}" + push_cmd = [git2cpp_path, "push", "origin", "--branches"] + p_push = subprocess.run(push_cmd, cwd=repo_path, capture_output=True, text=True, input=input) + assert p_push.returncode == 0 + assert " * [new branch] test-" in p_push.stdout + # assert "main" not in p_push.stdout + print("\n\n", p_push.stdout) From 81d859a8c7207b049ca9c4e93c4a69a7a8b80d7b Mon Sep 17 00:00:00 2001 From: Sandrine Pataut Date: Thu, 2 Apr 2026 15:31:52 +0200 Subject: [PATCH 2/3] change of plan --- src/subcommand/push_subcommand.cpp | 71 ++++++++++++++++-------------- src/subcommand/push_subcommand.hpp | 1 - src/utils/credentials.cpp | 32 +------------- src/utils/credentials.hpp | 9 ---- src/wrapper/repository_wrapper.cpp | 24 ++++++++++ src/wrapper/repository_wrapper.hpp | 2 + 6 files changed, 67 insertions(+), 72 deletions(-) diff --git a/src/subcommand/push_subcommand.cpp b/src/subcommand/push_subcommand.cpp index c59e7e2..c7ec456 100644 --- a/src/subcommand/push_subcommand.cpp +++ b/src/subcommand/push_subcommand.cpp @@ -1,8 +1,9 @@ #include "../subcommand/push_subcommand.hpp" +#include #include #include -#include +#include #include #include @@ -17,7 +18,6 @@ push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app) auto* sub = app.add_subcommand("push", "Update remote refs along with associated objects"); sub->add_option("", m_remote_name, "The remote to push to")->default_val("origin"); - sub->add_option("", m_branch_name, "The branch to push"); sub->add_option("", m_refspecs, "The refspec(s) to push"); sub->add_flag( "--all,--branches", @@ -71,22 +71,15 @@ void push_subcommand::run() else if (m_refspecs.empty()) { std::string branch; - if (!m_branch_name.empty()) + try { - branch = m_branch_name; + auto head_ref = repo.head(); + branch = head_ref.short_name(); } - else + catch (...) { - try - { - auto head_ref = repo.head(); - branch = head_ref.short_name(); - } - catch (...) - { - std::cerr << "Could not determine current branch to push." << std::endl; - return; - } + std::cerr << "Could not determine current branch to push." << std::endl; + return; } std::string refspec = "refs/heads/" + branch; m_refspecs.push_back(refspec); @@ -95,20 +88,34 @@ void push_subcommand::run() git_strarray* refspecs_ptr = nullptr; refspecs_ptr = refspecs_wrapper; - // Take a snapshot of remote branches to check which ones are new after push - git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; - callbacks.credentials = user_credentials; - credentials_payload creds_payload; - callbacks.payload = &creds_payload; - push_opts.callbacks.payload = &creds_payload; - - auto remote_heads = remote.list_heads(&callbacks); + // // Take a snapshot of remote branches to check which ones are new after push + // git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + // callbacks.credentials = user_credentials; + // credentials_payload creds_payload; + // callbacks.payload = &creds_payload; + // push_opts.callbacks.payload = &creds_payload; + // auto remote_heads = remote.list_heads(&callbacks); + // + // // Map with names of branches and their oids before push - std::unordered_map remote_heads_map; - for (const auto& h : remote_heads) + // std::unordered_map remote_heads_map; + // for (const auto& h : remote_heads) + // { + // remote_heads_map.emplace(h.name, h.oid); + // } + + // Take a snapshot of repo's references to check which ones are new after push + auto repo_refs = repo.reference_list(); + std::vector repo_refs_remote; + for (int i = 0; i < repo_refs.size(); ++i) { - remote_heads_map.emplace(h.name, h.oid); + std::string prefix_remote = "refs/remote/"; + if (repo_refs[i].substr(0, prefix_remote.size()) == prefix_remote) + { + std::string remote_short_name = repo_refs[i].substr(prefix_remote.size()); + repo_refs_remote.push_back(remote_short_name); + } } remote.push(refspecs_ptr, &push_opts); @@ -117,11 +124,11 @@ void push_subcommand::run() for (const auto& refspec : m_refspecs) { std::string_view ref_view(refspec); - std::string_view prefix = "refs/heads/"; + std::string_view prefix_local = "refs/heads/"; std::string local_short_name; - if (ref_view.substr(0, prefix.size()) == prefix) + if (ref_view.substr(0, prefix_local.size()) == prefix_local) { - local_short_name = ref_view.substr(prefix.size()); + local_short_name = ref_view.substr(prefix_local.size()); } else { @@ -148,14 +155,14 @@ void push_subcommand::run() } } - auto iter = remote_heads_map.find(remote_ref); - if (iter == remote_heads_map.end()) + auto iter = std::find(repo_refs_remote.begin(), repo_refs_remote.end(), remote_ref); + if (iter == repo_refs_remote.end()) { std::cout << " * [new branch] " << local_short_name << " -> " << remote_branch << std::endl; continue; } - git_oid remote_oid = iter->second; + git_oid remote_oid = repo.ref_name_to_id(*iter); std::optional local_oid_opt; if (auto ref_opt = repo.find_reference_dwim(("refs/heads/" + local_short_name))) diff --git a/src/subcommand/push_subcommand.hpp b/src/subcommand/push_subcommand.hpp index c4450bf..615931e 100644 --- a/src/subcommand/push_subcommand.hpp +++ b/src/subcommand/push_subcommand.hpp @@ -17,7 +17,6 @@ class push_subcommand private: std::string m_remote_name; - std::string m_branch_name; std::vector m_refspecs; bool m_branches_flag = false; }; diff --git a/src/utils/credentials.cpp b/src/utils/credentials.cpp index 8c9ae74..c8d43e3 100644 --- a/src/utils/credentials.cpp +++ b/src/utils/credentials.cpp @@ -15,8 +15,6 @@ int user_credentials( void* payload ) { - credentials_payload* cached = payload ? static_cast(payload) : nullptr; - // Check for cached credentials here, if desired. // It might be necessary to make this function stateful to avoid repeating unnecessary checks. @@ -24,24 +22,11 @@ int user_credentials( if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) { - std::string username; - if (username_from_url && username_from_url[0] != '\0') - { - username = username_from_url; - } - else if (cached && cached->username.has_value()) - { - username = *cached->username; - } - else + std::string username = username_from_url ? username_from_url : ""; + if (username.empty()) { username = prompt_input("Username: "); - if (cached && !username.empty()) - { - cached->username = username; - } } - if (username.empty()) { giterr_set_str(GIT_ERROR_HTTP, "No username specified"); @@ -49,19 +34,6 @@ int user_credentials( } std::string password = prompt_input("Password: ", false); - if (cached && cached->password.has_value()) - { - password = *cached->password; - } - else - { - password = prompt_input("Password: ", false); - if (cached && !password.empty()) - { - cached->password = password; - } - } - if (password.empty()) { giterr_set_str(GIT_ERROR_HTTP, "No password specified"); diff --git a/src/utils/credentials.hpp b/src/utils/credentials.hpp index f7a9fb8..ba970e6 100644 --- a/src/utils/credentials.hpp +++ b/src/utils/credentials.hpp @@ -1,16 +1,7 @@ #pragma once -#include -#include - #include -struct credentials_payload -{ - std::optional username; - std::optional password; -}; - // Libgit2 callback of type git_credential_acquire_cb to obtain user credentials // (username and password) to authenticate remote https access. int user_credentials( diff --git a/src/wrapper/repository_wrapper.cpp b/src/wrapper/repository_wrapper.cpp index 81b8372..e631a16 100644 --- a/src/wrapper/repository_wrapper.cpp +++ b/src/wrapper/repository_wrapper.cpp @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include #include "../utils/git_exception.hpp" #include "../wrapper/commit_wrapper.hpp" @@ -137,6 +141,26 @@ std::optional repository_wrapper::find_reference_dwim(std::st return rc == 0 ? std::make_optional(reference_wrapper(ref)) : std::nullopt; } +std::vector repository_wrapper::reference_list() const +{ + git_strarray* array; + throw_if_error(git_reference_list(array, *this)); + std::vector result; + for (size_t i = 0; i < array->count; ++i) + { + result.push_back(array->strings[i]); + } + git_strarray_free(array); + return result; +} + +const git_oid& repository_wrapper::ref_name_to_id(std::string ref_name) const +{ + git_oid* ref_id; + throw_if_error(git_reference_name_to_id(ref_id, *this, ref_name.c_str())); + return *ref_id; +} + // Index index_wrapper repository_wrapper::make_index() diff --git a/src/wrapper/repository_wrapper.hpp b/src/wrapper/repository_wrapper.hpp index 429617b..9ca193c 100644 --- a/src/wrapper/repository_wrapper.hpp +++ b/src/wrapper/repository_wrapper.hpp @@ -62,6 +62,8 @@ class repository_wrapper : public wrapper_base // References reference_wrapper find_reference(std::string_view ref_name) const; std::optional find_reference_dwim(std::string_view ref_name) const; + std::vector reference_list() const; + const git_oid& ref_name_to_id(std::string ref_name) const; // Index index_wrapper make_index(); From c20f6377cbe0ca087f26c571e2c3c62e95669755 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:32:07 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/subcommand/push_subcommand.cpp | 9 +++++---- src/wrapper/repository_wrapper.cpp | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/subcommand/push_subcommand.cpp b/src/subcommand/push_subcommand.cpp index c7ec456..dcd3b32 100644 --- a/src/subcommand/push_subcommand.cpp +++ b/src/subcommand/push_subcommand.cpp @@ -147,7 +147,7 @@ void push_subcommand::run() { std::string up_remote = up_name.substr(0, pos); std::string up_branch = up_name.substr(pos + 1); - if(up_remote == remote_name) + if (up_remote == remote_name) { remote_branch = up_name.substr(pos + 1); remote_ref = "refs/heads/" + remote_branch; @@ -168,7 +168,8 @@ void push_subcommand::run() if (auto ref_opt = repo.find_reference_dwim(("refs/heads/" + local_short_name))) { const git_oid* target = ref_opt->target(); - local_oid_opt = *target; // TODO: pas comprenu pourquoi je ne peux pas faire local_oid_opt = ref_opt->target(); + local_oid_opt = *target; // TODO: pas comprenu pourquoi je ne peux pas faire local_oid_opt = + // ref_opt->target(); } if (!local_oid_opt) @@ -183,8 +184,8 @@ void push_subcommand::run() std::string old_hex = oid_to_hex(remote_oid); std::string new_hex = oid_to_hex(local_oid); // TODO: check order of hex codes - std::cout << " " << old_hex.substr(0, 7) << ".." << new_hex.substr(0, 7) - << " " << local_short_name << " -> " << local_short_name << std::endl; + std::cout << " " << old_hex.substr(0, 7) << ".." << new_hex.substr(0, 7) << " " + << local_short_name << " -> " << local_short_name << std::endl; } } } diff --git a/src/wrapper/repository_wrapper.cpp b/src/wrapper/repository_wrapper.cpp index e631a16..6246865 100644 --- a/src/wrapper/repository_wrapper.cpp +++ b/src/wrapper/repository_wrapper.cpp @@ -5,6 +5,7 @@ #include #include #include + #include #include #include