Skip to content

Instantly share code, notes, and snippets.

@projected1
Last active June 16, 2021 20:20
Show Gist options
  • Save projected1/3cdc40c2d59523649345014bf2965b1e to your computer and use it in GitHub Desktop.
Save projected1/3cdc40c2d59523649345014bf2965b1e to your computer and use it in GitHub Desktop.
Git reference.

GIT

Command-Line Reference

Install the Latest Git Version on Windows

https://git-scm.com/download/

https://git-lfs.github.com/

Install the Latest Git Version on Debian/Ubuntu

$ sudo apt-add-repository ppa:git-core/ppa
$ sudo apt-get update
$ sudo apt-get install git

Unicode Support on Windows (e.g. Hebrew username)

Set the following environment variable:

$ set LC_ALL=C.UTF-8

Configure User Info

Ommit --global to setup different user details for each project.

$ git config --global user.name "John Doe"
$ git config --global user.email "[email protected]"
$ git config --list
$ git config --global --unset

CRLF Configuration

  • "true" on Windows/Linux/MAC
  • "input" on Linux/MAC
  • "false" on Windows
$ git config --global core.autocrlf input

Disabling "LF will be replaced by CRLF" warning:

$ git config --global core.safecrlf false

Cache Credentials (Linux)

$ git config credential.helper 'store'

Configure Autosquash by Default

$ git config --global rebase.autosquash true

Cleanup Unnecessary Files and Optimize the Local Repository

$ git gc --auto # Checks whether any housekeeping is required

Work Trees - Working on Multiple Simultaneous Branches

$ git worktree add -b emergency-fix ../temp master

or

$ git worktree add ../temp master
$ git worktree list
$ git commit -a -m 'emergency fix for boss'
$ rm -rf ../temp
$ git worktree prune

Configure Remotes

$ git remote -v
$ git remote rm origin
$ git remote add origin git@my-git-server:myrepository.git

or

$ git remote set-url origin git@my-git-server:myrepository.git

or setting another local repo as remote

$ git remote add origin /path/to/.git

Clone with Symlinks Support

$ git clone -c core.symlinks=true <URL>

Clone with Long Paths Support

$ git clone -c core.longpaths=true <URL>

Clone Repo and Claim Ownership (great for boilerplates)

$ git clone <path/to/repo>
$ cd repo
$ rm -rf .git
$ git init
$ git add .
$ git commit -m "Initial commit"
$ git commit -p
$ git status -s -b # --short --branch
$ git show
$ git --no-pager diff
$ git tag

Clone From tag/branch - Only Clone History Leading to Tip of the Tag

$ git clone <repo_url> --branch <tag_name> --single-branch

Clone From tag/branch - Do Not Clone History At All

$ git clone <repo_url> --branch <tag_name> --depth 1

Show Only Remote Tracking Branches

$ git branch -r

Show All Branches, Both Local and Remote

$ git branch -a

List Commits on All Branches

$ git log --branches=*

Show All Branches and the Latest Commit on Each Branch

$ git show-branch

Show Commits on a Local Branch Relative to Another Branch (e.g. master)

$ git log master..

Follow Only The First Parent Commit Upon Seeing a Merge Commit (e.g. master)

$ git log --first-parent master

Search everywhere

Looks for differences whose patch text contains added/removed lines that match

Flag Description
-i Case insensitive regex
-p Generate patch (shows diff)
--all Searches over all branches and tags
$ git log -G"regex" -i -p --all

Filter Search Results

$ git log -G"regex" -i -p | grep -i -E "regex|^\-{3}|^\+{3}|^@{2}|^diff\s|^index\s"

Blame/log line range history - parent commit of fe25b6d, lines [10,20]

$ git blame -L 10,+10 fe25b6d^ -- <path/to/file>
$ git log -L 10,20:<path/to/file>

Create and Switch to a New Branch

$ git checkout -b <branchname>
$ git branch <branchname>
$ git checkout <branchname>

Raname a Local Branch

$ git branch -m <newname>

Checkout a Tag

$ git checkout <tagname>

Delete a Branch

$ git branch -d <branchname>

Delete Branch, both From Local and Remote Repos

$ git branch -vv                  # List tracking branches
$ git branch -d --remotes origin/<branchname>
$ git push origin -d <branchname> # or git push origin :<branchname>
$ git branch -d <branchname>
$ git fetch origin --prune

Update Remote Tracking Branches

$ git fetch origin

or

$ git remote prune origin

or

$ git remote update origin --prune

Rename Local Branch

$ git branch -m <oldbranch> <newbranch>

or

$ git branch -m <newbranch>

Rename Remote Branch

$ git push origin origin/<old_name>:refs/heads/<new_name> :<old_name>

Rename Remote and Local Branches

$ git checkout -b <newbranch> <oldbranch> # create and switch to the newbranch branch
$ git push -u origin <newbranch>          # push the newbranch branch to the remote and track it
$ git branch -d <oldbranch>               # delete local branch
$ git push --delete origin <oldbranch>    # delete remote branch
$ git remote prune origin                 # delete the remote tracking branch

Visualize Commits (graph)

$ git log --graph -200 --oneline master
$ git log -S@EventListener --oneline --abbrev-commit
$ git log -p -S@EventListener
$ git grep "text" /src/main/java
$ git shortlog --since 2.days
$ git shortlog -ns
$ git log --graph --full-history --all --short --abbrev-commit
$ git log --graph --full-history --all --oneline --abbrev-commit
$ git log --graph --oneline --abbrev-commit --author="Daniel Gorbatov" --since="2015-01-01" --before="2015-01-03"
$ git --graph --oneline --abbrev-commit --author="Daniel Gorbatov"
$ git log --graph --oneline --abbrev-commit --author="Daniel Gorbatov"
$ git log --graph --full-history --all --oneline --abbrev-commit
$ git log --oneline --abbrev-commit

File History with Changes (patch)

$ git log --follow -p -- <path/to/file> | grep "some text\|commit"

File History without Changes, with Author, Commit Time, and Commit Message

$ git log --follow --format="%Cgreen%h %<(15,trunc)%Cblue%an %<(25)%Cred%ai %Creset%s" <path/to/file>

Alias

$ git config --global alias.l "!f() { if [ ># -gt 0 ]; then follow=--follow; else follow=; fi; git log >follow --format='%Cgreen%h %<(15,trunc)%Cblue%an %<(25)%Cred%ai %Creset%s' >@; }; f"

Basic Rebase - for Linear History

$ git fetch origin         # Updates origin/master
$ git rebase origin/master # Rebases current branch onto origin/master

Check Out the Client Branch, Figure Out the Patches From the Common Ancestor of the Client and Server Branches, and Then Replay Them Onto Master

$ git rebase <master> <topic>
$ git rebase --onto <master> <topicA> <topicB>

Delete All Commits - Soft Reset All Commits on Current Branch

$ git update-ref -d HEAD

Create an Orphan Branch with the Same Content But without Any Commit History (the Parent Is the New Root)

$ git checkout --orphan <newbranch>

Rename Unpublished Commits

$ git rebase --interactive '<commithash>'
$ git commit --all --amend --no-edit
$ git rebase --continue
$ git rebase --abort

Apply the Changes Introduced by Some Existing Commits (on Any Branch) - Create a New Commit with New Hash

$ git cherry-pick <commit_hash>

Chery Pick with "Their" Changes

$ git cherry-pick --strategy=recursive -X theirs <commit_hash>

Untrack

$ git rm --cached

Unstage

$ git reset HEAD

Pull all Remote Branches

$ git branch -r | grep -v '\->' | while read remote; do git branch --track ">{remote#origin/}" ">remote"; done
$ or
$ for remote in `git branch -r`; do git branch --track >{remote#origin/} >remote; done
$ git fetch --all
$ git pull --all

Rename Published Commits (Preserve Commits)

$ git rebase -i -p

Squash First Commit

$ git rebase -i --root master
$ git commit --allow-empty -m "Trigger notification"
$ git commit --amend -m "New commit message"
$ git push --set-upstream origin <branchname>

Change Last Commit Author

$ git commit --amend --author="Author Name <[email protected]>"

Change All Commits Author (BASH script)

See https://www.git-tower.com/learn/git/faq/change-author-name-email

$ git filter-branch --commit-filter 'if [ ">GIT_AUTHOR_NAME" = "Daniel Gorbatov" ]; then export GIT_AUTHOR_NAME="Daniel Gorbatov"; export [email protected]; fi; git commit-tree ">@"'

Simple Branch Merge

$ git merge <branchname>

Where the ~ means "the commit before"

$ git merge <branchname>~

List Branches that were Already Merged

$ git branch -a --merged <branchname>

List Unmerged Branches

$ git branch -a --no-merged <branchname>

List

$ for branch in `git branch -r | grep -v HEAD`;do echo -e `git status -sb >branch | head -n 1` \\t>branch; done | sort
$ for branch in `git branch -r | grep -v HEAD`;do echo -e `git show --format="%ci %cr" >branch | head -n 1` \\t>branch; done | sort

List Unmerged Branches by Date

$ for branch in `git branch -r --no-merged develop | grep -v HEAD`;do echo -e `git show --format="%ci %cr" >branch | head -n 1` \\t>branch; done | sort

Ignore "client" Branches

$ for branch in `git branch -r --no-merged develop | grep -v HEAD | grep -v _client>` ; do echo -e `git show --format="%ci %cr" >branch | head -n 1` \\t>branch ; done | sort

Branch-merging Flow

$ git checkout -b <branchname>
$ git commit -a -m "Commit title 1"
$ git commit -a -m "Commit title 2"
$ git commit -a -m "Commit title ..."
$ git merge master
$ git push origin <branchname>
$ git checkout master
$ git merge --no-ff --commit -m "Merge branch '<branchname>'" -m "Delivered feature/bugfix etc." <branchname>
$ git branch -d <branchname>
$ git push origin master
$ git add .
$ git commit -m "message paragraph" -m "message paragraph 2" -m "etc"
$ git push heroku <branchname>:master
$ heroku logs --tail

Reset

$ git reset --soft HEAD~1
$ git reset --soft ad28d93

Merge Reset

$ git reset --merge ORIG_HEAD

Hard Reset (History Rewrite)

$ git reset --hard HEAD~1

or

$ git reset --hard 80f05d0

Sync Local when History Diverged

$ git fetch
$ git reset --hard origin/<branchname>
$ git reset --merge ORIG_HEAD

Remove Any Range of Commits (History Rewrite)

# E---F---G---H---I---J  topicA
$ git rebase --onto topicA~5 topicA~3 topicA
# E---H'---I'---J'  topicA

Stash

$ git stash
$ git stash save "some message"
$ git stash -u                # Stash untracked
$ git stash save -p           # Interactive stash (pick the patch to stash)
$ git stash list              # List stashes
$ git stash show              # Show diffstat
$ git stash show -p           # Show diff (file contents)
$ git stash push path/to/file # Stash specific files
$ git stash pop
$ git stash apply stash@{0}
$ git stash clear

Merge Pull Request Into a Branch

$ git fetch origin pull/<pullrequestid>/head:<branchname>
$ git checkout <branchname>
$ git push origin <branchname>

Merge and Keep "Their" Change In Case Of a Conflict

$ git merge --no-ff -X theirs develop

Automatic Conflict Resolution

$ git checkout --ours <path/to/file>
$ git checkout --theirs <path/to/file>

Tagging and Versioning

$ git tag -a v1.4 -m "Version subject" -m "Version body"
$ git push origin --tags

$ git tag
$ git tag -l "<search_pattern>*"
$ git checkout tags/<tagname>

Diff the Same File Between Two Different Commits

$ git diff <startcommit>..<endcommig> -- <path/to/file>
$ git diff HEAD~2..HEAD -- <path/to/file>
$ git log -p --follow <path/to/file>

Diff Ignore Whitespaces

$ git diff -w

See All the Files that were Changed in the Commit <commit_id>

$ git diff-tree --no-commit-id --name-only -r <commit_id>

List All the Files that have Changed Between Commit SHA1 and SHA2

$ git diff --name-only SHA1 SHA2

Diff the Same File Between Two Different Branches

$ git diff <branch_a>..<branch_b> -- <path/to/file>

Restore Deleted Branch

$ git reflog
$ git checkout <sha>
$ git checkout -b <branchname>

Move File to Another Directory and Maintain Commit History - Only Works on a Single File at a Time!

To all files directories for automation (DOS):

> dir /s /b /a:-d > files.log
> dir /s /b /a:d > tree.log
$ git mv path/to/file newith path/to/file
$ git log --follow newith path/to/file

Force GIT to Pick Up Letter Case Changes

$ git mv --force lowercase.java UPPERCASE.java

Discard Uncommitted Changes

$ git checkout -- .

List Untracted Files

$ git ls-files --others --exclude-standard

Fork Your Own Project

$ git clone https://github.com/YOURNAME/old-proj.git new-proj
$ cd new-proj
$ vim .git/config
$ url = https://github.com/YOURNAME/new-proj.git # Replace "old-proj" with "new-proj"
$ git remote add https://github.com/YOURNAME/old-proj.git
$ git push -u origin master

Merge Upstream Changes

$ git remote add https://github.com/YOURNAME/old-proj.git
$ git fetch origin
$ git merge origin/master
$ or
$ git rebase origin/master
$ git push -f origin master

Create Patch

$ git format-patch --root <commit>
$ git format-patch -1
$ git format-patch R1..R2

Apply Patch (apply-mailbox)

$ git am -3 <path/to/patch>

Automatically Mark a Commit As a Fix for the Previous Commit

$ git commit --fixup <commit>
$ git rebase -i --autosquash

Remove File From All Branches

$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path/to/file>' -- --all
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive

Normalize Line Endings

$ echo "* text=auto" >.gitattributes
$ rm .git/index          # Remove the index [to force Git to re-scan the working directory]
$ git reset              # Re-scan the working directory
$ git status             # Show files that will be normalized
$ git add -u             # Update the index
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"
$ git checkout HEAD~1    # Checkout the previous commit
$ git checkout -f master # Checkout the (master) branch again with the normalized files

Untrack Ignored Files

$ git rm --cached <path/to/file>

Delete All Commmits on a Branch

$ git rev-list --max-parents=0 HEAD
$ git checkout --orphan temp >1
$ git rebase -p --onto SHA^ SHA
$ git checkout --orphan master 258081969eb4337284daae020db7530ae3734f29
$ git update-ref -d HEAD

Revert To a Specific Commit

$ git revert <commit>

Revert a Merge Commit to the First Parent

$ git cat-file -p HEAD # Show the parent branches in order
$ git revert -m 1 HEAD

Remove Untracked Files

$ git clean -n              # Dry run
$ git clean -f              # Remove files
$ git clean -fd             # Remove files and directories
$ git clean -fX             # Remove only files ignored by Git
$ git clean -f -e <pattern> # Exclude pattern
$ git clean -fx             # Don't use the .gitignore rules (still ignore rules given with -e)

Create and Apply Patches

$ git format-patch master --stdout > temp.patch   # Create a patch with commits on branch that are not on master
$ git format-patch -10 HEAD --stdout > temp.patch # Create patch form last 10 patches from head (or SHA)
$ git format-patch -1 <sha> --stdout > temp.patch # Create patch form a specific commit
$ git apply --stat temp.patch                     # Show the commits in patch file
$ git apply --check temp.patch                    # Dry run
$ git am --signoff < temp.patch                   # Apply patch [from mailbox] on current branch

Submodules

https://git-scm.com/book/en/v2/Git-Tools-Submodules

Add Submodules

$ git submodule add <path/to/repo>
$ git diff --cached --submodule
$ git diff --cached --submodule <submodule_name>
$ git push origin master

Clone Project with Submodules

$ git clone <path/to/repo>
$ git submodule init

or

$ git clone --recurse-submodules <path/to/repo>

Configure Diff for Submodules

$ git config --global diff.submodule log

Set Submodule to Track a Specific Branch

$ git config -f .gitmodules submodule.<submodule_name>.branch <branch_name>
$ git submodule update --remote

Configure git status For Submodules

$ git config status.submodulesummary 1
$ git status

Update All Submodules to the Remote State, and Reset Your Project to a Detached HEAD State

$ git submodule update --remote

Update All Submodules with Merge from Remote

$ git submodule update --remote --merge

Update All Submodules with Rebase on Top of Remote

$ git submodule update --remote --rebase

Publish Submodule Changes

Check that all your submodules have been pushed properly before pushing the main project:

$ git push --recurse-submodules=checkout

Configure as default push behaviour:

$ git config push.recurseSubmodules check

Push submodules automatically, before pushing the main project:

$ git push --recurse-submodules=on-demand

Configure as default push behaviour:

$ git config push.recurseSubmodules on-demand

Submodule "foreach"

$ git submodule foreach 'git stash'
$ git submodule foreach 'git checkout -b my_new_feature'

Show changes in main project and all the submodules:

$ git diff && git submodule foreach 'git diff'

GIT Comments

  • Separate subject from body with a blank line
  • Limit the subject line to 50 characters
  • Capitalize the subject line
  • Do not end the subject line with a period
  • Use the imperative mood in the subject line ("Add", "Fix", "Revert")
  • Wrap the body at 72 characters
  • Use the body to explain what and why, not how

GIT Commit Verbs

Add Fix Prune Return
Allow Flip Qualify Revert
Always Force Re-add Send
Apply Format Redesign Set
Assume Generate Redirect Simplify
Avoid Ignore Reduce Store
Change Implement Re-enable Stream
Clean Improve Refactor Stringify
Configure Inline Refine Strip
Consolidate Insert Reformat Switch
Convert Integrate Re-introduce Test
Declare Introduce Relate Throw
Depend Keep Remodel Trigger
Disable Load Remove Try
Display Make Rename Tune
Do Merge Repackage Un-ignore
Eliminate Modify Replace Update
Enable Move Reset Upgrade
Ensure Normalize Restore Use
Externalize Optimize Restrict Work
Extract Organize Restructure
Favour Polish Retrieve
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment