Packages

A Git library for Elixir, powered by Gitoxide.

Current section

Files

Jump to
ex_gix lib ex_gix repository.ex
Raw

lib/ex_gix/repository.ex

defmodule ExGix.Repository do
@moduledoc """
Git repository related functions.
"""
@doc """
Opens a Git repository at the given path, possibly expanding it to `path/.git` if `path` is a work tree dir.
## Examples
iex> {:ok, repo} = ExGix.Repository.open(".")
iex> is_reference(repo)
true
"""
@spec open(String.t()) :: {:ok, reference()} | {:error, String.t()}
def open(path) when is_binary(path) do
ExGix.Native.open(path)
end
@doc """
Create a repository with work-tree within `directory`, creating intermediate directories as needed.
"""
@spec init(String.t()) :: {:ok, reference()} | {:error, String.t()}
def init(directory) when is_binary(directory) do
ExGix.Native.init(directory)
end
@doc """
Try to open a git repository in `directory` and search upwards through its parents until one is found.
"""
@spec discover(String.t()) :: {:ok, reference()} | {:error, String.t()}
def discover(directory) when is_binary(directory) do
ExGix.Native.discover(directory)
end
@doc """
Try to open a git repository directly from the environment. If that fails, discover upwards from `directory` until one is found, while applying discovery options from the environment.
"""
@spec discover_with_environment_overrides(String.t()) ::
{:ok, reference()} | {:error, String.t()}
def discover_with_environment_overrides(directory) when is_binary(directory) do
ExGix.Native.discover_with_environment_overrides(directory)
end
@doc """
The path to the `.git` directory itself, or equivalent if this is a bare repository.
"""
@spec path(reference()) :: String.t()
def path(repo) when is_reference(repo) do
ExGix.Native.path(repo)
end
@doc """
Return the path to the repository itself, containing objects, references, configuration, and more.
Synonymous to `path/1`.
"""
@spec git_dir(reference()) :: String.t()
def git_dir(repo) when is_reference(repo) do
path(repo)
end
@doc """
Return the path to the working directory if this is not a bare repository.
"""
@spec work_dir(reference()) :: String.t() | nil
def work_dir(repo) when is_reference(repo) do
ExGix.Native.work_dir(repo)
end
@doc """
Return the path to the directory containing all objects.
"""
@spec objects_dir(reference()) :: String.t()
def objects_dir(repo) when is_reference(repo) do
ExGix.Native.objects_dir(repo)
end
@doc """
Return true if this repository is bare.
"""
@spec is_bare(reference()) :: boolean()
def is_bare(repo) when is_reference(repo) do
ExGix.Native.is_bare(repo)
end
@doc """
Return true if the repository is a shallow clone.
"""
@spec is_shallow(reference()) :: boolean()
def is_shallow(repo) when is_reference(repo) do
ExGix.Native.is_shallow(repo)
end
@doc """
Resolve the HEAD reference and obtain its object id.
"""
@spec head_id(reference()) :: {:ok, String.t()} | {:error, String.t()}
def head_id(repo) when is_reference(repo) do
ExGix.Native.head_id(repo)
end
@doc """
Return the tree id the HEAD reference currently points to after peeling it fully.
"""
@spec head_tree_id(reference()) :: {:ok, String.t()} | {:error, String.t()}
def head_tree_id(repo) when is_reference(repo) do
ExGix.Native.head_tree_id(repo)
end
@doc """
Return the name to the symbolic reference HEAD points to, or nil if the head is detached.
"""
@spec head_name(reference()) :: {:ok, String.t() | nil} | {:error, String.t()}
def head_name(repo) when is_reference(repo) do
ExGix.Native.head_name(repo)
end
@doc """
Return a list of local branch names (from `refs/heads/`).
## Examples
{:ok, repo} = ExGix.Repository.open(".")
{:ok, branches} = ExGix.Repository.local_branches(repo)
# ["main", "feature-branch", ...]
"""
@spec local_branches(reference()) :: {:ok, [String.t()]} | {:error, String.t()}
def local_branches(repo) when is_reference(repo) do
ExGix.Native.local_branches(repo)
end
@doc """
Return a list of remote tracking branch names (from `refs/remotes/`).
## Examples
{:ok, repo} = ExGix.Repository.open(".")
{:ok, branches} = ExGix.Repository.remote_branches(repo)
# ["origin/main", "origin/develop", ...]
"""
@spec remote_branches(reference()) :: {:ok, [String.t()]} | {:error, String.t()}
def remote_branches(repo) when is_reference(repo) do
ExGix.Native.remote_branches(repo)
end
@doc """
List references in the repository.
When called with no prefix, returns all references (excluding pseudo-refs).
When called with a prefix, returns only references matching that prefix.
Returns a list of `{name, target}` tuples where `name` is the full ref name
and `target` is either the object id or the symbolic target.
## Examples
{:ok, repo} = ExGix.Repository.open(".")
# All references
{:ok, refs} = ExGix.Repository.references(repo)
# [{"refs/heads/main", "abc123..."}, {"refs/remotes/origin/main", "abc123..."}]
# Only tags
{:ok, tags} = ExGix.Repository.references(repo, "refs/tags/")
"""
@spec references(reference(), String.t() | nil) ::
{:ok, [{String.t(), String.t()}]} | {:error, String.t()}
def references(repo, prefix \\ nil) when is_reference(repo) do
ExGix.Native.list_references(repo, prefix)
end
@doc """
Returns a sorted list unique of symbolic names of remotes.
"""
@spec remote_names(reference()) :: [String.t()]
def remote_names(repo) when is_reference(repo) do
ExGix.Native.remote_names(repo)
end
@doc """
Gets the status of the repository, returning a list of `ExGix.StatusItem` structs.
## Examples
{:ok, repo} = ExGix.Repository.open("path/to/repo")
{:ok, statuses} = ExGix.Repository.status(repo)
# Example output:
# [
# %ExGix.StatusItem{
# location: :index_worktree,
# path: "new_file.txt",
# status: :untracked
# },
# %ExGix.StatusItem{
# location: :tree_index,
# path: "staged.txt",
# status: :added
# }
# ]
"""
@spec status(reference()) :: {:ok, [ExGix.StatusItem.t()]} | {:error, String.t()}
def status(repo) when is_reference(repo) do
ExGix.Native.status(repo)
end
@doc """
Create a new commit on HEAD, automatically resolving the current tree and parent.
"""
@spec commit(reference(), String.t()) :: {:ok, String.t()} | {:error, String.t()}
def commit(repo, message) when is_reference(repo) and is_binary(message) do
with {:ok, tree_id} <- head_tree_id(repo),
{:ok, head_id} <- head_id(repo) do
commit(repo, "HEAD", message, tree_id, [head_id])
end
end
@doc """
Create a new commit object with message referring to tree with parents, and point reference to it.
"""
@spec commit(reference(), String.t(), String.t(), String.t(), [String.t()]) ::
{:ok, String.t()} | {:error, String.t()}
def commit(repo, reference, message, tree, parents) when is_reference(repo) do
ExGix.Native.commit(repo, reference, message, tree, parents)
end
@doc """
Create a new commit on HEAD using the specified committer and author, automatically resolving the current tree and parent.
## Examples
{:ok, repo} = ExGix.Repository.open("path/to/repo")
sig = %ExGix.Signature{
name: "Test Committer",
email: "test@example.com",
time_seconds: System.os_time(:second),
time_offset: 0
}
{:ok, commit_id} = ExGix.Repository.commit_as(repo, sig, sig, "Test commit message")
"""
@spec commit_as(reference(), ExGix.Signature.t(), ExGix.Signature.t(), String.t()) ::
{:ok, String.t()} | {:error, String.t()}
def commit_as(repo, committer, author, message)
when is_reference(repo) and is_binary(message) do
with {:ok, tree_id} <- head_tree_id(repo),
{:ok, head_id} <- head_id(repo) do
commit_as(repo, committer, author, "HEAD", message, tree_id, [head_id])
end
end
@doc """
Similar to commit/5, but allows to create the commit with committer and author specified.
"""
@spec commit_as(
reference(),
ExGix.Signature.t(),
ExGix.Signature.t(),
String.t(),
String.t(),
String.t(),
[String.t()]
) :: {:ok, String.t()} | {:error, String.t()}
def commit_as(repo, committer, author, reference, message, tree, parents)
when is_reference(repo) do
ExGix.Native.commit_as(repo, committer, author, reference, message, tree, parents)
end
@doc """
Create a new commit object and write it to the object database. Do not update any references.
"""
@spec new_commit(reference(), String.t(), String.t(), [String.t()]) ::
{:ok, String.t()} | {:error, String.t()}
def new_commit(repo, message, tree, parents) when is_reference(repo) do
ExGix.Native.new_commit(repo, message, tree, parents)
end
@doc """
Create a new commit object using the specified committer and author, and write it to the object database. Do not update any references.
"""
@spec new_commit_as(
reference(),
ExGix.Signature.t(),
ExGix.Signature.t(),
String.t(),
String.t(),
[String.t()]
) :: {:ok, String.t()} | {:error, String.t()}
def new_commit_as(repo, committer, author, message, tree, parents) when is_reference(repo) do
ExGix.Native.new_commit_as(repo, committer, author, message, tree, parents)
end
@doc """
Output the content of a blob object.
## Examples
{:ok, repo} = ExGix.Repository.open("path/to/repo")
# Read a file using a path revision spec
{:ok, content} = ExGix.Repository.cat_file(repo, "HEAD:README.md")
# Read a file using an object ID
{:ok, blob_id} = ExGix.Repository.rev_parse(repo, "HEAD:README.md")
{:ok, content} = ExGix.Repository.cat_file(repo, blob_id)
"""
@spec cat_file(reference(), String.t()) ::
{:ok, binary()} | {:error, String.t()}
def cat_file(repo, revspec)
when is_reference(repo) and is_binary(revspec) do
ExGix.Native.cat_file(repo, revspec)
end
@doc """
Find the object id for the given revision string.
## Examples
{:ok, repo} = ExGix.Repository.open("path/to/repo")
# Resolve a commit
{:ok, commit_id} = ExGix.Repository.rev_parse(repo, "HEAD")
# Resolve a tree
{:ok, tree_id} = ExGix.Repository.rev_parse(repo, "HEAD^{tree}")
# Resolve a blob
{:ok, blob_id} = ExGix.Repository.rev_parse(repo, "HEAD:README.md")
"""
@spec rev_parse(reference(), String.t()) :: {:ok, String.t()} | {:error, String.t()}
def rev_parse(repo, revspec) when is_reference(repo) and is_binary(revspec) do
ExGix.Native.rev_parse(repo, revspec)
end
@doc """
List the contents of a tree object, similar to `git ls-tree`.
Accepts options such as `recursive: true`.
## Examples
{:ok, repo} = ExGix.Repository.open("path/to/repo")
# List the root tree of the HEAD commit
{:ok, items} = ExGix.Repository.ls_tree(repo, "HEAD")
# List a specific subdirectory
{:ok, items} = ExGix.Repository.ls_tree(repo, "HEAD:lib")
# List recursively
{:ok, items} = ExGix.Repository.ls_tree(repo, "HEAD", recursive: true)
# Items are returned as a list of ExGix.TreeItem structs
# [
# %ExGix.TreeItem{
# filename: "README.md",
# kind: :blob,
# mode: "100644",
# oid: #Reference<...>
# },
# ...
# ]
"""
@spec ls_tree(reference(), String.t(), keyword()) ::
{:ok, [ExGix.TreeItem.t()]} | {:error, String.t()}
def ls_tree(repo, revspec, opts \\ []) when is_reference(repo) and is_binary(revspec) do
recursive = Keyword.get(opts, :recursive, false)
ExGix.Native.ls_tree(repo, revspec, recursive)
end
end