summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2023-03-27 18:15:08 +0200
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2023-03-30 13:45:00 +0200
commited9bfe29a1d54a6dca1fa85853457c56108a6183 (patch)
treedcfa02e41e34cb727855e2d8cdbf0bcb9bbb2fba /src
parent0c90ad4bf580a385aa7056298452980b5f8ceb83 (diff)
downloadjustbuild-ed9bfe29a1d54a6dca1fa85853457c56108a6183.tar.gz
GitRepo: Guard fake repository odb wrapping
In the current libgit2 implementation, a fake repository wrapped around an existing odb is being registered as owner the same way as a normal repository object. Therefore, one has to guard both the creation and destruction of the fake repository against all other git operations that might access the internal cache during this transfer of ownership.
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/file_system/git_cas.cpp32
-rw-r--r--src/buildtool/file_system/git_cas.hpp6
-rw-r--r--src/buildtool/file_system/git_repo.cpp149
-rw-r--r--src/buildtool/file_system/git_repo.hpp35
-rw-r--r--src/buildtool/file_system/git_utils.cpp6
-rw-r--r--src/buildtool/file_system/git_utils.hpp3
-rw-r--r--src/other_tools/git_operations/git_repo_remote.cpp8
7 files changed, 165 insertions, 74 deletions
diff --git a/src/buildtool/file_system/git_cas.cpp b/src/buildtool/file_system/git_cas.cpp
index 2a4a7142..1f8525fe 100644
--- a/src/buildtool/file_system/git_cas.cpp
+++ b/src/buildtool/file_system/git_cas.cpp
@@ -81,12 +81,15 @@ auto GitCAS::ReadObject(std::string const& id, bool is_hex_id) const noexcept
}
git_odb_object* obj = nullptr;
- if (git_odb_read(&obj, odb_.get(), &oid.value()) != 0) {
- Logger::Log(LogLevel::Error,
- "reading git object {} from database failed with:\n{}",
- is_hex_id ? id : ToHexString(id),
- GitLastError());
- return std::nullopt;
+ {
+ std::shared_lock lock{mutex_};
+ if (git_odb_read(&obj, odb_.get(), &oid.value()) != 0) {
+ Logger::Log(LogLevel::Error,
+ "reading git object {} from database failed with:\n{}",
+ is_hex_id ? id : ToHexString(id),
+ GitLastError());
+ return std::nullopt;
+ }
}
std::string data(static_cast<char const*>(git_odb_object_data(obj)),
@@ -111,13 +114,16 @@ auto GitCAS::ReadHeader(std::string const& id, bool is_hex_id) const noexcept
std::size_t size{};
git_object_t type{};
- if (git_odb_read_header(&size, &type, odb_.get(), &oid.value()) != 0) {
- Logger::Log(LogLevel::Error,
- "reading git object header {} from database failed "
- "with:\n{}",
- is_hex_id ? id : ToHexString(id),
- GitLastError());
- return std::nullopt;
+ {
+ std::shared_lock lock{mutex_};
+ if (git_odb_read_header(&size, &type, odb_.get(), &oid.value()) != 0) {
+ Logger::Log(LogLevel::Error,
+ "reading git object header {} from database failed "
+ "with:\n{}",
+ is_hex_id ? id : ToHexString(id),
+ GitLastError());
+ return std::nullopt;
+ }
}
if (auto obj_type = GitTypeToObjectType(type)) {
diff --git a/src/buildtool/file_system/git_cas.hpp b/src/buildtool/file_system/git_cas.hpp
index 44b61cb4..f95cb403 100644
--- a/src/buildtool/file_system/git_cas.hpp
+++ b/src/buildtool/file_system/git_cas.hpp
@@ -18,6 +18,7 @@
#include <filesystem>
#include <memory>
#include <optional>
+#include <shared_mutex>
#include <unordered_map>
#include <vector>
@@ -67,6 +68,11 @@ class GitCAS {
// git folder path of repo
std::filesystem::path git_path_{};
+ // mutex to guard odb while setting up a "fake" repository; it needs to be
+ // uniquely owned while wrapping the odb, but then git operations are free
+ // to share it.
+ mutable std::shared_mutex mutex_{};
+
[[nodiscard]] auto OpenODB(std::filesystem::path const& repo_path) noexcept
-> bool;
diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp
index 31bfed38..2e09f84d 100644
--- a/src/buildtool/file_system/git_repo.cpp
+++ b/src/buildtool/file_system/git_repo.cpp
@@ -243,6 +243,26 @@ auto const kInMemoryODBParent = CreateInMemoryODBParent();
} // namespace
#endif // BOOTSTRAP_BUILD_TOOL
+GitRepo::GuardedRepo::GuardedRepo(std::shared_mutex* mutex) noexcept
+ : mutex_{mutex} {}
+
+auto GitRepo::GuardedRepo::Ptr() -> git_repository* {
+ return repo_;
+}
+
+auto GitRepo::GuardedRepo::PtrRef() -> git_repository** {
+ return &repo_;
+}
+
+GitRepo::GuardedRepo::~GuardedRepo() noexcept {
+#ifndef BOOTSTRAP_BUILD_TOOL
+ if (repo_ != nullptr) {
+ std::unique_lock lock{*mutex_};
+ git_repository_free(repo_);
+ }
+#endif
+}
+
auto GitRepo::Open(GitCASPtr git_cas) noexcept -> std::optional<GitRepo> {
#ifdef BOOTSTRAP_BUILD_TOOL
return std::nullopt;
@@ -270,21 +290,31 @@ auto GitRepo::Open(std::filesystem::path const& repo_path) noexcept
GitRepo::GitRepo(GitCASPtr git_cas) noexcept {
#ifndef BOOTSTRAP_BUILD_TOOL
- if (git_cas != nullptr) {
- git_repository* repo_ptr{nullptr};
- if (git_repository_wrap_odb(&repo_ptr, git_cas->odb_.get()) != 0) {
+ try {
+ if (git_cas != nullptr) {
+ auto repo_ptr = std::make_shared<GuardedRepo>(&git_cas->mutex_);
+ {
+ // acquire the odb lock exclusively
+ std::unique_lock lock{git_cas->mutex_};
+ if (git_repository_wrap_odb(repo_ptr->PtrRef(),
+ git_cas->odb_.get()) != 0) {
+ Logger::Log(LogLevel::Error,
+ "could not create wrapper for git repository");
+ return;
+ }
+ }
+ repo_ = std::move(repo_ptr);
+ is_repo_fake_ = true;
+ git_cas_ = std::move(git_cas);
+ }
+ else {
Logger::Log(LogLevel::Error,
- "could not create wrapper for git repository");
- git_repository_free(repo_ptr);
- return;
+ "git repository creation attempted with null odb!");
}
- repo_.reset(repo_ptr); // retain repo
- is_repo_fake_ = true;
- git_cas_ = std::move(git_cas);
- }
- else {
+ } catch (std::exception const& ex) {
Logger::Log(LogLevel::Error,
- "git repository creation attempted with null odb!");
+ "opening git object database failed with:\n{}",
+ ex.what());
}
#endif // BOOTSTRAP_BUILD_TOOL
}
@@ -296,8 +326,8 @@ GitRepo::GitRepo(std::filesystem::path const& repo_path) noexcept {
std::unique_lock lock{repo_mutex};
auto cas = std::make_shared<GitCAS>();
// open repo, but retain it
- git_repository* repo_ptr{nullptr};
- if (git_repository_open_ext(&repo_ptr,
+ auto repo_ptr = std::make_shared<GuardedRepo>(&cas->mutex_);
+ if (git_repository_open_ext(repo_ptr->PtrRef(),
repo_path.c_str(),
GIT_REPOSITORY_OPEN_NO_SEARCH,
nullptr) != 0) {
@@ -305,14 +335,12 @@ GitRepo::GitRepo(std::filesystem::path const& repo_path) noexcept {
"opening git repository {} failed with:\n{}",
repo_path.string(),
GitLastError());
- git_repository_free(repo_ptr);
- repo_ = nullptr;
return;
}
- repo_.reset(repo_ptr); // retain repo pointer
+ repo_ = repo_ptr; // retain repo pointer
// get odb
git_odb* odb_ptr{nullptr};
- git_repository_odb(&odb_ptr, repo_.get());
+ git_repository_odb(&odb_ptr, repo_->Ptr());
if (odb_ptr == nullptr) {
Logger::Log(LogLevel::Error,
"retrieving odb of git repository {} failed with:\n{}",
@@ -326,7 +354,7 @@ GitRepo::GitRepo(std::filesystem::path const& repo_path) noexcept {
is_repo_fake_ = false;
// save root path
cas->git_path_ = ToNormalPath(std::filesystem::absolute(
- std::filesystem::path(git_repository_path(repo_.get()))));
+ std::filesystem::path(git_repository_path(repo_->Ptr()))));
// retain the pointer
git_cas_ = std::static_pointer_cast<GitCAS const>(cas);
} catch (std::exception const& ex) {
@@ -345,10 +373,13 @@ GitRepo::GitRepo(GitRepo&& other) noexcept
}
auto GitRepo::operator=(GitRepo&& other) noexcept -> GitRepo& {
- git_cas_ = std::move(other.git_cas_);
- repo_ = std::move(other.repo_);
- is_repo_fake_ = other.is_repo_fake_;
- other.git_cas_ = nullptr;
+ try {
+ git_cas_ = std::move(other.git_cas_);
+ repo_ = std::move(other.repo_);
+ is_repo_fake_ = other.is_repo_fake_;
+ other.git_cas_ = nullptr;
+ } catch (...) {
+ }
return *this;
}
@@ -416,8 +447,7 @@ auto GitRepo::GetGitCAS() const noexcept -> GitCASPtr {
return git_cas_;
}
-auto GitRepo::GetRepoRef() const noexcept
- -> std::unique_ptr<git_repository, decltype(&repo_closer)> const& {
+auto GitRepo::GetRepoRef() const noexcept -> GuardedRepoPtr {
return repo_;
}
@@ -443,9 +473,12 @@ auto GitRepo::StageAndCommitAllAnonymous(std::string const& message,
true /*fatal*/);
return std::nullopt;
}
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+
// add all files to be staged
git_index* index_ptr{nullptr};
- git_repository_index(&index_ptr, repo_.get());
+ git_repository_index(&index_ptr, repo_->Ptr());
auto index = std::unique_ptr<git_index, decltype(&index_closer)>(
index_ptr, index_closer);
@@ -496,7 +529,7 @@ auto GitRepo::StageAndCommitAllAnonymous(std::string const& message,
// get tree object
git_tree* tree_ptr = nullptr;
- if (git_tree_lookup(&tree_ptr, repo_.get(), &tree_oid) != 0) {
+ if (git_tree_lookup(&tree_ptr, repo_->Ptr(), &tree_oid) != 0) {
(*logger)(
fmt::format("tree lookup in git repository {} failed with:\n{}",
GetGitCAS()->git_path_.string(),
@@ -516,7 +549,7 @@ auto GitRepo::StageAndCommitAllAnonymous(std::string const& message,
git_oid commit_oid;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
if (git_commit_create_v(&commit_oid,
- repo_.get(),
+ repo_->Ptr(),
"HEAD",
signature.get(),
signature.get(),
@@ -557,9 +590,12 @@ auto GitRepo::KeepTag(std::string const& commit,
true /*fatal*/);
return false;
}
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+
// get commit spec
git_object* target_ptr{nullptr};
- if (git_revparse_single(&target_ptr, repo_.get(), commit.c_str()) !=
+ if (git_revparse_single(&target_ptr, repo_->Ptr(), commit.c_str()) !=
0) {
(*logger)(fmt::format("rev-parse commit {} in repository {} failed "
"with:\n{}",
@@ -597,7 +633,7 @@ auto GitRepo::KeepTag(std::string const& commit,
git_strarray tag_names{};
// check if tag hasn't already been added by another process
- if (git_tag_list_match(&tag_names, name.c_str(), repo_.get()) == 0 and
+ if (git_tag_list_match(&tag_names, name.c_str(), repo_->Ptr()) == 0 and
tag_names.count > 0) {
git_strarray_dispose(&tag_names);
return true; // success!
@@ -610,7 +646,7 @@ auto GitRepo::KeepTag(std::string const& commit,
while (max_attempts > 0) {
--max_attempts;
err = git_tag_create(&oid,
- repo_.get(),
+ repo_->Ptr(),
name.c_str(),
target.get(),
tagger.get(),
@@ -625,7 +661,7 @@ auto GitRepo::KeepTag(std::string const& commit,
break;
}
// check if tag hasn't already been added by another process
- if (git_tag_list_match(&tag_names, name.c_str(), repo_.get()) ==
+ if (git_tag_list_match(&tag_names, name.c_str(), repo_->Ptr()) ==
0 and
tag_names.count > 0) {
git_strarray_dispose(&tag_names);
@@ -662,9 +698,12 @@ auto GitRepo::GetHeadCommit(anon_logger_ptr const& logger) noexcept
true /*fatal*/);
return std::nullopt;
}
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+
// get root commit id
git_oid head_oid;
- if (git_reference_name_to_id(&head_oid, repo_.get(), "HEAD") != 0) {
+ if (git_reference_name_to_id(&head_oid, repo_->Ptr(), "HEAD") != 0) {
(*logger)(fmt::format("retrieving head commit in git repository {} "
"failed with:\n{}",
GetGitCAS()->git_path_.string(),
@@ -695,6 +734,9 @@ auto GitRepo::GetSubtreeFromCommit(std::string const& commit,
LogLevel::Debug,
"Subtree id retrieval from commit called on a real repository");
}
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+
// get commit object
git_oid commit_oid;
if (git_oid_fromstr(&commit_oid, commit.c_str()) != 0) {
@@ -708,7 +750,7 @@ auto GitRepo::GetSubtreeFromCommit(std::string const& commit,
}
git_commit* commit_ptr{nullptr};
- if (git_commit_lookup(&commit_ptr, repo_.get(), &commit_oid) != 0) {
+ if (git_commit_lookup(&commit_ptr, repo_->Ptr(), &commit_oid) != 0) {
(*logger)(fmt::format("retrieving commit {} in git repository {} "
"failed with:\n{}",
commit,
@@ -791,6 +833,9 @@ auto GitRepo::GetSubtreeFromTree(std::string const& tree_id,
"Subtree id retrieval from tree called on a real "
"repository");
}
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+
// get tree object from tree id
git_oid tree_oid;
if (git_oid_fromstr(&tree_oid, tree_id.c_str()) != 0) {
@@ -804,7 +849,7 @@ auto GitRepo::GetSubtreeFromTree(std::string const& tree_id,
}
git_tree* tree_ptr{nullptr};
- if (git_tree_lookup(&tree_ptr, repo_.get(), &tree_oid) != 0) {
+ if (git_tree_lookup(&tree_ptr, repo_->Ptr(), &tree_oid) != 0) {
(*logger)(fmt::format(
"retrieving tree {} in git repository {} failed "
"with:\n{}",
@@ -926,8 +971,13 @@ auto GitRepo::CheckCommitExists(std::string const& commit,
}
git_commit* commit_obj = nullptr;
- auto lookup_res =
- git_commit_lookup(&commit_obj, repo_.get(), &commit_oid);
+ int lookup_res{};
+ {
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+ lookup_res =
+ git_commit_lookup(&commit_obj, repo_->Ptr(), &commit_oid);
+ }
if (lookup_res != 0) {
if (lookup_res == GIT_ENOTFOUND) {
// cleanup resources
@@ -1027,7 +1077,12 @@ auto GitRepo::CheckTreeExists(std::string const& tree_id,
}
// get tree object
git_tree* tree_ptr = nullptr;
- auto lookup_res = git_tree_lookup(&tree_ptr, repo_.get(), &tree_oid);
+ int lookup_res{};
+ {
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+ lookup_res = git_tree_lookup(&tree_ptr, repo_->Ptr(), &tree_oid);
+ }
git_tree_free(tree_ptr);
if (lookup_res != 0) {
if (lookup_res == GIT_ENOTFOUND) {
@@ -1067,11 +1122,15 @@ auto GitRepo::ReadTree(std::string const& id, bool is_hex_id) const noexcept
// lookup tree
git_tree* tree_ptr{nullptr};
- if (git_tree_lookup(&tree_ptr, repo_.get(), &(*oid)) != 0) {
- Logger::Log(LogLevel::Debug,
- "failed to lookup Git tree {}",
- is_hex_id ? std::string{id} : ToHexString(id));
- return std::nullopt;
+ {
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
+ if (git_tree_lookup(&tree_ptr, repo_->Ptr(), &(*oid)) != 0) {
+ Logger::Log(LogLevel::Debug,
+ "failed to lookup Git tree {}",
+ is_hex_id ? std::string{id} : ToHexString(id));
+ return std::nullopt;
+ }
}
auto tree = std::unique_ptr<git_tree, decltype(&tree_closer)>{tree_ptr,
tree_closer};
@@ -1103,9 +1162,11 @@ auto GitRepo::CreateTree(tree_entries_t const& entries) const noexcept
#ifndef NDEBUG
gsl_ExpectsAudit(ValidateEntries(entries));
#endif // NDEBUG
+ // share the odb lock
+ std::shared_lock lock{GetGitCAS()->mutex_};
git_treebuilder* builder_ptr{nullptr};
- if (git_treebuilder_new(&builder_ptr, repo_.get(), nullptr) != 0) {
+ if (git_treebuilder_new(&builder_ptr, repo_->Ptr(), nullptr) != 0) {
Logger::Log(LogLevel::Debug, "failed to create Git tree builder");
return std::nullopt;
}
diff --git a/src/buildtool/file_system/git_repo.hpp b/src/buildtool/file_system/git_repo.hpp
index eba826d9..c66a54db 100644
--- a/src/buildtool/file_system/git_repo.hpp
+++ b/src/buildtool/file_system/git_repo.hpp
@@ -19,6 +19,10 @@
#include "src/buildtool/file_system/git_cas.hpp"
+extern "C" {
+struct git_repository;
+}
+
/// \brief Git repository logic.
/// Models both a real repository, owning the underlying ODB
/// (non-thread-safe), as well as a "fake" repository, which only wraps an
@@ -196,11 +200,35 @@ class GitRepo {
-> std::optional<bool>;
private:
+ /// \brief Wrapped git_repository with guarded destructor.
+ /// Kept privately nested to avoid misuse of its raw pointer members.
+ class GuardedRepo {
+ public:
+ GuardedRepo() noexcept = delete;
+ explicit GuardedRepo(std::shared_mutex* mutex) noexcept;
+ ~GuardedRepo() noexcept;
+
+ // prohibit moves and copies
+ GuardedRepo(GuardedRepo const&) = delete;
+ GuardedRepo(GuardedRepo&& other) = delete;
+ auto operator=(GuardedRepo const&) = delete;
+ auto operator=(GuardedRepo&& other) = delete;
+
+ // get the bare pointer
+ [[nodiscard]] auto Ptr() -> git_repository*;
+ [[nodiscard]] auto PtrRef() -> git_repository**;
+
+ private:
+ std::shared_mutex* mutex_;
+ git_repository* repo_{nullptr};
+ };
+
+ using GuardedRepoPtr = std::shared_ptr<GuardedRepo>;
+
// IMPORTANT! The GitCAS object must be defined before the repo object to
// keep the GitContext alive until cleanup ends.
GitCASPtr git_cas_{nullptr};
- std::unique_ptr<git_repository, decltype(&repo_closer)> repo_{nullptr,
- repo_closer};
+ GuardedRepoPtr repo_{nullptr};
// default to real repo, as that is non-thread-safe
bool is_repo_fake_{false};
@@ -210,8 +238,7 @@ class GitRepo {
/// \brief Open real repository at given location.
explicit GitRepo(std::filesystem::path const& repo_path) noexcept;
- [[nodiscard]] auto GetRepoRef() const noexcept
- -> std::unique_ptr<git_repository, decltype(&repo_closer)> const&;
+ [[nodiscard]] auto GetRepoRef() const noexcept -> GuardedRepoPtr;
[[nodiscard]] auto GetGitPath() const noexcept
-> std::filesystem::path const&;
diff --git a/src/buildtool/file_system/git_utils.cpp b/src/buildtool/file_system/git_utils.cpp
index a38fae39..a3b503ab 100644
--- a/src/buildtool/file_system/git_utils.cpp
+++ b/src/buildtool/file_system/git_utils.cpp
@@ -69,12 +69,6 @@ auto GitObjectID(std::string const& id, bool is_hex_id) noexcept
#endif // BOOTSTRAP_BUILD_TOOL
}
-void repo_closer(gsl::owner<git_repository*> repo) {
-#ifndef BOOTSTRAP_BUILD_TOOL
- git_repository_free(repo);
-#endif
-}
-
void odb_closer(gsl::owner<git_odb*> odb) {
#ifndef BOOTSTRAP_BUILD_TOOL
git_odb_free(odb);
diff --git a/src/buildtool/file_system/git_utils.hpp b/src/buildtool/file_system/git_utils.hpp
index 5749c8b5..fc43e542 100644
--- a/src/buildtool/file_system/git_utils.hpp
+++ b/src/buildtool/file_system/git_utils.hpp
@@ -23,7 +23,6 @@
extern "C" {
struct git_oid;
struct git_odb;
-struct git_repository;
struct git_tree;
struct git_treebuilder;
struct git_index;
@@ -48,8 +47,6 @@ constexpr std::size_t kGitLockNumTries{10};
/// \brief Retrieve error message of last libgit2 call.
[[nodiscard]] auto GitLastError() noexcept -> std::string;
-void repo_closer(gsl::owner<git_repository*> repo);
-
void odb_closer(gsl::owner<git_odb*> odb);
void tree_closer(gsl::owner<git_tree*> tree);
diff --git a/src/other_tools/git_operations/git_repo_remote.cpp b/src/other_tools/git_operations/git_repo_remote.cpp
index aa277c3e..0c925cc4 100644
--- a/src/other_tools/git_operations/git_repo_remote.cpp
+++ b/src/other_tools/git_operations/git_repo_remote.cpp
@@ -148,7 +148,7 @@ auto GitRepoRemote::GetCommitFromRemote(std::shared_ptr<git_config> cfg,
// create remote
git_remote* remote_ptr{nullptr};
if (git_remote_create_anonymous(
- &remote_ptr, GetRepoRef().get(), repo_url.c_str()) != 0) {
+ &remote_ptr, GetRepoRef()->Ptr(), repo_url.c_str()) != 0) {
(*logger)(
fmt::format("Creating anonymous remote for git repository {} "
"failed with:\n{}",
@@ -279,7 +279,7 @@ auto GitRepoRemote::FetchFromRemote(std::shared_ptr<git_config> cfg,
// create remote from repo
git_remote* remote_ptr{nullptr};
if (git_remote_create_anonymous(
- &remote_ptr, GetRepoRef().get(), repo_url.c_str()) != 0) {
+ &remote_ptr, GetRepoRef()->Ptr(), repo_url.c_str()) != 0) {
(*logger)(fmt::format("Creating remote {} for git repository {} "
"failed with:\n{}",
repo_url,
@@ -300,7 +300,7 @@ auto GitRepoRemote::FetchFromRemote(std::shared_ptr<git_config> cfg,
if (not cfg) {
// get config snapshot of current repo
git_config* cfg_ptr{nullptr};
- if (git_repository_config_snapshot(&cfg_ptr, GetRepoRef().get()) !=
+ if (git_repository_config_snapshot(&cfg_ptr, GetRepoRef()->Ptr()) !=
0) {
(*logger)(fmt::format("Retrieving config object in fetch from "
"remote failed with:\n{}",
@@ -621,7 +621,7 @@ auto GitRepoRemote::FetchViaTmpRepo(std::filesystem::path const& tmp_dir,
auto GitRepoRemote::GetConfigSnapshot() const -> std::shared_ptr<git_config> {
git_config* cfg_ptr{nullptr};
- if (git_repository_config_snapshot(&cfg_ptr, GetRepoRef().get()) != 0) {
+ if (git_repository_config_snapshot(&cfg_ptr, GetRepoRef()->Ptr()) != 0) {
return nullptr;
}
return std::shared_ptr<git_config>(cfg_ptr, config_closer);