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

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.