/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { IRepairDataStoreProvider } from "../repair";
import { ChangeRebaser } from "./changeRebaser";
import { GraphCommit } from "./types";
/**
 * Contains information about how the commit graph changed as the result of rebasing a source branch onto another target branch.
 * @remarks
 * ```text
 * Consider the commit graph below containing two branches, X and Y, with head commits C and E, respectively.
 * Branch Y branches off of Branch X at their common ancestor commit A, i.e. "Y is based off of X at commit A".
 *
 *   A ─ B ─ C ← Branch X
 *   └─ D ─ E ← Branch Y
 *
 * Branch Y is then rebased onto Branch X. This results in the following commit graph:
 *
 *   A ─ B ─ C ← Branch X
 *           └─ D'─ E'← Branch Y
 *
 * Commits D' and E' are the rebased versions of commits D and E, respectively. This results in:
 * deletedSourceCommits: [D, E],
 * targetCommits: [B, C],
 * sourceCommits: [D', E']
 * ```
 */
export interface RebasedCommits<TChange> {
    /**
     * The commits on the original source branch that were rebased. These are no longer referenced by the source branch and have
     * been replaced with new versions on the new source branch, see {@link sourceCommits}. In the case that the source
     * branch was already ahead of the target branch before the rebase, this list will be empty.
     */
    deletedSourceCommits: GraphCommit<TChange>[];
    /**
     * All commits on the target branch that the source branch's commits were rebased over. These are now the direct
     * ancestors of {@link sourceCommits}. In the case that the source branch was already ahead of the target branch
     * before the rebase, this list will be empty.
     */
    targetCommits: GraphCommit<TChange>[];
    /**
     * All commits on the source branch that are not also on the target branch after the rebase operation. In the case that the
     * source branch was already ahead of the target branch before the rebase, these are the same commits that were already on
     * the source branch before the rebase, otherwise these are the new, rebased versions of {@link deletedSourceCommits}.
     */
    sourceCommits: GraphCommit<TChange>[];
}
/**
 * Rebases a source branch onto another commit in a target branch.
 *
 * A "branch" is defined as a "head" commit and all ancestors of that commit, i.e. one linked list in a graph of commits.
 *
 * The source and target branch must share an ancestor.
 * @param changeRebaser - the change rebaser responsible for rebasing the changes in the commits of each branch
 * @param sourceRepairDataStoreProvider - the {@link IRepairDataStoreProvider} of the source branch. This is must be passed in
 * in order to update the repair data of the rebased commits. A branch may not have an {@link IRepairDataStoreProvider} if it
 * does not need to maintain repair data.
 * @param sourceHead - the head of the source branch, which will be rebased onto `targetHead`
 * @param targetHead - the commit to rebase the source branch onto
 * @returns the head of a rebased source branch, the cumulative change to the source branch (undefined if no change occurred),
 * and details about how the commits on the source branch changed
 * @remarks While a single branch must not have multiple commits with the same revision tag (that will result in undefined
 * behavior), there may be a commit on the source branch with the same revision tag as a commit on the target branch. If such
 * a pair is encountered while rebasing, it will be "cancelled out" in the new branch. For example:
 * ```
 * // (A)-(B)-(C) <- Branch X
 * //   \
 * //   (B')-(D) <- Branch Y
 * //
 * // As Branch Y is rebased onto Branch X, commits B and B' cancel out so there is no version of B on the new rebased source branch
 * //
 * // (A)-(B)-(C) <- Branch X
 * //           \
 * //           (D') <- Branch Y'
 * //
 * ```
 */
export declare function rebaseBranch<TChange>(changeRebaser: ChangeRebaser<TChange>, sourceRepairDataStoreProvider: IRepairDataStoreProvider<TChange> | undefined, sourceHead: GraphCommit<TChange>, targetHead: GraphCommit<TChange>): [
    newSourceHead: GraphCommit<TChange>,
    sourceChange: TChange | undefined,
    commits: RebasedCommits<TChange>
];
/**
 * Rebases a source branch onto another commit in a target branch.
 *
 * A "branch" is defined as a "head" commit and all ancestors of that commit, i.e. one linked list in a graph of commits.
 *
 * The source and target branch must share an ancestor.
 * @param changeRebaser - the change rebaser responsible for rebasing the changes in the commits of each branch
 * @param sourceRepairDataStoreProvider - the {@link IRepairDataStoreProvider} of the source branch. This is must be passed in
 * in order to update the repair data of the rebased commits. A branch may not have an {@link IRepairDataStoreProvider} if it
 * does not need to maintain repair data.
 * @param sourceHead - the head of the source branch, which will be rebased onto `newBase`
 * @param targetCommit - the commit on the target branch to rebase the source branch onto.
 * @param targetHead - the head of the branch that `newBase` belongs to. Must be `newBase` or a descendent of `newBase`.
 * @returns the head of a rebased source branch, the cumulative change to the source branch (undefined if no change occurred),
 * and details about how the commits on the source branch changed
 * @remarks While a single branch must not have multiple commits with the same revision tag (that will result in undefined
 * behavior), there may be a commit on the source branch with the same revision tag as a commit on the target branch. If such
 * a pair is encountered while rebasing, it will be "cancelled out" in the new branch. Additionally, this function will rebase
 * the source branch _farther_ than `newBase` if the source branch's next commits after `newBase` match those on the target branch.
 * For example:
 * ```
 * // (A)-(B)-(C)-(D)-(E) <- Branch X
 * //   \
 * //   (B')-(D')-(F) <- Branch Y
 * //
 * // If Branch Y is rebased onto commit C of Branch X, the branches must at least look like this afterwards (B was cancelled out):
 * //
 * // (A)-(B)-(C)-(D)-(E) <- Branch X
 * //           \
 * //           (D'')-(F') <- Branch Y'
 * //
 * // But this function will recognize that B is equivalent to B' and D is equivalent to D', and instead produce:
 * //
 * // (A)-(B)-(C)-(D)-(E) <- Branch X
 * //               \
 * //               (F') <- Branch Y'
 * ```
 */
export declare function rebaseBranch<TChange>(changeRebaser: ChangeRebaser<TChange>, sourceRepairDataStoreProvider: IRepairDataStoreProvider<TChange> | undefined, sourceHead: GraphCommit<TChange>, targetCommit: GraphCommit<TChange>, targetHead: GraphCommit<TChange>): [
    newSourceHead: GraphCommit<TChange>,
    sourceChange: TChange | undefined,
    commits: RebasedCommits<TChange>
];
/**
 * "Sandwich/Horseshoe Rebase" a change over the given source and target branches
 * @param changeRebaser - the change rebaser responsible for rebasing the change over the commits in each branch
 * @param change - the change to rebase
 * @param sourceHead - the head of the branch that `change` is based on
 * @param targetHead - the branch to rebase `change` onto
 * @returns the rebased change
 *
 * @remarks inverses will be cached.
 */
export declare function rebaseChange<TChange>(changeRebaser: ChangeRebaser<TChange>, change: TChange, sourceHead: GraphCommit<TChange>, targetHead: GraphCommit<TChange>): TChange;
/**
 * Find the furthest ancestor of some descendant.
 * @param descendant - a descendant. If an empty `path` array is included, it will be populated
 * with the chain of ancestry for `descendant` from most distant to closest (not including the furthest ancestor,
 * but otherwise including `descendant`).
 * @returns the furthest ancestor of `descendant`, or `descendant` itself if `descendant` has no ancestors.
 */
export declare function findAncestor<T extends {
    parent?: T;
}>(descendant: T | [descendant: T, path?: T[]]): T;
/**
 * Find the furthest ancestor of some descendant.
 * @param descendant - a descendant. If an empty `path` array is included, it will be populated
 * with the chain of ancestry for `descendant` from most distant to closest (not including the furthest ancestor,
 * but otherwise including `descendant`).
 * @returns the furthest ancestor of `descendant`, or `descendant` itself if `descendant` has no ancestors. Returns
 * `undefined` if `descendant` is undefined.
 */
export declare function findAncestor<T extends {
    parent?: T;
}>(descendant: T | [descendant: T | undefined, path?: T[]] | undefined): T | undefined;
/**
 * Find an ancestor of some descendant.
 * @param descendant - a descendant. If an empty `path` array is included, it will be populated
 * with the chain of ancestry for `descendant` from most distant to closest (not including the ancestor found by `predicate`,
 * but otherwise including `descendant`).
 * @param predicate - a function which will be evaluated on every ancestor of `descendant` until it returns true.
 * @returns the closest ancestor of `descendant` that satisfies `predicate`, or `undefined` if no such ancestor exists.
 * @example
 * ```ts
 * interface Parented {
 *   id: string;
 *   parent?: Parented;
 * }
 * const g = { id: "g" }; // Grandparent
 * const p = { parent: g, id: "p" }; // Parent
 * const c = { parent: p, id: "c" }; // Child
 * const path: Parented[] = [];
 * const ancestor = findAncestor<Parented>([c, path], (n) => n.id === "g");
 * // ancestor === g
 * // path === [p, c]
 * ```
 */
export declare function findAncestor<T extends {
    parent?: T;
}>(descendant: T | [descendant: T | undefined, path?: T[]] | undefined, predicate: (t: T) => boolean): T | undefined;
/**
 * Find a common ancestor between two descendants that are linked by parent pointers.
 * @param descendantA - a descendant. If an empty `path` array is included, it will be populated
 * with the chain of commits from the ancestor to `descendantA` (not including the ancestor).
 * @param descendantB - another descendant. If an empty `path` array is included, it will be populated
 * with the chain of commits from the ancestor to `descendantB` (not including the ancestor).
 * @returns the common ancestor of `descendantA` and `descendantB`, or `undefined` if no such ancestor exists.
 * @example
 * ```ts
 * interface Parented {
 *   parent?: Parented;
 * }
 * const shared = {};
 * const a = { parent: shared };
 * const b1 = { parent: shared };
 * const b2 = { parent: b1 };
 * const pathB: Parented[] = []
 * const ancestor = findCommonAncestor<Parented>(a, [b2, pathB]);
 * // ancestor === shared
 * // pathB === [b1, b2]
 * ```
 */
export declare function findCommonAncestor<T extends {
    parent?: T;
}>(descendantA: T | [descendantA: T, path?: T[]] | undefined, descendantB: T | [descendantB: T, path?: T[]] | undefined): T | undefined;
//# sourceMappingURL=utils.d.ts.map