guides/git.md

5.4 KiB

git

What is it

git is a distributed version control system. It tracks changes to files over time, lets you move between states (commits), and makes it safe to experiment because nothing is ever truly lost.

The mental model that makes everything click: git is a timeline of snapshots. Each commit is a complete snapshot of your project at a point in time, with a pointer to the commit before it. That's it. Branches are just named pointers to commits. Everything else follows from this.

What it is mainly used for

  • Tracking changes to files over time with a full history
  • Safely experimenting — you can always go back
  • Pushing code or content to a remote (like Forgejo) for safekeeping
  • Collaborating with others (or your future self) on the same codebase

Core concepts

Repository (repo) — a folder that git is tracking. The .git/ directory inside it holds the entire history. Don't touch .git/ directly.

Commit — a snapshot of your files at a point in time. Every commit has a unique hash (e.g. f649b2b) and a message describing what changed.

Branch — a named pointer to a commit. main is the default branch. Creating a branch lets you work on something without touching main.

Remote — a copy of the repo somewhere else. In your case, Forgejo. Conventionally named origin.

Staging area — a holding area between your working files and a commit. You explicitly choose what goes into each commit using git add.

Setting up a new repo

cd ~/my-project
git init
git add .
git commit -m "Initial commit"
git remote add origin git@vps-forgejo-01.warthog-rockhopper.ts.net:egeidal/my-project.git
git push -u origin main

The -u flag sets origin/main as the upstream — after this, a plain git push is enough.

Daily workflow

The loop you'll use constantly:

# 1. Check what has changed
git status

# 2. Stage the files you want to commit
git add filename.md        # specific file
git add .                  # everything changed

# 3. Commit with a message
git commit -m "Add rclone SSH key section"

# 4. Push to Forgejo
git push

Useful commands

Seeing what's going on

git status                 # what's changed, what's staged
git log                    # full commit history
git log --oneline          # compact one-line history
git diff                   # unstaged changes
git diff --staged          # staged changes (what will be committed)

Undoing things

# Unstage a file (undo git add, keep the changes)
git restore --staged filename.md

# Discard changes to a file entirely (cannot be undone)
git restore filename.md

# Amend the last commit (message or content)
git commit --amend --no-edit           # keep message, update content
git commit --amend -m "Better message" # change message

# Undo the last commit, keep the changes staged
git reset --soft HEAD~1

# Undo the last commit, keep the changes unstaged
git reset HEAD~1

Working with remotes

git remote -v                          # show configured remotes
git remote add origin <url>            # add a remote
git push                               # push current branch
git push -u origin main                # push and set upstream
git pull                               # fetch + merge from remote
git fetch                              # fetch without merging
git clone <url>                        # clone a remote repo locally

Branches

git branch                             # list branches
git branch my-feature                  # create a branch
git switch my-feature                  # switch to a branch
git switch -c my-feature               # create and switch in one step
git merge my-feature                   # merge branch into current branch
git branch -d my-feature               # delete a branch

.gitignore

A .gitignore file tells git which files to never track. Put it in the root of your repo.

# Example .gitignore
.DS_Store
*.log
secrets.env
node_modules/

Files already tracked by git won't be ignored just by adding them here — you need to untrack them first:

git rm --cached filename

Useful flags

Flag What it does
--oneline Compact log output — one commit per line
--all Show all branches in log
--graph Show branch/merge history as ASCII graph
--soft Reset keeping changes staged
--amend Modify the last commit
--no-edit Keep the existing commit message when amending
-u Set upstream remote when pushing
-v Verbose — show more detail (e.g. with git remote -v)
--cached Apply command to staging area only
--force Force push — overwrites remote history. Use with care

Notes

  • git push --force rewrites remote history. Fine on your own private repos, destructive in shared ones. Use --force-with-lease as a safer alternative.
  • Commit messages are for your future self. "Fix stuff" is useless in six months. "Fix rclone SSH key format in guide" is not.
  • Commit early and often. Small commits are easier to understand and undo than one giant commit with everything in it.
  • The staging area feels annoying at first but is actually useful — it lets you make two unrelated changes and commit them separately with clear messages.
  • If something goes wrong, git status and git log --oneline are always your first move. Understand the state before doing anything.