Skip to content

Instantly share code, notes, and snippets.

@bitsurgeon
Last active November 16, 2021 23:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitsurgeon/fafeba1ffaad7a2ad3210e6c76e7d003 to your computer and use it in GitHub Desktop.
Save bitsurgeon/fafeba1ffaad7a2ad3210e6c76e7d003 to your computer and use it in GitHub Desktop.
Git cheatsheet
# **********************************************************************
# type: Summarize changes in around 50 characters or less
#
# More detailed explanatory text, if necessary. Wrap it to about 72
# characters or so. In some contexts, the first line is treated as the
# subject of the commit and the rest of the text as the body. The
# blank line separating the summary from the body is critical (unless
# you omit the body entirely); various tools like `log`, `shortlog`
# and `rebase` can get confused if you run the two together.
#
# Explain the problem that this commit is solving. Focus on why you
# are making this change as opposed to how (the code explains that).
# Are there side effects or other unintuitive consequences of this
# change? Here's the place to explain them.
#
# Further paragraphs come after blank lines.
#
# - Bullet points are okay, too
#
# - Typically a hyphen or asterisk is used for the bullet, preceded
# by a single space, with blank lines in between, but conventions
# vary here
#
# If you use an issue tracker, put references to them at the bottom,
# like this:
#
# Resolves: #123
# See also: #456, #789
#
# **********************************************************************
# Message Structure:
#
# type: subject <- compulsory, single line
#
# body <- optional but preferred, multiple paragraphs okay
#
# footer <- optional but preferred, links to issues, stories
# **********************************************************************
# The type can be one of the followings:
# - feat: a new feature
# - fix: a bug fix
# - docs: changes to documentation
# - style: formatting, etc; no code change
# - refactor: refactoring production code
# - test: adding tests, refactoring test; no production code change
# - chore: updating build tasks, etc; no production code change
# **********************************************************************
#

Attributes

# .gitattributes file for per-repository setting

# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text

# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

# Large File Storage
*.p filter=lfs diff=lfs merge=lfs -text

Config Settings

# The order of priority for configuration levels is: local, global, system.

# machine: --system
# /etc/gitconfig on unix systems
# C:\ProgramData\Git\config on Windows

# user: --global
# in a user's home directory. ~ /.gitconfig on unix systems
# and C:\Users\<username>\.gitconfig on windows
git config --global -l

git config --global user.name "Mona Lisa"
git config --global user.name

git config --global user.email "email@example.com"
git config --global user.email

git config --global core.autocrlf input # for Linux
git config --global core.autocrlf true  # for Windows

git config --global core.editor emacs
git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -nosession"
git config --global core.editor "code --wait"

git config --global diff.tool vscode
git config --global difftool.vscode.cmd "code --wait --diff $LOCAL $REMOTE"

git config --global merge.tool kdiff3

git config --global commit.gpgsign true

git config --global commit.template commit_template.txt

# on Windows
git config --global credential.helper wincred
# Then go to: CONTROL PANEL\CREDENTIAL MANAGER\WINDOWS CREDENTIAL\GENERIC CREDENTIAL
# Internet or network address: git:https://{username}.github.com
# User: {username}
# Password: {Password/Token}

# on Linux
git config --global credential.helper cache
git config --global credential.helper 'cache --timeout=3600'

git config --global --unset user.name
git config --global --replace-all user.name "Your New Name"

# color default
color.ui=auto
# color.*
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto

# repository: --local
# in the repo's .git directory: .git/config
git config --list --show-origin

git config user.name "Mona Lisa"
git config user.name

git config user.email "email@example.com"
git config user.email

git config commit.gpgsign true

# disable SSL checks for one git server hosting several repositories
git config --bool --get-urlmatch http.sslverify https://my.bad.server false
# or
GIT_SSL_NO_VERIFY=true git clone https://url
cd <directory-of-the-clone>
git config http.sslVerify false

Collaboration model

  1. fork ORIGINAL repo as a CLONE
  2. clone CLONE for local development
  3. set origin to CLONE for local copy
  4. set upstream to ORIGINAL for local copy
  5. update local copy
  6. push/pull to/from CLONE for local development work
  7. raise pull request from CLONE to ORIGINAL
  8. pull new update from ORIGINAL to local development

Create repo

# create a shared repo
# only be able to push/pull
git init --bare --shared <repo_name>.git

# create a private local repo
# a workable repo
git init <repo_name>

Create branch

# create a branch
git branch <branch_name>
# switch to a branch
git checkout <branch_name>

# create a new branch and switch to it
git checkout -b <branch_name>
git switch -c <branch_name>

# detached branch
git checkout <commit_id>

Set tracking

# checkout existing remote branch
git checkout --track origin/<branch_name>

# publish local branch
git push -u origin <branch_name>

# set tracking for current HEAD
git branch -u origin/<branch_name>

Revert history

# revert shared public changes
git revert

# revert local private changes
git reset --hard <commit_id>

Stash work

# when work half way, not yet ready for commit
# save the work for future temporary
git stash
# can switch branch for other work now

# enables including temporary commit message, which will help you identify changes, among with other options
git stash save

# lists all previously stashed commits (yes, there can be more) that were not popped
git stash list

# redoes previously stashed changes and removes them from stashed list
git stash pop

# redoes previously stashed changes, but keeps them on stashed list
git stash apply

Delete branches

# delete local branch
git branch -d <branch_name>

# delete remote branch
git push origin --delete <branch_name>

# on all other machines
git fetch --all --prune

Commit list

# list locally commit list
git cherry -v

Pull request

# this is different from GitHub pull request which is a fully featured function
# GitHub pull request can discuss and resolve merge conflicts, and only for GitHub

# for standard Git
# create a summary of pull request printed on screen
# commit ID will be displayed in the summary
# -p to create details of changes
git request-pull <upstream_branch> <origin_url> <origin_branch> [-p]

# reviewer to check changes
git diff <commit_ID0> <commit_ID1>

# if reviewer have no access to <origin_url>
# switch to local feature branch
git format-patch master..
tar czf <feature>.tgz *.patch
# sent .tgz together with the pull request summary for review

Merge from other repo

# add remote repo as a remote branch
git remote add <remote_repo_name> <remote_repo_url>

# fetch remote repo
git remote update

# create new local branch
git checkout -b <local_branch_name>

# merge remote branch into local branch
# history of remote repo will be kept
git merge --allow-unrelated-histories <remote_repo_name/remote_branch_name>

# remove remote repo from current repo
git remote rm <remote_repo_name>

LFS

# remember to commit the local .gitattributes file into repository to avoid conflicts
git lfs track "*.psd"
git add path/to/file.psd
git commit -m "add file.psd"
git push origin master

# fetch LFS files
git lfs pull

Personal Access Token

  • It is used in place of a password when performing Git operations over HTTPS with Git on the command line or the API.
  • GitHub automatically removes personal access tokens that haven't been used in a year.
  • Once the token is generated, after you navigate off the page, you will not be able to see the token again.
# example usage
$ git clone https://github.com/username/repo.git
Username: your_username
Password: your_token

Quick References:

GPG

  • It can sign your work locally.
  • GitHub will verify these signatures so other people will know that your commits come from a trusted source.
  • GitHub will automatically sign commits you make using the GitHub web interface.
# list GPG keys for which you have both a public and private key
gpg --list-secret-keys --keyid-format LONG

# generate a GPG key pair
# key type: RSA and RSA
# key size: 4096 bits
# key expiration: default to never
# user id: GitHub verified email
# secure passphrase: type a passphrase
# list all keys to confirm
gpg --full-generate-key

# select the GPG key ID
# 3AA5C34371567BD2 in this case
gpg --list-secret-keys --keyid-format LONG
/Users/hubot/.gnupg/secring.gpg
------------------------------------
sec   4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10]
uid                          Hubot 
ssb   4096R/42B317FD4BA89E7A 2016-03-10

# Prints the GPG key ID, in ASCII armor format
# Copy GPG key, beginning with
# -----BEGIN PGP PUBLIC KEY BLOCK-----
# and ending with
# -----END PGP PUBLIC KEY BLOCK-----
# Paste it to GitHub key field in New GPG key
gpg --armor --export 3AA5C34371567BD2

# set GPG signing key in Git
git config --global user.signingkey 3AA5C34371567BD2
# extra steps for Linux and Mac
test -r ~/.bash_profile && echo 'export GPG_TTY=$(tty)' >> ~/.bash_profile
echo 'export GPG_TTY=$(tty)' >> ~/.profile

# edit GPG key
# Follow the prompts to supply your real name, email address, and any comments
# Enter your key's passphrase
# Prints the GPG key ID
# Update on GitHub
gpg --edit-key 3AA5C34371567BD2
gpg> adduid
Real Name: Octocat
Email address: octocat@github.com
Comment: GitHub key
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?

# Git sign commits by default
git config --global commit.gpgsign true
git config commit.gpgsign true

# Creates a signed commit
# Provide the passphrase
# a Verified tag will be associated with this commit
git commit -S -m your commit message
# Pushes your local commits to the remote repository
git push

# Creates a signed tag
git tag -s mytag
# Verifies the signed tag
git tag -v mytag

Quick References:

SSH

  • With SSH keys, you can connect to GitHub without supplying your username or password at each visit.
  • GitHub will automatically delete your inactive SSH key as a security precaution.
  • Adding the SSH key to the ssh-agent ensures that your SSH key has an extra layer of security through the use of a passphrase.
# Lists the files in your .ssh directory, if they exist
ls -al ~/.ssh

# Generate a new pair of public/private keys
# accepts the default file location
# type a secure passphrase
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# Start the ssh-agent in the background
eval $(ssh-agent -s)

# Add SSH private key to the ssh-agent
ssh-add ~/.ssh/id_rsa

# Copies the contents of the id_rsa.pub file to your clipboard
# paste to Key field in New SSH key on GitHub
# Windows
clip < ~/.ssh/id_rsa.pub    # Windows
# Linux
sudo apt-get install xclip
xclip -sel clip < ~/.ssh/id_rsa.pub
# Mac
pbcopy < ~/.ssh/id_rsa.pub

# Attempts to ssh to GitHub with the passphrase
ssh -T git@github.com
# the following message may display
> The authenticity of host 'github.com (IP ADDRESS)' can't be established.
  > RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
  > Are you sure you want to continue connecting (yes/no)?
> The authenticity of host 'github.com (IP ADDRESS)' can't be established.
  > RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
  > Are you sure you want to continue connecting (yes/no)?
# type yes

# Adding or changing a passphrase
ssh-keygen -p
# Start the SSH key creation process
> Enter file in which the key is (/Users/you/.ssh/id_rsa): [Hit enter]
> Key has comment '/Users/you/.ssh/id_rsa'
> Enter new passphrase (empty for no passphrase): [Type new passphrase]
> Enter same passphrase again: [One more time for luck]
> Your identification has been saved with the new passphrase.

# Auto-launching ssh-agent on Git for Windows
# Copy the following lines and paste them into your ~/.profile or ~/.bashrc file in Git shell
# START - copy #
env=~/.ssh/agent.env

agent_load_env () { test -f "$env" && . "$env" >| /dev/null ; }

agent_start () {
    (umask 077; ssh-agent >| "$env")
    . "$env" >| /dev/null ; }

agent_load_env

# agent_run_state: 0=agent running w/ key; 1=agent w/o key; 2= agent not running
agent_run_state=$(ssh-add -l >| /dev/null 2>&1; echo $?)

if [ ! "$SSH_AUTH_SOCK" ] || [ $agent_run_state = 2 ]; then
    agent_start
    ssh-add
elif [ "$SSH_AUTH_SOCK" ] && [ $agent_run_state = 1 ]; then
    ssh-add
fi

unset env
# END - copy #

# The ssh-agent process will continue to run until you log out, shut down your computer, or kill the process.

# Set ssh-agent auto forget key
ssh-add -t <seconds>

Quick References:

Undo Changes

Local Changes

Modified

# Discard all local changes, but save them for possible re-use later
git stash

# Discarding local changes (permanently) to a file
git checkout -- <file>

# Discard all local changes to all files permanently
git reset --hard

Staged

# Unstage the file to current commit (HEAD)
git reset HEAD <file>

# Unstage everything - retain changes
git reset

# Discard all local changes, but save them for later
git stash

# Discard everything permanently
git reset --hard

Committed

# Undo (swap additions and deletions) changes introduced by commit-id
git revert commit-id

# Undo changes on a single file or directory from commit-id, but retain them in the staged state
git checkout commit-id <file>

# Undo changes on a single file or directory from commit-id, but retain them in the unstaged state
git reset  commit-id <file>

To keep history, create new branch for fixes and merge back later:

# start new branch
git checkout commit-id
git checkout -b new-path-of-feature
# create <new commit>
git commit -a

To modify history A-B-C-D, when deleting B:

# Rebase the range from current commit D to A
git rebase -i A

# Command opens your favorite editor where you write drop in front of commit B, but you leave default pick with all other commits. Save and exit the editor to perform a rebase.
# Remember: if you want to cancel delete whole file content before saving and exiting the editor.

# If B need modification
# Command opens your favorite text editor where you write edit in front of commit B, but leave default pick with all other commits. Save and exit the editor to perform a rebase.
git commit -a

Remote Changes

Pushed

Keep History - a preferred way

# If you want to revert changes introduced in certain commit-id you can simply revert that commit-id (swap additions and deletions) in newly created commit
git revert commit-id

# or creating a new branch to work on
git checkout commit-id
git checkout -b new-path-of-feature

Modify History

  • This is useful when you want to hide certain things - like secret keys, passwords, SSH keys, etc. It is and should not be used to hide mistakes, as it will make it harder to debug in case there are some other bugs.

  • Modified history breaks the development chain of other developers, as changed history does not have matching commits’ids. For that reason it should not be used on any public branch or on branch that might be used by other developers.

  • Also keep in mind that, even with modified history, commits are just detached and can still be accessed through commit-id - at least until all repositories perform the cleanup of detached commits (happens automatically). For details, check here.

# modify history from commit-id to HEAD (current commit)
git rebase -i commit-id

# modify in between commits
git rebase -i commitA-id..commitZ-id

# To cancel the rebase, delete all uncommented lines before save and close.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment