Last active
November 2, 2023 21:49
-
-
Save xero/d921055f16d84ab43d064c4826fcddb7 to your computer and use it in GitHub Desktop.
"don't git good, grok git!" - presentation slides
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# grok git, presentation shell script | |
# by xero harrison https://x-e.ro | |
# house keeping | |
selfdestruct() { | |
err=$? | |
trap '' EXIT HUP INT QUIT PIPE TERM | |
[[ -d "$TMP" ]] && rm -rf "$TMP" | |
exit $err | |
} | |
trap selfdestruct EXIT HUP INT QUIT PIPE TERM | |
esc=$(printf '\033') | |
clear | |
cat << X0 | |
${esc}[0m | |
don't git good...${esc}[34m ██ ██ ██ | |
░██ ░░ ░██ | |
█████ ██████ ██████ ░██ ██ █████ ██ ██████ | |
██░░░██░░██░░█ ██░░░░██░██ ██ ██░░░██░██░░░██░ | |
░██ ░██ ░██ ░ ░██ ░██░████ ░██ ░██░██ ░██ | |
░░██████ ░██ ░██ ░██░██░██ ░░██████░██ ░██ | |
░░░░░██░███ ░░██████ ░██░░██ ░░░░░██░██ ░░██ | |
█████ ░░░ ░░░░░░ ░░ ░░ █████ ░░ ░░ | |
░░░░░ ░░░░░ | |
${esc}[0m | |
~ ${esc}[35mwhois xero${esc}[0m | |
${esc}[34m* ${esc}[0mdirector of security | |
${esc}[34m* ${esc}[0munix wizard | |
${esc}[34m* ${esc}[0mdevops sourcerer | |
${esc}[34m* ${esc}[0mserial minimalist | |
${esc}[34m* ${esc}[0mascii/ansi artist | |
${esc}[34m* ${esc}[0mx0^67^imp! | |
${esc}[34m* ${esc}[0mhttps://0w.nz | |
${esc}[34m* ${esc}[0mhttps://x-e.ro | |
${esc}[34m* ${esc}[0mhttps://xero.style | |
${esc}[34m* ${esc}[0mhttps://git.io/.files | |
${esc}[34m* ${esc}[0mhttps://github.com/xero | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## getting a copy of the slides${esc}[0m | |
* this presentation is actually a shell script | |
* it will run on shells like ${esc}[35mbash${esc}[0m, ${esc}[35mdash${esc}[0m, ${esc}[35mzsh${esc}[0m, ${esc}[35mksh${esc}[0m, ${esc}[35mmksh,${esc}[0m etc | |
* grab a copy of the script from ${esc}[33mgrokgit.0w.nz${esc}[0m | |
* or curl pipe it into your shell directly | |
* ${esc}[33mbash <(curl -sL grokgit.0w.nz)${esc}[0m | |
* if you trust me ;D | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## git good / git gud${esc}[0m | |
* An expression used to heckle inexperienced | |
players or newbies in online video games | |
* Similar to the use of the phrase ${esc}[33m"lurk more"${esc}[0m | |
often used on forums and image boards. | |
${esc}[34m## grok${esc}[0m | |
* To fully understand. | |
* Connotes intimate and exhaustive knowledge. | |
* Coined by American writer Robert A. Heinlein | |
* in his 1961 science fiction novel Stranger in a Strange Land. | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[38;5;34m xxx ${esc}[0m Git is fundamentally a content-addressable filesystem | |
${esc}[38;5;34m xxx ${esc}[0m with a VCS UI (version control system user interface) | |
${esc}[38;5;34m xxxxxxxxxxxxx${esc}[0m written on top of it. From the original commandline | |
${esc}[38;5;34m xxxxxxxxxxxxx${esc}[0m interface to GUI applications and even implementations | |
${esc}[38;5;34m xxx ${esc}[0m built into IDEs, they all build upon Git's core. | |
${esc}[38;5;34m xxx ${esc}[0m | |
${esc}[0m But because Git was initially a toolkit for a VCS | |
${esc}[38;5;124m xxxxxxxxxxxxx${esc}[0m rather than a full user-friendly one, it has a bunch | |
${esc}[38;5;124m xxxxxxxxxxxxx${esc}[0m of verbs that do low-level work that were designed | |
${esc}[0m to be chained together UNIX style {and,or} called from scripts. | |
${esc}[38;5;242m xx xxxxxx${esc}[0m | |
${esc}[38;5;242m xx xx xx ${esc}[0m These are generally referred to as 'plumbing' commands, | |
${esc}[38;5;242m xx xx xx${esc}[0m | |
${esc}[38;5;242m xx xx${esc}[0m the more user-friendly are called 'porcelain' commands. | |
${esc}[38;5;242m xx xx ${esc}[0m | |
${esc}[38;5;242m xxx xxx ${esc}[0m let's review some of these verbs... | |
${esc}[38;5;242m xxxxx ${esc}[0m | |
${esc}[0m | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## porcelain${esc}[0m | |
${esc}[35mgit-add git-rebase${esc}[0m git-cherry | |
git-am git-reset git-count-objects | |
git-archive git-revert git-difftool | |
git-bisect ${esc}[35mgit-rm${esc}[0m git-fsck | |
git-branch git-shortlog git-get-tar-commit-id | |
git-bundle git-show git-help | |
${esc}[35mgit-checkout git-stash${esc}[0m git-instaweb | |
git-cherry-pick ${esc}[35mgit-status${esc}[0m git-merge-tree | |
git-citool git-submodule git-rerere | |
git-clean git-tag git-rev-parse | |
${esc}[35mgit-clone${esc}[0m git-worktree git-show-branch | |
${esc}[35mgit-commit${esc}[0m git-verify-commit git-blame | |
git-describe git-config git-verify-tag | |
${esc}[35mgit-diff${esc}[0m git-fast-export git-whatchanged | |
git-fetch git-fast-import ${esc}[35mgit-pull${esc}[0m | |
git-format-patch git-filter-branch git-archimport | |
git-gc git-mergetool git-cvsexportcommit | |
${esc}[35mgit-grep${esc}[0m git-pack-refs git-cvsimport | |
git-gui git-prune git-cvsserver | |
git-init git-reflog git-imap-send | |
${esc}[35mgit-log${esc}[0m git-relink git-push | |
git-merge git-remote git-quiltimport | |
git-mv git-repack git-request-pull | |
git-notes git-replace git-send-email | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## plumbing${esc}[0m | |
git-apply git-for-each-ref git-receive-pack | |
git-checkout-index git-ls-files git-shell | |
git-commit-tree git-ls-remote git-upload-archive | |
git-hash-object git-ls-tree git-upload-pack | |
git-index-pack git-merge-base git-check-attr | |
git-merge-file git-name-rev git-check-ignore | |
git-merge-index git-pack-redundant git-check-mailmap | |
git-mktag git-rev-list git-check-ref-format | |
git-mktree git-show-index git-column | |
git-pack-objects git-show-ref git-credential | |
git-prune-packed git-unpack-file git-credential-cache | |
git-read-tree git-var git-credential-store | |
git-symbolic-ref git-verify-pack git-fmt-merge-msg | |
git-unpack-objects git-daemon git-interpret-trailers | |
git-update-index git-fetch-pack git-mailinfo | |
git-update-ref git-http-backend git-mailsplit | |
git-write-tree git-send-pack git-merge-one-file | |
git-cat-file git-update-server-info git-patch-id | |
git-diff-files git-http-fetch git-sh-i18n | |
git-diff-index git-http-push git-sh-setup | |
git-diff-tree git-parse-remote git-stripspace | |
X0 | |
read -rsp $'' -n1 key | |
TMP=$(mktemp -d -t x0-XXXXXXXXXX) | |
cd "$TMP" || { echo "failed to create temp directory"; exit 1; } | |
printf 'x\ngit.md' > .gitignore; git init; rm .git/hooks/*; git add .gitignore; git commit -m 'init' | |
clear | |
cat << X0 | |
${esc}[34m# Git internals${esc}[0m | |
${esc}[34m## Objects${esc}[0m | |
* Same content, never duplicated | |
${esc}[34m## Trees${esc}[0m | |
* Points to (hashed) objects by name | |
* A root tree object is a snapshot | |
${esc}[34m## Commits${esc}[0m | |
* Explains metadata (who/when/what/why) | |
* Points to a tree object | |
* Is a pointer, not a delta | |
${esc}[34m## References${esc}[0m | |
* Human alternatives to SHA1 hashes | |
* Stored in .git/refs | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## parse an object %s[0m\necho \"test\" | git hash-object -w --stdin\n" "$esc" "$esc" | |
echo "test" | git hash-object -w --stdin | sed "s/^...../${esc}[0;46;30m&${esc}[0m/" | |
printf '\necho "testing testing" | git hash-object -w --stdin\n' | |
echo "testing testing" | git hash-object -w --stdin | sed "s/^...../${esc}[0;43;30m&${esc}[0m/" | |
printf "\n%s[34m## find them%s[0m\nfind .git/objects -type f\n\n" "$esc" "$esc" | |
find .git/objects -type f | grep 'objects\/46\|objects\/9d' | sed "s!46/c2e!${esc}[0;43;30m&${esc}[0m!;s!9d/aea!${esc}[0;46;30m&${esc}[0m!" | |
printf "\n%s[34m## view content%s[0m\ngit cat-file -p %s[0;43;30m46c2e%s[0m\n" "$esc" "$esc" "$esc" "$esc" | |
git cat-file -p 46c2e | |
printf "\n%s[34m## view type%s[0m\ngit cat-file -t %s[0;43;30m46c2e%s[0m\n" "$esc" "$esc" "$esc" "$esc" | |
git cat-file -t 46c2e | |
printf "\n\n" | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## hash-object - what's happening?${esc}[0m | |
${esc}[0mcontent = "test" | |
${esc}[0mheader = "blob %d\0", length_of(content) | |
${esc}[0mstore = header + content | |
${esc}[0msha1 = sha1_of(store) | |
${esc}[0mdir = ".git/objects/" + sha1[0:2] + "/" | |
${esc}[0mfilename = sha1[2:] | |
${esc}[0mwrite(dir + filename, store) | |
${esc}[34m> saves compressed header + content | |
${esc}[0m | |
e.g. | |
X0 | |
find .git/objects -type f | grep 'objects\/46\|objects\/9d' | sed "s!46/c2e!${esc}[0;43;30m&${esc}[0m!;s!9d/aea!${esc}[0;43;30m&${esc}[0m!" | tail -1 | |
printf "\n\n\n\n" | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## file example %s[0m\necho \"xero\" > test.txt\ngit hash-object -w test.txt\n" "$esc" "$esc" | |
echo "xero" > test.txt | |
git hash-object -w test.txt| sed "s/^...../${esc}[0;43;30m&${esc}[0m/" | |
printf "\n\necho \"rulez\" > test.txt\ngit hash-object -w test.txt\n" | |
echo "rulez" > test.txt | |
git hash-object -w test.txt | sed "s/^...../${esc}[0;45;30m&${esc}[0m/" | |
printf "\n\n%s[34m## display tracked file contents%s[0m\ngit cat-file -p %s[0;43;30m885e1%s[0m\n" "$esc" "$esc" "$esc" "$esc" | |
git cat-file -p 885e | |
printf "\n\n%s[34m## display local file contents%s[0m\ncat test.txt\n" "$esc" "$esc" | |
cat test.txt | |
printf "\n\n" | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## tree objects%s[0m\n\nmkdir favs; echo \"converge\" > favs/band\ngit update-index --add favs/band\ngit write-tree\n" "$esc" "$esc" | |
[ -d favs ] && rm -rf favs | |
mkdir favs; echo "converge" > favs/band | |
git update-index --add favs/band | |
git write-tree | sed "s/^...../${esc}[0;43;30m&${esc}[0m/" | |
printf "\n\ngit cat-file -p %s[0;43;30mcad00%s[0m\n" "$esc" "$esc" | |
git cat-file -p cad00| grep -v ".gitignore\|test.txt" | sed "s/eb41f/${esc}[0;45;30meb41f${esc}[0m/" | |
printf "\n\ngit cat-file -p %s[0;45;30meb41f%s[0m\n" "$esc" "$esc" | |
git cat-file -p eb41f | |
printf "\n\n\n\n\n" | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## commit objects%s[0m\necho 'test commit' | git commit-tree %s[0;45;30meb41f%s[0m\n" "$esc" "$esc" "$esc" "$esc" | |
id1=$(echo 'test commit' | git commit-tree eb41f) | |
echo "${id1//^...../${esc}[0;43;30m&${esc}[0m}" | |
printf "\ngit cat-file -p %s[0;43;30m$(echo "${id1}" | cut -c1-5)%s[0m\n" "$esc" "$esc" | |
git cat-file -p "${id1}" | sed "s/9e730/${esc}[0;45;30m&${esc}[0m/" | sed "s/eb41f/${esc}[0;45;30m&${esc}[0m/" | |
printf "\necho \"leviathan\" > favs/band\ngit update-index --add favs/band; git write-tree\n" | |
echo "leviathan" > favs/band | |
git update-index --add favs/band | |
tree=$(git write-tree) | |
echo "${tree//^...../${esc}[0;46;30m&${esc}[0m}" | |
printf "\necho 'another commit' | git commit-tree %s[0;46;30m9e730%s[0m -p %s[0;43;30m$(echo "${id1}" | cut -c1-5)%s[0m\n" "$esc" "$esc" | |
id2=$(echo 'another commit' | git commit-tree 9e730 -p "${id1}") | |
echo "${id2//^...../${esc}[0;44;30m&${esc}[0m}" | |
printf "\ngit cat-file -p %s\n" "$id2" | |
git cat-file -p "$id2" | sed "s/9e730/${esc}[0;46;30m&${esc}[0m/" | sed "s/$(echo "${id1}" | cut -c1-5)/${esc}[0;43;30m&${esc}[0m/" | |
read -rsp $'' -n1 key | |
clear | |
hl1=$(echo "$id1" | sed "s/^\(.....\)/${esc}[0;43;30m\1${esc}[0m/") | |
hl2=$(echo "$id2" | sed "s/^\(.....\)/${esc}[0;46;30m\1${esc}[0m/") | |
printf "\n\n%s[34m## create a branch%s[0m\n\necho '%s' > ./.git/refs/heads/test-branch\ngit branch\n" "$esc" "$esc" "$hl1" | |
echo "$id1" > ./.git/refs/heads/test-branch | |
printf "\n" | |
git branch | |
printf "\n\n%s[34m## update refs%s[0m\n\n" "$esc" "$esc" | |
printf "git update-ref refs/heads/master %s\n" "$hl2" | |
git update-ref refs/heads/master "$id2" | |
printf "git log --graph\n\n" | |
git log --graph --color --pretty=format:"%C(yellow)%H%C(green)%d%C(reset)%n%x20%cd%n%x20%cn%C(blue)%x20(%ce)%x20%C(cyan)%C(reset)%n%x20%s%n" | sed "s/${id1}/${hl1}/; s/${id2}/${hl2}/;" | |
printf "\n" | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## HEAD%s[0m\n\n * a reference to the currently checked out commit.\n\ncat ./.git/HEAD\n" "$esc" "$esc" | |
cat ./.git/HEAD | |
printf "\n\ngit symbolic-ref HEAD refs/heads/test-branch\ncat ./.git/HEAD\n" | |
git symbolic-ref HEAD refs/heads/test-branch | |
cat ./.git/HEAD | |
printf "\n\ngit branch\n" | |
git branch | |
printf "\n" | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## HEAD hunting%s[0m\n\n" "$esc" "$esc" | |
printf "git checkout master\n" | |
git checkout master | |
printf "\n\ngit log -1 --pretty=oneline\n" | |
git log -1 --pretty=oneline | |
printf "\n\ngit reset HEAD~1\n" | |
git reset HEAD~1 | |
printf "\n\ngit log -1 --pretty=oneline\n" | |
git log -1 --pretty=oneline | |
printf "\n\ngit reset ORIG_HEAD\n" | |
git reset ORIG_HEAD | |
printf "\n\ngit log -1 --pretty=oneline\n" | |
git log -1 --pretty=oneline | |
printf "\n" | |
read -rsp $'' -n1 key | |
clear | |
printf "\n\n%s[34m## @ hunting%s[0m\n\n * @ is an alias for HEAD\n\ngit reflog\n\n" "$esc" "$esc" | |
git reflog | |
printf "\n\ncheckout your HEAD from 10 mins ago:\ngit checkout \"@{10 minutes ago}\"\n\ncheckout the 5th-last visited commit:\ngit checkout \"@{5}\"\n" | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## from plumbing to porcelain${esc}[0m | |
git diff @ | |
${esc}[35mgit ls-files -m${esc}[0m | |
git cherry master upstream/master | |
${esc}[35mgit rev-parse master..upstream/master${esc}[0m | |
git status | |
${esc}[35mgit ls-files --exclude-per-directory=.gitignore --exclude-from=.git/info/exclude --others --modified -t${esc}[0m | |
git commit -m "message" | |
${esc}[35mgit update-index --add && echo "message" | git commit-tree [SHA1] && git write-tree && git update-refs refs/heads/[BRANCH]${esc}[0m | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## git reset${esc}[0m | |
${esc}[33mgit reset [<mode>] [<commit>]${esc}[0m | |
${esc}[35m--soft${esc}[0m | |
Reset the HEAD back to the first commit, but any other commits that happened since would have | |
their changes staged together in our git 'index' waiting to be committed. | |
${esc}[35m--mixed${esc}[0m | |
Reset the HEAD back to the first commit, but any other commits that happened since would have | |
their changes applied to the working directory, ready for us to choose which changes to be added | |
to the index (i.e. staged) and then finally committed. | |
${esc}[35m--hard${esc}[0m | |
Any of the changes that came after the commit being reset to, are lost. They're not sitting in | |
your staging index, nor are they available within your working directory either. | |
So be careful whenever using the --hard flag. | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## git merge${esc}[0m | |
Incorporates changes from the named commits (since the time their histories diverged from the | |
current branch) into the current branch. This command is used by git pull to incorporate changes | |
from another repository and can be used by hand to merge changes from one branch into another. | |
${esc}[33mgit merge --abort${esc}[0m | |
* Abort the current conflict resolution process, and try to reconstruct the pre-merge state. | |
${esc}[33mgit merge --continue${esc}[0m | |
* Continue mergeing after resolving merge conflicts | |
${esc}[33mgit merge --squash [ref]${esc}[0m | |
* Squash all commits into one before merging | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## git rebase${esc}[0m | |
Reapply all the commit from your branch to the tip of another branch. | |
A rebase will sequentially take all the commit from the branch you’re | |
on, and then reapply them to the destination. | |
The golden rule of rebase: | |
"No one shall rebase a shared branch" — Everyone | |
${esc}[33mgit rebase --interactive${esc}[0m | |
* Make a list of the commits which are about to be rebased and lets the user | |
edit that list before rebasing. This mode can also be used to split/squash commits. | |
X0 | |
read -rsp $'' -n1 key | |
rm -rf favs test.txt .git | |
clear | |
cat << X0 | |
██████████ █████ ██████ █████ █████ | |
░░██░░██░░██ ██░░░██░░██░░█ ██░░░██ ██░░░██ | |
░██ ░██ ░██░███████ ░██ ░ ░██ ░██░███████ | |
░██ ░██ ░██░██░░░░ ░██ ░░██████░██░░░░ | |
███ ░██ ░██░░██████░███ ░░░░░██░░██████ | |
░░░ ░░ ░░ ░░░░░░ ░░░ █████ ░░░░░░ | |
░░░░░ | |
██ | |
░██ | |
░██ █████ ██████████ ██████ | |
██████ ██░░░██░░██░░██░░██ ██░░░░██ | |
██░░░██░███████ ░██ ░██ ░██░██ ░██ | |
░██ ░██░██░░░░ ░██ ░██ ░██░██ ░██ | |
░░██████░░██████ ███ ░██ ░██░░██████ | |
░░░░░░ ░░░░░░ ░░░ ░░ ░░ ░░░░░░ | |
X0 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
${esc}[34m## citations${esc}[0m | |
* http://catb.org/jargon/html/G/grok.html | |
* https://git-scm.com/book/en/v2 | |
* https://www.slideshare.net/th507/git-an-intro-of-plumbing-and-porcelain-commands | |
* http://www-cs-students.stanford.edu/~blynn/gitmagic/ch07.html#_don_8217_t_lose_your_head | |
* http://vimcasts.org/episodes/fugitive-vim-resolving-merge-conflicts-with-vimdiff/ | |
X0 | |
#shellcheck disable=SC2034 | |
read -rsp $'' -n1 key | |
clear | |
cat << X0 | |
██ ██ ██ | |
░██ ░██ ░██ | |
██████░██ ██████ ███████ ██ ██░██ | |
░░░██░ ░██████ ░░░░░░██ ░░██░░░██░░██ ██ ░██ | |
░██ ░██░░░██ ███████ ░██ ░██ ░░███ ░██ | |
░██ ░██ ░██ ██░░░░██ ░██ ░██ ██░██ ░░ | |
░░██ ░██ ░██░░████████ ███ ░██ ██ ░░██ ██ | |
░░ ░░ ░░ ░░░░░░░░ ░░░ ░░ ░░ ░░ ░░ | |
X0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment