DEV Community

Cover image for mani, a CLI Tool to Manage Multiple Repositories
Samir Alajmovic
Samir Alajmovic

Posted on


mani, a CLI Tool to Manage Multiple Repositories

TL;DR - Mani is a many-repo tool that helps you manage multiple repositories. It's useful when you are working with microservices, multi-project systems, or just a bunch of personal repositories and want a central place for pulling all repositories and running commands over them.

In mani, you specify repositories and commands in a config file and then run the commands over all or a subset of the projects.

Don't worry, this post isn't going to be about the old age debate of whether you should be using a mono- or a many-repo setup. I think there's a place for both, and the two approaches have their pros and cons.

Anyway, even if you're using a mono-repo in your current workplace, you're probably using a many-repo setup for your projects (work, personal projects, etc.), so you still might find Mani useful (or some of the alternatives).

Mani came about because I needed a CLI tool to manage multiple repositories, both at work and for my projects. The premise is, you have a bunch of repositories and want the following:

  1. a central place for your repositories, containing name, URL, and a small description of the repository
  2. ability to clone all repositories in 1 command
  3. ability to run ad-hoc and custom commands (perhaps git status to see working tree status) on 1, a subset, or all of the repositories
  4. ability to get an overview of 1, a subset, or all of the repositories and commands

Mani also standardizes one of the recurring patterns that I've seen in the workplace: on your first day, you're given access to an organization on Github, and perhaps if you're lucky, there's an outdated bash script which pulls some of the repositories you're supposed to work on. Other times, you're simply given a README document with links to all the projects you're supposed to visit manually and clone.


Let's install Mani, binaries are available on Github release page, or you can install it via cURL (only Linux & MacOS):

curl -sfL | sh
Enter fullscreen mode Exit fullscreen mode

There's also additional install methods in

Now, let's say you have a bunch git repositories:

$ tree -L 2

├── frontend
│   ├── dashgrid
│   └── pinto
└── template-generator
Enter fullscreen mode Exit fullscreen mode

We'll start by initializing Mani in this directory:

$ mani init

Initialized mani repository in /home/samir/tmp/init
- Created mani.yaml
- Created .gitignore

Following projects were added to mani.yaml

 Project            | Path
 init               | .
 dashgrid           | frontend/dashgrid
 pinto              | frontend/pinto
 template-generator | template-generator

Enter fullscreen mode Exit fullscreen mode

Let's see the content of the two files generated:

$ cat mani.yaml

    path: .

    path: frontend/dashgrid

    path: frontend/pinto


  desc: Print Hello World
  cmd: echo "Hello World"

$ cat .gitignore

# mani #
# mani #
Enter fullscreen mode Exit fullscreen mode

the mani init command created a mani.yaml file that contains our repositories as well as an example task named hello-world and a .gitignore file that contains all the projects. This is because when we initialize this directory as a git repository (which is recommended, as other users can simply clone this repository and then run mani sync to clone all repositories), we want to prevent the directories to be added to our Mani repository.

Mani has a bunch of different sub-commands that helps us view and manage our repositories:

# Open mani.yaml in your preferred editor
$ mani edit

# List projects
$ mani list projects


# List repositories in a tree-like format
$ mani list projects --tree

┌─ frontend
│  ├─ dashgrid
│  └─ pinto
└─ template-generator

# Describe all tasks
$ mani describe tasks

Name: hello
Description: Print Hello World
Theme: default
    All: false
    Cwd: false
    Output: text
    Parallel: false
    IgnoreError: false
    OmitEmpty: false
    echo "Hello World"

Enter fullscreen mode Exit fullscreen mode

Now, let's adds some tags and descriptions to our projects, and some new tasks:

    path: .
    desc: A mani example

    path: frontend/pinto
    desc: A vim theme editor
    tags: [frontend, node]

    desc: A simple bash script used to manage boilerplates
    tags: [cli, bash]
      branch: master

        draw_border: true
        separate_columns: true
        separate_header: true
        separate_rows: true

    desc: show working tree status
    cmd: git status

    desc: show last commit
    cmd: git log -1 --pretty=%B

    desc: show last commit date
    cmd: |
      git log -1 --format="%cd (%cr)" -n 1 --date=format:"%d  %b %y" \
      | sed 's/ //'

    desc: show current git branch
    cmd: git rev-parse --abbrev-ref HEAD

    desc: run npm install in node repos
      tags: [node]
    cmd: npm install

    desc: show branch, local and remote diffs, last commit and date
    theme: custom
      - task: git-branch
      - task: git-last-commit-msg
      - task: git-last-commit-date

Enter fullscreen mode Exit fullscreen mode

Run git-status task and target projects with the tag bash:

$ mani run git-status --tags bash

TASK [git-status: show working tree status] **************************

template-generator | On branch master
template-generator | Your branch is up to date with 'origin/master'.
template-generator |
template-generator | nothing to commit, working tree clean
Name:         git-status
Description:  Show git status
Shell:        sh -c
Command:      git status

Enter fullscreen mode Exit fullscreen mode

Run task git-status for repositories under the frontend directory:

TASK [git-status: show working tree status] *************

pinto | On branch main
pinto | Your branch is up to date with 'origin/main'.
pinto |
pinto | nothing to commit, working tree clean

Enter fullscreen mode Exit fullscreen mode

Run another task that has multiple commands and display the output in a table:

$ mani run git-overview  -t bash -d frontend/ -o table

| Project            | Git-Branch | Git-Last-Commit-Msg                       | Git-Last-Commit-Date              |
| pinto              | main       | Update readme                             | 22 Mar 22 (6 weeks ago)           |
|                    |            |                                           |                                   |
| template-generator | master     | Edit command should work without argument | 24 Jan 20 (2 years, 3 months ago) |
|                    |            |                                           |                                   |

Enter fullscreen mode Exit fullscreen mode

Now if we want to execute an ad-hoc command, for instance, count the number of files in all projects, we can use the mani exec sub-command:

$ mani exec --all --output table --parallel 'find . -type f | wc -l'

 Project            | Output
 example            | 486
 pinto              | 361
 template-generator | 42

Enter fullscreen mode Exit fullscreen mode


I hope you find this intro to Mani useful, and if you want to learn more, head to


Mani isn't the first of its kind, check out the following alternatives!

Top comments (0)

Why You Need to Study Javascript Fundamentals

The harsh reality for JS Developers: If you don't study the fundamentals, you'll be just another “Coder”. Top learnings on how to get to the mid/senior level faster as a JavaScript developer by Dragos Nedelcu.