/** * Merges two trees originating from a common tree * @param \gihp\Object\Tree $common_tree The common tree for both sides * @param \gihp\Object\Tree $base_tree Left side (their side) * @param \gihp\Object\Tree $head_tree Right side (our side) * @param int $mode Merge method to use * ({@link self::THEIRS} to solve conflicts by picking from the base branch, * {@link self::OURS} to solve conflicts by picking from the head branch, * {@link self::MANUAL} to write a conflicted file to the tree) * @return \gihp\Object\Tree * @throws \RuntimeException when trying to merge a tree and a blob */ public static function treeMerge(OTree $common_tree, OTree $base_tree, OTree $head_tree, $mode = self::MANUAL) { if ($base_tree->getSHA1() == $head_tree->getSHA1()) { // Trees are identical, return that one return $base_tree; } $base_objects = $base_tree->getNamesAndHashes(); $head_objects = $head_tree->getNamesAndHashes(); $common_objects = $common_tree->getNamesAndHashes(); $merged_tree = new OTree(); $identical_objects = array_intersect_assoc($base_objects, $head_objects); foreach ($identical_objects as $name => $sha1) { // Merge identical objects $merged_tree->addObject($name, $base_tree->getObject($sha1), $base_tree->getObjectMode($sha1)); } $diff_objects = array_diff_assoc($head_objects, $base_objects); foreach ($diff_objects as $name => $_) { $head_sha1 = $head_objects[$name]; $base_sha1 = $base_objects[$name]; $common_sha1 = $common_objects[$name]; $head_object = $head_tree->getObject($head_sha1); $base_object = $base_tree->getObject($base_sha1); $common_object = $common_tree->getObject($common_sha1); if ($head_object instanceof OTree && $base_object instanceof OTree && $common_object instanceof OTree) { // Both are trees, merge them recursively $merged_object = self::treeMerge($common_object, $base_object, $head_object, $mode); } elseif ($head_object instanceof Blob && $base_object instanceof Blob && $common_object instanceof Blob) { // Both are objects, merge them $merged_object = self::blobMerge($common_object, $base_object, $head_object, $mode); } elseif ($mode == self::OURS) { $merged_object = $head_object; } elseif ($mode == self::THEIRS) { $merged_object = $base_object; } else { throw new \RuntimeException('Cannot merge a blob and a tree (and no side chosen)'); } // Add the object to the merged tree $merged_tree->addObject($name, $merged_object); } }