├── README.md └── three-trees-watch-scripts.md /README.md: -------------------------------------------------------------------------------- 1 | # Git Workshop Reference 2 | 3 | We covered a lot of material! Here's a reference so you can look back later. 4 | 5 | ## Under the Hood 6 | 7 | Git is made up of four major object types: 8 | 9 | * **Blobs** store the contents of files 10 | * **Trees** store the contents of directories 11 | * **Commits** store a pointer to a tree along with metadata about the commit 12 | * **Refs** point, or refer to, other objects in the graph using a friendly name 13 | 14 | ### Plumbing Commands 15 | 16 | * `git cat-file ` shows information about an object in the repository; `-t` shows the type, `-p` shows the contents. 17 | * `git ls-files -s` shows the contents of the index. 18 | * `git rev-parse ` can turn any revision into a SHA that the revision refers to. 19 | * `git rev-list ` can turn revision lists like `A..B` and `A...B` into a list of commits. 20 | * `git merge-base ` finds the closest common ancestor (aka, the merge base) of `` and ``. 21 | 22 | ### Porcelain Commands 23 | 24 | * `git add` places files from your working directory onto the index. 25 | * `git commit` commits the current state of the index into the repository. 26 | * `git checkout ` moves `HEAD` to ``. 27 | * `git checkout -b ` creates a new branch called `` at `` (or at `HEAD` if not specified) and switches to that branch. 28 | * `git reset --hard ` moves `HEAD` to `` and resets the index and your working directory to match the contents of the repository at ``. 29 | * `git reflog ` shows the reflog for `` (or for `HEAD` if none specified). 30 | * `git merge ` merges `` into your current branch. 31 | * Passing the `--no-ff` keeps Git from performing fast-forward merges. 32 | * Passing `-X` allows you to specify an option for the current merge strategy, for example, `-X ignore-space-change`. 33 | * Passing `-s` allows you to specify a completely different merge strategy, for example, `-s ours`. 34 | * `git rebase ` replays the commits from `HEAD` to the merge base of `HEAD` and `` on top of ``, and moves your current branch to the newest created commit. 35 | * Passing the `-i` flag allows you to modify the commit history between `HEAD` and ``. 36 | * `git tag ` creates an unannotated tag called `` at `` (or at `HEAD` if none specified). 37 | * Passing the `-a` flag creates an annotated tag. 38 | * `git cherry-pick ` creates a new commit at `HEAD` containing the changes at ``. 39 | * If `` a merge commit, you must specify the `-m ` option, where `` is the parent to treat as the mainline for the merge. 40 | * `git bisect` allows you to find the commit that introduced a change via a binary search algorithm. 41 | 42 | ### Referring to Revisions 43 | 44 | * The first few characters of a SHA 45 | * The name of any ref, like `master` - the SHA referred to by the ref 46 | * `@{n}` - entry `n` in the reflog for `` 47 | * `@` - HEAD 48 | * `@{date}` - `` at the given date; found using the reflog 49 | * `@{n}` - nth prior version of the current branch 50 | * `^` and `^n` - nth parent of ``; `^` and `^1` is the first parent, `^0` is the commit itself 51 | * `~` and `~n` - nth generation ancestor of `` following first parents only 52 | * `:/` - youngest commit with message text matching regex `` 53 | * `^{/}` - youngest commit with message text matching regex `` accessible from `` 54 | 55 | Note that suffixes can be changed together, e.g. `HEAD^2~3^` is the first parent of the third ancestor of the second parent of `HEAD`. 56 | 57 | Some Git commands accept ranges of commits; the double and triple dot syntax is useful for specifying these: 58 | * `..` - all commits reachable from `rev2` but not reachable from `rev1` 59 | * Same as `^rev1 rev2` (aka `rev2 --not rev1`) 60 | * `...` - all commits reachable from either `rev1` or `rev2`, but not both 61 | * Same as `r1 r2 --not $(git merge-base --all r1 r2)` 62 | 63 | ## The Three Trees 64 | 65 | The official Git website has [a great page documenting `git reset` and `git checkout`](https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified). 66 | 67 | [Scripts](https://github.com/git-school/workshop-reference/blob/master/three-trees-watch-scripts.md) for watching the three trees. 68 | 69 | ## diff3 Conflict Style 70 | 71 | Set `git config --global merge.conflictStyle diff3` to enable the diff3 merge conflict style, which shows a new section in merge conflicts that represents the state of the file at the merge base. 72 | 73 | Run `git checkout --conflict=diff3 -- filename` to change the merge conflict markers in `filename` to the diff3 style (note that **any unsaved changes in `filename` will be lost!**) 74 | 75 | ## Reflog 76 | 77 | https://www.youtube.com/watch?v=Vxc9m_OVyo0 78 | 79 | Throughout the course we identified ways to alter the commit history, and we know that since commits are immutable in Git, when we change our Git history with commands like `reset`, `rebase`, and `amend`, what we’re really doing is changing what our branch reference is pointing to, sometimes creating new commits in the process. 80 | 81 | But what happens to the old commits that used to be in our branch history? Well if there is no longer a branch pointing to them, they become "dangling commits" and Git will eventually garbage collect them since it assumes they’re no longer needed. Thankfully this garbage collection doesn’t happen for a month or so, because sometimes we’ll find ourselves in situations where we want to recover those “dangling commits” and restore our history to what it was before we changed it. 82 | 83 | This can be the case when we do a `rebase`, `reset`, or `amend` and realize that we made a mistake and want to undo the operation. Fortunately, Git keeps a handy chronological history of every commit that `HEAD` has ever been on as well as a description of why `HEAD` moved to that particular commit. This history is knowns as the Reflog and can be viewed via the `reflog` command: 84 | 85 | ``` 86 | >> git reflog 87 | 70ad6cd HEAD@{0}: reset: moving to head~ 88 | 08c773c HEAD@{1}: rebase finished: returning to refs/heads/branch 89 | 08c773c HEAD@{2}: rebase: Fixed the thing 90 | da272e2 HEAD@{3}: rebase: checkout master 91 | 821ef69 HEAD@{4}: commit: Fixed the thing 92 | dce83e5 HEAD@{5}: pull origin branch: Fast-forward 93 | 5a24d37 HEAD@{6}: checkout: moving from master to branch 94 | 5feca61 HEAD@{7}: commit (amend): Initial commit 95 | 079d913 HEAD@{8}: commit: Initial commit 96 | 29345e6 HEAD@{9}: clone: from git@github.com:github/repo.git 97 | ``` 98 | 99 | Using the reflog, we can identify what commit we want to go back to, and use `git reset --hard ` to effectively undo and go back to the state we were in before re-writing our history. To go back `n` commits I would type `git reset --hard HEAD@{n}` 100 | 101 | Using the example reflog above, to “undo” my last `reset`, I can type `git reset --hard 08c773c 102 | ` or simply `git reset --hard HEAD@{1}` to go to the commit that head was on 1 commit ago. 103 | 104 | You can also view the reflog for your branches by typing `git reflog branch-name`. Fun fact - when you’re using Git’s stash feature you’re creating commits that get added to a special stash reflog. You can access these commits via `git reflog stash`. 105 | 106 | The reflog allows us to re-write history and delete branches without the fear of forever losing the commits. We can take comfort in the fact that we have a whole month to recover dangling commits and restore our branch to whatever previous state we had before. Commits in the reflog that are not danging and are still on a branch will be kept in the reflog for 3 months. 107 | 108 | In terms of enhancing your day-to-day workflow, you might consider taking advantage of the reflog by making frequent work-in-progress commits. Once your work is committed, even if you re-write history or delete branches, you can always recover it via the reflog. 109 | -------------------------------------------------------------------------------- /three-trees-watch-scripts.md: -------------------------------------------------------------------------------- 1 | advanced-git-workshop_key 2 | 3 | 3__kuychaco_c02qp3hqfvh8____src_three-trees-of-git__zsh__and_2__hub_log_--graph__--abbrev-commit__git__and_new_file 4 | 5 | Reference: [https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified#The-Workflow](https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified#The-Workflow) 6 | 7 | Set up watcher for working directory tree - `watch -n 1 -t show-working-dir` 8 | ``` 9 | #!/bin/bash 10 | 11 | set -e 12 | 13 | echo "Working Dir" 14 | echo "sandbox" 15 | echo "" 16 | for file in $(ls); do 17 | echo " $file : $(cat $file)" 18 | done 19 | ``` 20 | 21 | Set up watcher for index tree - `watch -n 1 -t show-stage` 22 | ``` 23 | #!/bin/bash 24 | 25 | set -e 26 | 27 | echo "Stage/Index" 28 | echo "next commit snapshot" 29 | echo "" 30 | while read -r line; do 31 | filename=$(echo "$line" | cut -d ' ' -f 2) 32 | sha=$(echo "$line" | cut -d ' ' -f 2) 33 | content=$(git cat-file -p $sha) 34 | echo "$sha $filename : $content" 35 | done <<< "$(git ls-files --abbrev -s)" 36 | ``` 37 | 38 | Set up watcher for head tree - `watch -n 1 -t show-head` 39 | 40 | ``` 41 | #!/bin/bash 42 | 43 | set -e 44 | 45 | echo "Head" 46 | echo "last commit snapshot" 47 | echo "" 48 | while read -r line; do 49 | filename=$(echo "$line" | cut -d ' ' -f 2) 50 | sha=$(echo "$line" | cut -d ' ' -f 3 | head -c 7) 51 | content=$(git cat-file -p $sha) 52 | echo "$sha $filename : $content" 53 | done <<< "$(git cat-file -p head^{tree})" 54 | ``` 55 | 56 | 57 | 58 | 59 | --------------------------------------------------------------------------------