README files and Markdown¶
The first thing a visitor sees on a repository page is its README. For the homelab, it is also the first thing Sam reads when coming back to the project after a few months. It is written in Markdown, the formatting language used everywhere on GitHub: files, issues, pull requests, and comments.
Editing a file in the browser¶
Small changes do not need a clone. On the repository page:
- Click
README.mdin the file list, or the pencil icon on the README displayed below it (Edit file). - Edit the text in the Edit tab. The Preview tab shows the result, rendered as it will appear on GitHub.
- Click Commit changes..., write a commit message (GitHub suggests
Update README.md), and choose Commit directly to themainbranch. - Click Commit changes.
The commit is an ordinary Git commit, authored by your GitHub account. Local clones receive it with git pull. Editing files and committing from the browser is covered in detail on Managing files on GitHub.
The full editor: .
On any repository page, press the . key: GitHub opens github.dev, a code editor (Visual Studio Code) in the browser, with every file of the repository. It is handy to change several files in a single commit.
Markdown basics¶
Markdown is plain text with a few symbols for formatting. The text stays readable as is, and GitHub renders it as formatted HTML. GitHub uses its own variant, GitHub Flavored Markdown (GFM).
Headings¶
A line starting with # is a heading. The number of # sets the level, from 1 (largest) to 6 (smallest):
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
The space after the # is required: #Homelab is displayed as plain text. On GitHub, levels 1 and 2 are underlined by a thin line. Use a single level 1 heading, as the title of the document.
Text formatting¶
| Markdown | Result |
|---|---|
**bold** |
bold |
*italics* or _italics_ |
italics |
***bold and italics*** |
bold and italics |
~~strikethrough~~ |
~~strikethrough~~ |
`inline code` |
inline code |
Paragraphs and line breaks¶
A blank line separates two paragraphs. A single line break inside a paragraph is displayed as a space: in Markdown files, lines are joined. To force a line break, end the line with a backslash \ (or two spaces).
In issues, pull requests, and comments, GitHub keeps single line breaks as they are typed.
Links¶
[Pi-hole](https://pi-hole.net/)
[the inventory](inventory.csv)
<https://github.com>
[text](url): a link. No space between]and(.- A relative path such as
inventory.csvlinks to a file of the repository, on the current branch. <url>: the URL itself, as a clickable link. On GitHub, plain URLs are also made clickable automatically.
Images¶

The syntax is a link preceded by !. The text in brackets is the alternative text, read by screen readers and displayed if the image cannot be loaded. The path can be relative, as for links. On GitHub, paths are case-sensitive: docs/Network.png and docs/network.png are two different files.
In the web editor, you can also drag and drop an image into the text: GitHub uploads it and inserts the Markdown, with a https://github.com/user-attachments/... URL.
Lists¶
- DNS server
- NAS
- Samba shares
- Backups
1. Unplug the NAS
2. Replace the disk
3. Start the rebuild
-,*or+start an unordered item. Indent to nest a list.1.starts a numbered item. GitHub numbers items in order, whatever the numbers typed.- Leave a blank line between a paragraph and the list that follows it.
Task lists add checkboxes. They are especially useful in issues and pull requests, where they can be ticked directly:
- [x] Install Pi-hole
- [ ] Configure backups
Code blocks¶
Wrap code between two lines of three backticks. The language name after the first backticks enables syntax highlighting:
```bash
git clone https://github.com/sam-rivera/homelab.git
```
Tables¶
| Hostname | IP | Role |
|---|---|---|
| pi-dns | 192.168.1.10 | dns |
| nas | 192.168.1.20 | storage |
The second line separates the header from the rows. Colons set the alignment: |:---| left, |:---:| centered, |---:| right.
Quotes and alerts¶
A line starting with > is a quotation. GitHub also renders five kinds of highlighted alerts:
> [!WARNING]
> The NAS is not backed up off-site yet.
The kinds are [!NOTE], [!TIP], [!IMPORTANT], [!WARNING] and [!CAUTION].
Escaping¶
To display a Markdown symbol as is, put a backslash before it: \*not italics\*, \# not a heading.
Writing a good README¶
A README must let anyone understand the project without help: a new contributor, a user, or yourself in six months.
The fundamentals¶
| Section | Content |
|---|---|
| Title | The name of the project, as the only level 1 heading |
| Description | What the project is and does, and why it exists |
| Technologies | What it uses, and why those choices |
| Installation and usage | How to get it running, step by step, with commands in code blocks |
| Contents | What the repository contains: the main files and folders |
| Table of contents | Links to the sections, for long READMEs |
On GitHub, the Outline button at the top right of a rendered Markdown file lists its headings automatically. A manual table of contents uses links to headings: [Hardware](#hardware). The anchor is the heading in lowercase, with spaces replaced by - and most punctuation removed.
Extras¶
Depending on the project: how it came about and the motivation, the problem it solves and its intended use, known limitations and challenges, how to contribute, credits, and the license.
Sam's README¶
# homelab
Notes and inventory of my home servers: what runs where, and how to rebuild it.
## Contents
| File | Content |
|---|---|
| [inventory.csv](inventory.csv) | One line per machine: `hostname,ip,role` |
| [services.md](services.md) | Which service runs on which machine |
## Network
All machines are on `192.168.1.0/24`. The DNS server is **pi-dns**.
## To do
- [x] Inventory every machine
- [ ] Document the backup job
- [ ] Draw the network diagram
Where GitHub looks for the README¶
GitHub displays the first README it finds in the .github/ folder, then at the root of the repository, then in docs/. Each folder can also have its own README.md, displayed when you browse that folder.
A repository with the same name as your username (for example sam-rivera/sam-rivera) is special: its README is displayed on your profile page. It is the usual way to present yourself on GitHub.
Summary¶
| Markdown | Result |
|---|---|
# to ###### + space |
Headings, levels 1 to 6 |
**bold**, *italics*, ~~strike~~ |
Text formatting |
`code` and ``` blocks |
Inline code and code blocks |
[text](url) |
Link, absolute or relative to the repository |
 |
Image |
- / 1. / - [ ] |
Unordered list, numbered list, task list |
Rows of cells between pipes, then a --- separator line under the header |
Table |
> and > [!NOTE] |
Quote and alert |
Common mistakes¶
- No space after
#.#Titleis not a heading. - A space between
]and(.[text] (url)is not a link. - Expecting a single line break to show. In files, it becomes a space: use a blank line or a trailing
\. - Wrong case in an image path. Paths are case-sensitive on GitHub.
- A README that only contains the title. Describe what the project is, why, and how to use it.
Hands-on labs¶
Three labs, from guided to more autonomous. They need your GitHub account. Replace <username> with your GitHub username.
Lab 1: format a README in the browser¶
Objective: edit a README with the web editor, check the rendering with the preview, commit, and receive the commit locally.
Prerequisites and initial state: a GitHub account, Git installed. Lab 1 recreates a fresh practice repository.
Setup: on GitHub, create a public repository homelab-practice-2, with a README and no other file. Then:
mkdir -p ~/git-practice/readme && cd ~/git-practice/readme
git clone https://github.com/<username>/homelab-practice-2.git
Tasks:
- On GitHub, edit
README.md(pencil icon). Below the title, add a description sentence with the word homelab in bold and the word notes in italics. - Add a level 2 heading
Machines, followed by a table with the columns Hostname, IP, Role, and two rows (pi-dns,192.168.1.10,dnsandnas,192.168.1.20,storage). - Add a level 2 heading
Links, followed by a list with a link tohttps://pi-hole.net/labeledPi-hole. - Add a level 2 heading
To do, followed by a task list with one ticked and one unticked item. - Check the Preview tab, fix anything that does not render, then commit directly to
mainwith the messageDescribe the homelab in the README. - In the terminal, pull the change into your clone, and display the latest commit.
Expected result and verification:
- The repository page shows the README with a table, a clickable link, and checkboxes. The Outline button lists
Machines,Links, andTo do. git pullin the clone is a fast-forward, andgit log -1showsDescribe the homelab in the README, with your GitHub account as the author.
Solution
# homelab-practice-2
The **homelab** repository contains the *notes* of my home servers.
## Machines
| Hostname | IP | Role |
|---|---|---|
| pi-dns | 192.168.1.10 | dns |
| nas | 192.168.1.20 | storage |
## Links
- [Pi-hole](https://pi-hole.net/)
## To do
- [x] Inventory every machine
- [ ] Document the backup job
cd ~/git-practice/readme/homelab-practice-2
git pull # Fast-forward
git log -1
- Commits made in the browser use your GitHub account as author, with your
noreplyaddress if your email is private. - Pulling from a public repository needs no authentication; pushing will (see Authenticating with personal access tokens).
Keep homelab-practice-2 for Lab 2. Clean up the clone when you are done: rm -rf ~/git-practice/readme.
Lab 2: repair a broken README¶
Objective: find and fix the most common Markdown mistakes, using the preview.
Prerequisites and initial state: the repository homelab-practice-2 from Lab 1 (or any repository of yours). The setup creates the broken file locally, to copy and paste.
Setup:
mkdir -p ~/git-practice/broken-readme && cd ~/git-practice/broken-readme
cat > README.md <<'EOF'
#Homelab
Notes about my home servers.
The DNS server runs Pi-hole.
Machines:
- pi-dns
- nas
See [the official site] (https://pi-hole.net/) for details.

| Hostname | IP |
| pi-dns | 192.168.1.10 |
EOF
cat README.md
Tasks:
- On GitHub, open
README.mdofhomelab-practice-2in the editor, replace its content with the broken file, and open the Preview tab (do not commit). List everything that does not render as intended. - Fix each problem in the editor, checking the preview after each fix. The second and third lines must stay on two separate lines. The image is stored at
docs/network.png. - Commit the fixed file with the message
Fix README formatting.
Expected result and verification:
- The problems found: the title is not a heading; the two sentences are merged on one line; the link is not clickable; the table is displayed as plain text; the image is broken (and would stay broken until a
docs/network.pngfile exists, with that exact case). - After the fixes, the preview shows a level 1 heading, a working link, and a two-column table.
Solution
# Homelab
Notes about my home servers.\
The DNS server runs Pi-hole.
Machines:
- pi-dns
- nas
See [the official site](https://pi-hole.net/) for details.

| Hostname | IP |
|---|---|
| pi-dns | 192.168.1.10 |
| Problem | Fix |
|---|---|
#Homelab |
A space after # |
| Lines merged | A trailing \ (or a blank line, for two paragraphs) |
] ( in the link |
No space between ] and ( |
| Table rendered as text | The separator line under the header row, and a blank line before the table |
Network.png |
The exact case: network.png |
- GitHub is tolerant about the list directly after
Machines:, but a blank line before a list is the safe habit: other Markdown renderers require it. - The image stays broken until the file exists. Upload one on the next page if you want to see it.
Clean up when you are done: rm -rf ~/git-practice/broken-readme, and delete homelab-practice-2 on GitHub (Settings > General > Danger Zone), unless you want to keep it for the next page.
Lab 3: your profile README¶
Objective: write a complete README from scratch, for a repository GitHub treats specially: your profile.
Prerequisites and initial state: a GitHub account. No repository named exactly like your username.
Tasks:
- Create a public repository named exactly like your username, with a README. GitHub shows a message about this special repository on the creation form.
- Write the README as a presentation of yourself, with: a title, a short description, a level 2 section listing what you are learning (with a task list of your progress in these notes), a table of the tools you use, and at least one link.
- Commit, then open your profile page.
- Decide whether to keep it. If you delete the repository, the profile goes back to its default display.
Expected result and verification:
- Your profile page (
https://github.com/<username>) displays the README above your pinned repositories. - The README contains a level 1 heading, at least one level 2 heading, a task list, a table, and a link, all rendered correctly.
Solution
# Hi, I'm Sam
I run a small homelab and I am preparing the **GitHub Foundations** certification.
## Learning
- [x] Introduction to Git
- [x] Intermediate Git
- [ ] Introduction to GitHub
## Tools
| Area | Tools |
|---|---|
| Servers | Raspberry Pi, Debian |
| Services | Pi-hole, Samba |
## Links
- [My notes](https://github.com/<username>)
- The profile README is the only README displayed outside its repository.
- It follows the same rules as any README: describe, structure, link.
To clean up, delete the <username>/<username> repository if you do not want to keep it.