Table of Contents

Git Cheat Sheet

Resources

Install

Run the following to create the user config file:

git config --global user.name "Stephen Heise"

Run the following to find where the .gitconfig file is:

git config --list --show-origin

Replace it with this:

[core]
	editor = 'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession
	pager = cat
	longpaths = true
 
[user]
	name = Stephen Heise
	email = Stephen@tallguyracing.com
 
[init]
	defaultBranch = main
 
[mergetool]
	prompt = false
	keepBackup = false
	keepTemporaries = false
 
[merge]
	tool = winmerge
 
[mergetool "winmerge"]
	name = WinMerge
	trustExitCode = true
	cmd = "/c/Program\\ Files\\ \\(x86\\)/WinMerge/WinMergeU.exe" -u -e -dl \"Local\" -dr \"Remote\" $LOCAL $REMOTE $MERGED
 
[diff]
	tool = winmerge
 
[difftool "winmerge"]
	name = WinMerge
	trustExitCode = true
	cmd = "/c/Program\\ Files\\ \\(x86\\)/WinMerge/WinMergeU.exe" -u -e $LOCAL $REMOTE
 
[push]
	default = current
	autoSetupRemote = true
 
[alias]
	st = status
	ci = commit -m
	ca = commit --amend --no-edit
	br = branch
	ba = branch -a
	co = checkout
	di = diff
	dt = difftool
	fa = fetch -a
	tf = !git reset && git checkout -- . && git clean -df
	as = !git add . && git stash
	pr = !git stash pop && git reset
	brdr = push --delete origin
	fp = push --force
	cp = cherry-pick
	ln = !git --no-pager log -n50 '--pretty=format:"%Cred%h%Creset %ad %Cgreen%<(10,trunc)%an%Creset %<(80,trunc)%s"' '--date=format:"%Y%m%d %H%M%S"'
	ro2m = !echo 'Rebasing onto master' && git fetch origin master:master && git rebase --onto master master && git pull -r origin master
	ro2mfp = !git ro2m && echo 'Force pushing' && git fp
 
[winUpdater]
	recentlySeenVersion = 2.15.1.windows.2
 
[remote "origin"]
	prune = true

Project Specific Settings

If you need project specific settings, like You Just Go, append this:

[includeIf "gitdir:C:/Dev/YouJustGo/"]
	path = .gitconfig-youjustgo

Then create a C:\Users\God\.gitconfig-youjustgo file with this:

[user]
	name = Stephen Heise
	email = stephen.heise@youjustgo.com

Verify the settings are correct by running the following. Last one wins.

git config --list --show-origin

Try Git

git init
git config --global core.editor "atom --wait" Make Atom the default editor.
git config --global user.name "Stephen Heise"
git config --global user.email "Stephen@tallguyracing.com"
git status
git add filename.txt
git commit -m "Commit message"
git log
git remote add origin https://whatever.com
git push -u origin master -u means remember these settings
git pull origin master
git diff head
git diff --staged
git reset octofamily/octodog.txt Unstages a file.
git checkout -- octocat.txt Go back to last checkout / undo.
git reset --hard origin/master Throw away all local commits.
git branch -a Show local and remote branches.
git branch clean_up Create new branch.
git checkout clean_up Switch branches.
git checkout -b new_branch Checkout and create branch at the same time.
git checkout filename.txt Undo local (unstaged) modification.
git rm '*.txt' Remove local files and include the removal in the staging area.
git rm -r folder_of_cats Recursively remove all folders and files from the given directory.
git commit -a Include the deletion of local files to staging area, do the commit.
git merge clean_up
git push origin --delete <branch_name> Delete a remote branch.
git branch -d <branch name> Delete a branch.
git branch -D <branch name> Force delete a branch. Use if branch not merged.
git remote prune origin Clean up remote branch list.
git branch -r --merged develop List remote branches that have been merged with develop.
git branch -r --no-merged develop List remote branches that have not been merged with develop.
git push
git push origin <hash>:<branch> Push up to a certain commit.
git push origin HEAD~10:<branch> Push up to the last 10 commits.
git push origin HEAD~10:$(git rev-parse --abbrev-ref HEAD) Push up to the last 10 commits.
git push --force origin HEAD~10:$(git rev-parse --abbrev-ref HEAD) Force push up to the last 10 commits.
gitk A commit viewer.
gitk 'stash@{0}' View the contents of the first stash.
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] }) Find a dropped stash.
git tag -a <tagname> -m "commit comment" Annotated tag (preferred over lightweight tags).
git tag <tagname>
git push origin <tagname>
Lightweight tag (good for temporary tags).
git rebase --interactive 44447348... Fix up unpushed commit messages. '44447348…' = parent commit hash.
git log --no-merges --oneline develop.. Show all commits on the current branch.
git cherry-pick ebe6942^..905e279 Cherry-pick an inclusive commit range.
git remote -v View remote / origin URL.

Workflows

Copy commits from one branch to another

git co <source-branch>
git rebase -i
Copy the commits you want to clipboard.
Delete all text, save, close. Aborts the rebase.
git co <target-branch>
git rebase -i Add HEAD if you only want to append commits.
Paste the commits. Delete ones you don't want.
Save, close.

Start new branch

git checkout -b branch-name Create new branch and checkout. Unstaged changes are retained.
git push --set-upstream origin branch-name Push and create branch on remote.

Get new remote branch

git pull Make sure git knows about the remote branch.
git checkout --track origin/branch_name Grab the remote branch.

Merge branch

git checkout master
git merge <branch-name>

Delete branch

git push origin --delete <branch-name> Delete the remote branch.
git branch -d <branch-name> Delete the local branch.

Rename branch

git branch -m <newname> Rename the current branch.
git branch -m <oldname> <newname> Rename any branch.
git push origin --delete <oldname>
git push origin -u <newname>
Update remote branch.

Undo last commit

git reset HEAD~ Reverts last commit, but does not change files. Only do if commit is not pushed.
git reset --hard HEAD~1 Reverts last commit and reverts changed files. Only do if commit is not pushed.

Reset tag position

git co develop Get on the correct branch.
git ls-remote --tags List remote tags.
git push --delete origin tagname Delete the remote tag.
git tag -d tagname Delete the local tag.
git tag tagname Create the local tag.
git push origin tagname Create the remote tag.
git ls-remote --tags Check you got it right.

Commit some stuff workflow

git add . Stage everything.
git stash push --keep-index Stash and keep staged changes.
git reset Unstage everything.
Hack, stage, commit…
git stash pop or git stash apply Get back original. Use apply for multi-commits. Will create merge conflicts.
VS, Take theirs Resolve conflicts.
git reset Unstage everything.

Remove last two commits from master

git co HEAD~2
git co -b masterfixed
git push --delete origin master
git br -D master
git br -m masterfixed master
git push origin --set-upstream master

Rebase onto master

git fetch origin master:master Update the master branch.
git rebase --onto master <source-branch> For example, <source-branch> = '2021.3.7946'.
git pull -r origin master
git push --force

Split up an existing commit

git rebase -i
Mark commit to be split with 'e'
Save & close
When the rebasing has stopped…
git reset HEAD~
Edit & commit.
git rebase --continue

Set up a bare repo

git init --bare BareRepo
git clone .\BareRepo\ LocalRepo URL will be something like file:///C:/Temp/BareRepo
git ci "Initial commit." --allow-empty If you need an initial commit.

Create a test repo

$scriptpath = Split-Path $MyInvocation.MyCommand.Path
Push-Location $scriptpath
 
$remoteRepoName = 'RemoteRepo'
$localRepoName = 'LocalRepo'
 
mkdir $remoteRepoName
git init --bare $remoteRepoName
git clone $remoteRepoName $localRepoName
 
# Create an initial commit - optional
git --git-dir "$localRepoName/.git" commit --allow-empty -m 'Initial commit.'
git --git-dir "$localRepoName/.git" push
 
Pop-Location

Import from SVN

git svn clone https://ares/svn/SVNRepository/Presentations --no-metadata --tags=Tags --trunk=Trunk --branches=Branches --authors-file=..\users.txt

Who needs to clean up

Lists the author and date of the last commit on each remote branch. Need to run it on bash.

for branch in `git branch -r | grep -v HEAD`;do echo -e `git show --format="%ai %ar by %an" $branch | head -n 1` \\t$branch; done | sort -r

How PRs work

When you create a PR on GitHub, it also creates some other refs for you. Different providers put these in different locations.

GitHub puts them under refs/pulls. I don’t believe that git has any rules around these refs, providers can define them however they want.

If you run git ls-remote <remote-name> on a repo, you’ll see all of these other magic refs coming through.

On a GitHub repo with some active and completed pull requests, I see these ones (PR #2 has been closed, PR #1 is still open):

5003f86523fa07e325d28f50a749685b93dffcf3	refs/pull/1/head
57c72505a9beed608fe73f474e77b70cd182616f	refs/pull/1/merge
622ba67a9d1279984dc763eb078d0e5d92ae790f	refs/pull/2/head

I believe that pull/1/head points to the head of the source branch. Source branch is dev, and it’s pointing at the same commit, so that seems correct 5003f86523fa07e325d28f50a749685b93dffcf3 refs/heads/dev.

pull/1/merge is what I think they’re referring to as the ‘merge branch’. It’s what the target branch will look like once the PR has merged.

Note that it’s a different commit hash to main 7adb1c92faa0ef0065e3aedb95fcdc4f523d79e3 refs/heads/main because it’s a different commit.

Now… to show when and how this changes I’ll need to create a new PR because there are conflicts on that example PR that I’m using.

As a side note: It seems as though these refs/pulls/<number>/merge refs just stay where they are if there are conflicts. They don’t go away, they just don’t update. Anyway…

Say we have a default branch main and some branch with some changes called some-changes. Here is what the refs look like on the remote.

a94afcad87e765e18d590cc4090a835e210acca6	refs/heads/main
e6317c4e97a465fe2f024e5a3cd5ff3f12c5f6a6	refs/heads/some-changes

Once I create a PR to merge some-changes into main two more refs are added:

a94afcad87e765e18d590cc4090a835e210acca6	refs/heads/main
e6317c4e97a465fe2f024e5a3cd5ff3f12c5f6a6	refs/heads/some-changes
e6317c4e97a465fe2f024e5a3cd5ff3f12c5f6a6	refs/pull/3/head
6b33d262276e1e5d520ffb8063dedffd6296664d	refs/pull/3/merge

Note pull/3/head is the same as heads/some-changes. pull/3/merge is pointing to some other magic commit that doesn’t really exist anywhere. That’s GitHub merging it in the background and creating a ref of what it will look like.

If I push changes to main, here is what our refs look like:

442fcf2d421c26f75339a82bd364d5fcc3bc0a52	refs/heads/main
e6317c4e97a465fe2f024e5a3cd5ff3f12c5f6a6	refs/heads/some-changes
e6317c4e97a465fe2f024e5a3cd5ff3f12c5f6a6	refs/pull/3/head
3a58fb072ff48e8bebf2c66491332556f3f935ef	refs/pull/3/merge

heads/main has changed because I made a commit there. pull/3/merge has changed because the merge of those two branches now looks different. heads/some-changes and pull/3/head are the same because they haven’t moved.

As for what these branches are used for: This is very useful for making sure that your code will still be valid after the merge is complete (not just in your branch). If there are any changes to the source or target branches, refs/pull/<number>/merge will update. Useful for stopping poison merges.