====== Git Cheat Sheet ======
===== Resources =====
* [[https://git-scm.com/book/en/v2|Pro Git Book]]
===== 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 '' | Delete a **remote** branch. |
| ''git branch -d '' | Delete a branch. |
| ''git branch -D '' | 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 :'' | Push up to a certain commit. |
| ''git push origin HEAD~10:'' | 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 -m "commit comment"'' | Annotated tag (preferred over lightweight tags). |
| ''git tag ''\\ ''git push origin '' | 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 '' | |
| ''git rebase -i'' | |
| // Copy the commits you want to clipboard. // | |
| // Delete all text, save, close. // | Aborts the rebase. |
| ''git co '' | |
| ''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 '' | |
==== Delete branch ====
| ''git push origin --delete '' | Delete the remote branch. |
| ''git branch -d '' | Delete the local branch. |
==== Rename branch ====
| ''git branch -m '' | Rename the current branch. |
| ''git branch -m '' | Rename any branch. |
| ''git push origin --delete ''\\ ''git push origin -u '' | 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 '' | For example, = '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 '' 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//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//merge'' will update. Useful for stopping poison merges.