## Table of Contents 1. [Git Checkout](#git-checkout) - [Checkout](#checkout) - [Switch](#switch) 2. [The 3 Rs of git](#the-3-rs-of-git) - [Restore](#restore) - [Reset](#reset) * [Soft](#soft) * [Mixed](#mixed) * [Hard](#hard) - [Revert](#revert) - [Further reading](#further-reading) # Git Checkout `git checkout` was, and still is, an overly ubiquitous command with syntax that wasn't nearly verbose enough. With git v2.23 (2019), this sub-command is now split into `switch` and `restore` We also covert `reset` and `revert`, since they're sort of similar ## Checkout Checkout was/is a way to control the state of the git working tree. It chose the state of your files, which roughly is their branch and commit. However, this worked way too broadly, consider these examples ```bash # Remove all current edits from a file, -- is optional # It bring back the version at HEAD git checkout git checkout -- git checkout HEAD git checkout HEAD -- # Bring back files from an older state git checkout git checkout -- # Shift HEAD over to another branch. Stash uncommitted changes git checkout # Shift HEAD over to an old commit (detached HEAD). Stash uncommitted changes git checkout ``` ## Switch Git switch is an all-inclusive command to move the HEAD. It requires uncommitted changes to be stashed ```bash # Set HEAD to another branch git switch # Set HEAD to an old commit. It's a detached HEAD git switch --detach ``` It can also create a new branch like `checkout -b` used to do ```bash # Create a new branch from HEAD git switch --create git switch --create HEAD # Create a new branch off an old commit git switch --create ``` Managing remote branches is simple. The below renames a local and remote branch, which showcases deleting and pushing to remotes ```bash git branch -m # Rename the branch locally git push --delete git push --set-upstream ``` # The 3 Rs of git The general idea of "undoing" is spread between 3 subcommands. Generally given commit tree ``` A - B - C - worktree ``` `restore` can make sepecific files look like they looked in commits `A`, `B`, or `C`. `restore` is the only one that won't modify the commit history and a good default `revert` attempts to undo commits backwards, attaching a new commit `D`, in which files look similar to themselves from `A`, `B`, or `C`, except for merge conflicts which are manually resolved `reset` can pop off commits, like `B` and `C` and either add them to an accumulating worktree, or discard them entirely. This is the most raw "undo", where we can end up with commit history `A - B` ## Restore This is the file-only portion of `checkout`. It operates exclusively on files and will never shift your HEAD Location can be one of `--worktree` or `--staged`. `--source` default to HEAD ```bash # Remove unstaged changes from files git restore git restore --source HEAD git restore --worktree --source HEAD # Unstage a file git restore --staged # Bring back files from an older state git restore --source ``` ## Reset This moves back in the commit history, changing different things based on its "hardness". All examples here assume we have commit tree ``` A - B - C <-HEAD Index: fileA.rs Worktree: fileB.rs ``` The only difference between hardness really is where the files from the previous commits go. In `soft` it's the index, in `mixed` it's the worktree, and in `hard` it's essentially `/dev/null` ### Soft By softly resetting, all the changes from previous commits go into the index, alongside current staged changes ``` $ git reset --soft A - B <-HEAD Index: fileA.rs fileModifiedInC.rs Worktree: fileB.rs ``` ### Mixed This is the default option. It's identical to a soft reset, except all changes from previous commits are moved into the worktree ``` $ git reset --mixed A - B <-HEAD Index: fileA.rs Worktree: fileB.rs fileModifiedInC.rs ``` ### Hard This option is the most destructive and effectively wipes out any evidence of the previous commits. Files are moved into the void. Use a `git reflog` to get them back ``` $ git reset --hard A - B <-HEAD Index: fileA.rs Worktree: fileB.rs Deleted (not there anymore): fileModifiedInC.rs ``` ## Revert This is a sort of inverse to reset. Like reset it undoes entire commits. Unlike reset, it does this by making a new commit that's the exact opposite of the old commit For example with commits ``` A - B - C <-HEAD ``` We can `git revert B` to get ``` A - B - C - B^-1 <-HEAD ``` Which puts us at commit `A` with changes from commit `C`, so it sort of functions like the below, except our history still clearly shows commit `B` ``` A - C <-HEAD ``` ## Further reading [How checkout became switch and restore](https://tanzu.vmware.com/developer/blog/git-switch-and-restore-an-improved-user-experience/)