pull method
- GitWorkingRepository repository, {
- String? remote,
- String? branch,
- GitMergeMode mode = GitMergeMode.auto,
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);
}