Skip to content

thiago-negri/gg

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gg

One command for all your git repos.

YouTube Video

Install

YOLO

curl -fsSL https://raw.githubusercontent.com/thiago-negri/gg/refs/heads/main/install.sh | bash

Usage

GG tries to be smart. The command structure works like that:

gg [|ls|cache|([.filter|id] [command])]

Everything is optional. Examples:

  • gg 2 will show state of repository with ID 2, and change directory.
  • gg 2 status will run status on repository with ID 2, and not change directory.
  • gg .model will show state of all repositories that contain the string model, if only one is found, it will change directory.
  • gg .model status will run status on all repositories that contain the string model, and not change directory.
  • gg status will run status on all repositories, and not change directory.

Summary:

  • If the command is missing, GG will show the state of the matching repositories.
  • If the filter is missing, GG will apply to all repositories.
  • If the filter is a number, GG will apply to the repository with the same ID.
  • If the filter starts with a ., GG will apply to repositories that directory match the filter (discarding the leading .).
  • If only one repository is found and command is missing, GG will change directory.

Special behaviors:

  • gg ls will show a summary of the state of all cached repositories.
  • gg cache will refresh the cache of all repositories.
  • gg with no arguments is the same as gg cache; gg ls. It will refresh the cached repository list and show a summary of the state of every repository.

List all

List all repositories, with branch and dirty flag.

gg

Output is a list of repositories in format:

<ID> <DIRECTORY> <BRANCH> <DIRTY_FLAG>

Example:

$ gg
1 /home/hunz/.config/nvim master [+]
2 /home/hunz/.config/wezterm master [+]
3 /home/hunz/.fzf master
4 /home/hunz/.gg main [+]
5 /home/hunz/.nvm HEAD
6 /home/hunz/projects/caresto master
7 /home/hunz/projects/crisp main [+]
8 /home/hunz/projects/dot-files master [+]
9 /home/hunz/projects/elixir-learning master [+]
10 /home/hunz/projects/pulse.git main [+]
11 /home/hunz/projects/utils master
12 /home/hunz/projects/vim-dark main

Search

Search repositories.

gg <FILTER>

Example:

$ gg .vim
1 /home/hunz/.config/nvim master [+]
12 /home/hunz/projects/vim-dark main

CD to a repo

Change to a repository directory using its ID.

gg <ID|FILTER>

Examples:

$ gg 8
8 /home/hunz/projects/dot-files master [+]
Changing directory...

$ pwd
/home/hunz/projects/dot-files

You can also use a string, GG will change directory if only one repository matches the string.

$ gg .dot
8 /home/hunz/projects/dot-files master [+]
Changing directory...

$ pwd
/home/hunz/projects/dot-files

Execute command in one repo

Execute a command in a repository from anywhere without leaving your current working directory.

gg <ID|FILTER> <COMMAND>

Examples:

$ pwd
/home/hunz/projects/dot-files

$ gg 1 status -s
1 /home/hunz/.config/nvim: git status -s
D  LICENSE.md
 D README.md
 D init.lua
?? init-old.lua
?? init-oldold.lua
?? plugins/

$ gg 1 add init.lua
1 /home/hunz/.config/nvim: git add init.lua

$ gg 1 status -s
1 /home/hunz/.config/nvim: git status -s
D  LICENSE.md
 D README.md
D  init.lua
?? init-old.lua
?? init-oldold.lua
?? plugins/

$ gg 1 reset --hard HEAD
1 /home/hunz/.config/nvim: git reset --hard HEAD
HEAD is now at 70f4ea6 trying nord colorscheme

$ gg 1 status -s
1 /home/hunz/.config/nvim: git status -s
?? init-old.lua
?? init-oldold.lua
?? plugins/

$ pwd
/home/hunz/projects/dot-files

You can also filter projects by a string to apply to multiple projects.

$ gg .conf fetch
1 /home/hunz/.config/nvim: git fetch
2 /home/hunz/.config/wezterm: git fetch

Execute command in all repos

Execute a command in all your repositories without leaving your current working directory.

gg <COMMAND>

Examples:

$ gg fetch
1 /home/hunz/.config/nvim: git fetch
2 /home/hunz/.config/wezterm: git fetch
3 /home/hunz/.fzf: git fetch
4 /home/hunz/.gg: git fetch
5 /home/hunz/.nvm: git fetch
6 /home/hunz/projects/caresto: git fetch
7 /home/hunz/projects/crisp: git fetch
8 /home/hunz/projects/dot-files: git fetch
9 /home/hunz/projects/elixir-learning: git fetch
10 /home/hunz/projects/pulse.git: git fetch
11 /home/hunz/projects/utils: git fetch
12 /home/hunz/projects/vim-dark: git fetch
$ gg status -s
1 /home/hunz/.config/nvim: git status -s
 D README.md
 M init.lua
?? plugins/
2 /home/hunz/.config/wezterm: git status -s
 M sessionizer.lua
3 /home/hunz/.fzf: git status -s
4 /home/hunz/.gg: git status -s
5 /home/hunz/.nvm: git status -s
6 /home/hunz/projects/caresto: git status -s
7 /home/hunz/projects/crisp: git status -s
?? input.crisp
8 /home/hunz/projects/dot-files: git status -s
9 /home/hunz/projects/elixir-learning: git status -s
?? erl_crash.dump
?? hello.exs
10 /home/hunz/projects/pulse.git: git status -s
 M .nvimrc
11 /home/hunz/projects/utils: git status -s
12 /home/hunz/projects/vim-dark: git status -s

Customization

By default it will only find git repositories in your home folder, up to 3 directories deep.

If you want to change the list of repositories that gg operates on, provide your own version of gg-find function before sourcing gg.bash in your .bashrc file.

That function should return all the repositories listed, one for each line. You probably want to sort them in a way so the repository IDs doesn't change every time you list your repositories.

The default implementation is at the very top of gg.bash file, you may use it to create your own.

Here's an example of a list of static git repositories:

gg-find() {
  echo "$HOME/projects/foo"
  echo "$HOME/.config/bar"
}

Here's a sample implementation that would search multiple directories, you may simply add more paths after "$HOME":

gg-find() {
    local folders=(
        "$HOME"
        # Add your paths here ...
    )
    find "${folders[@]}" -maxdepth 3 -type d -name .git -exec dirname '{}' \; | sort -u
}

So your .bashrc will look something like this:

gg-find() {
    local folders=(
        "$HOME"
        "$HOME/my/super/secret/repository"
        "/home/alice/projects"
    )
    find "${folders[@]}" -maxdepth 3 -type d -name .git -exec dirname '{}' \; | sort -u
}
. "$HOME/.gg/gg.bash"

Remember you need to reload your .bashrc to see your changes in effect (e.g. exec bash).

Cache

The list of repositories is built and cached when you first call gg. That cache is only refreshed when you call gg without any arguments.

This means two very important things:

  1. New repositories will not show up on the list until you call gg again;
  2. If you're chaining multiple commands to the same repo, you are safe that the ID of the repository will not change.

If you want to list the repositories without rebuilding the list (i.e. querying from the cache), use gg ls command.

The cache is stored in a file $GG_CACHE_FILE, which by default is "$HOME/.gg/.cache", you may change that location by setting that variable before sourcing gg.bash, same as you would do to customize gg-find.

So your fully customized .bashrc may look something like this:

gg-find() {
    local folders=(
        "$HOME"
        "$HOME/my/super/secret/repository"
        "/home/alice/projects"
    )
    find "${folders[@]}" -maxdepth 3 -type d -name .git -exec dirname '{}' \; | sort -u
}
GG_CACHE_FILE="$HOME/.gg_cache_file"
. "$HOME/.gg/gg.bash"

Uninstall

sed -i '/^[ -f "$HOME/.gg/gg.bash" ] && . "$HOME/.gg/gg.bash"/d' "$HOME/.bashrc"
rm -rf "$HOME/.gg"

If you have any customization (gg-find, or GG_CACHE_FILE), you'll need to delete those yourself.

About

One command for all your git repos.

Topics

Resources

License

Stars

Watchers

Forks

Languages