summaryrefslogtreecommitdiff
path: root/src/buildtool/file_system/git_repo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/buildtool/file_system/git_repo.cpp')
-rw-r--r--src/buildtool/file_system/git_repo.cpp66
1 files changed, 16 insertions, 50 deletions
diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp
index 2e142438..5ab010d4 100644
--- a/src/buildtool/file_system/git_repo.cpp
+++ b/src/buildtool/file_system/git_repo.cpp
@@ -608,60 +608,26 @@ auto GitRepo::CommitDirectory(std::filesystem::path const& dir,
// share the odb lock
std::shared_lock lock{GetGitCAS()->mutex_};
- // cannot perform this operation on a bare repository; this has to be
- // checked because git_index_add_bypath will not do it for us!
- if (not FileSystemManager::Exists(GetGitPath() / ".git")) {
- (*logger)("cannot commit directory in a bare repository!",
- true /*fatal*/);
- return std::nullopt;
- }
-
- // the index approach to adding entries requires them to be reachable
- // from root path
- auto rel_path = dir.lexically_relative(GetGitPath());
- if (rel_path.empty() or rel_path.string().starts_with("..")) {
- (*logger)(
- fmt::format("unsupported directory {}: not a subpath of {}",
- dir.string(),
- GetGitPath().string()),
- true /*fatal*/);
+ // Due to limitations of Git in general, and libgit2 in particular, by
+ // which updating the index with entries that have Git-specific magic
+ // names is cumbersome, if at all possible, we resort to creating
+ // manually the tree to be commited from the given subdirectory by
+ // recursively creating and writing to the object database all the blobs
+ // and subtrees.
+
+ // get tree containing the subdirectory entries
+ auto raw_id = CreateTreeFromDirectory(dir, logger);
+ if (not raw_id) {
return std::nullopt;
}
- // add all files to be staged
- git_index* index_ptr{nullptr};
- git_repository_index(&index_ptr, repo_->Ptr());
- auto index = std::unique_ptr<git_index, decltype(&index_closer)>(
- index_ptr, index_closer);
-
- // due to mismanagement of .gitignore rules by libgit2 when doing a
- // forced add all, we resort to using git_index_add_bypath manually for
- // all entries, instead of git_index_add_all with GIT_INDEX_ADD_FORCE.
- auto use_entry = [&index, rel_path](std::filesystem::path const& name,
- bool is_tree) {
- return is_tree or
- git_index_add_bypath(
- index.get(),
- (rel_path / name)
- .lexically_relative(".") // remove "." prefix
- .c_str()) == 0;
- };
- if (not FileSystemManager::ReadDirectoryEntriesRecursive(
- dir,
- use_entry,
- /*ignored_subdirs=*/{".git"})) {
- (*logger)(fmt::format("staging entries in git repository {} failed "
- "with:\n{}",
- GetGitPath().string(),
- GitLastError()),
- true /*fatal*/);
- return std::nullopt;
- }
- // build tree from staged files
+ // get tree oid
git_oid tree_oid;
- if (git_index_write_tree(&tree_oid, index.get()) != 0) {
- (*logger)(fmt::format("building tree from index in git repository "
- "{} failed with:\n{}",
+ if (git_oid_fromraw(&tree_oid,
+ reinterpret_cast<unsigned char const*>( // NOLINT
+ raw_id->data())) != 0) {
+ (*logger)(fmt::format("subdir tree object id parsing in git "
+ "repository {} failed with:\n{}",
GetGitPath().string(),
GitLastError()),
true /*fatal*/);