Helpers for augmenting and prettifying existing git functionality.
Git aliases and scripts.
Annotated histogram of my most-used Git aliases:
history | awk '{print $2}' | grep '^g' | sort | uniq -c | sort -rn | head -n 30
# 2776 gst # `git status -uno` (tracked files only)
# 2734 gd # `git diff`
# 2092 ggr # `git graph`: wrapper for `git log --graph`, with nice colorization and formatting options
# 2062 gs # `git status`
# 626 gcam # `git commit -am`
# 587 gp # `git push-x`: `push` to one or more remotes (comma-delimited)
# 538 gap # `git add -p` (add interactively, in chunks)
# 519 gcm # `git commit -m`
# 470 gsh # `git show`
# 463 gco # `git checkout`
# 448 ghh # `git help`
# 433 gb # `git branches` (pretty-print Git branches)
# 425 gr # `git remote -vv`
# 404 gau # `git add -u` (restrict to already-tracked files)
# 402 gdc # `git diff --cached` ("staged" changes only)
# 376 gf # `git fetch-x --tags`: fetch ≥1 remotes in parallel (comma-delimited), include tags
# 370 gg # `git graph-all` (graph all branches)
# 242 gcaan # `git commit --amend --no-edit`: squash uncommitted changes onto HEAD commit
# 217 ggracl # `git graph -a -c -l`: Git branch graph, displaying author and committer dates as relative times (e.g. "3 days ago")
# 208 gcp # `git cherry-pick`
# 194 ga # `git add`
# 192 ggp # `git grep --recurse-submodules`
# 175 g # `git`
# 174 gpf # `git push -f`
# 131 ggrh # `git graph HEAD` (Graph of HEAD commit, plus subsequent arg branches)
# 118 gl # `git ls-files`
# 113 grb # `git rebase`
# 111 glg # `git log -p --follow`, restricted to paths matching a substring argument
# 109 garc # `git-add-rebase-continue`: mark conflicted files resolved, continue rebase
There are over 900 possible 2-character Bash commands ([a-z][a-z\d]
) and 30k+ 3-characters; a goal of this repo is to help me always be within a couple keystrokes of most common Git commands.
Source .git-rc
in your .bashrc
:
echo ". $PWD/.git-rc" >> ~/.bashrc # Configure new shells to load `git-helpers`
. .bash-rc # "source" .bashrc, for immediate effect in existing shells
This will load all aliases, and add relevant directories to $PATH
. pip install -r requirements.txt
also ensures python-dateutil
is installed available, which some scripts here require.
More details about aliases/commands I use frequently:
ggr
(git-graph
) and gg
(git-graph-all
) are my preferred ways to visualize Git branches and history.
Example output from this repo:
The first line shows that local branch main
is checked out (HEAD -> main
), and up to date with remote branches gh/main
and gl/main
(GitHub and GitLab, resp., but that's just a convention I use).
runsascoded/.rc shows several parallel branch lineages I maintain:
I develop on gh-all
, and cherry-pick commits over to gh-server
, gl-all
, and gl-server
.
git/git shows wide merge lineages
gb
(git branches
) is an improved version of git branch -vv
:
TileDB-SOMA example:
gbr
(git-remote-branches
) is similar, but summarizes remotes' branches.
grbh
(git-rebase-head
) and gch
(git-cherry-pick-head
) print the SHA of the commit currently being rebased or cherry-picked.gshrh
(git-show-rebase-head
) and gshch
(git-show-cherry-pick-head
) pass that to git show
.rb <N>
: interactive rebase over the last N
commits.groc
(git-reorder-commits
): reorder ancestor commits, by index.
groc 0 1
swaps the last two commits, effectively a rebase HEAD~2
that "picks" HEAD~0
then HEAD~1
.grbcd
(git-rebase-preserve-commit-dates
): rebase, but inject -x git rcd
(reset-committer-date-rebase-head
) after each commit, so that the committer time is preserved.grd
(git-rebase-diff
): compute most recent pre-rebase SHA (ghblr
/ git-head-before-last-rebase
), diff that vs. current worktree.
gtw
(git-throw
): squash uncommitted changes onto an arbitrary previous commit.
gtwp
(git throw HEAD^
): squash staged changes onto the previous commit.gdg
(git-diff-gif.py
): create a GIF of an image at two commits, open in browsergdj
(git-diff-json.py
): diff two JSON files, after pretty-printinggdc
(git diff --cached
): show staged changes onlygds
(git diff --stat
): show file/line add/remove statsCreate a commit with a given tree and parents:
gcmp
(git-commit-multiple-parents
): takes an optional commit message (-m
) and commit (-b
) whose tree to usegsp
(git-set-parents
) uses the current HEAD
s message and treegsau
(git-set-author
): update HEAD
author, either from Git configs, an existing commit, or literal name/email arguments.gsad
(git-set-author-date
): update HEAD
author date; match another commit's, or HEAD
's committer date.gscd
(git-set-committer-date
): update HEAD
committer date; match another commit's, or HEAD
's author date.gsid
(git-set-id
), ggsid
(git-set-id -g
): set user.{name,email}
configs.gcd
(git copy-diffs
) pushes the state of your local repository to a "mirror" remote, preserving:
HEAD
pointer, upstreams.gitignore
d) filesI've been shocked to not find support for this in git
itself, or in any other tools people have written that solve versions of this problem. Common approaches (none of which do exactly what I want, or have undesired side-effects) are:
push -f
that.rsync
the entire directory
.gitignore
d files, as this will frequently contain compilation outputs and the like.git ls-files
to rsync
in a way that rsync
can digest.
git
tracks; what branch you're on, what commits all branches are on, etc. I want these things copied too.I've implemented it here in 3 steps:
rsync
the entire .git
directory
git reset --hard HEAD
.git
directory and none of the files that git
thinks should be there based on the contents of .git
; this puts everything there, but blows away the uncommitted staged changes that were stored in .git/index
.rsync
any unstaged, staged, and untracked (but not .gitignore
d) files, as well as .git/index
.git
state is equal as well.Simply create a remote using the add-mirror-remote
command:
$ git add-mirror-remote my-dev-box ryan@dev-box:path/to/repo
Then you can run:
$ git copy-diffs dev-box
$ gcd dev-box # for short
And all local state will be pushed to the remote, clobbering whatever was there previously.
As a shortcut, you can set environment variable $MIRROR_REMOTES
to a comma-seperated list of remote names for git copy-diffs
to look for by default:
$ export MIRROR_REMOTES=dev-box1,dev-box2
$ git copy-diffs # will push to the first remote named dev-box1 or dev-box2 found in your "remotes" list