Git LOVES pointers, a lot of the concepts are just glorified pointers
Commits
“Snapshots” of a project, stored as deltas from the previous commit. Contains pointers to the previous commit
git commit --amend just modifies the most recent commit
Branches
Just “pointers” to a commit.
To branch means that I want to include the work of this commit, and all parent from now on. You can commit on the branch to diverge it away.
git checkout to switch branches. Commits apply to the current branch, marked with a *git checkout -b to create a branch and switch to it
Merges
Merges take two commits, combines them and all of their parents.
git merge <branch> merge the branch with the current branch
Rebasing
Takes commits and attempts to “plop them” somewhere else. Rewrites history
git rebase <branch> Takes all the commits in current branch thats diverging, plops them onto the <branch>. Moves the current branch pointer
HEAD
Points to the most recent commit, unless you are in detached HEAD state.
Head -> Branch -> Most recent commit
HEAD points to a branch, a branch is just a pointer to the commit
Detaching
When you detach the HEAD, instead of pointing to a branch, it points to a commit. No changes will be saved onto a branch
Indexing
You can move upwards once with ^ and upwards any number of times with ~<num>. So like HEAD^^ is the same as HEAD~2
^ can actually take an optional number after it. It specifies which parent to follow (if we have a merge commit). main^ would follow first commit, main^2 would follow second. You can chain them so main~^2~2 would go to up 2, follow second parent, go up another 2.
Reverting Changes
You can rewrite history by using git reset, which moves the branch pointer to a previous commit. As if it never happened. Kinda like git branch -f
However, when working remotely, its usually nice to tell everyone that you are rewriting history. That’s what git revert is for. It introduces a new commit that has all the deltas to reverts the changes of a singular commit. It DOES NOT revert the commits afterwards.
Cherry-Pick
git cherry-pick <Commit1> <Commit2> <...>
It copies a series of commits to below your current location
Interactive rebase
Like cherry pick, when you dont exactly know the commits u want
git rebase -i
Tags
A more permanent Branches, marks a certain milestone. Once again, it is a pointer. However it is NEVER automatically moved like branch pointers.
git tag <tag_name> <commit pointer>
Describe
git describe <ref> ref just means commit pointer (head by default) The output is <tag>-<numCommitsAwayFromTag>-g<hash>
if the numcommits is 0, numcommits and hash is dropped
Remote Git
Remote vs Local
Remote refers to the state of the repository on the other machine. Local refers to your own changes. Git operates on a principle where local changes are not automatically synced - DO NOT think of it like google docs.
Remote branches have a special feature: when you check them out, you are in a detached HEAD.
Remote is usually called origin.
Remote branches will automatically appear in your local.
Fetch
git fetch downloads commits that remote has but we’re missing, and updates the origin/<branch> pointer. Git fetch DOES NOT update your main branch
git fetch <remote> <place> (git fetch origin main). Tells git to go to <remote> branch named <place>, grab all the commits, and download that onto that to <remote>/<place>
git fetch <remote> <source>:<destination>. This is called colon refspec (refs being a pointer to a commit that git can resolve). Pushes from remote source to local destination. Git will automatically create the destination branch if it does not exist. You would rarely be this dedicated but i mean okay.
Pull
Since fetching remot changes and then merging them is so common, git has a command for it: git pull
Oftentimes, you would pull, rebase. You can use git pull --rebase
Check out Fetch for some powerful args. It would fetch, and then merge those changes and advance the CURRENT CHECKOUD OUT branch pointer.
Push
git push uploads code to the remote!
However, when there is ambiguity (local state doesn’t reflect remote state), git wont let you push. You need to pull / incorporate changes before you can.
git push <remote> <place> (git push origin main). Tells git to go to branch named <place>, grab all the commits, and push that to <remote> on branch <place>
git push <remote> <source>:<destination>. This is called colon refspec (refs being a pointer to a commit that git can resolve). Pushes from local source to remote destination. Git will automatically create the destination branch if it does not exist.
Pull Request / Merge request
Tragically sometimes you accidentally committed to main. But main is locked to prevent idiots from pushing to prod. To solve this, move your changes to another branch called feature, push that. And then reset main
Remote Tracking
The reason git is able to synchronize with the branches is because of remote tracking. Usually, the main branch is designed to track the origin/main. This is set up for you automatically when you run git clone.
local branch "main" set to track remote branch "o/main"
You can do this manually by doing git checkout -b branchName origin/branchToTrack
or git branch -u origin/toTrack localBranchName. If you leave it out it uses current branch. It will set the localBranchName to track.