Revision history for Git-Libgit2

0.007     2026-08-30 14:06:50Z
  - New cert_hostkey_offsets: byte offsets of git_cert_hostkey's type,
    hash_sha1 and hash_sha256 fields, for reading host key hashes from
    the certificate handed to a certificate_check callback. Derived from
    the ABI's int size - the struct is padding-free up to the end of
    hash_sha256 and, unlike git_fetch_options.prune, nothing in it moves
    between libgit2 releases. Lets Git::Native drop its compiled-in
    copies of the same three numbers (its karr #30).
  - Fix t/11-revwalk.t failing on perl >= 5.41 (GH #1, reported against
    every release since 0.004; reproduced on 5.42.3). The fixture
    helpers returned scalar_to_buffer pointers to sub-local buffers, and
    the "pre-allocated at outer scope" commit buffers were parameter
    copies, so those pointers only stayed valid through copy-on-write
    buffer sharing. perl commit 06e421c559 (perl5#22704, in 5.41) gives
    constant-folded strings the COW flag, scalar_to_buffer then un-COWs
    them into a fresh buffer, and the shared-buffer coincidence the test
    leaned on was gone: the recorded c3 hex was stale memory and the b3
    walk "returned the wrong commit". t/11, t/12 and t/13 now pass OIDs
    between scopes as their 20-byte strings and take every pointer
    freshly in the scope that uses it; t/24 already did. No library
    change - oid_from_hex/oid_to_hex handle COW correctly, verified on
    5.42.3, and the full suite passes there.
  - cpanfile: require Alien::Libgit2 0.002, which raises the libgit2
    floor to 1.9.3. Below that an ssh peer that accepts the connection
    and then stays silent hangs the transport unboundedly (libgit2 PR
    #7165); the remote bindings here are how that loop is reached from
    Perl. Alien::Libgit2 0.002 must ship before this release.
  - cpanfile: Path::Tiny was missing from the test prereqs. 22 of the 30
    test files load it and it is not core, so a smoker without it already
    installed failed at `make test`. Predates this release.
  - t/03-error.t: pin GIT_EUNCHANGED (-38), GIT_ENOTSUPPORTED (-39) and
    GIT_EREADONLY (-40). The file stopped at GIT_TIMEOUT (-37), the old
    end of the enum, leaving the three codes this release adds exported
    but unasserted.
  - git_libgit2_opts_int: a second binding of git_libgit2_opts for its
    (int, int) vararg shape, plus the constants it exists for,
    GIT_OPT_SET_SERVER_CONNECT_TIMEOUT and GIT_OPT_SET_SERVER_TIMEOUT
    (libgit2 1.8+, milliseconds, 0 = no limit). Without them libgit2's
    network reads have no bound at all: a peer that completes the TCP
    handshake and then stays silent blocks the calling thread forever, with
    no callback in between, and the one attached vararg shape -- (int,
    string) -- could not carry an int value. The GET_* counterparts stay
    unbound: their vararg is an out pointer, and FFI::Platypus 2.11
    segfaults on a pointer type in a variadic argument list.
  - fetch_options_prune_offset: probe where `prune` sits inside
    git_fetch_options in the libgit2 this process is actually linked
    against, instead of leaving consumers to compile the offset in. The
    field follows the embedded git_remote_callbacks struct, which grew
    from 120 bytes in 1.5 to 128 in 1.9, so a fixed offset does not merely
    miss: under 1.9 it lands on `update_refs`, a function pointer that
    libgit2 prefers over `update_tips` and calls.
  - Complete the error-code mirror through the end of the C enum:
    GIT_EUNCHANGED (-38), GIT_ENOTSUPPORTED (-39), GIT_EREADONLY (-40).
  - Document git_fetch_options_init and git_push_options_init, the only two
    bound functions that had no POD. List fetch_options_prune_offset under
    EXPORTS, where it was missing since it was added.
  - Fix the SYNOPSIS: `printf "libgit2 %s\n", version()` called version() in
    list context, printing just the major number plus a redundant-argument
    warning. Now `scalar version()`.
  - Group headings in Git::Libgit2::FFI are =head1, not =head2. They used to
    sit at the same level as the 236 function entries, which left the
    generated table of contents unable to tell a group from a function.
  - CI installs Alien::Libgit2 from CPAN rather than checking out the sibling
    repo, so it exercises the install path users actually take. Both paths are
    now pinned with ALIEN_INSTALL_TYPE instead of left to whatever pkg-config
    happens to find, and a new linux job covers the share build (Alien's
    bundled libgit2 1.9.3) that a user without a system libgit2 gets. Each job
    reports the install type and libgit2 version it linked against.
  - README: state the situation instead of implying it. The layer stack down
    from App::karr is spelled out, so it is clear which questions this layer
    declines to answer; the runtime struct-layout hazard has its own section;
    TODO.md is linked as the record of what is deliberately unbound. The
    function list covers all 236 bindings (34 were missing, among them the
    whole git_object_* and git_oid_* families) and no longer claims a
    git_conflicts_next, which never existed.

0.006     2026-08-11 03:38:31Z
  - Bind git_object_lookup_prefix for abbreviated-OID lookups. Export
    GIT_OID_MINPREFIXLEN (4). The len argument counts hex characters
    (nibbles), not raw bytes.
  - Bind git_libgit2_opts (variadic) for the (int, string) form used by
    GIT_OPT_SET_SEARCH_PATH, enabling programmatic config-search-path
    isolation. Export GIT_OPT_SET_SEARCH_PATH and the full
    GIT_CONFIG_LEVEL_* enum.
  - Export git_sort_t, git_direction, git_branch_t, git_filemode_t, and
    git_status_t constant groups so consumers stop redeclaring them
    locally (drift risk for GIT_ITEROVER / GIT_PASSTHROUGH and friends).
  - Add gitconfig isolation (GIT_CONFIG_GLOBAL / GIT_CONFIG_SYSTEM) to
    t/00-load.t, t/03-error.t, and t/torture-init.t to match the rest of
    the suite.
  - Bind git_index_find_prefix, so "is anything under this path tracked?"
    can be answered natively instead of by shelling out to git ls-files.
    The match is a string prefix, not a path prefix: a caller asking about
    a directory must supply the trailing slash itself.
  - Export GIT_OID_RAWSZ (20) and GIT_OID_HEXSZ (40), so consumers sizing
    their own git_oid buffers stop redeclaring the widths locally.
  - Correct the git_index_find documentation: it returns an error code
    (GIT_ENOTFOUND on a miss), not UINT_MAX, and the position lands in the
    out-param, which libgit2 leaves untouched on a miss — so the position
    is only meaningful when the return code is 0.
  - Fix three vacuous tests that passed a raw buffer address for a typed
    pointer out-param (size_t*, git_reference**). FFI::Platypus passes
    NULL rather than the address in that case, so the buffer kept its
    zeroed initialisation and the assertions could not fail. Pointer
    out-params need a scalar ref; only git_oid out-params typed as plain
    opaque take an address.
  - Give t/16-config.t and t/34-cherrypick-revert.t assertions that can
    fail. The config test checked `rc < 0 || rc == 0`, true for every
    value libgit2 can return; it now pins the documented refusal of
    git_config_get_string on a live handle and reads the value back over
    a snapshot. The cherrypick/revert test asserted in both branches of
    an if/else and never reached the success path — its scenario was
    unpickable (no parent to diff against, plus mainline=1 on a
    non-merge commit). It now builds a real two-branch history and
    asserts the merged index, the mainline misuse, and the working-tree
    effect of git_cherrypick.
  - Correct the cherrypick/revert documentation. The out-param of
    git_cherrypick_commit / git_revert_commit is a git_index handle the
    caller must free, not an OID, and neither function creates a commit
    despite the name — they compute the resulting index. The fifth
    argument is mainline (the parent to diff a merge against, 0 for an
    ordinary commit), not a parent count. git_cherrypick / git_revert
    do write to the index and working directory, so they need a
    checked-out working directory.

0.005     2026-08-09 20:03:21Z
  - Bind git_reference_create_matching for compare-and-swap direct reference
    updates that reject stale expected OIDs with GIT_EMODIFIED.
  - Fix the git_reference_create test to treat its out-param as an owned
    git_reference handle and free it, rather than misreading pointer bytes as
    an OID.
  - New closure type git_transport_certificate_check_cb, so callers can
    install a host-key / TLS certificate verification callback on remote
    fetch/push/connect.
  - Bind git_config_get_bool, so callers can read booleans with libgit2's
    own parsing rules instead of reimplementing them.
  - Git::Libgit2::Error now decodes the `klass` field of git_error (the
    git_error_t category) instead of always reporting 0.
  - Export the git_error_code constants (GIT_OK, GIT_ERROR, GIT_ENOTFOUND,
    GIT_EEXISTS, GIT_EAUTH, GIT_ECERTIFICATE, GIT_ENONFASTFORWARD, ... up
    to GIT_TIMEOUT) so callers can compare $err->code symbolically.

0.004     2026-05-27 17:06:23Z
  - Fix git_tag_create binding: the oid out-param is a caller-allocated
    git_oid buffer, so it must be declared 'opaque' (not 'opaque*') like
    the lightweight/from_buffer variants. The old declaration made every
    git_tag_create call fail with "failed to create tag annotation". The
    existing test only exercised git_tag_create_from_buffer, so it slipped
    through; t/13-tag.t now also covers git_tag_create directly.

0.003     2026-05-27 14:53:34Z
  - New binding git_repository_set_head: pin HEAD at a (possibly unborn)
    branch, e.g. to force 'main' on a freshly init'd repo regardless of the
    compiled-in default or ambient init.defaultBranch
  - Group A accessor/predicate complements:
    repository_head/head_unborn/head_detached,
    reference_symbolic_create/symbolic_target/symbolic_set_target/set_target/
    resolve/shorthand/is_branch/is_remote/is_tag,
    commit_id/time/time_offset/summary
  - Add TODO.md cataloguing the remaining unbound libgit2 1.5.1 surface
    (Group B: merge content-level, diff/patch text, index conflicts, stash
    iteration, branch upstream, typed config, remote management; Group C:
    blame, describe, submodule, worktree, notes, apply, attr/ignore,
    pathspec, mailmap) with per-family FFI gotchas
  - CI: pin the sibling Alien::Libgit2 install step to bash (the perl
    container falls back to dash, which lacks 'set -o pipefail')
  - Fix t/01 workdir comparison on macOS (resolve the /var -> /private/var
    symlink so it matches libgit2's canonical path)

0.002     2026-05-27 12:43:29Z
  - Update CI workflows to use the shared dzil-test composite action from
    [@Author::GETTY]; fixes missing Test::Pod by using listdeps --author
    in the sibling Alien::Libgit2 install step
  - Comprehensive POD pass: document every FFI function with =func, every
    Error method with =method, add section headers per group, add README.md
    with full function tables and architecture overview
  - Fix three POD transcription typos in FFI.pm (broken code examples in
    git_revwalk_hide_ref, git_credential_username_new, git_graph_ahead_behind)

0.001     2026-05-24 17:56:31Z
  - Initial release
  - Low-level FFI::Platypus bindings to libgit2 (via Alien::Libgit2)
  - Core: init/shutdown, version, error_last, repository_open_ext/free,
    config_open_default, reference_lookup/create/delete/iterator_new/name/target,
    oid_fromstr/tostr, blob_create_from_buffer/lookup/rawcontent/rawsize/free,
    treebuilder_new/insert/write/free, commit_create/lookup/tree/message/free,
    object_lookup/free
  - Remote + auth: remote_lookup/url/create/create_anonymous/connect/ls/disconnect,
    remote_fetch/push/init_callbacks, fetch_options_init, push_options_init,
    credential_userpass_plaintext_new/ssh_key_new/ssh_key_from_agent/
    default_new/username_new/free, git_credential_acquire_cb closure type
  - General-purpose: clone/clone_options_init, revwalk_* (new/push/push_head/
    push_ref/push_glob/push_range/hide*/next/sorting/reset/simplify_first_parent/free),
    branch_create/lookup/delete/iterator_new/next/iterator_free/name/is_head/move,
    tag_create/create_lightweight/lookup/delete/list/list_match/target/target_id/
    message/name/tagger/free,
    status_options_init/foreach/foreach_ext/file,
    diff_options_init/tree_to_tree/tree_to_workdir/tree_to_index/index_to_workdir/
    num_deltas/get_delta/free,
    repository_index/index_free, strarray_free
  - Tested against libgit2 1.5 (Debian Bookworm) and 1.9 (vendored share build)
