Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 98 additions & 10 deletions src/subcommand/push_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#include "../subcommand/push_subcommand.hpp"

#include <iostream>
#include <optional>

#include <git2/net.h>
#include <git2/remote.h>
#include <git2/types.h>

#include "../utils/ansi_code.hpp"
#include "../utils/credentials.hpp"
#include "../utils/progress.hpp"
#include "../wrapper/repository_wrapper.hpp"
Expand All @@ -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("<remote>", m_remote_name, "The remote to push to")->default_val("origin");

sub->add_option("<branch>", m_branch_name, "The branch to push");
sub->add_option("<refspec>", 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 <refspec>."
);


sub->callback(
[this]()
Expand All @@ -24,6 +35,15 @@ push_subcommand::push_subcommand(const libgit2_object&, CLI::App& app)
);
}

int credential_cb(git_cred** out, const char* url, const char* username_from_url, unsigned int allowed_types, void* payload)
{
// Replace with your actual credentials
const char* username = user_credentials;
const char* password = "your_password_or_token";

return git_cred_userpass_plaintext_new(out, username, password);
}

void push_subcommand::run()
{
auto directory = get_current_git_path();
Expand All @@ -32,30 +52,98 @@ void push_subcommand::run()
std::string remote_name = m_remote_name.empty() ? "origin" : m_remote_name;
auto remote = repo.find_remote(remote_name);

git_direction direction = GIT_DIRECTION_FETCH;

// remote.connect(direction, );
// auto remote_branches_ante_push = remote.ls();

git_push_options push_opts = GIT_PUSH_OPTIONS_INIT;
push_opts.callbacks.credentials = user_credentials;
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;

remote.push(refspecs_ptr, &push_opts);
std::cout << "Pushed to " << remote_name << std::endl;
auto remote_branches_post_push = remote.ls();

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 short_name;
if (ref_view.substr(0, prefix.size()) == prefix)
{
short_name = ref_view.substr(prefix.size());
}
else
{
short_name = refspec;
}

// std::optional<std::string> branch_upstream_name = repo.branch_upstream_name(short_name);
std::string upstream_name;
upstream_name = short_name;
// if (branch_upstream_name.has_value())
// {
// upstream_name = branch_upstream_name.value();
// }
// else
// {
// // ???
// }
// if (std::find(remote_branches.begin(), remote_branches.end(), short_name) == remote_branches.end())
// {
// std::cout << " * [new branch] " << short_name << " -> " << short_name << std::endl;
// }
//
// if (std::find(remote_branches.begin(), remote_branches.end(), short_name) == remote_branches.end())
// {
// std::cout << " * [new branch] " << short_name << " -> " << short_name << std::endl;
// }

auto ref = repo.find_reference(ref_view);
if (!ref.is_remote())
{
std::cout << " * [new branch] " << short_name << " -> " << upstream_name << std::endl;
}
// std::cout << " * [new branch] " << short_name << " -> " << short_name << std::endl;
}
}
2 changes: 2 additions & 0 deletions src/subcommand/push_subcommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ class push_subcommand
private:

std::string m_remote_name;
std::string m_branch_name;
std::vector<std::string> m_refspecs;
bool m_branches_flag = false;
};
3 changes: 3 additions & 0 deletions src/utils/ansi_code.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 3 additions & 5 deletions src/utils/progress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
9 changes: 9 additions & 0 deletions src/utils/progress.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
#pragma once

#include <string>

#include <git2.h>

int sideband_progress(const char* str, int len, void*);
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*);
38 changes: 38 additions & 0 deletions src/wrapper/remote_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <vector>

#include <git2/remote.h>
#include <git2/types.h>

#include "../utils/git_exception.hpp"

Expand Down Expand Up @@ -53,6 +54,43 @@ std::vector<std::string> remote_wrapper::refspecs() const
return result;
}

std::vector<const git_remote_head*> remote_wrapper::ls() const
{
const git_remote_head** remote_heads;
size_t remote_heads_size;
throw_if_error(git_remote_ls(&remote_heads, &remote_heads_size, *this));

std::vector<const git_remote_head*> remote_heads_vec;
for (size_t i = 0; i < remote_heads_size; i++)
{
remote_heads_vec.push_back(remote_heads[i]);
}
return remote_heads_vec;
}

// std::vector<std::string> remote_wrapper::ls() const
// {
// const git_remote_head** remote_heads;
// size_t remote_heads_size;
// throw_if_error(git_remote_ls(&remote_heads, &remote_heads_size, *this));

// std::vector<std::string> remote_branches;
// for (size_t i = 0; i < remote_heads_size; i++)
// {
// const git_remote_head* head = remote_heads[i];
// if (!head->local)
// {
// remote_branches.push_back(head->name);
// }
// }
// return remote_branches;
// }

void remote_wrapper::connect(git_direction direction, const git_remote_callbacks* callbacks)
{
throw_if_error(git_remote_connect(*this, direction, callbacks, NULL, NULL));
}

void remote_wrapper::fetch(const git_strarray* refspecs, const git_fetch_options* opts, const char* reflog_message)
{
throw_if_error(git_remote_fetch(*this, refspecs, opts, reflog_message));
Expand Down
4 changes: 4 additions & 0 deletions src/wrapper/remote_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ class remote_wrapper : public wrapper_base<git_remote>

std::vector<std::string> refspecs() const;

std::vector<const git_remote_head*> ls() const;
// std::vector<std::string> ls() const;

void connect(git_direction direction, const git_remote_callbacks* callbacks);
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);

Expand Down
19 changes: 19 additions & 0 deletions src/wrapper/repository_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#include <algorithm>
#include <fstream>
#include <iostream>
#include <optional>
#include <string_view>

#include <git2/buffer.h>

#include "../utils/git_exception.hpp"
#include "../wrapper/commit_wrapper.hpp"
Expand Down Expand Up @@ -194,6 +198,21 @@ std::optional<reference_wrapper> repository_wrapper::upstream() const
}
}

std::optional<std::string> repository_wrapper::branch_upstream_name(std::string local_branch) const
{
git_buf buf;
int error = git_branch_upstream_name(&buf, *this, local_branch.c_str());
if (error != 0)
{
return std::nullopt;
}

std::optional<std::string> result;
result = std::string_view(buf.ptr);
git_buf_dispose(&buf);
return result;
}

branch_tracking_info repository_wrapper::get_tracking_info() const
{
branch_tracking_info info;
Expand Down
2 changes: 1 addition & 1 deletion src/wrapper/repository_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#include <git2.h>

#include "../utils/common.hpp"
#include "../utils/git_exception.hpp"
#include "../wrapper/annotated_commit_wrapper.hpp"
#include "../wrapper/branch_wrapper.hpp"
Expand Down Expand Up @@ -74,6 +73,7 @@ class repository_wrapper : public wrapper_base<git_repository>
branch_wrapper find_branch(std::string_view name) const;
branch_iterator iterate_branches(git_branch_t type) const;
std::optional<reference_wrapper> upstream() const;
std::optional<std::string> branch_upstream_name(std::string local_branch) const;
branch_tracking_info get_tracking_info() const;

// Commits
Expand Down
Loading
Loading