Git CheatSheet

Cherry-pick

NOTE: cherry-pick from current to another branch is impossible, you always need to checkout!

# pick the commit from "feature" branch to "main" branch
git checkout main
git cherry-pick abc123

# pick multiple non-consecutive commits
git cherry-pick abc123 def456 ghi789

# pick a range of commits
git cherry-pick abc123..def456

# resolve conflicts (if occur)
git cherry-pick --continue

# Abort the cherry-pick
git cherry-pick --abort

Stash

By default git SKIP untracked or ignored files for stash.

# Stash modified/staged files
git stash

# Stash modified/staged/untracked files
git stash -u

# Stash modified/staged/untracked/ignored files
git stash -a

# Stash modified/staged files with message
git stash save "stash message"

# Show all available stashes
git stash list

# Get stash to working gir & delete the stash (last or specified)
git stash pop
git stash pop stash@{1}

# Get stash to working gir, but not delete the stash  (last or specified)
git stash apply
git stash apply stash@{1}

# Recover dropped stash (you need to know it's hash)
git stash apply [stash-hash]

# Delete stash (last or specified)
git stash drop
git stash drop stash@{1}

# Show stash diff (last or specified)
git stash show
git stash show stash@{1}

# Show all details (the patch)
git stash show -p stash@{1}

# Create branch from stash & delete stash (last or specified)
git stash branch [branch-name]
git stash branch [branch-name] stash@{1}

Remote, Fetch, Pull, Push

fetch

Retrieving updates from another repository and updating local repos

# Add a git URL as an alias
git remote add [alias] [URL]
git remote add origin [email protected]:owner/repo.git

# Fetch down all branches from remote repo
git fetch
# or with alias
git fetch origin

# Fetch and delete remote branches locally (if it does not exist on remote)
git fetch --prune

pull

# (fetch + merge) Fetch and merge commits from related remote branch
git pull

# Pull and remove deleted remote branches
git pull --prune

# Updates your branch only if it can fast-forward (without creating new merge commits)
git pull --ff-only

# (fetch + rebase) Fetch commits and reapplies your commits on top
git pull --rebase

# Fetches branch from "origin" and updates your local branch
# Updates local branch manually without merge/rebase.
# Can be done on other branch (NOT current checkouted).
git fetch origin branch:branch

# pull --force - there is no "pull --force"
# To force your local branch to match the remote branch:
git fetch origin  &&  git reset --hard origin/branch_name

push

# push current branch to linked upstream
git push

# push current branch and set tracking branch
# Eg: if current branch is xyz - pushes xyz to origin/xyz
git push --set-upstream origin HEAD
git push -u origin HEAD

# the same but set origin branch name
# Eg: if current branch is xyz - pushes xyz to origin/branch_name
#     (creates origin/branch_name if not exists)
git push --set-upstream origin  branch_name
git push -u origin  branch_name

# Push local branch commits to remote branch
git push origin [branch]

# Force push (with changing history)
git push origin [branch] --forse   =   git push [alias] +[branch]

Merge, Rebase

merge

# merge the specified branch’s history into the current one
git merge branch_name

# merge the specified branch’s history into the current one
# fail if linear history fails
git merge branch_name --ff-only

# merge a remote branch into your current branch to bring it up to date
git merge alias_name/branch_name
# git merge origin/my-feat

# merge source_branch into target_branch
git switch target_branch && git merge source_branch

rebase

# Rebase the current branch onto the specified branch,
# which means the commits from the current branch will be
# reapplied on top of the specified branch
git rebase [branch]

# Interactive Rebase all commits that go before specified one (using hash)
git rebase -i 972078a

# Interactive Rebase last 3 commits (using offset)
git rebase -i HEAD~3

# Interactive Rebase starting from zero commit (root)
git rebase -i --root

Doc: https://git-scm.com/docs/git-rebase

Checkout, Branch

checkout

# Switch to another branch and check it out into your working directory
git checkout  branch_name

# Create branch on your local machine and checkout to it:
git checkout -b  new_branch_name

# Create new branch from source branch (specify source exactly)
git checkout -b  new_branch_name  source_branch_name

switch

# Create a local branch from the fetched remote branch (Git 2.23+)
git switch [branch-name]

# In this case Git is guessing that you are trying to checkout
# and track the remote branch with the same name.
# This can be disabled with --no-guess
git switch [branch-name] --no-guess

# -c to create a new local branch
git switch -c [local-branch-name] origin/[remote-branch-name]

branch

# Show all local branches
git branch

# Show all local branches & last commit message
git branch -v

# Show branches & related remote branch (upstream) & last commit
git branch -vv

# Show all remote branches
git branch -r
git branch --remotes

# Show local & remote branches
git branch --all
# List branches available for checkout
git branch -v -a

# Show of branches that already was merged with current
git branch --merged

# Show of branches that not merged with current
git branch --no-merged

# Create a new branch at the current commit
git branch  branch_name

# Rename branch
git branch --move  old_branch_name  new_branch_name

# Relate remote and current branches
git branch --set-upstream-to=origin/branch_name
git branch -u origin/branch_name

Delete branch:

# Delete local branch only if it was fully merged
git branch -d  branch_name

# Force delete local branch
git branch -D  branch_name

# Delete remote branch
git push origin --delete  branch_name
# OR
git push origin :branch_name

Commiting

status

# show modified files in working directory, staged for your next commit
git status

add

# Stage all repo files (not from .gitignore)
git add .

# Stage all changes in <directory> for the next commit.
git add [directory]

# Stage all changes in <file> for the next commit.
git add [file]

commit

# commit your staged content as a new commit snapshot
git commit -m "your commit message"

# add & commit
git commit -am "your commit message"

# Append current changes to last commit
git commit --amend

# Append current changes to last commit (adds changes files too)
git commit -a --amend

# Append current changes to last commit (take massage from last commit)
git commit -a --amend --no-edit

# Create empty commit
git commit --allow-empty -m 'Initial commit'

History

show

# show changes of the last commit
git show

# show any object in Git in human-readable format
git show [SHA]

diff

# diff of what is changed but not staged
git diff

# diff of what is staged but not yet commited
git diff --staged

# show the diff of what is in branchA that is not in branchB
git diff branchB...branchA

log

# show commits in the current branch’s history
git log

# Show all tree (even if HEAD is detached to another commit)
git log --all

# Show compact only last 5 commits
git log --oneline -n5

# Show tree
git log --graph
git log --graph --oneline

# display the commit history of a specific file,
# tracing its changes even if it has been renamed or moved
git log --follow [file]

# see the git log of a specific branch
git log <branch-name>

# show the commits on branchA that are not on branchB
git log branchB..branchA
# Search for added/removed lines with a specific string
git log -S "search_term"

# Search by pattern in diffs
git log -G "regex_pattern"

# Include File and Diff Details
git log -p -G "search_term"

# Search Across All Branches
git log --all -S "search_term"

Tagging

# list all tags
git tag
git tag -l
git tag --list

# see tag data along with the commit that was tagged
git show v1.4

# search for tags that match a particular pattern
git tag -l "v1.8.5*"

# create a simple tag (holds only commit)
git tag v1.4

# create an annotated tag  (holds commit and tag data)
git tag -a v1.4 -m "Version 1.4"

# create a tag later for commit 9fceb02
git tag -a v1.2 9fceb02

# push tag
git push origin v1.5

# push all tags
git push origin --tags
git push --tags

# delete tag (local only)
git tag -d v1.4

# delete tag remotely
git push origin --delete v1.4

# checkout the tag commit
git checkout v1.4

clone, init (create repo)

# Create Git repo in current folder
git init
git init <project name>

# Create remote repo in current folder by URL
git clone <URL>

# Copy remote repo in specified folder by URL
git clone <URL> <folder>

# Copy remote repo with only specified branches
git clone -b <branch_name> --single-branch <URL>

# Copy remote repo with only specified branches in specified folder
git clone -b <branch_name> --single-branch <URL> <folder>

# Copy remote repo with 5 commits last only (limit history)
git clone <URL> --depth=5 <folder>

config

Remote

# view remote URLs
git remote -v

# add remote repo (takes two arguments)
git remote add origin [email protected]:USERNAME/REPOSITORY.git

# change a remote repository's URL (takes two arguments)
git remote set-url origin [email protected]:USERNAME/REPOSITORY.git

# rename a remote repository (takes two arguments)
git remote rename origin my_name

More: https://docs.github.com/en/get-started/getting-started-with-git/managing-remote-repositories

List

# Show all settings
git config --list
# Or see files: `~/.gitconfig` (user wide) `.git/config` (repo wide)

# Show global options only
git config --global --list

# Show system options only
git config --system --list

# Show options and files where they defined (global, user, repo, etc...)
git config --list --show-origin

Get

# Show option value
git config user.name
# or
git config --get user.name

# Show option value and file where it places
git config --show-origin user.name

# Show option value from specified scope
git config --system user.name

Set

# Set exact setting for repo scope
git config  branch.master.merge  refs/heads/master

# Set exact setting for global scope
git config --global user.name "[Kama]"
git config --global user.email "[[email protected]]"

# Set automatic command line coloring for Git for easy reviewing
git config --global color.ui auto
# Set `core.autocrlf=true` in global scope
git config --global core.autocrlf true

# Set system wide .gitignore patern for all repos
git config --global core.excludesfile [file]

Remove / Unset

# Remove option from repo scope
git config --unset user.name

# Remove option from global scope
git config --global --unset user.name

Aliases

See: https://github.com/mathiasbynens/dotfiles/blob/main/.gitconfig

# add alias "git lg"
git config --global alias.lg "log --oneline --graph"
[alias]

	# List aliases.
	aliases = config --get-regexp alias

	# List contributors with number of commits.
	contributors = shortlog --summary --numbered

	# Show the user email for the current repository.
	whoami = config user.email

	# Amend the currently staged files to the latest commit.
	amend = commit --amend --reuse-message=HEAD

	# View abbreviated SHA, description, and history graph of the latest 20 commits.
	l = log --oneline --graph -n20

	# View the current working tree status using the short format.
	s = status -s

	# Show the diff between the latest commit and the current state.
	d = !"git diff-index --quiet HEAD -- || clear; git --no-pager diff --patch-with-stat"

	# Show verbose output about tags, branches or remotes
	tags = tag -l
	branches = branch --all
	remotes = remote --verbose

	# Interactive rebase with the given number of latest commits.
	reb = "!r() { git rebase -i HEAD~$1; }; r"

	# Remove the old tag with this name and tag the latest commit with it.
	retag = "!r() { git tag -d $1 && git push origin :refs/tags/$1 && git tag $1; }; r"

	# Remove branches that have already been merged with main.
	# a.k.a. ‘delete merged’
	dm = "!git branch --merged | grep -v '\\*' | xargs -n 1 git branch -d"

	# Find commits by source code
	fc = "!f() { git log --pretty=format:'%C(yellow)%h  %Cblue%ad  %Creset%s%Cgreen  [%cn] %Cred%d' --decorate --date=short -S\"$1\"; }; f"

	# Find commits by commit message
	fm = "!f() { git log --pretty=format:'%C(yellow)%h  %Cblue%ad  %Creset%s%Cgreen  [%cn] %Cred%d' --decorate --date=short --grep=\"$1\"; }; f"

And more:

[alias]
	# Switch to a branch, creating it if necessary.
	go = "!f() { git checkout -b \"$1\" 2> /dev/null || git checkout \"$1\"; }; f"

	# `git di $number` shows the diff between the state `$number` revisions ago and the current state.
	di = !"d() { git diff --patch-with-stat HEAD~$1; }; git diff-index --quiet HEAD -- || clear; d"

	# Pull in remote changes for the current repository and all its submodules.
	p = pull --recurse-submodules

	# Clone a repository including all submodules.
	c = clone --recursive

	# Commit all changes.
	ca = !git add ':(exclude,attr:builtin_objectmode=160000)' && git commit -av

	# Credit an author on the latest commit.
	credit = "!f() { git commit --amend --author \"$1 <$2>\" -C HEAD; }; f"

	# Interactive rebase with the given number of latest commits.
	reb = "!r() { git rebase -i HEAD~$1; }; r"

	# Find branches containing commit
	fb = "!f() { git branch -a --contains $1; }; f"

	# Find tags containing commit
	ft = "!f() { git describe --always --contains $1; }; f"

	# Remove branches that have already been merged with main.
	# a.k.a. ‘delete merged’
	dm = "!git branch --merged | grep -v '\\*' | xargs -n 1 git branch -d"

GIT Config Best Setup

https://blog.gitbutler.com/how-git-core-devs-configure-git/

[column]
	ui = auto

[branch]
	# Show most recently changed branches first.
	sort = -committerdate

[tag]
	sort = version:refname

[init]
	defaultBranch = main

[diff]
	algorithm = histogram
	colorMoved = plain
	mnemonicPrefix = true
	renames = true

[push]
	default = simple
	autoSetupRemote = true
	followTags = true

[fetch]
	prune = true
	pruneTags = true
	all = true

# why the hell not?

[help]
	autocorrect = prompt

[commit]
	verbose = true

[rerere]
	enabled = true
	autoupdate = true

[core]
	excludesfile = ~/.gitignore

[rebase]
	autoSquash = true
	autoStash = true
	updateRefs = true

# a matter of taste (uncomment if you dare)

[core]
	# fsmonitor = true
	# untrackedCache = true

[merge]
	# (just 'diff3' if git version < 2.3)
	# conflictstyle = zdiff3

[pull]
	# rebase = true

Tracking (rm mv)

# delete the file from project and stage the removal for commit
git rm [file]

# Remove single file from git stage
git rm --cached www/.env

# change an existing file path and stage the move
git mv [existing-path] [new-path]

Revert

# Creates new commit in which all changes of another commit will be reverted
git revert 0ad5a7a6

# Revert by modifying your working tree and index without creating a commit
git revert -n 0ad5a7a6
git revert --no-commit 0ad5a7a6

# The target commit is 2 commits behind HEAD on the current branch
git revert HEAD~2

# Revert a set of Git commits, between two revisions.
# The older commit should come first, followed by the newer commit.
# Revert these two commits, plus every commit in between them.
git revert HEAD~5..HEAD~2

# Revert merge and leave only 1 parent
git revert -m 1 HEAD
git revert --mainline 1 HEAD

Reset

reset

git reset   =   git reset --mixed HEAD

git reset HEAD
git reset [hash]

# reset last two commits
git reset HEAD~2

# reset all: commit history, stage snapshot, working dir
git reset --hard [hash]

# reset: commit history, stage snapshot
git reset --mixed [hash]

# reset: commit history
git reset --soft [hash]

# unstage a file, but retaining the changes in working dir
git reset [file]

# pull --force - there is no "pull --force"
# To force your local branch to match the remote branch:
git fetch origin
git reset --hard origin/<branch_name>

reflog

# log of all ref updates (e.g., checkout, reset, commit, merge)
git reflog

# undo the specified operation
git reset HEAD@{1}
git reset d27924e

Grep (serach)

# Search "search_query" in working dir
git grep -n search_query

# Find commits where ZLIB_BUF_MAX exists
git log -S ZLIB_BUF_MAX --oneline

# Search with Regex
git log -G regex --oneline

Submodules

https://git-scm.com/docs/git-submodule

# initializes all the submodules. In other words - sets up all
# submodules of the project to be fetched and updated.
git submodule update --init
# OR
git submodule init && git submodule update

# Provides info about submodules. Shows the current commit
# that each submodule is on, including an optional short status if any
# of the commits have not been checked out.
git submodule status
# Status symbols:
# "-" (minus sign): Submodule not checked out yet.
# " " (space): Checked out but commit doesn’t match any tracked branch.
# "+" (plus sign): Local changes or new commits in submodule.
# "U": Merge conflicts in submodule.

# Checkout all submodules to the expected commit - commit that currently
# specified for submodule (it may be in .gitmodules file). For example
# if your .gitmodules file has been changed to specify a different commit
# then calling "update" makes the submodule checkout that commit.
git submodule update
git submodule update  path/to/submodule

# Go into your submodules and fetch and update them to the latest commit
# on their main branch (pull the latest changes from the remote repository).
# checkout submodules to the latest commit on the branch specified in
# .gitmodules file. For example if new commits have been made to the submodule
# remote repo you can call "update --remote" to get those new changes.
git submodule update --remote
git submodule update --remote -- path/to/submodule

# Unregister specified submodule in git. And Clears submodule folder (files)
# leaves only one file with hash (dir).
git submodule deinit  path/to/submodule
# Unregister all submodules
git submodule deinit --all

# Remove a submodule from .gitmodules file:
git config --file .gitmodules --remove-section submodule.path/to/submodule

-

See: https://education.github.com/git-cheat-sheet-education.pdf