Skip to content

Latest commit

 

History

History
550 lines (457 loc) · 11.9 KB

Git.md

File metadata and controls

550 lines (457 loc) · 11.9 KB

Git cheatsheet

================================================================================

Config

Edit:

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"

================================================================================

Create repo

mkdir repodir
cd repodir
git init  # create new repo in cwd

================================================================================

Stage, commit

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

================================================================================

Stash

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.

================================================================================

Commits

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.

================================================================================

Branches

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

================================================================================

Remote

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

================================================================================

Worktree

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

================================================================================

git flow

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

================================================================================

git grep

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 example

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