Something went wrong. Try again.
A Zig library that reads git repositories without running git, with log, show and diff output byte-identical to git's.
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! Pathspecs on the command line: read as git reads them, with the//! `GIT_*_PATHSPECS` settings from the environment, the current directory//! as the prefix, and git's words when one cannot be read.
const std = @import("std");const Allocator = std.mem.Allocator;const Io = std.Io;
const git = @import("git");const Pathspec = git.Pathspec;const tool = @import("zig_git.zig");const Context = tool.Context;
/// Reads `args` as a pathspec for `repo`, run from its prefix. `command`/// names the command in a refusal.pub fn parse(ctx: Context, repo: *const git.Repository, args: []const []const u8, command: []const u8, stderr: *Io.Writer) !Pathspec { var diag: git.Diagnostics = .{}; const env = ctx.env; const settings = Pathspec.settingsFromEnvironment( env.get("GIT_LITERAL_PATHSPECS"), env.get("GIT_GLOB_PATHSPECS"), env.get("GIT_NOGLOB_PATHSPECS"), env.get("GIT_ICASE_PATHSPECS"), &diag, ) catch return tool.fatalMessage(stderr, "{s}", .{diag.detail()}); const work_tree = repo.location.work_tree orelse repo.location.work_dir; return Pathspec.parse(ctx.gpa, args, .{ .prefix = repo.location.prefix orelse "", .work_tree = work_tree, .settings = settings, }, &diag) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.UnsupportedMagic => { stderr.print("zig-git: {s}: the '{s}' pathspec magic is not supported\n", .{ command, diag.detail() }) catch {}; return error.Fatal; }, else => return tool.fatalMessage(stderr, "{s}", .{diag.detail()}), };}
/// Whether git takes `arg`, given without `--` where no revision could be/// read, for a path: one with a wildcard or in the long magic form, which/// need not exist; `:/<path>`, from the top, and `:!<path>` or/// `:^<path>`, from the current directory, which must; or a path that is/// there.pub fn takenForPath(ctx: Context, repo: *const git.Repository, arg: []const u8) !bool { if (std.mem.findAny(u8, arg, "*?[") != null) return true; if (std.mem.startsWith(u8, arg, ":(")) return true; if (std.mem.startsWith(u8, arg, ":/")) { const rest = arg[2..]; if (rest.len == 0) return true; const top = repo.location.work_tree orelse return false; return exists(ctx, top, rest); } var path = arg; if (std.mem.startsWith(u8, arg, ":!") or std.mem.startsWith(u8, arg, ":^")) path = arg[2..]; if (std.fs.path.isAbsolute(path)) return exists(ctx, "/", path); return exists(ctx, ctx.cwd, path);}
fn exists(ctx: Context, dir: []const u8, path: []const u8) !bool { const full = try std.fs.path.join(ctx.gpa, &.{ dir, path }); defer ctx.gpa.free(full); _ = Io.Dir.cwd().statFile(ctx.io, full, .{ .follow_symlinks = false }) catch return false; return true;}