- Config
- Create repo
- Stage, commit
- Stash
- Commits
- Branches
- Remote
- Worktree
- git-flow
- Grep search
- Hook example
================================================================================
git config -e
# flags:
--local # for current repository
--global # globally for user
~/.gitconfig
example:
[user]
name = oupirum
email = oupirum@gmail.com
[core]
autocrlf = input
# true - replace crlf to lf and vice-versa (for windows)
# input - only replace crlf to lf on commit (for linux|mac)
# false - disable
safecrlf = warn
# true - refuse irreversible autocrlf changes
# warn - only show warn message
editor = vim
[alias]
h = log --pretty=format:\"%C(red)%h%Creset %C(green)%ad%Creset%C(yellow)%d%Creset | %s\n %C(blue)[%an <%ae> ]%Creset\n\" --graph --date-order --date=short
ha = log --pretty=format:\"%h %ad%d | %s\n [%an <%ae>]\n\" --graph --date-order --date=short --all
co = checkout
s = status
d = diff
ds = diff --staged
a = add
ap = !git add -N . && git add -p
rs = reset
rsh = reset --hard HEAD
stm = stash push -m
stmp = stash push --patch -m
stl = stash list
sts = "!f() { git stash show -p stash@{${1:-0}}; }; f"
sta = "!f() { git stash apply stash@{${1:-0}}; }; f"
stp = "!f() { git stash pop stash@{${1:-0}}; }; f"
std = "!f() { git stash drop -p stash@{${1:-0}}; }; f"
c = commit
ca = commit --amend
psit = !git push origin $(git rev-parse --abbrev-ref HEAD)
plit = !git pull origin $(git rev-parse --abbrev-ref HEAD)
pldev = !git pull origin dev
plmas = !git pull origin master
upd = "!f() { git fetch origin $1:$1 --recurse-submodules=no --progress --prune; }; f"
================================================================================
mkdir repodir
cd repodir
git init # create new repo in cwd
================================================================================
Get the working tree state:
git status
working tree, staged/unstaged, untracked files.
Stage:
git add <path>
--all # include removals
-p|--patch # interactively select hanks
-N|--intent-to-add # add paths to index with no content
# useful for showing untracked files in diff
Unstage:
git reset <file>
-p|--patch
git reset <hash> # reset HEAD to the specified state (commit)
--mixed # reset index (default)
--soft # reset only head point to; doesn't touch index and working tree
--hard # reset both index and working tree
Commit staged changes:
git commit
-m <message>
--amend # change previous commit intead of creating a new one
Get diff of working area:
git diff
--staged # in staged area
--only-name
--word-diff=<mode> # none, color, plain, porcelain
git diff <file>
git diff <hash> <file> # between commit and working area
git diff <hash1> <hash2> # between two specified commits
git diff <hash1>:<file> <hash2>:<file>
Apply patch (e.g., generated by diff command):
git apply <patch_file>
Temporarily ignore file:
git update-index --assume-unchanged <file>
Remove file from working tree and index:
git rm <file>
--cached # remove only from index ("forget", i.e., stage file for removal)
Remove untracked files:
git clean [<path>]
-n # only show what would be done
-d # remove directories too
-f # force
-x # use -e for ignoring instead of .gitignore
-e <pattern> # exclude
-X # remove only ignored
================================================================================
Create and put a new stash entry:
git stash push [<paths>...]
-m <description>
-u # include untracked changes
# (stash and then clean up)
-S|--staged # only staged changes
--all # includes ignored files
# (stash and then clean up)
-p|--patch # interactively select hanks
# keeps index by default
-k|--keep-index # keep staged changes untouched
--no-keep-index
Create a new stash entry:
git stash create <description>
returns hash.
Put entry to list:
git stash store -m <description> <hash>
List stash entries:
git stash list
View stash entry contents:
git stash show -p stash@{<N>}
# or
git stash show -p stash^{/<regex>}
Apply stash entry to working tree:
git stash apply stash@{<N>}
Apply and delete:
git stash pop stash@{<N>}
Delete:
git stash drop stash@{<N>}
Useful shortcuts for referring stash entries by index here.
================================================================================
Print commits history:
git log
--all # all branches
--graph # tree view
--topo-order # default
--date-order # order by date
--max-count <n> # limit
--since <date> --until <date>
# `date` - string like "2013-01-31 01:30:00", "7 days ago", etc.
--first-parent # show only first parent commit for merged branch
-S <somestr> # search for commits where `somestr` added or deleted
-G <regex> # search by regex
View commit diff:
git show <hash>
Restore working tree to certain commit/head/tag:
git checkout <hash|tag|branch>
Only certain file:
git checkout <hash|tag|branch> -- <path>
Revert commit to its previous
git revert <hash|tag>
Create a tag:
git tag <name> # for current head
git tag <name> <hash> # for certain commit
-a <name> -m <description> # create annotated tag
Get history of refs:
git reflog
i.e., list of any changes in repository.
================================================================================
List branches:
git branch
-a # both local and remote
--merged|--no-merged
Create branch:
git branch <new_branch_name>
Create branch and switch to it:
git checkout -b <new_branch>
git checkout -b <new_branch> <from_base_branch>
Rename branch:
git branch -m <branch> <newname>
Delete branch:
git branch -d <branch>
-r # remote tracking
Merge branch into current branch:
git merge <branch>
--no-commit
-s|--strategy resolve|recursive|octopus|ours|subtree
-X theirs|ours # to prefer those|these changes if there are conflicts
# for recursive strategy
--squash # squash merged commits into one
Cancel merge:
git merge --abort
Reapply current branch's commits on top of specified branch:
git rebase <branch>
-i [HEAD~<N>] # interactive mode (e.g., for squashing)
# <N> - number of recent commits to rebase
-s|--strategy recursive|resolve|octopus|ours|subtree
# Do `git config core.hooksPath .no-hooks` to skip hooks. Dont forget to restore it when done.
git rebase --continue # continue rebase (e.g., after fixing conflicts)
git rebase --skip # skip step
git rebase --abort # cancel rebase
Apply specified commits to the current branch:
git cherry-pick <hash>...
-e # edit commit messages
-m # parent number of the mainline
--ff # fast forward (if head is the same as parent of picked)
git cherry-pick --continue
git cherry-pick --quit # skip
git cherry-pick --abort
================================================================================
Create local copy of remote repository:
git clone <repository> <target_dir>
--bare # create "clean" clone, that uses as shared repo
Set repo as remote for current repository:
git remote add <remote_name> <repository>
e.g., for later pull/push.
Remove:
git remote rm <remote_name>
View:
git remote # list
git remote show <remote_name> # show info
Fetch changes from remote repo:
git fetch <remote_name> <branch>
Fetch and merge:
git pull <remote_name> <branch>
# same as `fetch origin branch; merge origin/branch`
--rebase # pull and rebase
# e.g., `pull --rebase origin master` is same as:
# `checkout master; pull origin master;
# checkout current_branch; rebase master'`
-s|--strategy recursive|resolve|octopus|ours|subtree
Push local changes into remote repo:
git push <remote_name> <branch>
--tags # with tags
-f # force (for diverged branch)
git push <remote_name> :<remote_branch> # override remote branch
git push <remote_name> <local_branch>:<remote_branch>
Delete remote branch:
git push <remote_name> --delete <branch>
Remove stale remote-tracking branches:
git remote prune <remote>
--dry-run # only show what will be pruned
================================================================================
Multiple working trees attached to the same repository.
Create:
git worktree add <dir> [<branch>]
-b <new-branch> # create new branch
List:
git worktree list
Remove:
git worktree remove <worktree> # delete specified
git worktree prune # clean up stale worktree files
================================================================================
High-level operations for Driessen branch model.
There branches: develop
, feature
, release
, master
, hotfix
.
git flow init
git flow feature start <feature> # create branch <feature> from develop
git flow feature finish <feature> # merge <feature> into develop
git flow feature publish <feature>
git flow feature pull <remote> <feature>
git flow release start <release> [from_hash] # create release branch
# from develop,
# optionally from certain commit
git flow release finish <release> # merge release into master and
# back into develop
git flow release publish <release>
git flow release pull <remote> <release>
git flow hotfix start <version> [from_hash] # create hotfix branch
# from master
git flow hotfix finish <version> # merge hotfix into develop and
# back into master
git flow hotfix publish <version>
git flow hotfix pull <remote> <version>
# use -k option to keep branch after finish
================================================================================
Grep search in working tree.
git grep "<pattern>"
-G # use basic regex (default)
-E # use extended regex
-F # fixed string, dont interpret pattern as regex
--cached # include staged
--no-index # include not staged
--untracked # include untracked
-v # invert match
-i # ignore case
-w # match whole words
-n # show line numbers
-P # show preceding lines
-h # dont show filenames
-l # print only filenames
-c # print only count of matched lines per file
================================================================================
Hook that adds a jira ticket from branch name to commit messages:
.githooks/prepare-commit-msg
:
#!/bin/sh
# Get the current branch name
BRANCH_NAME=$(git symbolic-ref --short HEAD)
# Check it matches the pattern "feature/AB-123_some-branch-name"
if [ $(echo $BRANCH_NAME | grep -cEi "^(feature|bugfix)\/([a-z]+-[0-9]+)_.*") -eq 1 ]; then
# Trim it to get the ticket identifier
TICKET=$(
echo $BRANCH_NAME \
| sed -r \
-e 's/^(feature|bugfix)\/([a-z]+-[0-9]+)_.*/\2/I' \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
)
# If the message already starts with ticket name, do not edit the commit message.
ORIG_MESSAGE="$(cat $1)"
if [[ $ORIG_MESSAGE == $TICKET* ]]; then
exit
fi
# Preprend the ticket identifier to the commit message
if [ -n "$BRANCH_NAME" ] && [ -n "$TICKET" ]; then
sed -i.bak -e "1s/^/$TICKET: /" $1
fi
fi
Make it executable:
chmod a+x .githooks/prepare-commit-msg
And enable:
git config core.hooksPath .githooks