These are illustrated notes I made while working through Chris Achard's Fix Common Git Mistakes course on egghead.
The course is a great refresher on the fundamental structure of git, adding and removing commits, and (critically) undoing mistakes of all kinds.
The Basic Structure of Git
Chris covers all the various 'levels' your Git files can be at. I personally needed to think of it as a spatial stack to understand how files move between them.
Every time I push commits to Github I see something like this in my head:
I also found it helpful to think of the 'stash' as a side drawer you tuck files away in, and then can 'pop' them back out later.
Branches are Pointers
This framing of git branches as "pointers" you can move around changed the way I think about them a lot.
We can move the pointers to different commits, which are just different versions of our project at a specific point in time.
Git Log
git log
is a handy feature that shows you all your previous commits and their details. It's quite verbose though.
git log --oneline
is much easier to read since it only shows you the commit hashes and messages
git log --graph
draws a tiny graph in the terminal showing branches and merges
Undoing Mistakes
Git Commit Ammend
git commit --ammend
lets us add or change files in our last commit, as well as the commit message
Git Reset
git reset
will move a file backwards. If you're committed a file to either staging or the local repo, we can bring it back to our working directory.
Git gives us three levels of "intensity" for resetting - git reset --hard
, git reset --soft
, and mixed.
If you don't specify one, mixed is the default which just moves it from the local repo back to your working files.
Git Diff
git diff
is a handy utility for seeing what's changed between two commits or two files
You can compare two commits using their branch names or commit hashes: git diff main new-feature
You can also compare two files by passing in both file names: git diff path/to/file/ComponentA.js path/to/file/ComponentB.js
Detached Head
A detached head is less morbid than it sounds. It just means we've checked out a commit using it's specific hash name, such as git checkout 49da32
That commit is now the "head" because it's the most recent version of our project.
It's "detached" because we've navigated there directly and aren't on our usual branch structure. We have to "reattach" the commit back to our branch with git checkout -b my-new-branch-name
It feels good to be less lost in the git forest now.
I hope some of these techniques make your git log less sad too :)
There's plenty more in Chris' course that I left out here.
👁🗨 If these are hard to read, you can download a free high-res PDF version on the course itself.
Dev.to limits image sizes a lot and it's hard to make it readable on here. Apologies!
Top comments (6)
Love those graphics. Is it okay if I use them in an internal presentation (including credits of course)?
Of course! Thanks for asking 👍
Newer git versions introduced the commands
restore
andswitch
.Restore (from 2.25.0)
Restore specified paths in the working tree with some contents from a restore source. If a path is tracked but does not exist in the restore source, it will be removed to match the source.
The command can also be used to restore the content in the index with --staged, or restore both the working tree and the index with --staged --worktree.
By default, if --staged is given, the contents are restored from HEAD, otherwise from the index. Use --source to restore from a different commit.
Switch (from 2.27.0)
Switch to a specified branch. The working tree and the index are updated to match the branch. All new commits will be added to the tip of this branch.
Optionally a new branch could be created with either -c, -C, automatically from a remote branch of same name (see --guess), or detach the working tree from any branch with --detach, along with switching.
Switching branches does not require a clean index and working tree (i.e. no differences compared to HEAD). The operation is aborted however if the operation leads to loss of local changes, unless told otherwise with --discard-changes or --merge.
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
Absolutely love your designs Maggie :)
Your post make git looks less scary 😂 thanks for writing this! I never heard about the amend option and it looks very useful mostly to remove private information added accidentally.
Amend is convenient when you want to change something in the lastest commit. If you want to modify earlier commits else you can do fixup-commits that you squash into the original, or do an interactive rebase and (e)dit the concerned commits.