diff --git a/assets/drawio/git-bare-after.drawio b/assets/drawio/git-bare-after.drawio
new file mode 100644
index 0000000..0d50fc4
--- /dev/null
+++ b/assets/drawio/git-bare-after.drawio
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/drawio/git-bare-before.drawio b/assets/drawio/git-bare-before.drawio
new file mode 100644
index 0000000..6c46b42
--- /dev/null
+++ b/assets/drawio/git-bare-before.drawio
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/drawio/git-bare-overwrite.drawio b/assets/drawio/git-bare-overwrite.drawio
new file mode 100644
index 0000000..664ede4
--- /dev/null
+++ b/assets/drawio/git-bare-overwrite.drawio
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/images/git-bare-after.png b/assets/images/git-bare-after.png
new file mode 100644
index 0000000..78e1fd3
Binary files /dev/null and b/assets/images/git-bare-after.png differ
diff --git a/assets/images/git-bare-before.png b/assets/images/git-bare-before.png
new file mode 100644
index 0000000..7e0a557
Binary files /dev/null and b/assets/images/git-bare-before.png differ
diff --git a/assets/images/git-bare-overwrite.png b/assets/images/git-bare-overwrite.png
new file mode 100644
index 0000000..056e7fc
Binary files /dev/null and b/assets/images/git-bare-overwrite.png differ
diff --git a/chapters/02-building-blocks.md b/chapters/02-building-blocks.md
index edabfbe..46a7148 100644
--- a/chapters/02-building-blocks.md
+++ b/chapters/02-building-blocks.md
@@ -37,19 +37,36 @@ A repository can be **local** (on your machine) or **remote** (on a
server like GitHub). Git treats both as equals — you can push to and
pull from any repository you have access to.
-Git supports two repository layouts:
+### Repository Layouts
-### Bare Repository
+Typically, the layout of a **local** repository has a `.git`
+folder with all the internals, and a working tree with your project. This type
+of layout is called a **non-bare repository**. The `.git` folder stores the
+full history and configuration. When you clone a repository, you get a
+non-bare repository by default.
-A **bare repository** is a Git repository without a working tree — it
-contains only the `.git` internals (objects, refs, config) and no
-checked-out files. Hosting services like GitHub and GitLab store repositories as bare
-on the server. When you edit a file through GitHub's web interface,
-GitHub creates a commit directly — it does not use a working tree.
+```text
+git clone project.git
-> **Note:** "bare" and "remote" are not the same thing. A remote is any
-> repository you connect to via URL. Remotes are *usually* bare, but a
-> remote can also be a regular repository on another machine.
+PROJECT/
+│ readme.md # Working tree — your editable files
+└───.git # Repository internals
+ ├───hooks # Event scripts
+ ├───info # Repository metadata
+ ├───objects # All Git objects
+ │ ├───info # Object storage metadata
+ │ └───pack # Compressed object packs
+ └───refs # Named references
+ ├───heads # Branch tips
+ └───tags # Tag references
+```
+
+In contrast, the layout of remote repositories on hosting services like GitHub
+and GitLab is different — they are **bare repositories**. A
+**bare repository** has no working tree — only the Git internals
+(objects, refs, config) and no editable files. When you edit a file through
+GitHub's web interface, GitHub creates a commit directly — it does not use a
+working tree.
```text
git init --bare project.git
@@ -65,32 +82,88 @@ PROJECT.GIT/
└───tags # Tag references
```
-### Non-bare Repository
+As a rule of thumb, if you see a `.git` folder, it's a regular repository with
+a working tree. If you see a folder that ends with `.git` but has no `.git`
+inside it, it's a bare repository.
-A **non-bare repository** (also called a regular or working repository)
-is what you get when you clone or run `git init`. It has a working tree
-where you create, edit and delete files, plus a hidden `.git` folder
-that stores the full history and configuration.
+Both `git clone` and `git init` can create either type of repository. By default,
+they create regular repositories with a working tree. To create a bare
+repository, use the `--bare` flag:
```text
-git clone project.git
+# creates a bare repository from a remote
+$ git clone --bare
-PROJECT/
-│ readme.md # Working tree — your editable files
-└───.git # Repository internals (same as bare)
- ├───hooks # Event scripts
- ├───info # Repository metadata
- ├───objects # All Git objects
- │ ├───info # Object storage metadata
- │ └───pack # Compressed object packs
- └───refs # Named references
- ├───heads # Branch tips
- └───tags # Tag references
+# creates a new bare repository locally
+$ git init --bare
```
-The `.git` folder contains the same structure as a bare repository.
-The difference is that a non-bare repository also has a working tree
-next to it — the place where you do your actual work.
+### Why bare repositories exist
+
+Imagine two developers — Alice and Bob — working on the same project
+over a local network. Each has a non-bare repository with a working
+tree. There is no central server — Bob pushes his changes directly
+into Alice's `.git/` directory.
+
+
+
+The problem: when Bob pushes his changes, Git updates the branch
+inside Alice's `.git/` to point to Bob's latest commit immediately.
+But Alice's working tree is **not** updated — her files still reflect
+the old commit, plus whatever edits she has in progress. Alice's
+branch and her working tree are now out of sync. If she commits at
+this point, she unknowingly **reverts Bob's changes** without any
+error or warning — because her files do not contain them.
+
+
+
+What if the two developers never touch each other's repositories
+directly? A popular solution to this kind of synchronization problem
+is to introduce an intermediary repository that both developers push
+to and pull from.
+
+
+
+This is called a **shared hub**. The shared hub is a bare repository — it has no
+working tree, only the Git internals. Its purpose is to hold commits and
+references, not to be edited directly. Because nobody edits files in it,
+updating a branch is always safe.
+
+With a bare repository in the middle, each developer works
+independently. Bob pushes his changes to the bare repository whenever
+he is ready. Alice commits her own work first, then pulls Bob's
+changes from the bare repository when **she** is ready. No one
+reaches into anyone else's working tree. This is exactly how
+hosting services like GitHub and GitLab work — every repository on
+the server is bare.
+
+### The core.bare flag
+
+Git controls this with a configuration flag called `core.bare`, stored
+inside the repository's config file:
+
+```text
+$ cat project.git/config
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = true
+```
+
+In a non-bare repository, `bare = false` — the default. Git checks
+this flag when receiving a push: if it is `false`, the push is
+rejected to protect the working tree. Only bare repositories have
+`bare = true`, which tells Git there is no working tree and pushes
+are safe to accept. The `git init --bare` command sets this flag
+automatically.
+
+Now, when Bob pushes to Alice's repository, Git checks `core.bare` and
+rejects the push because it is not a bare repository. This prevents
+Alice from silently overwriting Bob's changes on her next commit.
+
+Bob must push to a shared hub (a bare repository) instead, and Alice must
+pull from it. This way, both developers have control over when they receive
+each other's changes, and there are no surprises.
## 3. Object Model
diff --git a/chapters/07-playbook.md b/chapters/07-playbook.md
index 758e197..cfaa6b5 100644
--- a/chapters/07-playbook.md
+++ b/chapters/07-playbook.md
@@ -39,6 +39,7 @@ For definitions, see [Glossary](09-glossary.md).
| [Remote Operations](playbook/remote-operations.md) | Push, pull, force push safely, sync forks |
| [Remote Management](playbook/remote-management.md) | Add, rename, remove remotes, switch URL, SSH setup |
| [SSH Setup](playbook/ssh-setup.md) | Key generation, agent, GitHub registration, troubleshooting |
+| [Bare Repositories](playbook/bare-repositories.md) | Create, clone, convert, and use bare repos as local remotes |
## Project Structure
diff --git a/chapters/recipes/bare-repositories.md b/chapters/recipes/bare-repositories.md
new file mode 100644
index 0000000..8471cb2
--- /dev/null
+++ b/chapters/recipes/bare-repositories.md
@@ -0,0 +1,147 @@
+---
+title: "Bare Repositories"
+description: "Git recipes for creating, cloning, and working with bare repositories — the standard layout for central and shared repositories."
+section: "playbook/bare-repositories"
+order: 93
+---
+
+## Bare Repositories
+
+A bare repository has no working tree — only the Git internals (objects,
+refs, config). It is the standard layout for central repositories that
+multiple developers push to. Hosting services like GitHub and GitLab
+store every repository as bare on the server.
+
+For the theory behind bare vs non-bare repositories, see
+[Building Blocks](../02-building-blocks.md#2-repository).
+
+### Create a bare repository
+
+```text
+$ git init --bare project.git
+Initialized empty Git repository in /home/user/project.git/
+```
+
+The `.git` suffix is a convention, not a requirement — it signals that
+the directory is a bare repository.
+
+### Compare the layouts
+
+```text
+# Bare — no working tree, internals at the top level
+project.git/
+├── HEAD
+├── config
+├── hooks/
+├── objects/
+└── refs/
+
+# Non-bare — working tree + .git folder
+project/
+├── .git/
+│ ├── HEAD
+│ ├── config
+│ ├── hooks/
+│ ├── objects/
+│ └── refs/
+└── README.md
+```
+
+In a bare repository, what normally lives inside `.git/` sits at the
+top level. There is no place to check out files.
+
+### Use a bare repository as a local remote
+
+This is the most common use case — simulate a central server on your
+own machine for practice or local collaboration.
+
+```text
+# 1. Create the bare (central) repository
+$ git init --bare /tmp/central.git
+
+# 2. Clone it into a working copy
+$ git clone /tmp/central.git /tmp/dev-alice
+$ cd /tmp/dev-alice
+
+# 3. Make a commit and push
+$ echo "Hello" > greeting.txt
+$ git add greeting.txt
+$ git commit -m "Add greeting"
+$ git push origin main
+
+# 4. Clone again to simulate a second developer
+$ git clone /tmp/central.git /tmp/dev-bob
+$ cd /tmp/dev-bob
+$ cat greeting.txt
+Hello
+```
+
+Both clones push to and pull from the same bare repository, exactly
+like working with GitHub.
+
+### Convert a non-bare repository to bare
+
+```text
+$ git clone --bare project project.git
+```
+
+This copies only the Git data — no working tree files. The result is
+a bare repository you can use as a central remote.
+
+You can also convert in place:
+
+```text
+$ cd project
+$ mv .git ../project.git
+$ cd ..
+$ rm -rf project
+$ cd project.git
+$ git config --bool core.bare true
+```
+
+### Clone a bare repository
+
+```text
+$ git clone --bare https://github.com/user/project.git
+```
+
+Useful for creating mirrors or backup copies that do not need a
+working tree.
+
+### Push to a non-bare repository (and why it fails)
+
+Pushing to a non-bare repository is rejected by default:
+
+```text
+$ git push /tmp/dev-alice main
+remote: error: refusing to update checked out branch: refs/heads/main
+```
+
+Git refuses because a push updates the branch reference but not the
+working tree — this would leave the two out of sync and could cause
+the recipient to unknowingly revert the pushed changes on their next
+commit. For a full walkthrough of the problem, see
+[Building Blocks — Why bare repositories exist](../02-building-blocks.md#why-bare-repositories-exist).
+
+If you need to accept pushes on a non-bare repository (rare), you
+can enable it:
+
+```text
+$ git config receive.denyCurrentBranch updateInstead
+```
+
+This tells Git to update both the branch and the working tree on push.
+Use this only for special setups like deployment targets — not for
+regular development.
+
+### Gotchas
+
+- **You cannot run `git add` or `git commit` in a bare repository** —
+ there is no working tree to stage files from. All changes must arrive
+ via `git push` from another repository.
+- **The `.git` suffix is convention only.** Git does not require it,
+ but omitting it makes the directory harder to identify.
+- **Bare does not mean read-only.** A bare repository accepts pushes,
+ runs hooks, and stores the same history as a non-bare one.
+- **`git clone` of a bare repository produces a non-bare clone by
+ default.** Use `git clone --bare` if you want another bare copy.