====== Git Cheat-Sheet ======
A lot of this info was collected from the following sources as I used them myself to learn Git.
* https://git-scm.com/doc - Comprehensive and well organized documentation.
* https://githowto.com - A hands-on tutorial that is a wonderful learning tool for beginners.
* https://www.atlassian.com/git/tutorials - More great tutorials here.
* https://help.github.com - GitHub documentation.
* https://guides.github.com/features/mastering-markdown - Markdown reference.
I was using ''git version 2.16.2.windows.1'' in the //Bash// shell while documenting and testing these commands.
===== First Time Configuration =====
After installing //Git// on a new system, there are a few things that should be setup first.
For further configuration options, see the [[https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration| Git documentation]].
==== Contact Info for Commits ====
git config --global user.name "First Last"
git config --global user.email "email@domain.com"
==== Handling Line Endings ====
# For Windows
git config --global core.autocrlf true
git config --global core.safecrlf true
# For Mac/Unix
git config --global core.autocrlf input
git config --global core.safecrlf true
A complementary setting in //Visual Studio Code// when developing on Windows is to enforce CRLF.
{
// this assumes Windows dev environment with Git config option "core.autocrlf=true"
"files.eol": "\r\n"
}
==== Pretty Log Alias ====
More helpful aliases are demonstrated [[https://githowto.com/aliases|here]].
This log command will give nice and pretty output:
git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short
# or without pagination
git --no-pager log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short
It can be configured in to a global alias like so:
git config --global alias.hist "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"
# unfortunately these won't work...
git config --global alias.hist "--no-pager log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"
git config --global alias.hist "!git --no-pager log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"
# but, this will disable pagination for all calls to 'log'
git config --global pager.log false
# I've recently discovered some prettier log outputs, so my .gitconfig aliases are like so...
hist = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
hist1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)'
hist2 = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
# first two are courtesy of https://stackoverflow.com/a/9074343
So now it's simply enough to do:
git hist
# or for all branches
git hist --all
==== VSCode as Editor and Diff Tool ====
More info [[https://code.visualstudio.com/docs/editor/versioncontrol|here]] about //Git// integration with //Visual Studio Code//.
Set //Visual Studio Code// as the default //Git// editor, and configure it to wait for the editor to close before continuing:
git config --global core.editor "code --wait"
Now it's possible to edit the //Git// config in //Visual Studio Code// like so:
git config --global -e
Leveraging the above, add the following to ''.gitconfig'':
[diff]
tool = default-difftool
[difftool "default-difftool"]
cmd = code --wait --diff $LOCAL $REMOTE
===== Review Git Configuration =====
# show all configuration settings
git config -l
# show global settings only
# these live in the user profile
git config --global -l
# show system settings only
# these live in the git installation path
git config --system -l
# show local settings only
# these live in the repo
git config --local -l
===== Create and Clone Repos =====
A **repo** is created with ''git init'', and cloned with ''git clone''.
Create a **repo** in the current folder:
git init
Create a **repo** in the folder ''MyRepo''(folder will be created if it doesn't exist):
git init MyRepo
From the parent folder, it's possible to clone a **repo** with:
git clone
# ex:
git clone MyRepo cloned_MyRepo
NOTE: A cloned **repo** will have a single ''master'' **branch** and remote **branches** tracked from the origin **repo**.
==== Bare Repos ====
Doing ''git init'' or ''git clone'' commands with the ''--bare'' switch will make a **repo** without a working directory, only //Git// data. A **bare repo** is intended for sharing (fetch/push/pull) only.
It's common for **bare repos** to have the suffix ''.git''.
# create a new bare repo in current folder
git init --bare
# create a new bare repo in folder MyRepo.git
git init --bare MyRepo.git
# clone repo MyRepo into a bare repo MyRepo.git
git clone --bare MyRepo MyRepo.git
===== Multiple Repos =====
==== Syncing ====
Commits are pulled down from a remote **repo** via ''git fetch'', however this doesn't automatically merge them in to the local **branches**.
# ex:
git fetch
# review status
git hist --all
However, [[#merging]] remote fetched commits is the same as any other commits. This will merge all the commits from ''origin/master'' in to the currently checked out **branch**:
git merge origin/master
It's possible to effectively perform ''git fetch'' and ''git merge'' in a single command via ''git pull''.
# fetch and merge origin/master in to current branch
git pull
Sending changes upstream to a remote **repo** is done via ''git push''.
# push to local
git push
# ex:
git push origin master
# push everything
git push --all
If, as mentioned in [[#managing remote repos]], local **branches** are already configured to track remote **branches**, it shouldn't be necessary to specify any parameters. Simply running ''git push'' should be enough.
==== Tracking Branches ====
When a **repo** is cloned, the only local **branch** is ''master'', and while the other remote **branches** are tracked, ''git pull'' and ''git push'' are only setup between the local and remote ''master'' **branches**. This can be confirmed by reviewing the remote configuration.
# check configured remote repos
git remote
# show details for a configured remote repo
git remote show
# ex:
git remote show origin
It is possible to create a local **branch** that tracks commits from a remote **branch**:
# create a new localbranch to track remotebranch
git branch --track
# ex:
git branch --track dev1 origin/dev1
It is also possible to modify an existing local **branch** and set it to track commits from a remote **branch**:
# for currently checked out branch
git branch -u
# ex:
git branch -u origin/dev1
# for NOT currently checked out branch
git branch -u
# ex:
git branch -u origin/dev1 dev1
NOTE: After using ''git branch -u'' the local **branch** will display as ''fast-forwardable'' via ''git remote show origin''. To clear this up, simply force a ''git push'':
# push all refs
git push --all
==== Managing Remote Repos ====
# add a remote repo
git remote add
# ex:
git remote add origin ../folder
# remove remote repo
git remote rm
# ex:
git remote rm origin
With ''git push -u'' it's possible accomplish the same things as ''git branch -u'', the latter being more specific in how to link **branches**.
# configure branchname to track remote branchname on reponame
git push -u
# ex:
git push -u origin master
git push -u origin dev1
# alternatively, this will do above for all branches
git push -u --all
When a **repo** is cloned, remote ''HEAD'' tracking is configured automatically. When setting up remote **repos** manually it's possible to do this with ''git remote set-head''.
# set reponame/HEAD as master
git remote set-head -a
# ex:
git remote set-head origin -a
# remove reponame/HEAD as master
git remote set-head -d
# ex:
git remote set-head origin -d
In some cases it may be desired to disable ''git push'' and effectively setup a pull only **repo**. There is no official disable switch, but it's possible to provide a bogus URL that will generate an error.
# set the remoterepo push url
git remote set-url --push
# ex:
git remote set-url --push origin DISABLE
To track certain remote **branches** use ''git remote set-branches''. Using the ''--add'' switch will append the current configuration, otherwise it will be replaced.
# track only
git remote set-branches
# ex:
git remote set-branches origin master
# whoops, also want to track dev1 branch
git remote set-branches --add origin dev1
When a tag is removed from the local **repo** it will not be removed from the remote **repo** via standard ''git push'' or even ''git push --all'', but there is a way to do it.
# delete from
git push :
# ex:
git push origin :v1.0
Alternatively, if new tags were created but there are no new commits, it's possible to push the tags to the remote **repo** via ''git push --tags''.
===== Stage, Confirm, Commit, and Tag =====
Note: Before the initial commit occurs on a new **repo**, the ''master'' **branch** doesn't exist yet, and many commands will throw errors.
Stage files:
# a single file
git add file.txt
# multiple via wildcard
git add *.txt
# all via shell wildcard
# - will ignore what shell ignores, like .folders
git add *
# all via git wildcard
# - will pull in everything that isn't in .gitignore
git add .
Confirm **repo** status:
git status
Commit changes:
# commit and launch default editor to provide comment
git commit
# commit and provide comment in-line
git commit -m "Commit comment"
To correct a mistake in the last commit:
* Make the necessary changes
* Stage the necessary files
* Perform a new commit with the ''--amend'' switch
git commit --amend -m "Commit comment"
Tag commits for easier management:
# tag the current commit with a friendly name
git tag
# ex:
git tag v1
# tag the previous commit using '^' notation
git checkout v1^
git tag v0
git checkout v1
# remove tag
git tag -d v1
===== Undo Changes =====
Unstaged changes can be rolled back via ''git checkout''.
# checkout a single file
git checkout file.txt
# checkout all files
git checkout .
This is not an undo, but instead of checking out files, it's possible to checkout a commit via the first 7 digits of the hash (from ''git hist'' if the [[#set alias for pretty log output|alias]] is defined), or tags:
git checkout
# ex:
git checkout 9b2c81a
To return to the latest commit do:
git checkout
# ex:
git checkout master
Staged changes can be rolled back via ''git reset''.
# unstage all currently staged changes
git reset
# unstage a particular file
git reset HEAD
# ex:
git reset HEAD file.txt
NOTE: The working directory still has modified and unstaged files, use ''git checkout'' to replace them with committed version:
git checkout .
# or, for a single single file
git checkout file.txt
Commits can be canceled (but not removed) via ''git revert''. Cancel commits by targeting their hash, or other identifiers.
This will cancel wherever ''HEAD'' is, which is usually the last commit:
git revert HEAD
Commits can be removed from history via ''git reset''.
To revert the working directory to a specified commit, and remove all later commits from history:
git reset --hard
# ex:
git reset --hard e54ff04
NOTE: If removed commits had tags, those tags need to be removed or the commits will remain in history. This can be done after ''git reset'':
git tag -d BadVersion
===== Moving Content =====
Content can be moved inside the **repo** via ''git mv'', this is the best option when moving a single file, although more files just mean repeating the command for them.
# files and/or folders can be moved like this
git mv
# ex:
git mv file.txt folder\file.txt
git mv folder1 folder2
# it's better to use 'git mv' instead of native file system
# to avoid more steps:
mv file.txt lib
git add folder/file.txt
git rm file.txt
If using the file system to move content around, especially serious restructuring, it's a better idea to use ''git add -A''.
# update the entire worktree
git add -A
# update current folder and down
git add -A .
# update a specific folder
git add -A MyFolder
===== Branches =====
Branches are managed via ''git branch'', switched via ''git checkout'', and merged via ''git merge''.
==== Create, List, Checkout, and Delete ====
# list branches
git branch
# create a new branch
git branch
# ex:
git branch dev1
# list local branches
git branch
# list all branches
git branch -a
# switch working directory to branch dev1
git checkout dev1
# it's possible to create a new branch and checkout in one command
git checkout -b dev2
# to delete a branch (can't be checked out)
git branch -d dev1
==== Merging ====
# merge in to the currently checked out branch
git merge
# ex: # this brings all the changes from dev1 in to master
git checkout master
git merge dev1
==== Rebasing ====
Branches can be rebased with ''git rebase''. Rebasing merges the **branch** histories in to a single thread, effectively performing a merge and then flattening the commit tree.
# rebase the currently checked out branch in to
git rebase
# ex: # this flattens the dev1 history in to master
git checkout dev1
git rebase master
NOTE: Rebasing can get tricky in some scenarios and cause issues, check the documentation for further details:
git rebase --help
===== Ignoring Content =====
It's possible to tell //Git// to ignore files and/or folders by using a ''.gitignore'' file.
See the following for more details and examples:
* https://git-scm.com/docs/gitignore - official documentation.
* https://www.gitignore.io - great tool for getting a quick and simple starting template.
* https://www.atlassian.com/git/tutorials/saving-changes/gitignore - more examples here.
* https://jasonstitt.com/gitignore-whitelisting-patterns - a helpful blog post.
# matching is done on the whole path string, so
# this will ignore everything regardless of depth
*
# whatever exceptions are made, will only work in
# the current folder, unless recursion is allowed with
!*/
# this will whitelist at the top level
!*.ps1
# this will whitelist everywhere
!**/*.xml
# lines are processed in order, so it's possible
# to undo everything above with
!*
==== PowerShell Visual Studio Code Template ====
This is my baseline template for starting a //PowerShell// project in //Visual Studio Code//. It's effectively a white-list.
# ignore everything eveywhere
*
# allow folder recursion
!*/
# allow .git* at top level
!.git*
# allow .md at top level
!*.md
# whitelist VSCode settings at the top level
!/.vscode/settings.json
# whitelist contents of these folders at the top level
!/ProjectFolderContainingAllTheGoodies/**
# regardless of above, ignore these folders and files everywhere
**/_logs*
**/_testing*
Here is a template generated by [[https://www.gitignore.io|gitignore.io]] for //PowerShell//, //Visual Studio Code//, and //Windows//.
# Created by https://www.gitignore.io/api/windows,powershell,visualstudiocode
### PowerShell ###
# Exclude packaged modules
*.zip
# Exclude .NET assemblies from source
*.dll
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/windows,powershell,visualstudiocode
{{tag>computing git}}