Remove a current tracking relationship
$ git branch --unset-upstream
Cryptographically sign all commits
Revert a single file with uncommitted changes to HEAD
$ git checkout <filename>
Unstage a file
$ git reset HEAD <file>
Print changed files in last commit
$ git show --name-only [commit]
Undo commit and keep changes
$ git reset --soft @~1
Merge patches like you're a kernel maintainer
Kernel maintainers use the
git am (apply-mail) command to get patches from a
mailing list. GitHub has extended this command in
hub to work with PR urls.
This allows you to omit those nasty merge commits and update / prune files
$ hub am -3 <pull-request-url>
git-flow is probably the most popular branching technique out there. It's
also shit. There are many caveats in it, and it doesn't use some use git
primitives where it should. A successful branching model for simple projects is:
- master is the truth of all merges
- each feature gets their own branch on the contributor's fork
- whenever a feature is done, it's pulled in
- master gets a tag
It doesn't need to be complex to be efficient. If hotfixes need to be performed, master can be rebased on top of that. If features need to be removed, just request the commit range for certain tag to roll back. Tada!
- git flow considered harmful
- follow up: git flow considered harmful
- chronological git history is silly
Git hooks are a way of extending git with functionality whenever things happen.
To some extent
npm has a similar mechanism called
npm scripts. Git hooks
are just regular bash scripts that are triggered on actions. They live in
.git/hooks, where the filename is the name of the hook. The following hooks
applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-receive update post-receive post-update pre-auto-gc post-rewrite pre-push
Git hook scripts cannot be checked into version control. If you want to persist scripts between multiple users you must check them into the project itself and then symlink them back in, preferably in a bootstrap script. Be careful when running hard symlinks though, as they will overwrite any local files. Instead create an aggregator script that moves the original scripts and then imports the original + repo scripts back in.
Example functionality for git hooks includes: checking code style on commit, running extended tests on rebase to master, verify that no commit is performed while rebasing, semver is updated, etc.
Find by binary search the change that introduced a bug.
$ git bisect start master f596075 # git bisect <bad> <good> $ git bisect good # mark a commit as good $ git bisect bad # mark a commit as bad $ git bisect reset # exit git bisect $ git bisect run ./test # run an auto script after git bisect start
Manage main and fix commits
--fixup you can create fix commits for your main commit; this is a
better alternative to continuously rebasing on top of your previous commit.
--fixup commits are automatically squashed into their
$ git commit --fixup <commit-sha> # automatically marks your commit as a fix # of a previous commit $ git rebase -i --autosquash # automatically organize merging of these # fixup commits and associated normal # commits
To create a temporary commit message of which the value can be discarded during
a rebase, prefix the message with
To create a temporary commit message of which the value should be rolled back
into the original commit, prefix the message with
A best practice is to create a new empty commit, create a TODO list of the
scope of the commits and roll back all relevant commits into this commit using
- keep your branch clean with git fixup and autosquash
- what's the difference between fixup! and squash! ?
- autosquashing git commits
$ git rm --cached -r dir
$ git reset HEAD <file>
Change remote to SSH
$ git remote set-url origin [email protected]:<username>/<repo>.git
Rebase the first 2 commits in git
The root commit is protected by default, the
--root flag enables
$ git rebase -i --root
Sometimes you want to know who wrote a certain piece of code.
git blame to
$ git blame <filename> # git blame a complete file $ git blame -L <start>,<end> <filename> # git blame between certain lines
Safer force push
--force is dangerous as it blindly overwrites;
check if the ref hasn't been modified before force pushing.
$ git push --force-with-lease
Git get theirs / pull --force
$ git reset --hard origin
Show staged files changes
$ git diff --cached
Git stash pop conflicts
git stash pop fails, the stash is not dropped, but changes are floating.
You can safely
git reset --hard on top of this to unapply the stash since
it's kept in the stash list still.
Safe git stash
git stash apply- apply a git stash without destroying the stash
Inspect individual objects in the DB.
git tag v1.0.0 # create tag called 'v1.0.0' git push --delete origin <tag> # delete remote tag git tag -d <tag> # delete local tag
$ git submodules add <repo-name> $ git submodule update --recursive
$ git remote -vv # display remote branches $ git branch --unset-upstream # remove tracking relationship with upstream $ git push -u origin head # push to current branchname on origin remote
Show root commit
$ tag_commit="$(git rev-list --max-parents=0 HEAD)"
git branch status
$ git branch -vv
create a new empty branch
Create a new branch that's detached from the history from the branch that it's being forked off.
$ git checkout --orphan <branchname>
stash files that haven't been checked in yet
$ git stash save -u
save stash with name
$ git stash save "<name>"
Check out a branch into a directory
$ git worktree add <path> <branch>
$ git fetch --all $ git reset --hard origin/master
Get current git branch
$ git rev-parse --abbrev-ref HEAD
Fix refs errors
In case of
remote: fatal error in commit_refs, run
$ git gc