# 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 ```bash 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: ```bash # 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 ```bash 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 ```bash # 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 ```bash git remote -v # show configured remotes git remote add origin # 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 # clone a remote repo locally ``` ### Branches ```bash 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: ```bash 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.