This post is basically a collection of things I think I should remember about git: setup, commands, multiple repos, more obscure options etc.
Config
Two things: enable colors, and make git push push the current branch to a branch of the same name (and not all the branches, which is the default). This means when you do git push, it pushes your working branch but not other branches.
git config --global color.ui true git config --global push.default current
Zsh/bash aliases
These are small things, but they make things so easy. I instinctively type gs after changing directory nowadays.
alias ga='git add' alias gp='git push' alias gl='git log' alias gs='git status' alias gd='git diff' alias gdc='git diff --cached' alias g='git'
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
Apparently, the “git lg” above can be replicated fairly well with:
git log --decorate --graph --oneline
For more git log related discussion, see this HN thread.
Managing multiple git repositories
A fairly simple way of doing this is to add a function that you can use to run the same command in multiple directories. This one is for zsh:
gr() {
local cmd="$*"
for dir in /home/m/repos/{one,two,three}; do
(
print "nin $dir"
cd $dir
eval "$cmd"
)
done
}
alias grs="gr git --no-pager status -sb"
alias grl="gr git --no-pager log --decorate --graph --oneline -n 3"
alias grd="gr git diff"
alias grdc="gr git diff --cached"
alias grn="gr npm ls"
In the example below, I 1) switch all working repos to master, 2) fetch the recent remote changes, 3) check the status of every repository, and 4) after going into those couple of dirs and stashing stuff (not shown in detail), pull all repos to update them
gr git checkout master gr git fetch grs in /home/m/repos/one ## master in /home/m/repos/two ## master...origin/master [behind 8] in /home/m/repos/three ## master...origin/master [behind 4] M Makefile gr git pull
Add all changes or all changes to existing files
$ git add -A
Adds all files and file deletes, so you don’t need to enter them manually.
$ git add -u
Same, but doesn’t add files that didn’t exist before.
Log-fu
$ git log -p
.. to show the patches alongside the log
$ git fetch && \ git log --author="`git config --get user.name`"\ --pretty=format:'%h %an %Cred%ar %Cgreen%s' refactor..master
6591466 Mikito Takada 7 months ago Port over more code 1f464fb Mikito Takada 7 months ago Refactor window 41a3ec9 Mikito Takada 9 months ago Handle switching from window to root window
$ git log staging -1 -p -- my/subdir
Show the latest commit that affects the my/subdir path on the branch “staging” with the patch.
$ git log --stat
Show the changed files only.
$ git log --author=foo
Only commits by author foo.
$ git log --stat -- subdirectory
Show the commits affecting only “./subdirectory”, with a summary of the files (–stat).
For example:
$ git log --stat -- .
Shows the summary of commits affecting the current directory.
$ git log --grep='.*foo.*'
Grep for a specific log message.
$ git log --since="1 week ago" --until="2 weeks ago"
Filter commits by date.
$ git shortlog -sn
Shows a “top contributors list” by commits.
Diff-fu
Differences between the staged files and the last commit:
$ git diff --cached
I use that a lot just before committing the changes to check what my commit changed.
So git diff is for the files that are unstaged, while git diff –cached is for staged files.
What’s different between my branch and some other branch, e.g. master?
$ git diff my_branch..master
What changed in the last three commits?
$ git diff HEAD^3
Ignore whitespace?
$ git diff HEAD^ --word-diff
What’s different between my branch and some other branch in subdirectory (or file)?
$ git diff my_branch..master subdirectory
Remember, git diff outputs an applicable patch:
$ git diff > my.patch
$ git apply < my.patch
Grep-fu
$ git grep -e foo --or -e bar --not -e baz
Grep for foo or bar, but exclude the expression baz.
$ git grep --untracked foo
Include untracked files in grep.
$ git grep --cached foo
Include cached (staged) files in grep.
$ git grep --no-index foo /var/bar
Use “git grep” instead of regular grep, grep for foo in /var/bar. Compared to regular grep, git grep is nicer due to the colors and paging defaults.
Creating a feature branch and merging it back
Checkout the branch you want to base your work on:
$ git checkout master
Then create a branch and check it out:
$ git checkout -b local_name
Push the branch to the remote
$ git push -u origin local_name
Later on, merge it:
$ git checkout master
$ git merge local_name
Look at the unmerged branches:
$ git branch --no-merged
Look at branches that contain a particular commit (e.g. when cherrypicking):
$ git branch --contains 1234abcd
Stashing changes
$ git stash
$ git stash list
$ git stash apply
Blaming
$ git blame path/to/file
See who changed what.
$ git blame abce1234^ path/to/file
See the blame, starting one commit before abce1234. E.g. when you need to trace back a particular line of code in history.
Working with remotes
Changing from Github to Bitbucket
$ git remote -v # look at remotes
$ git remove rm origin # delete
$ git remote add origin git://addr/to/repo # add new remote
$ git push -u origin master # push to new remote
Adding a upstream repo to pull in new changes from a forked project
$ git remote add upstream git://addr/to/repo
$ git checkout master && git pull upstream master
Keeping the number of merges lower on small commits
For small commits made on top of a frequently changing branch like master, you might want to rebase your local changes on top of the current remote before you merge a feature branch (more in depth):
$ git pull --rebase
$ git push
Resetting the current branch
When you want to reset to the current HEAD.
$ git reset --hard HEAD
When a branch tracking a remote has become outdated (e.g. you are on staging now but your commits have diverged):
$ git reset --hard origin/staging
Cherry-picking a commit
$ git cherry-pick sha1_of_commit
Reverting (unapplying) a bad commit:
$ git revert sha1_of_commit
Total number of remote branches
First, remove local branches that do not exist on origin (–dry-run if you want to preview):
$ git remote prune origin
$ git branch -r | wc -l 123
Get the latest commit of all remote branches
Get the latest commit of all remote branches, and summary, ordered by age
Use this Node script:
https://gist.github.com/91ba46dee32b221b3a84
Delete a local or remote branch
Delete a local branch:
git branch -d some_branch_name
Really delete a local branch, even if git complains about it in the previous command:
git branch -D some_branch_name
Delete a remote branch, e.g. in Github:
git push origin :some_branch_name
The reason for that syntax is that you can do `git push origin local_branch_name:remote_branch_name` so what that line above is doing is essentially pushing NULL to the remote branch, thereby killing it off.
