{"id":13491816,"url":"https://github.com/nosarthur/gita","last_synced_at":"2025-05-13T21:12:49.691Z","repository":{"id":43351326,"uuid":"119705647","full_name":"nosarthur/gita","owner":"nosarthur","description":"Manage many git repos with sanity 从容管理多个git库","archived":false,"fork":false,"pushed_at":"2025-01-26T02:17:06.000Z","size":2339,"stargazers_count":1718,"open_issues_count":23,"forks_count":73,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-28T17:18:36.354Z","etag":null,"topics":["cli","command-line","command-line-tool","developer-tools","git","git-delegation","management","productivity","terminal"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nosarthur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"nosarthur","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2018-01-31T15:30:46.000Z","updated_at":"2025-04-24T14:39:39.000Z","dependencies_parsed_at":"2023-02-16T14:16:14.933Z","dependency_job_id":"1c7216aa-233b-49f4-a9f0-6c2655cfd2e6","html_url":"https://github.com/nosarthur/gita","commit_stats":{"total_commits":373,"total_committers":26,"mean_commits":"14.346153846153847","dds":"0.38069705093833783","last_synced_commit":"63894703d53b30034161ef81171724bd2f3c9503"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nosarthur%2Fgita","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nosarthur%2Fgita/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nosarthur%2Fgita/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nosarthur%2Fgita/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nosarthur","download_url":"https://codeload.github.com/nosarthur/gita/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254029008,"owners_count":22002284,"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":["cli","command-line","command-line-tool","developer-tools","git","git-delegation","management","productivity","terminal"],"created_at":"2024-07-31T19:01:00.496Z","updated_at":"2025-05-13T21:12:44.676Z","avatar_url":"https://github.com/nosarthur.png","language":"Python","funding_links":["https://github.com/sponsors/nosarthur"],"categories":["Git","Version Control","Python","For Developers","terminal","\u003ca name=\"git\"\u003e\u003c/a\u003eGit and accessories"],"sub_categories":["Snippets Manager","Git","Directory Navigation"],"readme":"[![PyPi version](https://img.shields.io/pypi/v/gita.svg?color=blue)](https://pypi.org/project/gita/)\n[![Build Status](https://travis-ci.org/nosarthur/gita.svg?branch=master)](https://travis-ci.org/nosarthur/gita)\n[![codecov](https://codecov.io/gh/nosarthur/gita/branch/master/graph/badge.svg)](https://codecov.io/gh/nosarthur/gita)\n[![licence](https://img.shields.io/pypi/l/gita.svg)](https://github.com/nosarthur/gita/blob/master/LICENSE)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/gita.svg)](https://pypistats.org/packages/gita)\n[![Gitter](https://badges.gitter.im/nosarthur/gita.svg)](https://gitter.im/nosarthur/gita?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n[![Chinese](https://img.shields.io/badge/-中文-lightgrey.svg)](https://github.com/nosarthur/gita/blob/master/doc/README_CN.md)\n\n```\n _______________________________\n(  ____ \\__   __|__   __(  ___  )\n| (    \\/  ) (     ) (  | (   ) |\n| |        | |     | |  | (___) |\n| | ____   | |     | |  |  ___  |\n| | \\_  )  | |     | |  | (   ) |\n| (___) |__) (___  | |  | )   ( |\n(_______)_______/  )_(  |/     \\|   v0.16\n```\n\n# Gita: a command-line tool to manage multiple git repos\n\nThis tool has two main features\n\n- display the status of multiple git repos such as branch, modification, commit message side by side\n- (batch) delegate git commands/aliases and shell commands on repos from any working directory\n\n![gita screenshot](https://github.com/nosarthur/gita/raw/master/doc/screenshot.png)\n\nIn this screenshot, the `gita ll` command displays the status of all repos.\nThe `gita remote dotfiles` command translates to `git remote -v`\nfor the `dotfiles` repo, even though we are not in the repo.\nThe `gita fetch` command fetches from all repos and two of them have updates.\nTo see the pre-defined commands, run `gita -h` or take a look at\n[cmds.json](https://github.com/nosarthur/gita/blob/master/gita/cmds.json).\nTo add your own commands, see the [customization section](#custom).\nTo run arbitrary `git` command, see the [superman mode section](#superman).\nTo run arbitrary shell command, see the [shell mode section](#shell).\n\nMake sure to `gita add` your repos first!\n\nI also made a youtube video to demonstrate the common usages\n[![Img alt text](https://github.com/nosarthur/gita/raw/master/doc/video-outline.png)](https://www.youtube.com/watch?v=ySWbwQcbhqI)\n\nThe branch color distinguishes 5 situations between local and remote branches:\n\n| color  | meaning                                  |\n| ------ | ---------------------------------------- |\n| white  | local has no remote                      |\n| green  | local is the same as remote              |\n| red    | local has diverged from remote           |\n| purple | local is ahead of remote (good for push) |\n| yellow | local is behind remote (good for merge)  |\n\nThe choice of purple for ahead and yellow for behind is motivated by\n[blueshift](https://en.wikipedia.org/wiki/Blueshift) and [redshift](https://en.wikipedia.org/wiki/Redshift),\nusing green as baseline.\nYou can change the color scheme using the `gita color` command.\nSee the [customization section](#custom).\n\nThe additional status symbols denote\n\n| symbol | meaning                 |\n| ------ | ----------------------- |\n| `+`    | staged changes          |\n| `*`    | unstaged changes        |\n| `?`    | untracked files/folders |\n| `$`    | stashed contents        |\n\nThe bookkeeping sub-commands are\n\n- `gita add \u003crepo-path(s)\u003e [-g \u003cgroupname\u003e]`: add repo(s) to `gita`, optionally into an existing group\n- `gita add -a \u003crepo-parent-path(s)\u003e`: add repo(s) in \u003crepo-parent-path(s)\u003e recursively\n  and automatically generate hierarchical groups. See the [customization section](#custom) for more details.\n- `gita add -b \u003cbare-repo-path(s)\u003e`: add bare repo(s) to `gita`. See the [customization section](#custom) for more details on setting custom worktree.\n- `gita add -r \u003crepo-parent-path(s)\u003e`: add repo(s) in \u003crepo-parent-path(s)\u003e recursively\n- `gita clear`: remove all groups and repos\n- `gita clone \u003cURL\u003e`: clone repo from `URL` at current working directory\n- `gita clone \u003cURL\u003e -C \u003cdirectory\u003e`: change to `directory` and then clone repo\n- `gita clone -f \u003cconfig-file\u003e`: clone repos in `config-file` (generated by `gita freeze`) to current directory.\n- `gita clone -p -f \u003cconfig-file\u003e`: clone repos in `config-file` to prescribed paths.\n- `gita context`: context sub-command\n  - `gita context`: show current context\n  - `gita context \u003cgroup-name\u003e`: set context to `group-name`, all operations then only apply to repos in this group\n  - `gita context auto`: set context automatically according to the current working directory\n  - `gita context none`: remove context\n- `gita color`: color sub-command\n  - `gita color [ll]`: Show available colors and the current coloring scheme\n  - `gita color reset`: Reset to the default coloring scheme\n  - `gita color set \u003csituation\u003e \u003ccolor\u003e`: Use the specified color for the local-remote situation\n- `gita flags`: flags sub-command\n  - `gita flags set \u003crepo-name\u003e \u003cflags\u003e`: add custom `flags` to repo\n  - `gita flags [ll]`: display repos with custom flags\n- `gita freeze`: print information of all repos such as URL, name, and path. Use with\n  `gita clone`.\n- `gita group`: group sub-command\n  - `gita group add \u003crepo-name(s)\u003e -n \u003cgroup-name\u003e`: add repo(s) to a new or existing group\n  - `gita group [ll]`: display existing groups with repos\n  - `gita group ls`: display existing group names\n  - `gita group rename \u003cgroup-name\u003e \u003cnew-name\u003e`: change group name\n  - `gita group rm \u003cgroup-name(s)\u003e`: delete group(s)\n  - `gita group rmrepo \u003crepo-name(s)\u003e -n \u003cgroup-name\u003e`: remove repo(s) from existing group\n- `gita info`: info sub-command\n  - `gita info [ll]`: display the used and unused information items\n  - `gita info add \u003cinfo-item\u003e`: enable information item\n  - `gita info rm \u003cinfo-item\u003e`: disable information item\n- `gita ll`: display the status of all repos\n- `gita ll \u003cgroup-name\u003e`: display the status of repos in a group\n- `gita ll -g`: display the repo summaries by groups\n- `gita ls`: display the names of all repos\n- `gita ls \u003crepo-name\u003e`: display the absolute path of one repo\n- `gita rename \u003crepo-name\u003e \u003cnew-name\u003e`: rename a repo\n- `gita rm \u003crepo-name(s)\u003e`: remove repo(s) from `gita` (won't remove files on disk)\n- `gita -v`: display gita version\n\nThe `git` delegating sub-commands are of two formats\n\n- `gita \u003csub-command\u003e [repo-name(s) or group-name(s)]`:\n  optional repo or group input, and **no input means all repos**.\n- `gita \u003csub-command\u003e \u003crepo-name(s) or groups-name(s)\u003e`:\n  required repo name(s) or group name(s) input\n\nThey translate to `git \u003csub-command\u003e` for the corresponding repos.\nBy default, only `fetch` and `pull` take optional input. In other words,\n`gita fetch` and `gita pull` apply to all repos.\nTo see the pre-defined sub-commands, run `gita -h` or take a look at\n[cmds.json](https://github.com/nosarthur/gita/blob/master/gita/cmds.json).\nTo add your own sub-commands or override the default behaviors, see the [customization section](#custom).\nTo run arbitrary `git` command, see the [superman mode section](#superman).\n\nIf more than one repos are specified, the `git` command runs asynchronously,\nwith the exception of `log`, `difftool` and `mergetool`,\nwhich require non-trivial user input.\n\nRepo configuration global is saved in `$XDG_CONFIG_HOME/gita/repos.csv`\n(most likely `~/.config/gita/repos.csv`) or if you prefered at project configuration add environment variable `GITA_PROJECT_HOME`.\n\n## Installation\n\nTo install the latest version, run\n\n```\npip3 install -U gita\n```\n\nIf you prefer development mode, download the source code and run\n\n```\npip3 install -e \u003cgita-source-folder\u003e\n```\n\nIn either case, calling `gita` in terminal may not work,\nthen put the following line in the `.bashrc` file.\n\n```\nalias gita=\"python3 -m gita\"\n```\n\nWindows users may need to enable the ANSI escape sequence in terminal for\nthe branch color to work.\nSee [this stackoverflow post](https://stackoverflow.com/questions/51680709/colored-text-output-in-powershell-console-using-ansi-vt100-codes) for details.\n\nNow you are ready to `gita add` your repos!\n\n## Auto-completion\n\nYou can download the generated auto-completion file in the following locations for your specific shell. Alternatively, if you have installed `argcomplete` on your system, you can also directly run `eval \"$(register-python-argcomplete gita -s SHELL)\"` (e.g. `SHELL` as `bash`/`zsh`) in your dotfile.\n\n### Bash\n\nDownload [.gita-completion.bash](https://github.com/nosarthur/gita/blob/master/.gita-completion.bash) and source it in shell.\n\n### Zsh\n\nThere are 2 options :\n\n- [.gita-completion.zsh](https://github.com/nosarthur/gita/blob/master/contrib.completion/zsh/.gita-completion.zsh). Use the help of gita command to display options. It uses the bash completion system for zsh.\n  Add `autoload -U +X bashcompinit \u0026\u0026 bashcompinit` in .zshrc and source the zsh file\n- [\\_gita](https://github.com/nosarthur/gita/blob/master/contrib.completion/zsh/_gita_).\n  Completion more Zsh style. Copy it in a folder and add this folder path in `FPATH` variable. This completion file doesn't take account to command from cmds.json\n\n### Fish\n\nDownload [gita.fish](https://github.com/nosarthur/gita/tree/master/auto-completion/fish/gita.fish) and place it in `~/.config/fish/completions/`\n\n## \u003ca name='superman'\u003e\u003c/a\u003e Superman mode\n\nThe superman mode delegates any `git` command or alias.\nUsage:\n\n```\ngita super [repo-name(s) or group-name(s)] \u003cany-git-command-with-or-without-options\u003e\n```\n\nHere `repo-name(s)` or `group-name(s)` are optional, and their absence means all repos.\nFor example,\n\n- `gita super checkout master` puts all repos on the master branch\n- `gita super frontend-repo backend-repo commit -am 'implement a new feature'`\n  executes `git commit -am 'implement a new feature'` for `frontend-repo` and `backend-repo`\n\n## \u003ca name='shell'\u003e\u003c/a\u003e Shell mode\n\nThe shell mode delegates any shell command.\nUsage:\n\n```\ngita shell [repo-name(s) or group-name(s)] \u003cany-shell-command\u003e\n```\n\nHere `repo-name(s)` or `group-name(s)` are optional, and their absence means all repos.\nFor example,\n\n- `gita shell ll` lists contents for all repos\n- `gita shell repo1 repo2 mkdir docs` create a new directory `docs` in `repo1` and `repo2`\n- `gita shell \"git describe --abbrev=0 --tags | xargs git checkout\"`: check out the latest tag for all repos\n\n## \u003ca name='custom'\u003e\u003c/a\u003e Customization\n\n### define repo group and context\n\nWhen the project contains several independent but related repos,\nwe can define a group and execute `gita` command on this group.\nFor example,\n\n```\ngita group add repo1 repo2 -n my-group\ngita ll my-group\ngita pull my-group\n```\n\nTo save more typing, one can set a group as context, then any `gita` command\nis scoped to the group\n\n```\ngita context my-group\ngita ll\ngita pull\n```\n\nThe most useful context maybe `auto`.\nIn this mode, the context is automatically determined from the\ncurrent working directory (CWD): the context is the group whose member repo's\npath contains CWD. To set it, run\n\n```\ngita context auto\n```\n\nTo remove the context, run\n\n```\ngita context none\n```\n\nIt is also possible to recursively add repos within a directory and\ngenerate hierarchical groups automatically. For example, running\n\n```\ngita add -a src\n```\n\non the following folder structure\n\n```\nsrc\n├── project1\n│   ├── repo1\n│   └── repo2\n├── repo3\n├── project2\n│   ├── repo4\n│   └── repo5\n└── repo6\n```\n\ngives rise to 3 groups:\n\n```\nsrc:repo1,repo2,repo3,repo4,repo5,repo6\nsrc-project1:repo1,repo2\nsrc-project2:repo4,repo5\n```\n\n### add user-defined sub-command using json file\n\nCustom delegating sub-commands can be defined in `$XDG_CONFIG_HOME/gita/cmds.json`\n(most likely `~/.config/gita/cmds.json`)\nAnd they shadow the default ones if name collisions exist.\n\nDefault delegating sub-commands are defined in\n[cmds.json](https://github.com/nosarthur/gita/blob/master/gita/cmds.json).\nFor example, `gita stat \u003crepo-name(s)\u003e` is registered as\n\n```json\n\"stat\":{\n  \"cmd\": \"git diff --stat\",\n  \"help\": \"show edit statistics\"\n}\n```\n\nwhich executes `git diff --stat` for the specified repo(s).\n\nTo disable asynchronous execution, set `disable_async` to be `true`.\nSee the `difftool` example:\n\n```json\n\"difftool\":{\n  \"cmd\": \"git difftool\",\n  \"disable_async\": true,\n  \"help\": \"show differences using a tool\"\n}\n```\n\nIf you want a custom command to behave like `gita fetch`, i.e., to apply to all\nrepos when no repo is specified, set `allow_all` to be `true`.\nFor example, the following snippet creates a new command\n`gita comaster [repo-name(s)]` with optional repo name input.\n\n```json\n\"comaster\":{\n  \"cmd\": \"checkout master\",\n  \"allow_all\": true,\n  \"help\": \"checkout the master branch\"\n}\n```\n\nAny command that runs in the [superman mode](#superman) mode or the\n[shell mode](#shell) can be defined in this json format.\nFor example, the following command runs in shell mode and fetches only the\ncurrent branch from upstream.\n\n```json\n\"fetchcrt\":{\n  \"cmd\": \"git rev-parse --abbrev-ref HEAD | xargs git fetch --prune upstream\",\n  \"allow_all\": true,\n  \"shell\": true,\n  \"help\": \"fetch current branch only\"\n}\n```\n\n### customize the local/remote relationship coloring displayed by the `gita ll` command\n\nYou can see the default color scheme and the available colors via `gita color`.\nTo change the color coding, use `gita color set \u003csituation\u003e \u003ccolor\u003e`.\nThe configuration is saved in `$XDG_CONFIG_HOME/gita/color.csv`.\n\n### customize information displayed by the `gita ll` command\n\nYou can customize the information displayed by `gita ll`.\nThe used and unused information items are shown with `gita info`, and the\nconfiguration is saved in `$XDG_CONFIG_HOME/gita/info.csv`.\n\nFor example, the default setting corresponds to\n\n```csv\nbranch,commit_msg,commit_time\n```\n\nHere `branch` includes both branch name and status.\nThe status symbols are similar to the ones used in [spaceship-prompt](https://spaceship-prompt.sh/sections/git/#Git-status-git_status).\n\nTo customize these symbols, add a file in `$XDG_CONFIG_HOME/gita/symbols.csv`.\nThe default settings corresponds to\n\n```csv\ndirty,staged,untracked,local_ahead,remote_ahead,diverged,in_sync,no_remote\n*,+,?,↑,↓,⇕,,∅\n```\n\nOnly the symbols to be overridden need to be defined.\nYou can search unicode symbols [here](https://www.compart.com/en/unicode/).\n\n### customize git command flags\n\nOne can set custom flags to run `git` commands. For example, with\n\n```\ngita flags set my-repo --git-dir=`gita ls dotfiles` --work-tree=$HOME\n```\n\nany `git` command/alias triggered from `gita` on `dotfiles` will use these flags.\nNote that the flags are applied immediately after `git`. For example,\n`gita st dotfiles` translates to\n\n```\ngit --git-dir=$HOME/somefolder --work-tree=$HOME status\n```\n\nrunning from the `dotfiles` directory.\n\nThis feature was originally added to deal with\n[bare repo dotfiles](https://www.atlassian.com/git/tutorials/dotfiles).\n\n## Requirements\n\nGita requires Python 3.6 or higher, due to the use of\n[f-string](https://www.python.org/dev/peps/pep-0498/)\nand [asyncio module](https://docs.python.org/3.6/library/asyncio.html).\n\nUnder the hood, gita uses `subprocess` to run git commands/aliases.\nThus the installed git version may matter.\nI have git `1.8.3.1`, `2.17.2`, and `2.20.1` on my machines, and\ntheir results agree.\n\n## Tips\n\n| effect                    | shell command                            |\n| ------------------------- | ---------------------------------------- |\n| enter `\u003crepo\u003e` directory  | `` cd `gita ls \u003crepo\u003e` ``                |\n| delete repos in `\u003cgroup\u003e` | `gita group ll \u003cgroup\u003e \\| xargs gita rm` |\n\n## Contributing\n\nTo contribute, you can\n\n- report/fix bugs\n- request/implement features\n- star/recommend this project\n\nRead [this article](https://www.dataschool.io/how-to-contribute-on-github/) if you have never contribute code to open source project before.\n\nChat room is available on [![Join the chat at https://gitter.im/nosarthur/gita](https://badges.gitter.im/nosarthur/gita.svg)](https://gitter.im/nosarthur/gita?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nTo run tests locally, simply `pytest` in the source code folder.\nNote that context should be set as `none`.\nMore implementation details are in\n[design.md](https://github.com/nosarthur/gita/blob/master/doc/design.md).\nA step-by-step guide to reproduce this project is [here](https://nosarthur.github.io/side%20project/2019/05/27/gita-breakdown.html).\n\nYou can also sponsor me on [GitHub](https://github.com/sponsors/nosarthur). Any amount is appreciated!\n\n## Other multi-repo tools\n\nI haven't tried them but I heard good things about them.\n\n- [myrepos](https://myrepos.branchable.com/)\n- [repo](https://source.android.com/setup/develop/repo)\n- [mu-repo](https://github.com/fabioz/mu-repo)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnosarthur%2Fgita","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnosarthur%2Fgita","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnosarthur%2Fgita/lists"}