Working with documentation files
Beginner Core Git GitLab UI GitHub UI
Why this matters
Documentation in a repository is code-adjacent: reviewed, versioned, built and deployed like the program. That gives you history and review; it also imposes a few conventions, and one real limitation: Git is excellent with text and poor with images. Knowing both keeps your documentation changes small, reviewable and fast to clone.
Where documentation lives
Most projects follow this layout, and the playground does:
| Place | Content |
|---|---|
README.md at the root |
Entry point: what, how to run, links |
docs/ |
Guides, references, decisions; one Markdown file per page, sometimes subfolders per topic |
docs/images/ (or docs/assets/) |
Images the pages use |
CONTRIBUTING.md, CHANGELOG.md, LICENSE at the root |
Conventions, release history, legal |
| A wiki (GitLab, GitHub) | Sometimes used for informal notes; it is a separate repository behind the scenes |
If a documentation site is generated (MkDocs, Docusaurus, Sphinx, or GitLab/GitHub Pages), there is also a configuration file at the root (mkdocs.yml, docusaurus.config.js) that lists the pages in navigation order. Adding a page often means adding a line there too; look at how existing pages are registered.
Naming and linking
- File names: lowercase, words separated by hyphens,
.mdextension:getting-started.md,release-process.md. No spaces (they break links), no capitals (case-sensitive systems treatFaq.mdandfaq.mdas different files). - Links between pages: relative to the current file:
[FAQ](faq.md),[install](../README.md). They work on GitLab, GitHub, in editor previews and on generated sites. Absolute paths or full URLs to the repository break when the project moves. - Links to headings:
[see the rules](contributing.md#branches); the anchor is the heading text lowercased with hyphens. - One page, one topic, with a single
#title at the top.
Images and other binaries
Git stores any file, but it treats text and binaries very differently:
$ git diff --staged --stat docs/images/photo.png | Bin 0 -> 9 bytes
1 file changed, 0 insertions(+), 0 deletions(-)$ git diff --stageddiff --git a/docs/images/photo.png b/docs/images/photo.png
new file mode 100644
index 0000000..aa860ab
Binary files /dev/null and b/docs/images/photo.png differ"Binary files differ" is all Git can say: no lines, no review of what changed, and no merging if two people change the same image. Every version of every image stays in history forever, so a 3 MB screenshot replaced ten times costs 30 MB for everyone who clones.
Rules of thumb:
- Prefer SVG for diagrams (it is text: diffable, small, scales). Draw.io and Excalidraw export it.
- Compress screenshots (PNG, under 300 KB; crop to the relevant part). Store them in
docs/images/with descriptive names:merge-request-approve-button.png. - Never commit videos, large PDFs or datasets to a documentation repository; link to where they live.
- Reference images relatively:
.
Git LFS
For projects that genuinely need large or frequently changed binaries (design files, datasets, game assets), Git LFS (Large File Storage) stores the file contents outside the repository and keeps only small pointers in Git. GitLab and GitHub both support it. You recognize an LFS project by a .gitattributes file with lines such as *.psd filter=lfs diff=lfs merge=lfs -text, and by needing the git lfs extension installed before cloning. Lesson 13.10 explains what to do when you meet one; a documentation project rarely needs it.
In the platforms
Nothing special: create the Markdown file and the image, git add docs/, commit with a docs: prefix, push. Check the size of what you are adding before committing: ls -lh docs/images/.
Markdown preview (Ctrl+K then V) renders relative image links so you can verify them before committing. Dragging an image into the Explorer copies it into the folder; drag it while holding Shift into an open Markdown file and VS Code inserts the image link for you.
The Markdown preview renders relative images. Pasting an image into a Markdown file (Ctrl+V / ⌘V with an image on the clipboard) offers to save it into a folder and insert the link. Check the folder is docs/images/, not the project root.
GitLab renders images referenced relatively when viewing a Markdown file, and shows image diffs side by side (before/after, with a slider) in merge requests. Files over the project's size limit (typically 100 MB) are rejected on push. Dragging an image into an issue or merge request description uploads it to GitLab and inserts a link — convenient there, but such uploads are not part of the repository.
GitHub renders relative images and shows image diffs in pull requests (2-up, swipe, onion skin). Files over 100 MB are rejected; over 50 MB triggers a warning. Images dropped into issue comments are hosted by GitHub outside the repository, like on GitLab.
Common mistakes
- Spaces in file names.
Getting Started.mdneeds%20in links and breaks on some sites. Use hyphens. - Absolute links.
/Users/ana/…orC:\…work for one person only. - Uncompressed screenshots. Full-screen 4K PNGs are several megabytes each. Crop and compress.
- Editing an image many times in a branch. Each version is stored; squash the branch on merge or replace the image once at the end.
- Committing generated site output (
site/,_build/,public/) instead of the source. Ignore it; the pipeline builds it.
Try it yourself
Goal: add a documentation page with an image and a link, and read the diff.
- Copy the playground's logo as a new image:
cp docs/images/logo.svg docs/images/trail-icon.svg. - Create
docs/icons.mdwith a title, one sentence, an image link toimages/trail-icon.svgand a link tofaq.md. - Preview it in your editor; then
git add docs/andgit diff --staged --stat.
Expected result: the stat shows the Markdown file with a few insertions and the SVG as a text file with insertions too (SVG is text, so Git can diff it). A PNG would show Bin.
Show solution
# Icons
The trail icon used in the guide.

See also the [FAQ](faq.md).git diff --staged shows its content line by line; that is one reason to prefer SVG for diagrams.