NAME

Git::Native::Remote::Result - Per-ref outcomes from a Remote fetch or push

VERSION

version 0.005

SYNOPSIS

my $r = $remote->fetch(
  refspecs => ['+refs/heads/*:refs/remotes/origin/*'],
);
if ( !$r->ok ) {
  for my $u ( @{ $r->updated } ) {
    warn sprintf "updated %s: %s -> %s\n", $u->{ref},
      $u->{from} // '(new)', $u->{to} // '(deleted)';
  }
  for my $u ( @{ $r->rejected } ) {
    warn "rejected $u->{ref}: $u->{reason}\n";
  }
}

DESCRIPTION

Structured return value from Git::Native::Remote's fetch and push. It exists because libgit2 returns 0 from git_remote_fetch / git_remote_push even when individual refs were skipped or refused; the per-ref outcome is only visible through the callbacks Remote installs (update_tips on fetch, push_update_reference on push). See "updated", "rejected", and "ok".

updated

for my $u ( @{ $result->updated } ) {
  say $u->{ref}, defined $u->{to} ? " -> $u->{to}" : ' (deleted)';
}

Arrayref of hashrefs, one per ref that actually moved on the receiving side. Every entry carries the same four keys, ref / from / to / reason, whether it came from a fetch or a push, so code that reads a Result does not have to know which operation produced it. A value the operation cannot supply is present as an explicit undef rather than as a missing key.

# fetch
{ ref => 'refs/karr/x', from => undef, to => 'b8f9ae41...', reason => '' }
# push
{ ref => 'refs/karr/x', from => undef, to => 'b8f9ae41...', reason => '' }

ref is the name of the ref on the side that changed, and that side differs by operation: a fetch names the local destination the refspec mapped to, a push names the ref as the remote calls it. That asymmetry is the semantics of the underlying libgit2 callbacks (update_tips fires after the local ref is written, push_update_reference relays the server's own report) and is deliberately left alone.

to is the OID the ref now points at, or undef when the ref was deleted rather than moved — a stale mirror ref dropped by a prune => 1 fetch, or a delete refspec on a push. On a push it is read off the local source side of the refspec, not from the server, and is therefore also undef for a source that is not a resolvable local reference.

from is the OID the ref pointed at before. It is undef when the ref did not exist on the receiving side yet, and always undef on a push: the previous remote-side OID would take a ref listing before the push, and "push" in Git::Native::Remote does not spend an extra network round trip on it. Call "list_refs" in Git::Native::Remote first if you need that snapshot.

reason is the empty string on every updated entry — a non-empty reason means the ref was refused, and refused refs are in "rejected" instead. Refs that were already up to date are not reported at all.

rejected

die "push refused: $_->{ref}: $_->{reason}" for @{ $result->rejected };

Arrayref of { ref => $name, reason => $message }, one per ref the server refused, with reason the status string it sent (non-fast-forward, pre-receive hook declined, ...). Refused refs never carry an empty reason — an empty status is libgit2's "accepted, nothing to say" and lands in "updated".

Only a push can populate this. A fetch leaves it empty even when libgit2 skipped a non-fast-forward ref, because that path does not reach the update_tips callback; on a fetch, a skipped ref shows up as a missing entry in "updated".

ok

$result->ok    # 1 when nothing at all happened

True iff both updated and rejected are empty, i.e. the operation moved no ref and no ref was refused. A fully successful push of N refs reports all N in updated and is therefore not ok — the check for "did anything go wrong" is @{ $result->rejected }, and ok answers the different question "was this a no-op?".

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-git-native/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.