# Module 4 — Git & Version Control

Track, share, and collaborate on code: Git's model, the everyday commit workflow, branching/merging/conflicts, and remotes on the lab's Gitea server.

# Lesson: Git's Mental Model

## What you'll learn
- Why version control exists and what problems it solves on a real team.
- The four core places your work lives: the working tree, the staging area, the local repository, and (later) a remote.
- What a commit actually is — a *snapshot*, not a list of changes — and why that matters.
- What the hidden `.git` directory holds and why you must never delete it by accident.
- How to create a repository with `git init` and set your identity with `git config`.

By the end you will be able to explain, in your own words, what happens when you "save" work in Git — the foundation everything else in this module builds on.

## The lesson

### 1. What problem does version control solve?
Imagine you wrote a backup script last week. Today you "improved" it, but now it is broken, and you cannot remember exactly what you changed. You start making copies: `backup.sh`, `backup-final.sh`, `backup-final-REALLY.sh`. This is chaos, and it gets far worse when two people edit the same file.

A **version control system** (VCS) — a tool that records changes to files over time — fixes this. It lets you:
- See exactly what changed, when, and who changed it.
- Return to any earlier state of your project.
- Work on a new feature without breaking the working version.
- Combine your changes with a teammate's safely.

**Git** is the VCS the whole industry uses. It is *distributed*: every copy of a project is a full repository with the complete history, not just a checkout from a central server.

### 2. The repository (repo)
A **repository** is a project folder that Git is tracking. Physically, it is your normal files *plus* one hidden subfolder named `.git`. That hidden folder is the actual database of your history. Delete `.git` and you have an ordinary folder again — all history is gone. The visible files are just one version Git has written out for you to edit.

### 3. The three areas you work in
Git work flows through three areas inside one repo. Picture it like this:

```
   working tree            staging area (index)        repository (.git)
  ┌──────────────┐  add   ┌──────────────────┐ commit ┌──────────────────┐
  │ files you    │ ─────> │ changes you have  │ ────>  │ permanent history │
  │ edit on disk │        │ marked to save    │        │ of snapshots      │
  └──────────────┘        └──────────────────┘        └──────────────────┘
        ^                                                       │
        └─────────────── checkout / restore ◄──────────────────┘
```

1. **Working tree** — the real files in your folder that you open and edit.
2. **Staging area** (also called the **index**) — a holding zone. You *stage* a change to say "I want this to be part of my next save." This lets you commit some changes now and others later.
3. **Repository** — when you **commit**, Git takes everything currently staged and stores it permanently in `.git`.

The staging area is the part beginners find surprising. It exists so you can craft a clean, deliberate commit instead of dumping every random edit together.

### 4. A commit is a snapshot, not a diff
Many people think Git stores "the lines you changed." It does not. Each **commit** is a complete **snapshot** — a photo of what every tracked file looked like at that moment. Git is smart about storage (unchanged files are reused, not copied), but mentally you should think: *every commit is a full picture of the project.*

Each commit has:
- A unique ID (a long **hash** like `a1b2c3d…`) computed from its contents.
- The author, a date, and a **commit message** describing the change.
- A pointer to its **parent** — the commit that came before it.

Because each commit points to its parent, the history forms a chain:

```
  (A) ──> (B) ──> (C) ──> (D)   <- HEAD (where you are now)
 first                  latest
```

`HEAD` is simply Git's bookmark for "the commit you are currently on."

### 5. Inside the `.git` directory
You rarely touch `.git` by hand, but knowing it is real helps. It contains the object database (your commits, file contents, and directory listings), the **refs** (names like branches pointing at commits), the `HEAD` file, and your repo-local config. Everything Git "remembers" lives here. Treat it as read-only and let Git commands manage it.

### 6. Create your first repository
Open a terminal on your lab VM and run:

```bash
mkdir my-scripts
cd my-scripts
git init
```

`git init` creates the `.git` folder — that folder is now a repository. You can confirm it exists:

```bash
ls -a        # you should see  .  ..  .git
git status   # Git tells you it's a fresh repo with nothing committed yet
```

### 7. Tell Git who you are
Every commit records an author. Set this once per machine (the `--global` flag writes to your user config, used by all your repos):

```bash
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
```

A couple of friendly defaults worth setting now:

```bash
git config --global init.defaultBranch main   # name the first branch "main"
git config --global core.editor nano           # editor Git opens for messages
```

Check what you set at any time:

```bash
git config --global --list
```

That is the entire mental model. Three areas, snapshots linked by parents, all stored in `.git`, with your identity stamped on each commit. In the next lesson you will actually move work through those three areas with `add` and `commit`.

## Dig deeper
- [Pro Git — Getting Started (Git Basics)](https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F)
- [Pro Git — Recording Changes to the Repository](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository)
- [Atlassian — What is version control?](https://www.atlassian.com/git/tutorials/what-is-version-control)
- [Official git config documentation](https://git-scm.com/docs/git-config)

## Search terms
- `what is git version control for beginners`
- `git working tree staging area explained`
- `why git stores snapshots not diffs`
- `git init and git config first time setup`
- `what is inside the .git directory`

## Check yourself
1. Name the three areas a change passes through and what each one is for.
2. What is actually stored in a single commit — a snapshot or a list of changed lines?
3. What happens to your project history if you delete the `.git` folder?
4. Which command turns an ordinary folder into a Git repository?
5. Why do you set `user.name` and `user.email`, and what does `--global` mean?

# Lesson: Status, Add, Commit, Log

## What you'll learn
- The everyday loop every developer repeats dozens of times a day: edit → status → add → commit.
- How to read `git status` and `git diff` to see exactly what changed.
- How to write commit messages that your future self and teammates will thank you for.
- How to keep junk out of your repo with a `.gitignore` file.
- How to safely undo mistakes with `git restore` and the basics of `git reset`.

By the end you will be able to record clean, well-described history in your own repo without fear.

## The lesson

This lesson assumes you have a repo from the previous lesson (`git init` done, identity set). All commands below run inside that repo on your lab VM.

### 1. The everyday loop
Almost all daily Git work is one short cycle:

```
  edit a file  ─>  git status  ─>  git add  ─>  git commit  ─>  (repeat)
                       │
                       └─ git diff  (see exactly what changed before staging)
```

Let's walk through it with a real example. Create a script:

```bash
echo '#!/bin/bash' > hello.sh
echo 'echo "hello lab"' >> hello.sh
```

### 2. `git status` — your constant companion
`git status` tells you the state of your three areas. Run it now:

```bash
git status
```

You will see `hello.sh` listed under **Untracked files** — Git sees it but is not yet recording it. Get into the habit of running `git status` before and after every action. It is impossible to use too often.

### 3. `git add` — stage what you want to save
**Staging** marks a change for the next commit. Stage the file:

```bash
git add hello.sh
git status        # hello.sh now shows under "Changes to be committed"
```

Useful forms:
```bash
git add file1 file2     # stage specific files
git add .                # stage everything new/changed in the current folder
```

Prefer naming files over `git add .` until you are comfortable, so you never stage something by accident.

### 4. `git diff` — see the actual changes
`git diff` shows changes you have **not** staged yet. `git diff --staged` shows what you have staged (i.e., what your next commit will contain). Try editing the file, then:

```bash
echo 'echo "goodbye"' >> hello.sh
git diff             # shows the new line you just added (unstaged)
git diff --staged    # shows what is already staged
```

Lines starting with `+` are additions; `-` are removals. Always diff before you commit so you know exactly what you are saving.

### 5. `git commit` — save a snapshot
Commit everything currently staged:

```bash
git commit -m "Add hello.sh script"
```

The `-m` flag supplies the message inline. Without it, Git opens your editor so you can write a longer message. After committing, `git status` shows a **clean** working tree — nothing left to save.

A common shortcut once files are already tracked is `git commit -am "msg"`, which stages all *modified* tracked files and commits in one step. Note: it does **not** pick up brand-new (untracked) files, so you still need `git add` for those.

### 6. Writing good commit messages
A commit message explains *why* a change exists. The widely used convention:
- First line: a short summary, ~50 characters, in the imperative mood ("Add", "Fix", "Remove" — as if completing "This commit will…").
- Then a blank line, then optional detail explaining the reasoning.

```
Fix backup script failing on empty directories

The find command returned a non-zero exit when no files matched,
which aborted the script. Added a guard for the empty case.
```

Good: `Add log-rotation to backup script`. Bad: `stuff`, `fix`, `asdf`, `final changes`. Your history is documentation — write it for the next person.

### 7. `.gitignore` — keep junk out
Some files should never be committed: logs, temporary files, secrets, editor backups, build output. List patterns in a file named `.gitignore` at the repo root:

```bash
cat > .gitignore <<'EOF'
*.log
*.tmp
.env
EOF
git add .gitignore
git commit -m "Add .gitignore for logs, temp files, and secrets"
```

Now Git stops nagging you about those files and you cannot stage them by accident. **Never commit passwords or tokens** — that is exactly what `.env` and similar patterns protect against.

### 8. `git log` — read your history
View the chain of commits:

```bash
git log                  # full history, newest first
git log --oneline        # one compact line per commit
git log --oneline --graph --all   # a visual tree (great once you have branches)
```

`--oneline` is the one you will use most:

```
a1b2c3d Add .gitignore for logs, temp files, and secrets
e4f5g6h Add hello.sh script
```

Each line shows the short hash and the summary. Press `q` to quit the log viewer.

### 9. Undoing mistakes safely
Things go wrong; Git makes most of it reversible.

**Discard unstaged edits to a file** (throw away changes since the last commit):
```bash
git restore hello.sh
```

**Unstage a file** (keep your edits, just remove it from the staging area):
```bash
git restore --staged hello.sh
```

**Undo the last commit but keep the changes** (commit too early? wrong message?):
```bash
git reset --soft HEAD~1     # moves HEAD back one commit; your changes stay staged
```

`HEAD~1` means "one commit before HEAD." Be careful with `git reset --hard`, which **discards** changes permanently — only use it when you are certain you want the edits gone. Until you have pushed work to a remote, your safest habit is: commit often, and prefer `restore` and `--soft reset`.

That is the complete everyday workflow. Edit, `status`, `diff`, `add`, `commit`, `log` — over and over. Master this loop and the rest of Git is variations on a theme.

## Dig deeper
- [Pro Git — Recording Changes to the Repository](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository)
- [Pro Git — Viewing the Commit History](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History)
- [Pro Git — Undoing Things](https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things)
- [Atlassian — Saving changes (git add / commit)](https://www.atlassian.com/git/tutorials/saving-changes)
- [gitignore.io — generate .gitignore files](https://www.toptal.com/developers/gitignore)

## Search terms
- `git add commit workflow tutorial`
- `how to write good git commit messages`
- `git diff staged vs unstaged`
- `git restore vs git reset explained`
- `gitignore file examples`

## Check yourself
1. What is the difference between `git diff` and `git diff --staged`?
2. Why run `git status` so frequently? What does it tell you?
3. Write a good commit message for a change that fixes a typo in a script's help text.
4. What belongs in `.gitignore`, and why must secrets never be committed?
5. You committed too early. Which command moves the commit back but keeps your changes? Which command would instead destroy them?

# Lesson: Branches, Merges & Conflicts

## What you'll learn
- What a branch really is (a cheap, movable pointer — not a copy of your files).
- How to create and switch branches with `git branch` and `git switch`.
- How to combine work with `git merge`, and the difference between a fast-forward and a merge commit.
- How a merge conflict happens, and a calm, step-by-step way to resolve one.
- Why branching is the foundation of safe teamwork.

By the end you will be able to develop a change in isolation, merge it back, and handle conflicts without panic.

## The lesson

### 1. What a branch is
A **branch** is just a lightweight, movable pointer to a commit. It is *not* a copy of your project. Creating a branch is instant and nearly free, which is why Git users branch constantly.

Recall from Module 4 Lesson 1 that commits form a chain, each pointing at its parent. A branch name simply points at the newest commit on a line of work, and `HEAD` points at the branch you are currently on:

```
            main
              │
  (A) ─> (B) ─> (C)   <- HEAD points here (you are on main)
```

When you commit, the branch pointer moves forward to the new commit automatically.

### 2. Why branch at all?
Branches let you work on something new without touching the known-good version. Your `main` branch stays stable and deployable while you experiment on a `feature` branch. If the experiment fails, you delete the branch and `main` is untouched. If it succeeds, you merge it in. On a team, everyone works on their own branch and merges when ready — that is how people avoid stepping on each other.

### 3. Creating and switching branches
The modern commands are `git switch` (change branches) and `git branch` (list/create/delete). Older tutorials use `git checkout` for both; `switch` is clearer and is what we use here.

```bash
git branch                 # list branches; * marks the current one
git switch -c add-logging   # create a new branch AND switch to it
```

`-c` means "create." After this, `HEAD` points at `add-logging`, which starts at the same commit `main` is on:

```
                  main
                   │
  (A) ─> (B) ─> (C)
                   │
              add-logging  <- HEAD
```

Now make a commit on the feature branch:

```bash
echo 'echo "logging enabled"' >> hello.sh
git add hello.sh
git commit -m "Add logging line to hello.sh"
```

The picture is now:

```
                  main
                   │
  (A) ─> (B) ─> (C) ─> (D)
                        │
                   add-logging  <- HEAD
```

`main` still points at C; only `add-logging` moved forward to D. Switch back any time with `git switch main` — your files change to match that branch.

### 4. Merging: bringing work together
**Merging** takes the commits from one branch and combines them into another. You merge *into* the branch you are currently on. To bring `add-logging` into `main`:

```bash
git switch main
git merge add-logging
```

There are two outcomes.

### 5. Fast-forward merge
If `main` has not moved since you branched (it still points at C), Git can simply slide `main` forward to D. No new commit is needed — this is a **fast-forward**:

```
  before:  (C:main) ─> (D:add-logging)
  after:   (C) ─> (D)   <- main and add-logging both here
```

The history stays perfectly linear. This is the common case for a quick solo feature.

### 6. Merge commit (true merge)
If `main` *also* gained commits while you worked (say someone added commit E), the two lines have diverged:

```
  (A) ─> (B) ─> (C) ─> (E)        <- main
                 │
                 └────> (D)        <- add-logging
```

Git cannot just slide the pointer. It creates a new **merge commit** (M) that has *two* parents — E and D — tying the histories together:

```
  (A) ─> (B) ─> (C) ─> (E) ─> (M)  <- main
                 │            │
                 └────> (D) ──┘
```

Git opens an editor for the merge commit message; usually you accept the default and save.

### 7. When a conflict happens
Most merges are automatic. A **conflict** occurs only when the *same lines* of the *same file* were changed differently on both branches — Git cannot know which version you want, so it asks you.

Let's create one on purpose to learn the fix. On `main`, edit line 2 of `hello.sh` to say `echo "hello from main"` and commit it. Then switch to a branch where line 2 says `echo "hello from feature"` and commit that. Now merge:

```bash
git switch main
git merge feature
```

Git stops and reports a conflict. `git status` will list `hello.sh` under "Unmerged paths."

### 8. Resolving a conflict, step by step
Open the conflicted file. Git has inserted **conflict markers**:

```
<<<<<<< HEAD
echo "hello from main"
=======
echo "hello from feature"
>>>>>>> feature
```

- Between `<<<<<<< HEAD` and `=======` is *your current branch's* version.
- Between `=======` and `>>>>>>> feature` is the *incoming branch's* version.

To resolve, do these in order:
1. **Edit the file** so it contains exactly what you want the final result to be. Delete all three marker lines (`<<<<<<<`, `=======`, `>>>>>>>`) and keep/blend the correct content. For example, settle on `echo "hello from the team"`.
2. **Stage the resolved file** to tell Git you have settled it:
   ```bash
   git add hello.sh
   ```
3. **Complete the merge** by committing:
   ```bash
   git commit          # accept the default merge message, or write your own
   ```

That's it — the merge commit is created and the conflict is resolved. If you ever feel lost mid-conflict, you can abort and return to the pre-merge state:

```bash
git merge --abort
```

### 9. Cleaning up
Once a feature branch is merged, delete it to keep things tidy:

```bash
git branch -d add-logging   # -d refuses if not yet merged (safe)
```

Conflicts feel scary the first time, but the routine is always the same: edit to the desired result, remove the markers, `add`, then `commit`. Practice it a few times and it becomes routine. In the next lesson you take all of this online, pushing branches to the lab's Gitea server and merging through pull requests.

## Dig deeper
- [Pro Git — Branches in a Nutshell](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell)
- [Pro Git — Basic Branching and Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging)
- [Atlassian — Git merge tutorial](https://www.atlassian.com/git/tutorials/using-branches/git-merge)
- [Atlassian — Merge conflicts](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts)
- [Official git switch documentation](https://git-scm.com/docs/git-switch)

## Search terms
- `git branch and switch tutorial beginner`
- `git fast forward vs merge commit difference`
- `how to resolve a git merge conflict step by step`
- `git merge conflict markers explained`
- `git merge abort undo a merge`

## Check yourself
1. A branch is a pointer to what? Is it a copy of your files?
2. What is the difference between a fast-forward merge and a merge commit, and when does each happen?
3. Under exactly what condition does a merge produce a conflict?
4. List the three steps to resolve a conflict once you see the markers.
5. Which command throws away an in-progress merge and returns you to where you started?

# Lesson: Working with Gitea

## What you'll learn
- What a remote is, and how your local repo and a server repo stay in sync.
- How to `clone`, and how to wire up an existing local repo with `git remote add`.
- The push/fetch/pull cycle, and what a tracking branch is.
- How to push your Module 3 scripts to the lab's Gitea server.
- The pull-request (PR) workflow — how real teams review and merge changes.

By the end you will be able to publish your work to the lab Gitea server and propose changes through a pull request, just like on GitHub.

## The lesson

### 1. What a remote is
So far everything lived only on your VM. A **remote** is a copy of your repository hosted somewhere else — on a server — that you and your teammates share. Git can sync commits between your local repo and the remote.

Our lab runs **Gitea**, a self-hosted Git server that behaves just like GitHub for everyday use: web UI, repositories, branches, pull requests. Its addresses:
- Public URL: `https://git.example.com`
- Internal (from inside the lab network): `http://10.100.100.2:3000`

```
   your VM (local repo)                 Gitea server (remote)
  ┌────────────────────┐    push  ───>  ┌──────────────────────┐
  │ commits A,B,C       │               │ commits A,B,C          │
  │ branch: main        │  <─── fetch   │ branch: main           │
  └────────────────────┘               └──────────────────────┘
```

A remote is normally nicknamed **`origin`** — that is just a convention for "the main remote I cloned from / push to."

### 2. Two ways to start

**(a) Clone an existing remote repo** — copies the whole repo, history and all, to your machine and auto-configures `origin`:

```bash
git clone http://10.100.100.2:3000/yourname/my-scripts.git
cd my-scripts
```

**(b) Connect a local repo you already created** — you built `my-scripts` locally in earlier lessons. First create an empty repo named `my-scripts` in the Gitea web UI (do **not** let it add a README, so it stays empty). Then link and push:

```bash
git remote add origin http://10.100.100.2:3000/yourname/my-scripts.git
git remote -v       # verify: shows the fetch and push URLs for origin
```

`git remote -v` should print `origin` twice (one fetch, one push line).

### 3. Pushing for the first time
**Pushing** uploads your local commits to the remote. The first push of a branch also sets up tracking with `-u`:

```bash
git push -u origin main
```

Gitea will ask for your username and password (or a personal access token created in the Gitea UI under Settings → Applications — never paste a real token into shared notes; treat it as `<REDACTED>`). After this, the commits appear on the Gitea website.

The `-u` (short for `--set-upstream`) creates a **tracking branch**: it links your local `main` to `origin/main`. Once linked, you can simply type `git push` and `git pull` with no extra arguments — Git knows where they go.

### 4. fetch vs pull
Two commands bring remote work down to you:

- **`git fetch`** downloads new commits from the remote into your local copy of the remote branches (e.g. `origin/main`), but does **not** change your working files. It is the safe "let me see what's new" command.
- **`git pull`** does a `fetch` *and then* merges those changes into your current branch. It is `fetch` + `merge` in one step.

```bash
git fetch origin          # see what changed on the server, no merge yet
git log --oneline origin/main   # inspect the remote branch
git pull                   # bring it into your branch (fetch + merge)
```

Habit to build: **pull before you start working** each session, so you begin from the latest shared state and avoid conflicts later.

### 5. The everyday remote cycle

```
  git pull            <- get latest from server
  ... edit, add, commit locally ...
  git push            <- send your commits to the server
```

If `git push` is rejected because the remote moved ahead of you, do `git pull` first (resolve any conflict as you learned in Lesson 3), then `git push` again.

### 6. Why pull requests exist
On a real team you usually do **not** push straight to `main`. Instead you push a *branch* and open a **pull request (PR)** — a proposal that says "please review my branch and merge it into `main`." A PR gives teammates a place to read your diff, comment, request changes, and approve before the code lands. It is the heart of collaborative Git.

### 7. A basic pull-request flow on Gitea
Walk through the full loop:

1. **Start from the latest main** and create a feature branch:
   ```bash
   git switch main
   git pull
   git switch -c add-readme
   ```
2. **Do the work and commit:**
   ```bash
   echo "# My Scripts" > README.md
   git add README.md
   git commit -m "Add project README"
   ```
3. **Push the branch** to Gitea:
   ```bash
   git push -u origin add-readme
   ```
4. **Open the PR in the web UI.** Go to `https://git.example.com/yourname/my-scripts`. Gitea shows a banner offering to create a pull request from your just-pushed branch. Click it, set the target to `main`, write a clear title and description of *what* and *why*, and create the PR.
5. **Review.** A teammate (or your mentor) reads the diff and comments. If they request changes, you make more commits on the same branch and `git push` again — the PR updates automatically.
6. **Merge.** Once approved, click **Merge Pull Request** in Gitea. Your change is now in `main` on the server.
7. **Sync and clean up locally:**
   ```bash
   git switch main
   git pull                       # bring the merged change down
   git branch -d add-readme       # delete the local feature branch
   ```

```
  local feature branch ─push─> Gitea branch ─PR─> review ─merge─> origin/main ─pull─> your local main
```

### 8. Inspecting and tidying remotes
```bash
git remote -v                 # list remotes and URLs
git branch -r                 # list remote-tracking branches (e.g. origin/main)
git fetch --prune             # drop local refs to branches deleted on the server
```

That's the full collaboration loop: clone or add a remote, branch, commit, push, open a PR on Gitea, get review, merge, and pull. This is exactly how professional teams ship code every day — and it is what you'll practice in this module's assignments.

## Dig deeper
- [Pro Git — Working with Remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)
- [Gitea documentation — Usage](https://docs.gitea.com/usage/pull-request)
- [Atlassian — Syncing (fetch, pull, push)](https://www.atlassian.com/git/tutorials/syncing)
- [Atlassian — Making a pull request](https://www.atlassian.com/git/tutorials/making-a-pull-request)
- [Official git push documentation](https://git-scm.com/docs/git-push)

## Search terms
- `git remote add origin push first time`
- `git fetch vs git pull difference`
- `git tracking branch upstream explained`
- `how to open a pull request gitea`
- `git pull rejected push remote ahead fix`

## Check yourself
1. What is a remote, and what does the name `origin` conventionally refer to?
2. What does the `-u` flag do on your first `git push`, and how does it change later pushes?
3. Explain the difference between `git fetch` and `git pull`.
4. Why do teams use pull requests instead of pushing directly to `main`?
5. List the steps to take a local change all the way to merged on Gitea via a PR.

# Assignment 1: Version your Module 3 scripts on Gitea

**Goal:** Take the shell scripts you wrote in Module 3, turn their folder into a real Git repository with clean commit history, and publish it to the lab's Gitea server.

**Where:** On your lab VM, in the folder holding your Module 3 scripts. The remote is the lab Gitea server — public URL `https://git.example.com`, internal `http://10.100.100.2:3000`.

## Tasks
1. If you haven't already, set your Git identity once on the VM:
   ```bash
   git config --global user.name "Your Name"
   git config --global user.email "you@example.com"
   git config --global init.defaultBranch main
   ```
2. Go into your Module 3 scripts folder and initialise a repository with `git init`. Confirm with `git status`.
3. Create a `.gitignore` that excludes at least logs and any environment/secret files (e.g. `*.log`, `*.tmp`, `.env`). Make sure no real secrets or passwords are anywhere in the tracked files.
4. Stage your scripts deliberately (name them with `git add`, inspect with `git status` and `git diff --staged`).
5. Make **at least three separate commits**, each grouping related changes, with clear imperative-mood messages (e.g. `Add backup script`, `Add .gitignore`, `Document usage in README`). Add a short `README.md` describing what the scripts do as one of those commits.
6. In the Gitea web UI, create a new **empty** repository named `module3-scripts` (do not let Gitea add a README, so it starts empty).
7. Wire up the remote and push:
   ```bash
   git remote add origin http://10.100.100.2:3000/yourname/module3-scripts.git
   git remote -v
   git push -u origin main
   ```
8. Open the repo in the Gitea web UI and confirm your files, commits, and messages all appear.

## Deliverable
A Gitea repository `module3-scripts` containing your Module 3 scripts, a `README.md`, and a `.gitignore`, with at least three meaningful commits visible in the history, pushed to `origin/main`.

## Acceptance criteria — you're done when:
- [ ] `git status` in the folder reports a clean working tree (nothing uncommitted).
- [ ] `git log --oneline` shows at least three commits with clear, imperative-mood messages.
- [ ] A `.gitignore` is committed and excludes logs, temp files, and secret/env files.
- [ ] No passwords, tokens, or secrets appear in any tracked file.
- [ ] A `README.md` describing the scripts is committed.
- [ ] `git remote -v` shows `origin` pointing at your Gitea repo.
- [ ] The repository and all commits are visible in the Gitea web UI under `module3-scripts`.
- [ ] `git push` reports everything is up to date (local `main` matches `origin/main`).

## Hints
- Run `git status` constantly — before and after every `add` and `commit`. It is your map.
- To split work into multiple commits, stage and commit one logical group at a time instead of `git add .` then one big commit.
- Gitea asks for credentials on push. Prefer a personal access token (Gitea → Settings → Applications) over your password; never paste a real token anywhere shared — treat it as `<REDACTED>`.
- If your first push is rejected, re-read Lesson 4 section 3, and confirm the remote repo you created was empty.
- Forgot to ignore a file you already committed? `git rm --cached <file>` untracks it while leaving it on disk, then commit.
- Blocked for >~30 min after re-reading the lessons? Bring what you've tried to your mentor.

# Assignment 2: Branch, conflict, resolve, and open a PR

**Goal:** Practice the full collaboration loop — create a feature branch, deliberately cause a merge conflict, resolve it correctly, and land your change through a pull request on Gitea.

**Where:** On your lab VM, in the `module3-scripts` repository you pushed in Assignment 1. The remote is the lab Gitea server — public URL `https://git.example.com`, internal `http://10.100.100.2:3000`.

## Tasks
1. Make sure you start from the latest `main`:
   ```bash
   git switch main
   git pull
   ```
2. Create and switch to a feature branch:
   ```bash
   git switch -c improve-readme
   ```
3. On `improve-readme`, edit one specific line of `README.md` (for example, change the project description line). Commit it with a clear message.
4. **Deliberately create a conflict.** Switch back to `main` and change the *same line* of `README.md` differently, then commit:
   ```bash
   git switch main
   # edit the same README line a different way
   git add README.md
   git commit -m "Reword project description on main"
   ```
5. Merge your feature branch into `main` and trigger the conflict:
   ```bash
   git merge improve-readme
   ```
6. Resolve the conflict: open `README.md`, remove the `<<<<<<<`, `=======`, `>>>>>>>` markers, craft the final wording you actually want, then `git add README.md` and `git commit` to complete the merge. (See Lesson 3, section 8.)
7. Now practice the PR flow on a *new* branch so there's something to review. From the resolved `main`:
   ```bash
   git switch -c add-usage-examples
   # add a "Usage" section to README.md, then:
   git add README.md
   git commit -m "Add usage examples to README"
   git push -u origin add-usage-examples
   ```
8. In the Gitea web UI, open a **pull request** from `add-usage-examples` into `main` with a clear title and description of what and why.
9. Have your mentor (or a teammate) review it. Then merge the PR in Gitea, and locally:
   ```bash
   git switch main
   git pull
   git branch -d add-usage-examples
   ```

## Deliverable
A `module3-scripts` repo on Gitea showing: a merge commit that resolved a real conflict, and a merged pull request from `add-usage-examples` into `main`. Your local `main` matches `origin/main`.

## Acceptance criteria — you're done when:
- [ ] You created a feature branch with `git switch -c` and committed on it.
- [ ] A genuine merge conflict occurred on the same line of `README.md` and you resolved it (no conflict markers remain in the file).
- [ ] `git log --oneline --graph --all` shows the merge commit joining the two lines of work.
- [ ] You pushed a second branch and opened a pull request into `main` on Gitea.
- [ ] The pull request was reviewed and merged in the Gitea web UI.
- [ ] After merging, `git pull` on `main` brings the change down and the feature branch is deleted locally.
- [ ] `git status` is clean and local `main` matches `origin/main`.

## Hints
- Lost in the middle of a conflict and want to start over? `git merge --abort` returns you to the pre-merge state.
- The final resolved line should be exactly what you want the file to read — you are not forced to pick one side; you can blend them.
- Verify no markers slipped through: `grep -n '<<<<<<<\|=======\|>>>>>>>' README.md` should print nothing.
- `git log --oneline --graph --all` is the best way to *see* that the branches merged.
- If pushing the second branch is rejected, you probably need to `git pull` on `main` first; re-read Lesson 4, section 5.
- Blocked for >~30 min after re-reading the lessons? Bring what you've tried to your mentor.