in src/commit_interleaver.h [382:463]
int commit_interleaver::finish_making_tree_outside_source(
int head_p, sha1_ref base_commit, dir_mask source_dirs,
bool source_includes_root, const std::vector<sha1_ref> &parents,
const std::vector<int> &revs, std::vector<git_tree::item_type> &items,
sha1_ref &tree_sha1) {
if (parents.size() > max_parents)
return error(std::to_string(parents.size()) +
" is too many parents (max: " + std::to_string(max_parents) +
")");
if (head_p != -1)
dirs.active_dirs.bits |= source_dirs.bits;
// Pick parents for all the other directories.
std::array<int, dir_mask::max_size> parent_for_d;
parent_for_d.fill(-1);
std::bitset<max_parents> contributed;
std::array<git_tree, max_parents> trees;
// Index the head first so that its content takes precedence.
int inactive_p = -1;
if (head_p != -1)
if (index_parent_tree_items(
head_p, head_p, source_dirs, source_includes_root, inactive_p,
parents[head_p], trees[head_p], parent_for_d, contributed, revs))
return 1;
for (int p = 0, pe = parents.size(); p != pe; ++p)
if (p != head_p)
if (index_parent_tree_items(head_p, p, source_dirs, source_includes_root,
inactive_p, parents[p], trees[p],
parent_for_d, contributed, revs))
return 1;
auto get_dir_p = [&](int d) -> const int & {
return dirs.active_dirs.test(d) ? parent_for_d[d] : inactive_p;
};
// Fill up the items for the tree.
for (int p = 0, pe = parents.size(); p != pe; ++p) {
if (!contributed.test(p))
continue;
const git_tree &tree = trees[p];
for (int i = 0; i < tree.num_items; ++i) {
auto &item = tree.items[i];
if (source_includes_root && item.type != git_tree::item_type::tree)
continue;
int d = dirs.find_dir(item.name);
assert(d != -1);
if (!source_dirs.test(d))
if (p == get_dir_p(d))
items.push_back(item);
}
}
// Sort and assert that we don't have any duplicates.
std::sort(items.begin(), items.end(),
[](const git_tree::item_type &lhs, const git_tree::item_type &rhs) {
return strcmp(lhs.name, rhs.name) < 0;
});
assert(std::adjacent_find(items.begin(), items.end(),
[](const git_tree::item_type &lhs,
const git_tree::item_type &rhs) {
return strcmp(lhs.name, rhs.name) == 0;
}) == items.end());
// Make the tree.
if (items.size() > dir_mask::max_size)
return error("too many items (max: " + std::to_string(dir_mask::max_size) +
"); constructing tree for " +
(base_commit ? base_commit.sha1->to_string()
: std::string("merge commit")));
git_tree tree;
tree.num_items = items.size();
tree.items = cache.make_items(items.data(), items.data() + items.size());
items.clear();
if (cache.mktree(tree))
return 1;
tree_sha1 = tree.sha1;
return 0;
}