Module Vcs_base.Vcs

Extended Vcs API

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
type -'a t

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.

Error handling

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.

Creating repositories

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.

Revisions

module Mock_rev_gen = Vcs.Mock_rev_gen
module Mock_revs = Vcs.Mock_revs

Commits

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.

Files

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 ]

Files IO

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 ".", "..".

Branches & Tags

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.

Computing diffs

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

Manipulating the graph in memory

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

Rev parse utils

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

User config

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

Low level Git cli

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
;;

Non-raising APIs

For convenience and to allow experimenting with different error handling strategies, Vcs exports non-raising APIs. The functions there return Result.ts instead of raising.

module Result : sig ... end

An Vcs API based on Result and Vcs.Err.

module Rresult : sig ... end

An Vcs API in the style of Rresult.

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.

Additional modules

module Or_error : sig ... end

An Vcs API based on Base.Or_error.