View Source egit - Erlang interface to Git

build

This project is an Erlang NIF wrapper to libgit2 library. It allows to execute commands to access and manage a git repository without depending on the external git tool and internally doesn't involve any parsing of text output produced by the git executable.

Though it appears to be stable, the project is currently in the alpha stage and more functionality is being added.

Source code: https://github.com/saleyn/egit

Documentation: https://hexdocs.pm/egit

currently-supported-functionality

Currently supported functionality

  • Init a repository (including creation of bare repositories)
  • Clone a repository
  • Open a repository at given local path
  • Fetch from remote
  • Pull from remote
  • Push to remote
  • Add files to repository
  • Commit
  • Checkout
  • Get status
  • Cat-file
  • Rev-parse
  • Rev-list
  • Branch list/create/rename/delete
  • Configuration get/set at various levels (e.g. system/global/local/app/default)
  • List files in index
  • List/add/delete/rename/set-url on a remote
  • List/create/delete tags
  • Reset

installation

Installation

  • Make sure you have libgit2 installed.

    • On Ubuntu run: sudo apt-get install libgit2-dev
    • On Arch Linux run: sudo pacman -S libgit2
    • On Mac OS run: brew install libgit2
  • If you are building locally from source, clone egit and run:

    $ make
    
  • For Erlang projects add the dependency in rebar.config:

    {deps,
     [% ...
      {egit, "~> 0.1"}
     ]}.
  • For Elixir projects add the dependency in mix.exs:

    def deps do
      [
        {:egit, "~> 0.1"}
      ]
    end

usage

Usage

To clone a repository, give it a URL and a local path:

1> Repo = git:clone("http://github.com/saleyn/egit.git", "/tmp").
#Ref<...>

To open a local repository, give it a path:

1> Repo = git:open(<<"/tmp/egit">>).
#Ref<...>

All functions accept either charlists or binaries as arguments, so they work conveniently in Erlang and Elixir.

The cloned/opened repository resource is owned by the current process, and will be automatically garbage collected when the owner process exits.

After obtaining a repository reference, you can call functions in the git module as illustrated below. For complete reference of supported functions see the documentation.

erlang-example

Erlang Example

2> git:branch_create(R, "tmp", [{target, <<"1b74c46">>}]).
ok
3> git:checkout(R, "tmp").
ok
4> file:write_file("/tmp/egit/temp.txt", <<"This is a test">>).
ok
5> git:add(R, ".").
#{mode => added,files => [<<"temp.txt">>]}
6> git:commit(R, "Add test files").
ok
7> git:cat_file(R, <<"tmp">>, [{abbrev, 5}]).
#{type => commit,
  author =>
      {<<"Serge Aleynikov">>,<<"test@gmail.com">>,1686195121, -14400},
  oid => <<"b85d0">>,
  parents => [<<"1fd4b">>]}
8> git:cat_file(R, "b85d0", [{abbrev, 5}]).
#{type => tree,
  commits =>
      [{<<".github">>,<<"tree">>,<<"1e41f">>,16384},
       {<<".gitignore">>,<<"blob">>,<<"b893a">>,33188},
       {<<".gitmodules">>,<<"blob">>,<<"2550a">>,33188},
       {<<".vscode">>,<<"tree">>,<<"c7b1b">>,16384},
       {<<"LICENSE">>,<<"blob">>,<<"d6456">>,33188},
       {<<"Makefile">>,<<"blob">>,<<"2d635">>,33188},
       {<<"README.md">>,<<"blob">>,<<"7b3d0">>,33188},
       {<<"c_src">>,<<"tree">>,<<"147f3">>,16384},
       {<<"rebar.config">>,<<"blob">>,<<"1f68a">>,33188},
       {<<"rebar.lock">>,<<"blob">>,<<"57afc">>,33188},
       {<<"src">>,<<"tree">>,<<"1bccb">>,16384}]}
8> git:cat_file(R, "b893a", [{abbrev, 5}]).
#{type => blob,
  blob => <<"*.swp\n*.dump\n/c_src/*.o\n/c_src/fmt\n/priv/*.so\n/_build\n/doc\n">>}

elixir-example

Elixir example

iex(1)> repo = :git.init("/tmp/egit_repo")
#Reference<0.739271388.2889220102.160795>
iex(2)> :git.remote_add(repo, "origin", "git@github.com:saleyn/test_repo.git")
:ok
iex(3)> :git.list_remotes(repo)
[{"origin", "git@github.com:saleyn/test_repo.git", [:push, :fetch]}]
iex(4)> ok = File.write!("/tmp/egit_repo/README.md", <<"This is a test\n">>)
:ok
iex(5)> :git.add(repo, "README.md")
%{mode: :added, files: ["README.md"]}
iex(6)> :git.status(repo)
[%{index: [{:new, "README.md"}]}]
iex(7)> :git.commit(repo, "Initial commit")
{:ok, "dc89c6b26b22f41d34300654f8d36252925d5d67"}

patching

Patching

If you find some functionality lacking, feel free to add missing functions and submit a PR. The implementation recommendation would be to use one of the examples provided with libgit2 as a guide, add the functionality as lg2_*() function in c_src/git_*.hpp, modify git.cpp to call that function accordingly, write unit tests in git.erl and sumbmit a pull request.

author

Author

Serge Aleynikov saleyn@gmail.com

license

License

Apache 2.0