Skip to content

Commit 74cb19a

Browse files
brabojclaude
andcommitted
docs: fix typos and add push-rejection line in bare repo section
Fix missing space, "thumb rule" → "rule of thumb", and restore the line explaining that Git refuses the push to prevent desync. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a92a9c2 commit 74cb19a

1 file changed

Lines changed: 59 additions & 49 deletions

File tree

chapters/02-building-blocks.md

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,37 @@ A repository can be **local** (on your machine) or **remote** (on a
3737
server like GitHub). Git treats both as equals — you can push to and
3838
pull from any repository you have access to.
3939

40-
Git supports two repository layouts — **bare** and **non-bare**.
40+
Typically, the layout of a **local** repository has a .git
41+
folder with all the internals, and a working tree with your project. This type
42+
of layout is called a **non-bare repository**. The `.git` folder stores the
43+
full history and configuration. When you clone a repository, you get a regular
44+
repository with both the working tree and the `.git` folder.
4145

42-
A **bare repository** has no working tree — only the Git internals
43-
(objects, refs, config) and no checked-out files. Hosting services like
44-
GitHub and GitLab store repositories as bare on the server. When you
45-
edit a file through GitHub's web interface, GitHub creates a commit
46-
directly — it does not use a working tree.
46+
```text
47+
git clone project.git
48+
49+
PROJECT/
50+
│ readme.md # Working tree — your editable files
51+
└───.git # Repository internals (same as bare)
52+
├───hooks # Event scripts
53+
├───info # Repository metadata
54+
├───objects # All Git objects
55+
│ ├───info # Object storage metadata
56+
│ └───pack # Compressed object packs
57+
└───refs # Named references
58+
├───heads # Branch tips
59+
└───tags # Tag references
60+
```
4761

48-
> **Note:** "bare" and "remote" are not the same thing. A remote is any
49-
> repository you connect to via URL. Remotes are *usually* bare, but a
50-
> remote can also be a regular repository on another machine.
62+
In contrast, the layout of remote repositories on hosting services like GitHub
63+
and GitLab is a little bit different — they are **bare repositories**. A
64+
**bare repository** has no working tree — only the Git internals
65+
(objects, refs, config) and no checked-out files. When you edit a file through
66+
GitHub's web interface, GitHub creates a commit directly — it does not use a
67+
working tree.
5168

5269
```text
53-
git init --bare project.git
70+
git clone --bare project.git
5471
5572
PROJECT.GIT/
5673
├───hooks # Scripts that run on events (pre-commit, post-merge, etc.)
@@ -63,31 +80,22 @@ PROJECT.GIT/
6380
└───tags # Tag references
6481
```
6582

66-
A **non-bare repository** (also called a regular or working repository)
67-
is what you get when you clone or run `git init`. It has a working tree
68-
where you create, edit and delete files, plus a hidden `.git` folder
69-
that stores the full history and configuration.
83+
As a rule of thumb, if you see a `.git` folder, it's a regular repository with
84+
a working tree. If you see a folder that ends with `.git` but has no `.git`
85+
inside it, it's a bare repository.
86+
87+
Both git clone and git init can create either type of repository. By default,
88+
they create regular repositories with a working tree. To create a bare
89+
repository, use the `--bare` flag:
7090

7191
```text
72-
git clone project.git
92+
# creates a bare repository from a remote
93+
$ git clone --bare <repository-url>
7394
74-
PROJECT/
75-
│ readme.md # Working tree — your editable files
76-
└───.git # Repository internals (same as bare)
77-
├───hooks # Event scripts
78-
├───info # Repository metadata
79-
├───objects # All Git objects
80-
│ ├───info # Object storage metadata
81-
│ └───pack # Compressed object packs
82-
└───refs # Named references
83-
├───heads # Branch tips
84-
└───tags # Tag references
95+
# creates a new bare repository locally
96+
$ git init --bare <directory-name>
8597
```
8698

87-
The `.git` folder contains the same structure as a bare repository.
88-
The difference is that a non-bare repository also has a working tree
89-
next to it — the place where you do your actual work.
90-
9199
### Why bare repositories exist
92100

93101
Imagine two developers — Alice and Bob — working on the same project
@@ -102,46 +110,48 @@ his remote and sends changes directly into her `.git/` directory.
102110
│ files from A │ │ │
103111
│ + uncommitted │ │ │
104112
├──────────────────┤ ├──────────────────┤
105-
│ .git/ │ git push │ .git/ │
106-
│ main → B ───────│◄────────────│ main → B │
113+
│ .git/ │ git push │ .git/ │
114+
│ main → B ───────│◄────────────│ main → B │
107115
│ (moved by push) │ │ │
108116
└──────────────────┘ └──────────────────┘
109117
⚠ OUT OF SYNC
110118
branch says B, files say A
111119
```
112120

113-
The problem: when Bob sends his changes, Git updates the branch
114-
inside Alice's `.git/` to point to Bob's latest commit. But Alice's
115-
working tree is **not** updated — her files still reflect the old
116-
commit, plus whatever edits she has in progress. Alice's branch and
117-
her working tree are now out of sync. If she commits at this point,
118-
she unknowingly **reverts Bob's changes** — because her files do not
119-
contain them.
120-
121-
Git prevents this by refusing to accept changes sent to a non-bare
122-
repository that has the target branch checked out.
121+
The problem: when Bob pushes his changes, Git updates the branch
122+
inside Alice's `.git/` to point to Bob's latest commit immediately. But Alice's
123+
working tree is **not** updated — her files still reflect the old commit, plus
124+
whatever edits she has in progress. Alice's branch and her working tree are
125+
now out of sync. If she commits at this point, she unknowingly **reverts Bob's
126+
changes** — because her files do not contain them. Git prevents this by
127+
refusing to accept a push to a non-bare repository that has the target
128+
branch checked out.
123129

124-
The solution is to place a **bare repository** between the two
125-
developers. A bare repository has no working tree — it holds only
126-
objects and references. Because nobody edits files in it, updating a
127-
branch is always safe.
130+
A popular solution to this kind of synchronization problem is to decouple the
131+
direct push/pull between two developers and introduce an intermediary
132+
repository that both developers push to and pull from.
128133

129134
```text
130135
Alice (non-bare) Shared hub (bare) Bob (non-bare)
131136
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
132137
│ Working Tree │ │ │ │ Working Tree │
133-
│ │ │ objects + refs │ │ │
134-
├──────────────────┤ │ no working tree │ ├──────────────────┤
138+
│ │ │ objects + refs │ │ │
139+
├──────────────────┤ │ no working tree │ ├──────────────────┤
135140
│ .git/ │ │ │ │ .git/ │
136141
│ │◄───│ │◄───│ │
137142
└──────────────────┘ └──────────────────┘ └──────────────────┘
138143
pull push
139144
(when ready)
140145
```
141146

147+
This is called a **shared hub**. The shared hub is a bare repository — it has no
148+
working tree, only the Git internals. Its purpose is to hold commits and
149+
references, not to be edited directly. Because nobody edits files in it,
150+
updating a branch is always safe.
151+
142152
With a bare repository in the middle, each developer works
143153
independently. Bob sends his changes to the bare repository whenever
144-
he is ready. Alice commits her own work first, then downloads Bob's
154+
he is ready. Alice commits her own work first, then pulls Bob's
145155
changes from the bare repository when **she** is ready. No one
146156
reaches into anyone else's working tree. This is exactly how
147157
hosting services like GitHub and GitLab work — every repository on

0 commit comments

Comments
 (0)