pull method

  1. @override
Future<GitMergeResult> pull(
  1. GitWorkingRepository repository, {
  2. String? remote,
  3. String? branch,
  4. GitMergeMode mode = GitMergeMode.auto,
})
inherited

Fetches branch from remote and merges it into the current branch of repository — the composition of fetch and GitWorkingMerge.merge (git pull), running inside that repository's context.

With remote and branch, the fetch retrieves that branch of that remote, and the merge folds the remote-tracking branch it obtained into the current branch. Without remote and branch, the fetch follows the upstream of the current branch: the remote and the branch its configuration names, and the merge folds the fetched upstream in. With remote alone, the fetch retrieves the current branch from it. branch without remote is an ArgumentError, exactly as a refspec without a remote in fetch.

The result is the merge's: up to date, fast-forward, merge commit or conflicts — a conflicted merge is a result, never an exception. There is no rebase: mode only selects which merges the merge half allows.

Throws GitNoUpstreamException without running git when no branch is given and none can be derived — HEAD is detached, or the current branch has no upstream. The fetch half throws the failures of fetch (GitUnsupportedUrlException, GitRemoteRefNotFoundException, GitAuthenticationException, GitRemoteUnreachableException, GitRemoteRepositoryNotFoundException); the merge half throws the failures of GitWorkingMerge.merge — GitMergeNotFastForwardException when mode is GitMergeMode.fastForwardOnly and the history cannot fast-forward, and GitLocalChangesOverwrittenException when the merge would overwrite local changes or untracked files. Every other failure is a GitException.

Implementation

@override
Future<GitMergeResult> pull(
  GitWorkingRepository repository, {
  String? remote,
  String? branch,
  GitMergeMode mode = GitMergeMode.auto,
}) async {
  if (branch != null && remote == null) {
    throw ArgumentError.value(
      branch,
      'branch',
      'requires a remote, otherwise nothing would be fetched',
    );
  }
  String pullRemote = remote ?? '';
  String pullBranch = branch ?? '';
  if (branch == null) {
    final String? current = await repository.branches.current();
    if (current == null) {
      throw GitNoUpstreamException(
        'HEAD is detached; name the remote and the branch to pull',
      );
    }
    if (remote == null) {
      final String? configuredRemote =
          await repository.config.get('branch.$current.remote');
      final String? mergeRef =
          await repository.config.get('branch.$current.merge');
      if (configuredRemote == null || mergeRef == null) {
        throw GitNoUpstreamException(
          'branch "$current" has no upstream; name the remote and the '
          'branch to pull',
        );
      }
      pullRemote = configuredRemote;
      pullBranch = _upstreamBranchOf(mergeRef);
    } else {
      pullBranch = current;
    }
  }
  final GitOid? fetched = await _fetch(
    repository,
    remote: pullRemote,
    refspecs: <String>[pullBranch],
    readFetchedOid: true,
  );
  final String trackingRef = 'refs/remotes/$pullRemote/$pullBranch';
  final GitOid? tracking =
      await repository.revisions.resolveRevision(trackingRef);
  final String revision;
  if (fetched == null) {
    revision = tracking != null ? trackingRef : 'FETCH_HEAD';
  } else if (tracking == fetched) {
    revision = trackingRef;
  } else {
    revision = fetched.value;
  }
  return repository.merge.merge(revision, mode: mode);
}