Vcs_base.Vcs
module Author : sig ... end
module Branch_name : sig ... end
module Commit_message : sig ... end
module Err : sig ... end
module File_contents : sig ... end
module Git : sig ... end
module Graph : sig ... end
module Name_status : sig ... end
module Num_lines_in_diff : sig ... end
module Path_in_repo : sig ... end
module Platform : sig ... end
module Ref_kind : sig ... end
module Refs : sig ... end
module Remote_branch_name : sig ... end
module Remote_name : sig ... end
module Repo_name : sig ... end
module Repo_root : sig ... end
module Rev : sig ... end
module Tag_name : sig ... end
module Url : sig ... end
module User_email : sig ... end
module User_handle : sig ... end
module User_name : sig ... end
include module type of Vcs
with module Author := Vcs.Author
and module Branch_name := Vcs.Branch_name
and module Commit_message := Vcs.Commit_message
and module Err := Vcs.Err
and module File_contents := Vcs.File_contents
and module Git := Vcs.Git
and module Graph := Vcs.Graph
and module Name_status := Vcs.Name_status
and module Num_lines_in_diff := Vcs.Num_lines_in_diff
and module Path_in_repo := Vcs.Path_in_repo
and module Platform := Vcs.Platform
and module Ref_kind := Vcs.Ref_kind
and module Refs := Vcs.Refs
and module Remote_branch_name := Vcs.Remote_branch_name
and module Remote_name := Vcs.Remote_name
and module Repo_name := Vcs.Repo_name
and module Repo_root := Vcs.Repo_root
and module Rev := Vcs.Rev
and module Tag_name := Vcs.Tag_name
and module Url := Vcs.Url
and module User_email := Vcs.User_email
and module User_handle := Vcs.User_handle
and module User_name := Vcs.User_name
module Trait = Vcs.Trait
At its core, a 'a Vcs.t
is a value encapsulating the functionalities implemented by a set of traits, represented by the 'a
parameter. It is a phantom type used to provide compiler guidance on which functions from the API you can use with such a vcs
. The type is contravariant in its parameter : indeed, if you need a set of traits, having access to a provider implementing more traits makes it compatible.
val create : 'a Provider.packed -> 'a t
create provider
returns a vcs
that implements a given set of traits. Typical users do not use create
directly, but rather will rely on an actual provider. See for example Vcs_git_eio.create
.
The default API of Vcs
is one that exposes functions that may raise a single exception, named E
, which carries an abstract payload err
containing printable information. err
is not meant for pattern matching - we're only targeting a non-specialized error recovery.
A general design principle that we follow here is that if an error result is of interest for pattern matching, we want to incorporate it into the successful branch of the function's result, rather than in its error part - either by making the result a variant type, or otherwise adding more functions to the API with finer granularity for particular use cases. Consider opening an issue on GitHub
if what you'd like to match on isn't available.
As library authors we realize that manipulating Result.t
is a popular choice too: we also export the Vcs
's functionality via non-raising APIs if you prefer.
exception E of Vcs.Err.t
E
is meant to be the only exception ever raised by functions from the Vcs
interface. Err.t
doesn't carry the raw backtrace, so you'll need to manipulate the backtrace yourself if you care about it (like you would with any other exceptions).
module Exn : sig ... end
Handling of exceptions in Vcs
.
val init :
[> Trait.init ] t ->
path:Fpath_sexp0.Absolute_path.t ->
Vcs.Repo_root.t
Initialize a Git repository at the given path. This errors out if a repository is already initialized there.
val find_enclosing_repo_root :
[> Trait.file_system ] t ->
from:Fpath_sexp0.Absolute_path.t ->
store:(Fpath_sexp0.Fsegment.t * 'store) list ->
('store * Vcs.Repo_root.t) option
find_enclosing_repo_root vcs ~from:dir ~store
walks up the path from the given directory dir
and stops when at the root of a repository. If no repo root has been found when reaching the root path "/"
, the function returns None
.
The way we determine whether we are at the root of a repo is by looking for the presence of one of the store entries in the directory (e.g. ".git"
).
When present, we do not check that the store is itself a directory, so that this function is able to correctly infer and return the root of Git repos where ".git"
is not a directory (e.g. Git worktrees).
You may supply several stores if you want to stop at the first store that is encountered, if you do not know in what kind of repo you are. For example, [".git", `Git; ".hg", `Hg]
. The store that was matched is returned as part of the result.
If you know you are in a Git repository you may want to use the wrapper find_enclosing_git_repo_root
instead.
val find_enclosing_git_repo_root :
[> Trait.file_system ] t ->
from:Fpath_sexp0.Absolute_path.t ->
Vcs.Repo_root.t option
find_enclosing_git_repo_root vcs ~from:dir
is a convenient wrapper around find_enclosing_repo_root
for Git repositories. This is looking for the deepest directory containing a ".git"
entry, starting from dir
and walking up.
module Mock_rev_gen = Vcs.Mock_rev_gen
module Mock_revs = Vcs.Mock_revs
val add :
[> Trait.add ] t ->
repo_root:Vcs.Repo_root.t ->
path:Vcs.Path_in_repo.t ->
unit
val commit :
[> Trait.rev_parse | Trait.commit ] t ->
repo_root:Vcs.Repo_root.t ->
commit_message:Vcs.Commit_message.t ->
Vcs.Rev.t
When this succeeds, this returns the revision of the commit that was just created.
val ls_files :
[> Trait.ls_files ] t ->
repo_root:Vcs.Repo_root.t ->
below:Vcs.Path_in_repo.t ->
Vcs.Path_in_repo.t list
val show_file_at_rev :
[> Trait.show ] t ->
repo_root:Vcs.Repo_root.t ->
rev:Vcs.Rev.t ->
path:Vcs.Path_in_repo.t ->
[ `Present of Vcs.File_contents.t | `Absent ]
Vcs contains some basic provider based functions to manipulate files from the file system. The goal is to allow some users of Vcs
to use this simple API without committing to a particular implementation. If the Vcs
provider used at runtime is based on Eio
, these functions will use Eio.Path
underneath.
val load_file :
[> Trait.file_system ] t ->
path:Fpath_sexp0.Absolute_path.t ->
Vcs.File_contents.t
val save_file :
?perms:int ->
[> Trait.file_system ] t ->
path:Fpath_sexp0.Absolute_path.t ->
file_contents:Vcs.File_contents.t ->
unit
Create a new file, or truncate an existing one.
val read_dir :
[> Trait.file_system ] t ->
dir:Fpath_sexp0.Absolute_path.t ->
Fpath_sexp0.Fsegment.t list
Returns the entries of the supplied directory, ordered increasingly according to String.compare
. The result does not include the unix entries ".", "..".
val rename_current_branch :
[> Trait.branch ] t ->
repo_root:Vcs.Repo_root.t ->
to_:Vcs.Branch_name.t ->
unit
This translates to git branch --move $NAME
, which is used to enforce the name of a default branch during tests. If the current branch already has this name, this has no further effect.
module Num_status = Vcs.Num_status
val name_status :
[> Trait.name_status ] t ->
repo_root:Vcs.Repo_root.t ->
changed:Vcs.Name_status.Changed.t ->
Vcs.Name_status.t
val num_status :
[> Trait.num_status ] t ->
repo_root:Vcs.Repo_root.t ->
changed:Num_status.Changed.t ->
Num_status.t
module Log = Vcs.Log
val log : [> Trait.log ] t -> repo_root:Vcs.Repo_root.t -> Log.t
val refs : [> Trait.refs ] t -> repo_root:Vcs.Repo_root.t -> Vcs.Refs.t
val graph :
[> Trait.log | Trait.refs ] t ->
repo_root:Vcs.Repo_root.t ->
Vcs.Graph.t
val current_branch :
[> Trait.rev_parse ] t ->
repo_root:Vcs.Repo_root.t ->
Vcs.Branch_name.t
val current_revision :
[> Trait.rev_parse ] t ->
repo_root:Vcs.Repo_root.t ->
Vcs.Rev.t
During tests in the GitHub environment we end up having issues if we do not set the user name and email. Also, we rather not do it globally. If this is never called, the current user config is used as usual by Git processes invocations.
val set_user_name :
[> Trait.config ] t ->
repo_root:Vcs.Repo_root.t ->
user_name:Vcs.User_name.t ->
unit
val set_user_email :
[> Trait.config ] t ->
repo_root:Vcs.Repo_root.t ->
user_email:Vcs.User_email.t ->
unit
This part of Vcs provides direct access to the "git"
command line interface. This should be considered non portable and brittle. Generally speaking, one hope is that you shouldn't have to use git
directly. Instead, consider requesting proper integration of your use case into the typed and parametrized API of Vcs
. However, sometimes this is just what you need e.g. in tests, or for quick one-off, and if your backend happens to be a CLI
based vcs provider, we might as well expose this. Use at your own risk/convenience.
val git :
?env:string array ->
?run_in_subdir:Vcs.Path_in_repo.t ->
[> Trait.git ] t ->
repo_root:Vcs.Repo_root.t ->
args:string list ->
f:(Vcs.Git.Output.t -> 'a) ->
'a
Note a non trivial behavior nuance depending on whether you are using this function using the raising or non-raising API. In the raising API, f
is allowed to raise: git
will catch any exception raised by f
, and rewrap it under a proper E err
exception with added context. In the non-raising APIs, if f
raises instead of returning an Error
, that exception would escape the function git
and be raised by git
as an uncaught exception. This would be considered a programming error.
Some helpers are provided by the module Git
to help you build the f
parameter. Non-raising modules are also included in the Git
module dedicated to their respective result type (see for example Vcs_base.Vcs.Git.Or_error
).
The expectation is that you should be using the Git
module of the API you are using to access the git
function, and not mix and match.
For example:
let git_status () : string =
Vcs.git vcs ~repo_root ~args:[ "status" ] ~f:Vcs.Git.exit0_and_stdout
;;
Or:
let git_status () : string Vcs.Result.t =
Vcs.Result.git
vcs
~repo_root
~args:[ "status" ]
~f:Vcs.Git.Result.exit0_and_stdout
;;
For convenience and to allow experimenting with different error handling strategies, Vcs
exports non-raising APIs. The functions there return Result.t
s instead of raising.
module Result : sig ... end
An Vcs
API based on Result
and Vcs.Err
.
module Non_raising = Vcs.Non_raising
module Private : sig ... end
This part of the interface is not stable. Things may break without notice when upgrading to a new version of Vcs
. This is used e.g. by tests or libraries with strong ties to Vcs
.
module Or_error : sig ... end
An Vcs
API based on Base.Or_error
.