Skip to content

Instantly share code, notes, and snippets.

@xero
Last active November 2, 2023 21:49
Show Gist options
  • Save xero/d921055f16d84ab43d064c4826fcddb7 to your computer and use it in GitHub Desktop.
Save xero/d921055f16d84ab43d064c4826fcddb7 to your computer and use it in GitHub Desktop.
"don't git good, grok git!" - presentation slides
#!/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