forked from QuantStack/git2cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheckout_subcommand.cpp
More file actions
107 lines (95 loc) · 3.39 KB
/
checkout_subcommand.cpp
File metadata and controls
107 lines (95 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
#include <sstream>
#include "../subcommand/checkout_subcommand.hpp"
#include "../utils/git_exception.hpp"
#include "../wrapper/repository_wrapper.hpp"
checkout_subcommand::checkout_subcommand(const libgit2_object&, CLI::App& app)
{
auto* sub = app.add_subcommand("checkout", "Switch branches or restore working tree files");
sub->add_option("<branch>", m_branch_name, "Branch to checkout");
sub->add_flag("-b", m_create_flag, "Create a new branch before checking it out");
sub->add_flag("-B", m_force_create_flag, "Create a new branch or reset it if it exists before checking it out");
sub->add_flag("-f, --force", m_force_checkout_flag, "When switching branches, proceed even if the index or the working tree differs from HEAD, and even if there are untracked files in the way");
sub->callback([this]() { this->run(); });
}
void checkout_subcommand::run()
{
auto directory = get_current_git_path();
auto repo = repository_wrapper::open(directory);
if (repo.state() != GIT_REPOSITORY_STATE_NONE)
{
std::runtime_error("Cannot checkout, repository is in unexpected state");
}
git_checkout_options options;
git_checkout_options_init(&options, GIT_CHECKOUT_OPTIONS_VERSION);
if(m_force_checkout_flag)
{
options.checkout_strategy = GIT_CHECKOUT_FORCE;
}
if (m_create_flag || m_force_create_flag)
{
auto annotated_commit = create_local_branch(repo, m_branch_name, m_force_create_flag);
checkout_tree(repo, annotated_commit, m_branch_name, options);
update_head(repo, annotated_commit, m_branch_name);
}
else
{
auto optional_commit = repo.resolve_local_ref(m_branch_name);
if (!optional_commit)
{
// TODO: handle remote refs
std::ostringstream buffer;
buffer << "error: could not resolve pathspec '" << m_branch_name << "'" << std::endl;
throw std::runtime_error(buffer.str());
}
checkout_tree(repo, *optional_commit, m_branch_name, options);
update_head(repo, *optional_commit, m_branch_name);
}
}
annotated_commit_wrapper checkout_subcommand::create_local_branch
(
repository_wrapper& repo,
const std::string_view target_name,
bool force
)
{
auto branch = repo.create_branch(target_name, force);
return repo.find_annotated_commit(branch);
}
void checkout_subcommand::checkout_tree
(
const repository_wrapper& repo,
const annotated_commit_wrapper& target_annotated_commit,
const std::string_view target_name,
const git_checkout_options& options
)
{
auto target_commit = repo.find_commit(target_annotated_commit.oid());
throw_if_error(git_checkout_tree(repo, target_commit, &options));
}
void checkout_subcommand::update_head
(
repository_wrapper& repo,
const annotated_commit_wrapper& target_annotated_commit,
const std::string_view target_name
)
{
std::string_view annotated_ref = target_annotated_commit.reference_name();
if (!annotated_ref.empty())
{
auto ref = repo.find_reference(annotated_ref);
if (ref.is_remote())
{
auto branch = repo.create_branch(target_name, target_annotated_commit);
repo.set_head(branch.reference_name());
}
else
{
repo.set_head(annotated_ref);
}
}
else
{
repo.set_head_detached(target_annotated_commit);
}
}