int commit_interleaver::mark_independent_targets()

in src/commit_interleaver.h [801:869]


int commit_interleaver::mark_independent_targets(MergeRequest &merge) {
  if (!merge.is_octopus) {
    assert(merge.targets.size() == 1);
    if (!head) {
      merge.targets.front().is_independent = true;
      return 0;
    }
    if (head == merge.targets.front().mono) {
      merge.head_is_independent = true;
      return 0;
    }

    // Just assume they're independent.  There's work done already when
    // preparing sources to ensure that generated merges will not be redundant,
    // only including them if they're newer than some mandatory commit to
    // merge.  It's too expensive to call git-merge-base on every repeat merge.
    merge.head_is_independent = merge.targets.front().is_independent = true;
    return 0;
  }

  // fprintf(stderr, "mark independent targets\n");
  assert(!merge.targets.empty());

  // Figure out which ones are independent.
  merge.head_is_independent = false;
  std::vector<sha1_ref> commits;
  if (head)
    commits.push_back(head);
  for (const MergeTarget &target : merge.targets)
    if (target.mono != head)
      commits.push_back(target.mono);
  if (commits.size() > 1)
    if (cache.merge_base_independent(commits))
      return error("failed to find independent target commits");

  // There should be at least one, or we have a logic bug.
  assert(!commits.empty());

  // Update the flags.
  std::sort(commits.begin(), commits.end());
  if (head)
    if (std::binary_search(commits.begin(), commits.end(), head))
      merge.head_is_independent = true;
  for (MergeTarget &target : merge.targets)
    if (target.mono != head)
      if (std::binary_search(commits.begin(), commits.end(), target.mono))
        target.is_independent = true;

  // Put the independent targets first.
  std::stable_sort(merge.targets.begin(), merge.targets.end(),
                   [](const MergeTarget &lhs, const MergeTarget &rhs) {
                     if (lhs.is_independent > rhs.is_independent)
                       return true;
                     if (lhs.is_independent < rhs.is_independent)
                       return false;

                     // Prefer putting a repeat commit first, since it makes
                     // the first commit from a new branch land better.
                     return lhs.source->is_repeat > rhs.source->is_repeat;
                   });

  // There should be at least one, or we have a logic bug.
  assert(merge.head_is_independent || merge.targets.front().is_independent);
  // fprintf(stderr, "sorted targets\n");
  // for (auto &target : merge.targets)
  //   fprintf(stderr, " - %s (independent = %d)\n",
  //           target.commit->to_string().c_str(), target.is_independent);
  return 0;
}