{"id":13447476,"url":"https://github.com/cksource/mrgit","last_synced_at":"2025-09-26T06:18:38.499Z","repository":{"id":15775497,"uuid":"78744790","full_name":"cksource/mrgit","owner":"cksource","description":"A tool for managing projects build using multiple repositories.","archived":false,"fork":false,"pushed_at":"2024-01-09T09:42:47.000Z","size":1919,"stargazers_count":49,"open_issues_count":17,"forks_count":8,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-04-15T10:05:20.048Z","etag":null,"topics":["git","management","multi-repo","repository"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cksource.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-01-12T12:50:00.000Z","updated_at":"2024-04-03T20:11:11.000Z","dependencies_parsed_at":"2024-01-09T10:58:26.724Z","dependency_job_id":"7b68cfe1-4f6e-4e28-94f2-6aa22dfee305","html_url":"https://github.com/cksource/mrgit","commit_stats":{"total_commits":307,"total_committers":11,"mean_commits":27.90909090909091,"dds":0.5895765472312704,"last_synced_commit":"e30a42858c977d7b8700d25ef0b90c6495279e3b"},"previous_names":["cksource/mgit2"],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cksource%2Fmrgit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cksource%2Fmrgit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cksource%2Fmrgit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cksource%2Fmrgit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cksource","download_url":"https://codeload.github.com/cksource/mrgit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244893395,"owners_count":20527584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["git","management","multi-repo","repository"],"created_at":"2024-07-31T05:01:18.865Z","updated_at":"2025-09-26T06:18:38.491Z","avatar_url":"https://github.com/cksource.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Mr. Git\n\n![Mrgit npm package badge](https://img.shields.io/npm/v/mrgit.svg)\n[![Build Status](https://circleci.com/gh/cksource/mrgit.svg?style=shield)](https://app.circleci.com/pipelines/github/cksource/mrgit?branch=master)\n[![Coverage Status](https://coveralls.io/repos/github/cksource/mrgit/badge.svg?branch=master)](https://coveralls.io/github/cksource/mrgit?branch=master)\n![Dependency Status](https://img.shields.io/librariesio/release/npm/mrgit)\n\nMulti-repo manager for git. A tool for managing projects build using multiple repositories.\n\n`mrgit` is designed to work with [workspaces](https://pnpm.io/workspaces) and [Lerna](https://github.com/lerna/lerna) out of the box, hence, it mixes the \"package\" and \"repository\" concepts. In other words, every repository is meant to be a single [npm](https://npmjs.com) package. It doesn't mean that you must use it with Lerna and npm, but don't be surprised that mrgit talks about \"packages\" and works best with npm packages.\n\n# Table of content\n\n1. [Cloning](#cloning)\n1. [Installation](#installation)\n1. [Usage](#usage)\n1. [Configuration](#configuration)\n    1. [The `dependencies` option](#the-dependencies-option)\n    1. [The `presets` option](#the-presets-option)\n    1. [The `$rootRepository` option](#the-rootrepository-option)\n    1. [Recursive cloning](#recursive-cloning)\n    1. [Cloning repositories on CI servers](#cloning-repositories-on-ci-servers)\n    1. [Base branches](#base-branches)\n1. [Commands](#commands)\n    1. [`sync`](#sync)\n    1. [`pull`](#pull)\n    1. [`push`](#push)\n    1. [`fetch`](#fetch)\n    1. [`exec`](#exec)\n    1. [`commit` or `ci`](#commit-alias-ci)\n    1. [`close`](#close)\n    1. [`save`](#save)\n    1. [`status` or `st`](#status-alias-st)\n    1. [`diff`](#diff)\n    1. [`checkout` or `co`](#checkout-alias-co)\n1. [Projects using mrgit](#projects-using-mrgit)\n\n## Cloning\n\n\u003e [!NOTE]\n\u003e This project requires **pnpm v10** or higher. You can check your version with `pnpm --version` and update if needed with `npm install -g pnpm@latest`.\n\n1. Clone this repository.\n1. Do `pnpm install` inside.\n1. You're ready to go!\n\n## Installation\n\n```bash\nnpm install -g mrgit\n```\n\nUse:\n\n```bash\nmrgit --help\n```\n\n## Usage\n\nFirst, create a configuration file `mrgit.json`. If the project already contains `mrgit.json` file, but you want to provide your own settings, create another `*.json` file and use the `--config \u003cpath\u003e` option (described below) to load your custom configuration when executing a command.\n\n```json\n{\n  \"dependencies\": {\n    \"@ckeditor/ckeditor5-engine\": \"ckeditor/ckeditor5-engine\",\n    \"mrgit\": \"cksource/mrgit\"\n  }\n}\n```\n\n(Keys of the `dependencies` object are package names and values are repository URLs (GitHub identifiers in this case). Read more about the [`dependencies` option](#the-dependencies-option).)\n\nAnd run `mrgit sync` to clone all the repositories. By default, they will be cloned to `\u003ccwd\u003e/packages/` directory:\n\n```bash\npackages/\n  ckeditor5-engine/\n  mrgit/\n```\n\n## Configuration\n\nCLI options:\n\n```\n--config                    Name or path to custom configuration file.\n                            Default: '\u003ccwd\u003e/mrgit.json'\n\n--branch                    For \"save\" command: whether to save branch names.\n                            For \"checkout\" command: name of branch that would be created.\n\n--hash                      Whether to save current commit hashes. Used only by \"save\" command.\n\n--ignore                    Ignores packages which names match the given glob pattern. E.g.:\n                            \u003e mrgit exec --ignore=\"foo*\" \"git status\"\n\n                            Will ignore all packages which names start from \"foo\".\n                            Default: null\n\n--message                   Message that will be used as an option for git command. Required for \"commit\"\n                            command but it is also used by \"close\" command (append the message to the default).\n\n--packages                  Directory to which all repositories will be cloned or are already installed.\n                            Default: '\u003ccwd\u003e/packages/'\n\n--recursive                 Whether to install dependencies recursively. Used only by \"sync\" command.\n\n--resolver-path             Path to a custom repository resolver function.\n                            Default: '@mrgit/lib/default-resolver.js'\n\n--resolver-url-template     Template used to generate repository URL out of a\n                            simplified 'organization/repository' format of the dependencies option.\n                            Default: 'git@github.com:${ path }.git'.\n\n--resolver-directory-name   Defines how the target directory (where the repository will be cloned)\n                            is resolved. Supported options are: 'git' (default), 'npm'.\n\n                            * If 'git' was specified, then the directory name will be extracted from\n                            the git URL (e.g. for 'git@github.com:a/b.git' it will be 'b').\n                            * If 'npm' was specified, then the package name will be used as a directory name.\n\n                            This option can be useful when scoped npm packages are used and one wants to decide\n                            whether the repository will be cloned to packages/@scope/pkgname' or 'packages/pkgname'.\n                            Default: 'git'\n\n--resolver-default-branch   The branch name to use if not specified in dependencies in configuration file.\n                            Default: master\n\n--scope                     Restricts the command to packages which names match the given glob pattern.\n                            Default: null\n\n--preset                    Uses an alternative set of dependencies defined in the config file.\n\n--skip-root                 Allows skipping root repository when executing command,\n                            if \"$rootRepository\" is defined in the config file.\n```\n\nAll these options can also be specified in configuration file (options passed through CLI takes precedence):\n\n```json\n{\n    \"packages\": \"/workspace/modules\",\n    \"resolverDirectoryName\": \"npm\",\n    \"resolverDefaultBranch\": \"dev\",\n    \"dependencies\": {\n        \"foo\": \"bar\"\n    }\n}\n```\n\n### The `dependencies` option\n\nThis option specifies repositories which `mrgit` is supposed to clone. It can also clone its dependencies recursively (see [Recursive cloning](#recursive-cloning)).\n\nThe dependency keys can be any strings, but it's recommended to use package names (e.g. npm package names, just like in `package.json`). The values are repository URLs which `mrgit` will clone.\n\nExamples:\n\n```json5\n// Clone 'git@github.com:cksource/foo.git' and check out to 'master'.\n{\n    \"foo\": \"git@github.com:cksource/foo.git\"\n}\n```\n\n```json5\n// Short format. Clone 'git@github.com:cksource/foo.git' and check out to branch 'dev'.\n{\n    \"@cksource/foo\": \"cksource/foo#dev\"\n}\n```\n\n```json5\n// Clone 'https://github.com/cksource/foo.git' (via HTTPS) and check out to tag 'v1.2.3'.\n{\n    \"foo\": \"https://github.com/cksource/foo.git@v1.2.3\"\n}\n```\n\n```json5\n// Clone 'cksource/foo' and check out to the latest available tag.\n{\n    \"foo\": \"cksource/foo@latest\"\n}\n```\n\n### The `presets` option\n\nThis option allows the user to switch between different states of dependencies easily. When using any command with the `--preset` option, it will behave as if the `dependencies` option was using values from the given preset. Dependencies not specified in the preset but in the `dependencies` object will use a version from the latter as a fallback.\n\nExample:\n\n```json5\n{\n    \"presets\": {\n        \"dev\": {\n            \"@cksource/foo\": \"cksource/foo#dev\"\n        },\n        \"example-feature\": {\n            \"@cksource/foo\": \"cksource/foo#i/1-example-feature\",\n            \"@cksource/bar\": \"cksource/foo#i/1-example-feature\"\n        }\n    }\n}\n```\n\n### The `$rootRepository` option\n\n`mrgit` allows executing git commands in the root repository as well. If such behavior is desired, configure the `$rootRepository` option in the config. When configured, the requested command (e.g. `pull`) will be executed in the root repository and in all defined dependencies. Additionally, the `$rootRepository` key can be included in any preset, and will work accordingly to presets logic.\n\nIf the `$rootRepository` option is configured you can still disable this feature with the `--skip-root` CLI option.\n\nNot all commands support execution in the root repository. If a command does not support this feature, it is executed normally, without affecting the root repository. Currently supported commands are:\n\n - `checkout`\n - `commit`\n - `diff`\n - `exec`\n - `fetch`\n - `pull`\n - `push`\n - `status`\n - `sync`\n\nExample config:\n\n```json5\n{\n    \"packages\": \"/workspace/modules\",\n    \"$rootRepository\": \"cksource/root-repository\",\n    \"dependencies\": {\n       \"@cksource/foo\": \"cksource/foo\"\n    },\n    \"presets\": {\n        \"dev\": {\n           \"@cksource/foo\": \"cksource/foo#dev\",\n            \"$rootRepository\": \"cksource/root-repository#dev\"\n        }\n    }\n}\n```\n\n### Recursive cloning\n\nWhen the `--recursive` option is used `mrgit` will clone repositories recursively. First, it will clone the `dependencies` specified in configuration file and, then, their `dependencies` and `devDependencies` specified in `package.json` files located in cloned repositories.\n\nHowever, `mrgit` needs to know repository URLs of those dependencies, as well as which dependencies to clone (usually, only the ones maintained by you). In order to configure that you need to use a custom repository resolver (`--resolver-path`).\n\nResolver is a simple Node.js module which exports the resolver function.\n\nFor example, assuming that you want to clone all `@ckeditor/ckeditor5-*` packages, your resolver could look like this:\n\n```js\n'use strict';\n\nconst parseRepositoryUrl = require( 'mrgit/lib/utils/parserepositoryurl' );\n\n/**\n * Resolves repository URL for a given package name.\n *\n * @param {String} packageName Package name.\n * @param {Options} options The options object.\n * @returns {Repository|null}\n */\nmodule.exports = function resolver( packageName, options ) {\n    // If package name starts with '@ckeditor/ckeditor5-*' clone it from 'ckeditor/ckeditor5-*'.\n    if ( packageName.startsWith( '@ckeditor/ckeditor5-' ) ) {\n        const repositoryUrl = packageName.slice( 1 );\n\n        return parseRepositoryUrl( repositoryUrl );\n    }\n\n    // Don't clone any other dependencies.\n    return null;\n};\n```\n\nYou can also check the [default resolver](https://github.com/cksource/mrgit/blob/master/lib/default-resolver.js) used by `mrgit` and [the config object definition](https://github.com/cksource/mrgit/blob/master/lib/utils/getoptions.js).\n\n### Cloning repositories on CI servers\n\nCI servers, such as Travis, can't clone repositories using Git URLs (such as `git@github.com:cksource/mrgit.git`). By default, `mrgit` uses Git URLs because it assumes that you'll want to commit to these repositories (and don't want to be asked for a password every time).\n\nIf you need to run `mrgit` on a CI server, then configure it to use HTTPS URLs:\n\n```bash\nmrgit --resolver-url-template=\"https://github.com/\\${ path }.git\"\n```\n\nYou can also use full HTTPS URLs to configure `dependencies` in your configuration file.\n\n### Base branches\n\nWhen you call `mrgit sync` or `mrgit co`, mrgit will use the following algorithm to determine the branch to which each repository should be checked out:\n\n1. If a branch is defined in configuration file, use it. A branch can be defined after `#` in a repository URL. For example: `\"@cksource/foo\": \"cksource/foo#dev\"`.\n2. If a tag is defined in configuration file, use it. A tag can be defined after `@` in a repository URL. Its either a specific tag name, such as `@v30.0.0`, or `@latest` tag that will look for the latest available tag.\n3. If the root repository (assuming, it is a repository) is on one of the \"base branches\", use that branch name.\n4. Otherwise, use `master` branch.\n\nYou can define the base branches as follows:\n\n```json5\n{\n  // ...\n  \"baseBranches\": [ \"master\", \"stable\" ],\n  // ...\n}\n```\n\nWith this configuration, if the root repository is on `stable`, calling `mrgit co` will check out all repositories to `stable`. If you change the branch of the root repository to `master` and call `mrgit co`, all sub repositories will be checked out to `master`.\n\n## Commands\n\n```bash\n$ mrgit [command]\n```\n\nFor displaying help screen for specified command, type:\n\n```bash\n$ mrgit [command] --help\n```\n\n### sync\n\nUpdates dependencies. Switches repositories to correct branches or tags (specified in configuration file) and pulls changes.\n\nIf any dependency is missing, the command will install this dependency as well.\n\nThis command does not touch repositories in which there are uncommitted changes.\n\nIf in the packages directory will be located some directories that are not specified in configuration file, paths to these directories\nwill be printed out on the screen.\n\nExamples:\n\n```bash\nmrgit sync --recursive\n```\n\n### pull\n\nPulls changes in existing repositories. It does not change branches in the repositories. It does not pull the changes if the repository contains uncommitted changes. It skips repositories that are in detached head mode (are checked out on a tag).\n\nExamples:\n\n```bash\nmrgit pull\n```\n\n### push\n\nPushes changes in existing repositories. It skips repositories that are in detached head mode (are checked out on a tag).\n\nExamples:\n\n```bash\nmrgit push\n```\n\n### fetch\n\nFetches changes in existing repositories.\n\nExamples:\n\n```bash\nmrgit fetch\n```\n\n### exec\n\nExecutes specified shell command in existing repositories.\n\nExample:\n\n```bash\nmrgit exec 'git status'\n\n# Executes `git status` command on each repository.\n```\n\nDuring the task execution, `cwd` is set to the repository path:\n\n```bash\nmrgit exec 'echo `pwd`'\n\n# /home/mrgit/packages/organization/repository-1\n# /home/mrgit/packages/organization/repository-2\n```\n\n### commit (alias: `ci`)\n\nFor every repository that contains changes which can be committed, makes a commit with these files. You need to specify the message for the commit. It skips repositories that are in detached head mode (are checked out on a tag).\n\nExample:\n\n```bash\nmrgit commit --message 'Introduce PULL_REQUEST_TEMPLATE.md.'\n\n# Executes `git commit --message 'Introduce PULL_REQUEST_TEMPLATE.md.'` command on each repository.\n# Commit will be made in repositories that \"git status\" returns a list if changed files (these files must be tracked by Git).\n```\n\n### close\n\nRequires a second argument which is a branch name that will be merged to current one. You can also specify the message which will be added to the default git-merge message. Repositories which do not have specified branch will be ignored. It skips repositories that are in detached head mode (are checked out on a tag).\n\nAfter merging, the merged branch will be removed from the remote and the local registry.\n\nExample:\n\n```bash\n# Assumptions: we are on \"master\" branch and \"develop\" branch exists.\nmrgit merge develop --message 'These changes are required for the future release.'\n\n# Branch \"develop\" will be merged into \"master\".\n# Branch \"develop\" will be removed from the origin.\n```\n\n### save\n\nSaves hashes of packages in configuration file. It allows to easily fix project to a specific state.\n\nExample:\n\n```bash\nmrgit save\n```\n\nIf you would like to save name of branches instead of current commit, you can use an option `--branch`:\n\n```bash\nmrgit save --branch\n```\n\n### status (alias: `st`)\n\nPrints a table which contains useful information about the status of repositories.\n\nExample:\n\n```bash\nmrgit status\n# or\nmrgit st\n```\n\nIn order to save space in your terminal, you can define the `packagesPrefix` option in your configuration file.\nThe prefix will be removed from packages' names. Full names of packages aren't needed so we can cut the names.\n\n![An example response of `mrgit status` command.](https://user-images.githubusercontent.com/2270764/28871104-5915289e-7783-11e7-8d06-9eac6d7d96ab.png)\n\n### diff\n\nPrints changes from packages where something has changed.\n\nIt accepts additional options which will be passed directly to the `git diff` command which is used to gather the changes.\n\nThese options must be separated by a double dash `--`, the same way as [`npm scripts`](https://docs.npmjs.com/cli/run-script#synopsis) does.\n\n#### Examples\n\nPrints changes from all repositories:\n\n```bash\nmrgit diff\n```\n\nPrints diffstat from all repositories:\n\n```bash\nmrgit diff -- --stat\n```\n\nPrints staged changes from restricted scope:\n\n```bash\nmrgit diff --scope=*@(engine|typing)* -- --staged\n```\n\nPrints changes from repositories which are not on `master`:\n\n```bash\nmrgit diff -- master...HEAD\n```\n\n![An example response of `mrgit diff` command.](https://user-images.githubusercontent.com/2270764/28918716-c6f90002-784a-11e7-95ae-8d08c47c5427.png)\n\n### checkout (alias: `co`)\n\nChanges branches in repositories according to the configuration file. It does not pull the changes and hance is much faster than `mrgit sync`.\nThe command is useful for bisecting if your main repository contain a revision log like CKEditor 5's [`master-revision`](https://github.com/ckeditor/ckeditor5/commits/master-revisions) branch.\n\n```bash\nmrgit checkout\n# or\nmrgit co\n```\n\nIf specified an argument, specified branch will be used instead of default or saved in configuration file.\n\n```bash\n# Checkout all repositories to \"stable\" branch.\nmrgit checkout stable\n```\n\nAlso you can specify the `--branch` option which means that `mrgit` creates a new branches in repositories that contains changes (that could be committed).\nIt works on the same terms like `mrgit commit`.\n\n```bash\n# Create the branch \"t/foo\" in repositories where \"git status\" returns a list if changed files (these files must be tracked by Git).\nmrgit checkout --branch t/foo\n```\n\n## Projects using mrgit\n\n* [CKEditor 5](https://github.com/ckeditor/ckeditor5)\n\n## Releasing the package\n\nCircleCI automates the release process and can release both channels: stable (`X.Y.Z`) and pre-releases (`X.Y.Z-alpha.X`, etc.).\n\nBefore you start, you need to prepare the changelog entries.\n\n1. Make sure the `#master` branch is up-to-date: `git fetch \u0026\u0026 git checkout master \u0026\u0026 git pull`.\n1. Prepare a release branch: `git checkout -b release-[YYYYMMDD]` where `YYYYMMDD` is the current day.\n1. Generate the changelog entries: `pnpm run release:prepare-changelog`.\n\t* You can specify the release date by passing the `--date` option, e.g., `--date=2025-06-11`.\n\t* By passing the `--dry-run` option, you can check what the script will do without actually modifying the files.\n\t* Read all the entries, correct poor wording and other issues, wrap code names in backticks to format them, etc.\n\t* Add the missing `the/a` articles, `()` to method names, \"it's\" -\u003e \"its\", etc.\n\t* A newly introduced feature should have just one changelog entry – something like \"The initial implementation of the FOO feature.\" with a description of what it does.\n1. Commit all changes and prepare a new pull request targeting the `#master` branch.\n1. Ping the `@ckeditor/ckeditor-5-platform` team to review the pull request and trigger the release process.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcksource%2Fmrgit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcksource%2Fmrgit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcksource%2Fmrgit/lists"}