Learn Git
Git is a famously powerful and famously confusing version control system used by software engineers everywhere. Increasingly, as other types of work begin to look more like software engineering (in my case network and systems engineering), git becomes useful for those folks as well. In that regard, here are some resources to learn git. I recommend you start at the top, get enough to work with, play with git by yourself, and return for the more advanced stuff when the basics don't cover your needs anymore.
- Atlassian covers some good ways to install Git. I recommend the Homebrew method if you're on a Mac and use Homebrew. It'll make it easy to install and update Git as well as other software.
- Git Essentials LiveLessons is a Safari Books Online video course for teaching the very beginnings of git. It's not a free resource, but it's a good one.
- The Git Tutorial is a short text introduction to using git.
- GitHub makes an interactive tutorial.
- js.org has a very nice interactive tutorial on Git branches.
Once you have a decent workflow with git, you need to learn some of the theory behind it and the more in-depth commands it offers:
- The Git User Manual is a relatively short introduction to some of git's features
- Pro Git is a free online book for learning git that goes from beginner level to expert level. Very useful for learning the commands.
- “Getting Git” by Scott Chacon is a great video explaining how git tracks content internally. A lot of git suddenly makes much more sense once you see it from the inside out.
- Git For Ages 4 And Up is another really good video explaining git internals (though it's not perfect: questions interrupt the presenter, and it's cut short). As a bonus, I think everyone was required to dress like a hipster for it.
Git is such a flexible tool that there are multiple workflows possible for it. Different teams will choose different workflows, but here are some of the more popular ones:
- Atlassian makes a git tutorial centered around their product BitBucket - a pretty good git hosting center. It includes a comparison of workflows.
- GitHub also highlights a workflow method in one of their guides.
Git Notes
Forking and Syncing with GitHub
Sometimes I need to make a change to a public repo I own (like my dotfiles) from my work laptop. I can't simply clone the repo and make the change because my work laptop doesn't have access to my personal logins so I don't have permissions to push (by design, not necessity). So, here's how to do a PR workflow
- Work PC: In GitHub, fork the repo to my work GitHub account
- Work PC: In the terminal, clone the repo
- Work PC: In the terminal, make the change, commit, and push
- Work PC: In GitHub, make a PR to the personal repo
- Home PC: In GitHub, merge the PR
- Work PC: In GitHub, sync the fork (button at the top)
- Work PC: In the terminal:
git pull
to pull the merge commit
Many of these steps use GitHub's web UI. There's other ways to do parts of this with Git directly, but they're not as convenient for me.
Moving commits to a new branch
I try to work on new features in a branch, but sometimes I just work on master and need to move to different branches. Luckily, Stackoverflow has me covered:
git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit
Delete a local remote-tracking branch
From StackOverflow:
$ git branch -a
helpcolumns
* master
remotes/origin/bbkane/issue46
remotes/origin/helpcolumns
remotes/origin/master
remotes/origin/searchFuncPtr
$ git fetch origin --prune
From https://github.com/bbkane/warg
- [deleted] (none) -> origin/bbkane/issue46
- [deleted] (none) -> origin/searchFuncPtr
Git blame with Log Ranges
From Git Tips 1: Oldies but Goodies
git blame -L 28,43 path/to/file
or
git log -L28,43:gitbutler-ui/src/lib/vbranches/types.ts
See the post for more options, like looking for code that moved.
Merge a repo into a subdirectory into another repo
This is from StackOverflow. I was able to follow the steps exactly, except for needing to use absolute paths instead of relative ones.
Fix up repo1
cd path/to/repo1
mkdir repo1
# move all non-hidden files and folders into `repo1/`
mv * repo1/
# move all hidden files and folders into `repo1/`
mv .* repo1/
# Now move the .git dir back to where it belongs, since it was moved by the
# command just above
mv repo1/.git .
# commit all these changes into this repo
git add -A
git status
git commit -m "Move all files & folders into a subdir"
cd path/to/new_repo
# --------------------------------------------------------------------------
# 1. Merge repo1, with all files and folders and git history, into new_repo
# --------------------------------------------------------------------------
# Add repo1 as a local "remote" named `repo1`
# - Note: this assumes that new_repo, repo1, and repo2 are all at the same
# directory level and inside the same parent folder. If this is *not* the
# case, no problem. Simply change `"../repo1"` below to the proper
# relative *or* absolute path to that repo! Ex: `"path/to/repo1"`.
git remote add repo1 "../repo1"
# View all of your remotes.
# - You'll now see `repo1` as a remote which points to the local "URL"
# of "../repo1"
git remote -v
# Fetch all of repo1's files and history into new_repo's .git dir.
# - Note that `repo1` here is the name of the remote alias that you just
# added above.
git fetch repo1
# View the new locally-stored, remote-tracking hidden branch that was just
# created for you.
# - `git branch -r` will now show a new hidden branch named `repo1/main` or
# `repo1/master` or whatever your main branch was named there.
git branch -r
# Assuming that your new hidden branch that you just fetched is called
# `repo1/main`, let's merge that into our currently-checked-out branch now.
# - This merges repo1's files and folders and git history into new_repo.
# - change `repo1/main` to `repo1/some_other_branch` if you want to merge in
# `some_other_branch` instead.
# - Immediately after running this command, you will now see a new folder,
# `repo1`, with all of its files and folders within it, created inside
# the `new_repo` directory.
git merge --allow-unrelated-histories repo1/main
# Since you have independent sub-folders prepared inside repo1 and repo2,
# there will be no conflicts whatsoever. When the git merge editor opens
# up, just save and close it to complete the merge. Optionally, add any
# comments you wish before saving and closing it.
# Now, remove the remote named "repo1", since we no longer need it.
git remote remove repo1
# View all remotes to ensure it is now gone
git remote -v
# See the new commit status. If `repo1` had 100 commits in it, for instance,
# `git status` will now show this, since `new_repo` now has those 100
# commits plus this new merge commit in it:
#
# $ git status
# On branch main
# Your branch is ahead of 'origin/main' by 101 commits.
# (use "git push" to publish your local commits)
#
# nothing to commit, working tree clean
#
git status
# Push to a remote, if you have one configured
git push