#!/bin/sh esc=$(printf '\033') clear cat << X0 ${esc}[31m don't git good... ██ ██ ██ ░██ ░░ ░██ █████ ██████ ██████ ░██ ██ █████ ██ ██████ ██░░░██░░██░░█ ██░░░░██░██ ██ ██░░░██░██░░░██░ ░██ ░██ ░██ ░ ░██ ░██░████ ░██ ░██░██ ░██ ░░██████ ░██ ░██ ░██░██░██ ░░██████░██ ░██ ░░░░░██░███ ░░██████ ░██░░██ ░░░░░██░██ ░░██ █████ ░░░ ░░░░░░ ░░ ░░ █████ ░░ ░░ ░░░░░ ░░░░░ ${esc}[0m ~ whois xero * unix wizard * devops sourcerer * serial minimalist * {h,cr,sl}acker * ascii/ansi artist * x0^67^imp! * http://0w.nz * http://xero.nu * github.com/xero X0 read -rsp $'' -n1 key clear cat << X0 ${esc}[31m## getting a copy of the slides${esc}[0m * this presentation is actually a POSIX 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}[33mgit.io/gitgrok${esc}[0m * or curl pipe it into your shell directly * ${esc}[33mcurl git.io/grokgit | sh${esc}[0m * if you trust me ;D X0 read -rsp $'' -n1 key clear cat << X0 ${esc}[31m## 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}[31m## 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}[31m## porcelain${esc}[0m git-add git-rebase git-cherry git-am git-reset git-count-objects git-archive git-revert git-difftool git-bisect git-rm git-fsck git-branch git-shortlog git-get-tar-commit-id git-bundle git-show git-help git-checkout git-stash git-instaweb git-cherry-pick git-status git-merge-tree git-citool git-submodule git-rerere git-clean git-tag git-rev-parse git-clone git-worktree git-show-branch git-commit git-verify-commit git-blame git-describe git-config git-verify-tag git-diff git-fast-export git-whatchanged git-fetch git-fast-import git-pull git-format-patch git-filter-branch git-archimport git-gc git-mergetool git-cvsexportcommit git-grep git-pack-refs git-cvsimport git-gui git-prune git-cvsserver git-init git-reflog git-imap-send git-log 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}[31m## 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 [ -d ./.git ] && rm -rf .git printf 'x\ngit.md' > .gitignore; git init; rm .git/hooks/*; git add .gitignore; git commit -m 'init' clear cat << X0 ${esc}[31m#Git internals${esc}[0m ${esc}[31m## Objects${esc}[0m * Same content, never duplicated ${esc}[31m## Trees${esc}[0m * Points to (hashed) objects by name * A root tree object is a snapshot ${esc}[31m## Commits${esc}[0m * Explains metadata (who/when/what/why) * Points to a tree object * Is a pointer, not a delta ${esc}[31m## References${esc}[0m * Human alternatives to SHA1 hashes * Stored in .git/refs X0 read -rsp $'' -n1 key clear printf "\n\n${esc}[31m## parse an object ${esc}[0m\necho \"test\" | git hash-object -w --stdin\n" echo "test" | git hash-object -w --stdin | sed "s/^...../${esc}[41m&${esc}[0m/" printf '\necho "testing testing" | git hash-object -w --stdin\n' echo "testing testing" | git hash-object -w --stdin | sed "s/^...../${esc}[43m&${esc}[0m/" printf "\n${esc}[31m## find them${esc}[0m\nfind .git/objects -type f\n\n" find .git/objects -type f | grep 'objects\/46\|objects\/9d' | sed "s!46/c2e!${esc}[43m&${esc}[0m!;s!9d/aea!${esc}[41m&${esc}[0m!" printf "\n${esc}[31m## view content${esc}[0m\ngit cat-file -p ${esc}[43m46c2e${esc}[0m\n" git cat-file -p 46c2e printf "\n${esc}[31m## view type${esc}[0m\ngit cat-file -t ${esc}[43m46c2e${esc}[0m\n" git cat-file -t 46c2e printf "\n\n" read -rsp $'' -n1 key clear cat << X0 ${esc}[31m## 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}[31m> saves compressed header + content ${esc}[0m e.g. X0 find .git/objects -type f | grep 'objects\/46\|objects\/9d' | sed "s!46/c2e!${esc}[43m&${esc}[0m!;s!9d/aea!${esc}[43m&${esc}[0m!" | tail -1 printf "\n\n\n\n" read -rsp $'' -n1 key clear printf "\n\n${esc}[31m## file example ${esc}[0m\necho \"xero\" > test.txt\ngit hash-object -w test.txt\n" echo "xero" > test.txt git hash-object -w test.txt| sed "s/^...../${esc}[43m&${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}[45m&${esc}[0m/" printf "\n\n${esc}[31m## display tracked file contents${esc}[0m\ngit cat-file -p ${esc}[43m885e1${esc}[0m\n" git cat-file -p 885e printf "\n\n${esc}[31m## display local file contents${esc}[0m\ncat test.txt\n" cat test.txt printf "\n\n" read -rsp $'' -n1 key clear printf "\n\n${esc}[31m## tree objects${esc}[0m\n\nmkdir favs; echo \"converge\" > favs/band\ngit update-index --add favs/band\ngit write-tree\n" [ -d favs ] && rm -rf favs mkdir favs; echo "converge" > favs/band git update-index --add favs/band git write-tree | sed "s/^...../${esc}[43m&${esc}[0m/" printf "\n\ngit cat-file -p ${esc}[43mcad00${esc}[0m\n" git cat-file -p cad00| grep -v ".gitignore\|test.txt" | sed "s/71c51/${esc}[45m71c51${esc}[0m/" printf "\n\ngit cat-file -p ${esc}[45meb41f${esc}[0m\n" git cat-file -p eb41f printf "\n\n\n\n\n" read -rsp $'' -n1 key clear printf "\n\n${esc}[31m## commit objects${esc}[0m\necho 'test commit' | git commit-tree ${esc}[45meb41f${esc}[0m\n" id1=`echo 'test commit' | git commit-tree eb41f` echo $id1| sed "s/^...../${esc}[43m&${esc}[0m/" printf "\ngit cat-file -p ${esc}[43m`echo ${id1} | cut -c1-5`${esc}[0m\n" git cat-file -p ${id1} | sed "s/9e730/${esc}[45m&${esc}[0m/" | sed "s/eb41f/${esc}[45m&${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 | sed "s/^...../${esc}[41m&${esc}[0m/" printf "\necho 'another commit' | git commit-tree ${esc}[41m9e730${esc}[0m -p ${esc}[43m`echo ${id1} | cut -c1-5`${esc}[0m\n" id2=`echo 'another commit' | git commit-tree 9e730 -p ${id1}` echo $id2| sed "s/^...../${esc}[44m&${esc}[0m/" printf "\ngit cat-file -p ${id2}\n" git cat-file -p $id2 | sed "s/9e730/${esc}[41m&${esc}[0m/" | sed "s/`echo ${id1} | cut -c1-5`/${esc}[43m&${esc}[0m/" read -rsp $'' -n1 key clear printf "\n\n${esc}[31m## create a branch${esc}[0m\n\necho '$id1' > ./.git/refs/heads/test-branch\n" echo $id1 > ./.git/refs/heads/test-branch printf "\n" git branch printf "\n\n${esc}[31m## update refs${esc}[0m\n\n" printf "git update-ref refs/heads/master $id2\n" 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" printf "\n" read -rsp $'' -n1 key clear printf "\n\n${esc}[31m## HEAD${esc}[0m\n\n * a reference to the currently checked out commit.\n\ncat ./.git/HEAD\n" 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${esc}[31m## HEAD hunting${esc}[0m\n\n" 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${esc}[31m## @ hunting${esc}[0m\n\n * @ is an alias for HEAD\n\ngit reflog\n\n" 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}[31m## from plumbing to porcelain${esc}[0m git diff @ git ls-files -m git cherry master upstream/master git rev-parse master..upstream/master git status git ls-files --exclude-per-directory=.gitignore --exclude-from=.git/info/exclude --others --modified -t git commit git update-index --add && echo "message" | git commit-tree [SHA1] && git write-tree X0 read -rsp $'' -n1 key clear cat << X0 ${esc}[31m## git reset${esc}[0m ${esc}[33mgit reset [] []${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}[31m## 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}[31m## 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 clear cat << X0 ██████████ █████ ██████ █████ █████ ░░██░░██░░██ ██░░░██░░██░░█ ██░░░██ ██░░░██ ░██ ░██ ░██░███████ ░██ ░ ░██ ░██░███████ ░██ ░██ ░██░██░░░░ ░██ ░░██████░██░░░░ ███ ░██ ░██░░██████░███ ░░░░░██░░██████ ░░░ ░░ ░░ ░░░░░░ ░░░ █████ ░░░░░░ ░░░░░ ██ ░██ ░██ █████ ██████████ ██████ ██████ ██░░░██░░██░░██░░██ ██░░░░██ ██░░░██░███████ ░██ ░██ ░██░██ ░██ ░██ ░██░██░░░░ ░██ ░██ ░██░██ ░██ ░░██████░░██████ ███ ░██ ░██░░██████ ░░░░░░ ░░░░░░ ░░░ ░░ ░░ ░░░░░░ X0 read -rsp $'' -n1 key clear cat << X0 ## citations * 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 read -rsp $'' -n1 key clear cat << X0 ██ ██ ██ ░██ ░██ ░██ ██████░██ ██████ ███████ ██ ██░██ ░░░██░ ░██████ ░░░░░░██ ░░██░░░██░░██ ██ ░██ ░██ ░██░░░██ ███████ ░██ ░██ ░░███ ░██ ░██ ░██ ░██ ██░░░░██ ░██ ░██ ██░██ ░░ ░░██ ░██ ░██░░████████ ███ ░██ ██ ░░██ ██ ░░ ░░ ░░ ░░░░░░░░ ░░░ ░░ ░░ ░░ ░░ X0