├── .gitignore └── gitfromtheinsideout ├── diagrams.graffle ├── essay.md └── images ├── 1-a1-tree-graph.png ├── 10-a3-detached-head.png ├── 11-a3-on-deputy.png ├── 12-a3-on-master-on-a2.png ├── 13-a3ondeputy.png ├── 14-a3-on-master-on-a2.png ├── 15-a3-on-master.png ├── 16-a4-b3-on-deputy.png ├── 17-a4-b3-on-deputy.png ├── 18-b4-on-deputy.png ├── 19-b6-on-master.png ├── 2-a1-commit.png ├── 20-b6-on-master-with-merge-head.png ├── 21-b13-on-master.png ├── 22-b13-with-objects-wc-and-index.png ├── 23-b13-letter-removed-from-wc-and-index.png ├── 24-13.png ├── 25-13-cp-alpha-to-bravo.png ├── 26-14-bravo.png ├── 27-14-fetched-to-alpha.png ├── 28-14-merged-to-alpha.png ├── 29-15-alpha-cloned-to-delta-bare.png ├── 3-a1-refs.png ├── 30-16-alpha.png ├── 31-16-pushed-to-delta.png ├── 4-a1-wc-and-index.png ├── 5-a1-wc-number-set-to-2.png ├── 6-a1-wc-and-index-number-set-to-2.png ├── 7-a2.png ├── 8-a2-just-objects-commits-and-refs.png └── 9-a2-detached-head.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /gitfromtheinsideout/diagrams.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/diagrams.graffle -------------------------------------------------------------------------------- /gitfromtheinsideout/essay.md: -------------------------------------------------------------------------------- 1 | Hi everyone. Thanks for visiting. This content is a draft. The final version of the essay (complete with working images) is here: https://codewords.recurse.com/issues/two/git-from-the-inside-out 2 | 3 | --------------------------------------------- 4 | 5 | # Git from the inside out 6 | 7 | This essay shows you how Git works. It focuses on the graph that underpins Git and how the properties of this graph dictate the behaviors of Git. This focus on fundamentals lets you build your mental model on the truth, rather than on hypotheses constructed from evidence gathered while experimenting with the API. This truer model gives you a better understanding of what Git has done, what it is doing and what it will do. 8 | 9 | The text is structured as a series of Git commands run on a single project. At intervals, there are observations about the graph data structure that Git is built on. These observations illustrate a property of the graph and the behavior that this property produces. 10 | 11 | It is assumed that you understand Git well enough to use it to version control your projects. 12 | 13 | ## Create a project 14 | 15 | ```bash 16 | ~ $ mkdir alpha 17 | ~ $ cd alpha 18 | ``` 19 | 20 | The user creates `alpha`, a directory for their project. 21 | 22 | ```bash 23 | ~/alpha $ mkdir data 24 | ~/alpha $ printf 'a' > data/letter.txt 25 | ``` 26 | 27 | They move into the `alpha` directory and create a directory called `data`. Inside, they create a file called `letter.txt` that contains `a`. The alpha directory looks like this: 28 | 29 | ``` 30 | alpha 31 | └── data 32 | └── letter.txt 33 | ``` 34 | 35 | # Initialize a repository 36 | 37 | ```bash 38 | ~/alpha $ git init 39 | Initialized empty Git repository 40 | ``` 41 | 42 | `git init` turns the current directory into a Git repository. To do this, it creates a `.git` directory and writes some files to it. These files define everything about the configuration and history of a project. They are just ordinary files. No magic in them. The user can read and change them with a text editor or shell. Which is to say: the user can read and edit the history of their project as easily as their project files. 43 | 44 | The `alpha` directory now looks like this: 45 | 46 | ``` 47 | alpha 48 | ├── data 49 | | └── letter.txt 50 | └── .git 51 | ├── objects 52 | etc... 53 | ``` 54 | 55 | 56 | The `.git` directory and its contents are Git's. All the other files are collectively known as the working copy. They are the user's. 57 | 58 | ## Add some files 59 | 60 | ``` 61 | ~/alpha $ git add data/letter.txt 62 | ``` 63 | 64 | The user runs `git add` on the `data/letter.txt` file. This has two effects. 65 | 66 | First, it creates a new blob file in the directory at `alpha/.git/objects/`. 67 | 68 | This file contains the compressed content of the `data/letter.txt` file. 69 | 70 | The name of this file is derived by hashing the file's content. Hashing a piece of text means running a program on it that turns it into a smaller[^1] piece of text that uniquely[^2] identifies the original. For example, Git hashes `a` to `5e40c0877058c504203932e5136051cf3cd3519b`. This hash is a short, unique identifier for the current content of `number.txt`. The first two characters are used as the name of a directory inside `alpha/.git/objects/`: `5e`. The rest of the hash is used as the name of the file that holds the content of added file: `40c0877058c504203932e5136051cf3cd3519b`. 71 | 72 | Notice how just adding a file to Git saves its content to the objects directory. If the user were to delete the `data/letter.txt` file the working copy, its content would still be safe inside Git. 73 | 74 | Second, `git add` adds the file to the index. The index is a list that contains every file that Git has been told to keep track of. It is just a file that lives at `alpha/.git/index`. Each line of the file maps a tracked file to a hash of its content at the moment it was added. 75 | 76 | ``` 77 | data/letter.txt 5e40c0877058c504203932e5136051cf3cd3519b 78 | ``` 79 | 80 | ```bash 81 | ~/alpha $ printf '1234' > data/number.txt 82 | ``` 83 | 84 | The user makes a file called `data/number.txt` that contains `1234`. The working copy looks like this: 85 | 86 | ```text 87 | alpha 88 | └── data 89 | └── letter.txt 90 | └── number.txt 91 | ``` 92 | 93 | ```bash 94 | ~/alpha $ git add data 95 | ``` 96 | 97 | The user adds the file to Git. This creates a blob file that contains the content of `data/number.txt`. And it adds another index entry that maps the `data/number.txt` file to a hash of its content. 98 | 99 | ``` 100 | data/letter.txt 5e40c0877058c504203932e5136051cf3cd3519b 101 | data/number.txt 274c0052dd5408f8ae2bc8440029ff67d79bc5c3 102 | ``` 103 | 104 | Note that, though the user ran `git add data`, only the files in the `data` directory are listed. The `data` directory is not listed separately. 105 | 106 | ```bash 107 | ~/alpha $ printf '1' > data/number.txt 108 | ~/alpha $ git add data 109 | ``` 110 | 111 | When the user originally created `data/number.txt`, they meant to type `1`, not `1234`. They make the correction and add the file to the index again. This creates a new blob with the new content. It updates the index entry for `data/number.txt` so it maps to the hash of the latest content. 112 | 113 | ## Make a commit 114 | 115 | ```bash 116 | ~/alpha $ git commit -m 'a1' 117 | [master (root-commit) c388d51] a1 118 | ``` 119 | 120 | Committing has three steps. It creates a tree graph to represent the content of the version being committed. It creates a commit object. It pointsthe current branch at the new commit object. 121 | 122 | ### Create a tree graph 123 | 124 | Git records the current state of the project by creating a tree graph from the index. This tree graph records the location and content of every file in the project. 125 | 126 | The graph is composed of two types of object: blobs and trees. 127 | 128 | Blobs are stored by `git add`. They represent the content of files. 129 | 130 | Trees are stored when a commit is made. A tree represents a directory in the working copy. It has one line for each item in the directory. An item might be a file or another directory. Each line records the four things required to reproduce the item in the project. The item's permissions. The type of object (blob or tree) that represents the item. The hash of the object. The name of the item. 131 | 132 | Below is the tree object that records the state of the `data` directory for the current commit. It has entries for the `number.txt` and `letter.txt` files. Notice that the entries use hashes to point at the blob objects that represent their content. 133 | 134 | ``` 135 | 100664 blob 5e40c0877058c504203932e5136051cf3cd3519b letter.txt 136 | 100664 blob 274c0052dd5408f8ae2bc8440029ff67d79bc5c3 number.txt 137 | ``` 138 | 139 | Below is the tree object for `alpha`, the root directory of the project. It has a line that points at the `data` tree. 140 | 141 | ``` 142 | 040000 tree 0eed1217a2947f4930583229987d90fe5e8e0b74 data 143 | ``` 144 | 145 | The tree graph is built from the index. The index only contains files, not directories. This means that empty directories will not appear in tree graphs. This is what people mean when they say, "Git only tracks files." 146 | 147 | 148 |
Tree graph for the `a1` commit
149 | 150 | ### Create a commit object 151 | 152 | After creating the tree graph, `git commit` creates a commit object. This is just another text file in the `.git/objects/` directory. It looks like this: 153 | 154 | ``` 155 | tree ffe298c3ce8bb07326f888907996eaa48d266db4 156 | author Mary Rose Cook 1424798436 -0500 157 | committer Mary Rose Cook 1424798436 -0500 158 | 159 | a1 160 | ``` 161 | 162 | The first line is a pointer to the tree graph of the content of the index at the moment the commit was made. This pointer is actually to the root of the tree graph: the tree object that represents the `alpha` directory. 163 | 164 | The last line is the commit message. 165 | 166 | 167 |
`a1` commit object pointing at its tree graph
168 | 169 | ### Update the commit the current branch points at 170 | 171 | Finally, the commit command points the current branch at the new commit object. 172 | 173 | What is the current branch? To find out, Git goes to the `HEAD` file at `alpha/.git/HEAD` and finds: 174 | 175 | ``` 176 | ref: refs/heads/master 177 | ``` 178 | 179 | It finds a path to a file called `master`. This indicates that `master` is the current branch. This file does not exist, because this is the first commit to the repository. Git creates the file and writes to it the hash of the commit object: 180 | 181 | ``` 182 | a87cc0f39d12e51be8d68eab5cef1d31e8807a1c 183 | ``` 184 | 185 | 186 |
`master` pointing at the `a1` commit
187 | 188 | `HEAD` still points at `master`. But `master` now exists and points at the new commit object. 189 | 190 | `HEAD` and `master` are both refs. A ref is a label used by Git or the user to identify a specific commit. All refs are simply text files on disk. The `master` ref is represented by a file called `master`. It contains the hash of the commit it points at. 191 | 192 | Graph property: it has three "current" versions. Git behavior: changes can be made easily, then grouped into a commit. The first current version is the working copy. This represents the moment by moment changes that the user makes to their content. It has no history, but is the most current version. The second current version is the index. This, too, has no history. But it is a subset of the working copy changes. It is the place where the user gathers the changes that comprise a commit. The third current version is the current commit. This represents a set of changes made to the working copy that are meaningful enough to the user that they can be labelled with a commit message. 193 | 194 | 195 |
`a1` commit shown with the working copy and index
196 | 197 | ## Make a commit that is not the first commit 198 | 199 | ```bash 200 | ~/alpha $ printf '2' > data/number.txt 201 | ``` 202 | 203 | The user sets the content of `data/number.txt` to `2`. This updates the working copy, but leaves the index and current commit as they are. 204 | 205 | 206 |
`data/number.txt` set to `2` in the working copy
207 | 208 | ```bash 209 | ~/alpha $ git add data/number.txt 210 | ``` 211 | 212 | The user adds the file to Git. This adds a blob containing `2`. And it updates the index with the hash of the new version of `data/number.txt`. 213 | 214 | 215 |
`data/number.txt` set to `2` in the working copy and index
216 | 217 | ```bash 218 | ~/alpha $ git commit -m 'a2' 219 | [master ae78f19] a2 220 | ``` 221 | 222 | The user commits. The steps for the commit are the same as before. 223 | 224 | First, a new tree graph is created to represent the content of the index. 225 | 226 | A new tree object is created to represent the `data` directory. This must be created because the hash of the content of the `data/number.txt` file has changed. 227 | 228 | ``` 229 | 100664 blob 2e65efe2a145dda7ee51d1741299f848e5bf752e letter.txt 230 | 100664 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4 number.txt 231 | ``` 232 | 233 | A new tree object is created to represent the `alpha` directory. This must be created because the hash of the `data` tree object has changed. 234 | 235 | ``` 236 | 040000 tree 40b0318811470aaacc577485777d7a6780e51f0b data 237 | ``` 238 | 239 | Second, a new commit object is created that points at the new tree object. 240 | 241 | ``` 242 | tree ce72afb5ff229a39f6cce47b00d1b0ed60fe3556 243 | parent 30ec3334aaa3954ef44fb6b68cfbf1a225c3d5af 244 | author Mary Rose Cook 1424813101 -0500 245 | committer Mary Rose Cook 1424813101 -0500 246 | 247 | a2 248 | ``` 249 | 250 | The second line of the commit object points at the commit's parent: `a1`. To find the parent commit, Git went to `HEAD`, followed it to `master` and found the commit hash of `a1`. 251 | 252 | Third, just like for the previous commit, the content of the `master` branch file is set to the hash of the new commit. 253 | 254 | 255 |
`a2` commit
256 | 257 | 258 |
Git graph without the working copy and index
259 | 260 | Graph property: content is stored as a tree of objects. Git's behavior: only diffs are stored in the objects database. Look at the graph above. The `a2` commit reuses the `a` blob that was made before the `a1` commit. Similarly, if a whole directory doesn't change from commit to commit, its tree and all the blobs and trees below it can be reused. Generally, there are few content changes from commit to commit. This means that Git can store large commit histories in a small amount of space. 261 | 262 | Graph property: each commit has a parent. Git behavior: a repository stores the history of a project. To see the history preceding a commit, move from parent to parent, all the way back to the first commit. 263 | 264 | Graph property: the nodes in the graph are all text files. Git behavior: the content in the nodes can be easily retrieved, edited, converted and explored with programs other than Git. 265 | 266 | Graph property: refs are entry points to one part of the commit history or another. Git behavior: commits can be given meaningful names. The user uses concrete refs like `fix-for-bug-376` to organise their work into lineages that are meaningful to their project. Symbolic refs like `HEAD`, `MERGE_HEAD` and `FETCH_HEAD` identify points in the commit history that are meaningful to Git. These support commands that can manipulate the history: committing, merging, fetching. 267 | 268 | Graph property: the nodes in the `objects/` directory are immutable. Git behavior: content can be edited, not deleted. Every piece of content ever added and every commit ever made is somewhere in the `objects` directory[^3]. 269 | 270 | Graph property: refs are mutable. Git behavior: the meaning of a ref can change. Though the commit that `master` points at now might be the best version of a project, soon enough, it will be superceded be a newer and better commit. 271 | 272 | Graph property: refs and the working copy are readily available, but unreferenced commits are not. Git behavior: recent history is easier to recall, but more changeable. Or: Git has a fading memory that must be jogged with increasingly vicious prods. 273 | 274 | The working copy is the easiest point in history to recall because it is in the root of the repository. Recalling it doesn't even require a Git command. It is also the least permanent point in history. The user can make a dozen versions of a file, but, unless they are added, Git won't record any of them. 275 | 276 | The commit that `HEAD` points is very easy to recall. It is at the tip of the branch that is checked out. To see its content, the user can just stash[^4] and then examine the working copy. At the same time, `HEAD` is the most frequently changing ref. 277 | 278 | The commit that a concrete ref points at is easy to recall. The user can simply check out that branch. The tips of branches change less frequently that `HEAD`, but still frequently enough for them to be ephemeral. 279 | 280 | It is possible to recall a commit that is not pointed at by any ref. The further back the user goes, the harder it will be for them to sort through the content and reassemble the meaning of a commit in their human brain. But, the further back they go, the less likely it is that someone will have changed history since they last looked[^5]. 281 | 282 | ## Check out a commit 283 | 284 | ```bash 285 | ~/alpha $ git checkout 37888c2 286 | You are in 'detached HEAD' state... 287 | ``` 288 | 289 | The user checks out the `a2` commit using its hash. Checking out has four steps. 290 | 291 | First, Git gets the `a2` commit and gets the tree graph it points at. 292 | 293 | Second, it writes the file entries in the tree graph to the working copy. This results in no changes. Because `HEAD` was already pointing (via `master`) at the `a2` commit, the working copy already has the same content as the tree graph being written to it. 294 | 295 | Third, Git writes the file entries in the tree graph to the index. This, too, results in no changes. The index already has the same content as the `a2` commit. 296 | 297 | Fourth, the content of `HEAD` is set to the hash of the `a2` commit: 298 | 299 | ``` 300 | 37888c274ecb894b656829d55e88cd086c9b2f72 301 | ``` 302 | 303 | Setting the content of `HEAD` to a hash puts the repository in the detached `HEAD` state. Notice that `HEAD` points directly at the `a2` commit in the graph below. 304 | 305 | 306 |
Detached `HEAD`
307 | 308 | ```bash 309 | ~/alpha $ printf '3' > data/number.txt 310 | ~/alpha $ git add data/number.txt 311 | ~/alpha $ git commit -m 'a3' 312 | [master 05f9ae6] a3 313 | ``` 314 | 315 | The user sets the content of `data/number.txt` to `3` and commits the change. To get the parent of the `a3` commit, Git follows the detached `HEAD` directly to the hash of the previous `a2` commit, rather than going via a branch. 316 | 317 | Git updates `HEAD` to point directly at the hash of the new `a3` commit. This means that the repository is still in the detached `HEAD` state. Because no commit points at either `a3` or one of its descendents, it is not on a branch. This means it is easy to lose. 318 | 319 | 320 |
`a3` commit that is not on a branch
321 | 322 | Note that, from now on, trees and blobs will mostly be omitted from the graph diagrams. 323 | 324 | ## Create a branch 325 | 326 | ```bash 327 | ~/alpha $ git branch deputy 328 | ``` 329 | 330 | The user creates a new branch called `deputy`. This just creates a new file at `alpha/.git/refs/heads/deputy` that contains the hash that `HEAD` is pointing at. That is, the hash of the `a3` commit. 331 | 332 | Graph property: refs, like `deputy`, are just files. Git behavior: it is computationally cheap to create and modify a file. This is why Git branches are considered lightweight. 333 | 334 | The creation of the `deputy` branch puts the new `a3` commit safely on a branch. `HEAD` still points directly at a commit, so it is still detached. 335 | 336 | 337 |
`a3` commit now on the `deputy` branch
338 | 339 | ## Check out a branch 340 | 341 | ```bash 342 | ~/alpha $ git checkout master 343 | Switched to branch 'master' 344 | ``` 345 | 346 | The user checks out the `master` branch. 347 | 348 | First, Git gets the `a2` commit that `master` points at and gets the tree graph the commit points at. 349 | 350 | Second, Git writes the file entries in the tree graph to the files of the working copy. This sets the content of `data/number.txt` to `2`. 351 | 352 | Third, Git writes the file entries in the tree graph to the index. The index becomes: 353 | 354 | ``` 355 | data/number.txt d8263ee9860594d2806b0dfd1bfd17528b0ba2a4 356 | ``` 357 | 358 | Fourth, Git points `HEAD` at `master` by changing its content from a hash to: 359 | 360 | ``` 361 | ref: refs/heads/master 362 | ``` 363 | 364 | 365 |
`master` checked out and pointing at the `a2` commit
366 | 367 | ## Check out a branch that is incompatible with the working copy 368 | 369 | ```bash 370 | ~/alpha $ printf '789' > data/number.txt 371 | ~/alpha $ git checkout deputy 372 | Your changes to these files would be overwritten 373 | by checkout: 374 | data/number.txt 375 | Commit your changes or stash them before you 376 | switch branches. 377 | ``` 378 | 379 | The user accidentally sets the content of `data/number.txt` to `789`. They try to check out `deputy`. Git prevents the check out. 380 | 381 | `HEAD` points at `master` which points at `a2` where `data/number.txt` reads `2`. `deputy` points at `a3` where `data/number.txt` reads `3`. The working copy version of `data/number.txt` reads `789`. Because all these versions are different, checking out would require a merge. For simplicity, Git does not allow check outs that require a merge. Files in the working copy must either be new, or have the same content as the current commit, or have the same content as the commit being checked out. 382 | 383 | ```bash 384 | ~/alpha $ printf '2' > data/number.txt 385 | ~/alpha $ git checkout deputy 386 | Switched to branch 'deputy' 387 | ``` 388 | 389 | The user notices that they accidentally edited `data/number.txt` and sets the content back to `2`. They check out `deputy` successfully. 390 | 391 | 392 |
`deputy` checked out
393 | 394 | ## Merge an ancestor 395 | 396 | ```bash 397 | ~/alpha $ git merge master 398 | Already up-to-date. 399 | ``` 400 | 401 | The user merges `master` into `deputy`. Merging two branches means merging two commits. The first commit is the one that `master` points at: the giver. The second commit is the one that `deputy` points at: the receiver. For this merge, Git does nothing, reporting it is `Already up-to-date.`. 402 | 403 | Graph property: the series of commits in the graph are interpreted as a series of changes made to the content of the repository. Git behavior: if the giver commit is an ancestor of the receiver commit, Git will do nothing. Those changes have already been incorporated. 404 | 405 | ## Merge a descendent 406 | 407 | ```bash 408 | ~/alpha $ git checkout master 409 | Switched to branch 'master' 410 | ``` 411 | 412 | The user checks out `master`. 413 | 414 | 415 |
`master` checked out and pointing at the `a2` commit
416 | 417 | ``` 418 | ~/alpha $ git merge deputy 419 | Fast-forward 420 | ``` 421 | 422 | They merge `deputy` into `master`. Git discovers that the receiver commit is an ancestor of the giver commit. This means it can do a fast-forward merge. 423 | 424 | It gets `a3`, the giver commit, and gets the tree graph that it points at. It writes the file entries in the tree graph to the working copy and the index. It "fast-forwards" `master` to point at `a3`. 425 | 426 | 427 |
`a3` commit from `deputy` fast-forward merged into `master`
428 | 429 | Graph property: the series of commits in the graph are interpreted as a series of changes made to the content of the repository. Git behavior: in a merge, if the giver is a descendent of the receiver, history is not changed. There is already a sequence of commits that describe the change to make: the sequence of commits between the receiver and the giver. But, though the Git history doesn't change, the Git graph does change. The concrete ref that `HEAD` points at is pointed at the giver commit. 430 | 431 | ## Merge a commit from a different lineage 432 | 433 | ```bash 434 | ~/alpha $ printf '4' > data/number.txt 435 | ~/alpha $ git add data/number.txt 436 | ~/alpha $ git commit -m 'a4' 437 | [master c6b955e] a4 438 | ``` 439 | 440 | The user sets the content of `number.txt` to `4` and commits the change to `master`. 441 | 442 | ```bash 443 | ~/alpha $ git checkout deputy 444 | Switched to branch 'deputy' 445 | ~/alpha $ printf 'b' > data/letter.txt 446 | ~/alpha $ git add data/letter.txt 447 | ~/alpha $ git commit -m 'b3' 448 | [deputy d75b998] b3 449 | ``` 450 | 451 | The user checks out `deputy`. They set the content of `data/letter.txt` to `b` and commit the change to `deputy`. 452 | 453 | 454 |
`a4` committed to `master`, `b3` committed to `deputy` and `deputy` checked out
455 | 456 | Graph property: commits can share parents. Git behavior: new lineages can be created in the commit history. 457 | 458 | Graph property: commits can have multiple parents. Git behavior: separate lineages can be joined by a commit with two parents: a merge commit. 459 | 460 | ```bash 461 | ~/alpha $ git merge master -m 'b4' 462 | Merge made by the 'recursive' strategy. 463 | ``` 464 | 465 | The user merges `master` into `deputy`. 466 | 467 | Git discovers that the receiver, `b3`, and the giver, `a4`, are in different lineages. It makes a merge commit. This process has six steps. 468 | 469 | First, Git writes the hash of the giver commit to a file at `alpha/.git/MERGE_HEAD`. The presence of this file tells Git it is in the middle of merging. 470 | 471 | Second, Git finds the base commit: the most recent common ancestor of the receiver and giver commits. 472 | 473 | 474 |
`a3`, the base commit of `a4` and `b3`
475 | 476 | Graph property: commits have parents. Git behavior: it is possible to find the point at which two lineages diverged. Git traces backwards from `b3` to find all its ancestors and backwards from `a4` to find all its ancestors. It finds the most recent ancestor shared by both lineages. This is the base commit. 477 | 478 | Third, Git generates the indices for the base, receiver and giver commits. 479 | 480 | Fourth, Git generates a diff that contains the changes required to go from the content of the receiver commit to the content of the giver commit. This diff is a list of file paths that point to a change: add, remove, modify or conflict. 481 | 482 | Git gets the list of all the files that appear in at least one of the indices. For each one, it compares the index entries to see what change was made to the file. It writes a corresponding entry to the diff. In this case, the diff has two entries. 483 | 484 | The first is for `data/letter.txt`. The content of this file is `a` in the base, `b` in the receiver and `a` in the giver. The content is different in the base and receiver. But it is the same in the base and giver. This means that Git can see that the content was only modified by the giver, not the receiver. Which means that the diff entry for `data/letter.txt` is a modification, not a conflict. 485 | 486 | The second entry in the diff is for `data/number.txt`. In this case, the content is the same in the base and receiver, and different in the giver. This means that the diff entry for `data/letter.txt` is also a modification. 487 | 488 | Graph property: it is possible to find the base commit of a merge. Git behavior: if a file has changed from the base in just the receiver or giver, Git can automatically resolve the merge of that file. This means less work for the user. 489 | 490 | Fifth, the changes indicated by the entries in the diff are applied to the index. This means that the entry for `data/letter.txt` is pointed at the `b` blob and the entry for `data/number.txt` is pointed at the `4` blob. 491 | 492 | Sixth, the changes indicated by the entries in the diff are applied to the working copy. This means that the content of `data/letter.txt` is set to `b` and the content of `data/number.txt` is set to `4`. 493 | 494 | Seventh, the updated index is committed: 495 | 496 | ``` 497 | tree 20294508aea3fb6f05fcc49adaecc2e6d60f7e7d 498 | parent d75b9983183df12a8e745318d0c31cc1782eaf2f 499 | parent c6b955e6d3d26248112b29176d47b4186a9a20c8 500 | author Mary Rose Cook 1425596551 -0500 501 | committer Mary Rose Cook 1425596551 -0500 502 | 503 | b4 504 | ``` 505 | 506 | Notice that the commit has two parents. 507 | 508 | Eighth, Git points the current branch, `deputy`, at the new commit. 509 | 510 | 511 |
`b4`, the merge commit resulting from the recursive merge of `a4` into `b3`
512 | 513 | ## Merge two commits in different lineages that both modify the same file 514 | 515 | ```bash 516 | ~/alpha $ printf '5' > data/number.txt 517 | ~/alpha $ git add data/number.txt 518 | ~/alpha $ git commit -m 'b5' 519 | [deputy 15b9e42] b5 520 | ``` 521 | 522 | The user sets the content of `data/number.txt` to `5` and commits the change to `deputy`. 523 | 524 | ```bash 525 | ~/alpha $ git checkout master 526 | Switched to branch 'master' 527 | ~/alpha $ printf '6' > data/number.txt 528 | ~/alpha $ git add data/number.txt 529 | ~/alpha $ git commit -m 'b6' 530 | [master 6deded9] b6 531 | ``` 532 | 533 | The user checks out `master`. They set the content of `data/number.txt` to `6` and commit the change to `master`. 534 | 535 | 536 |
`b6` commit on `master`
537 | 538 | ```bash 539 | ~/alpha $ git merge deputy 540 | CONFLICT in data/number.txt 541 | Automatic merge failed; fix conflicts and then 542 | commit the result. 543 | ``` 544 | 545 | The user merges `deputy` into `master`. There is a conflict and the merge is paused. The process for a conflicted merge follows the same first six steps as the process for an unconflicted merge: set `alpha/.git/MERGE_HEAD`, find the base commit, generate the indices of the base, receiver and giver commits, create a diff, update the index and update the working copy. Because of the conflict, steps four, five and six have different outcomes. Because of the conflict, the seventh commit step and eighth ref update step are never taken. Let's go through the steps again and see what happened. 546 | 547 | First, Git writes the hash of the giver commit to a file at `alpha/.git/MERGE_HEAD`. 548 | 549 | 550 |
`MERGE_HEAD` written during merge of `b5` into `b6`
551 | 552 | Second, Git finds the base commit. 553 | 554 | Third, Git generates the indices for the base, receiver and giver commits. 555 | 556 | Those steps are the same as before. 557 | 558 | Fourth, Git creates a diff that contains the changes required to go from the receiver commit to the giver commit. In this case, the diff contains only one entry: `data/number.txt`. Because the content for `data/number.txt` is different in the receiver, giver and base, the entry is marked as a conflict. 559 | 560 | Fifth, the changes indicated by the entries in the diff are applied to the index. Entries in the index are uniquely identified by a combination of their file path and stage. The entry for an unconflicted file has a stage of `0`. Before this merge, the index looked like this, where `0` is the stage: 561 | 562 | ``` 563 | 0 data/letter.txt 63d8dbd40c23542e740659a7168a0ce3138ea748 564 | 0 data/number.txt 62f9457511f879886bb7728c986fe10b0ece6bcb 565 | ``` 566 | 567 | After the merge diff is written to the index, the index looks like this: 568 | 569 | ``` 570 | 0 data/letter.txt 63d8dbd40c23542e740659a7168a0ce3138ea748 571 | 1 data/number.txt bf0d87ab1b2b0ec1a11a3973d2845b42413d9767 572 | 2 data/number.txt 62f9457511f879886bb7728c986fe10b0ece6bcb 573 | 3 data/number.txt 7813681f5b41c028345ca62a2be376bae70b7f61 574 | ``` 575 | 576 | The entry for `data/letter.txt` at stage `0` is the same as it was before the merge. The entry for `data/number.txt` at stage `0` is gone. There are three new entries in its place. The entry for stage `1` has the hash of the `data/number.txt` content from the base commit. The entry for stage `2` has the hash of the `data/number.txt` content from the receiver commit. The entry for stage `3` has the hash of the `data/number.txt` content from the giver commit. The presence of these three entries tells Git that `data/number.txt` is in conflict. 577 | 578 | Sixth, the changes indicated by the entries in the diff are applied to the working copy. For a conflict, Git writes both versions to the file in the working copy. The content of `data/number.txt` is set to: 579 | 580 | ``` 581 | <<<<<<< HEAD 582 | 6 583 | ======= 584 | 5 585 | >>>>>>> deputy 586 | ``` 587 | 588 | The merge pauses here. 589 | 590 | ```bash 591 | ~/alpha $ printf '13' > data/number.txt 592 | ~/alpha $ git add data/number.txt 593 | ``` 594 | 595 | The user integrates the content of the two conflicting versions by setting the content of `data/number.txt` to `13`. They add the file to the index. Adding a conflicted file tells Git that the conflict is resolved. Git removes the `data/number.txt` entries for stages `1`, `2` and `3` from the index. It adds a blob containing the `13`, the new content of `data/number.txt`. It adds adds an entry for `data/number.txt` at stage `0` with the hash of the new blob. The index now reads: 596 | 597 | ``` 598 | 0 data/letter.txt 63d8dbd40c23542e740659a7168a0ce3138ea748 599 | 0 data/number.txt ca7bf83ac53a27a2a914bed25e1a07478dd8ef47 600 | ``` 601 | 602 | ```bash 603 | ~/alpha $ git commit -m 'b13' 604 | [master 28118a0] b13 605 | ``` 606 | 607 | Seventh, the user commits. Git sees `alpha/.git/MERGE_HEAD` in the repository, which tells it that a merge is in progress. It checks the index and finds there are no conflicts. It creates a new commit, `b13`, to record the content of the resolved merge. It deletes the file at `alpha/.git/MERGE_HEAD`. This completes the merge. 608 | 609 | Eighth, Git points the current branch, `master`, at the new commit. 610 | 611 | 612 |
`b4`, the merge commit resulting from the conflicted, recursive merge of `b5` into `b6`
613 | 614 | ## Remove a file 615 | 616 | A diagram of the Git graph that includes the trees and blobs for the current commit, the working copy and index: 617 | 618 | 619 |
`b13` commit with associated trees, and working copy and index
620 | 621 | ```bash 622 | ~/alpha $ git rm data/letter.txt 623 | rm 'data/letter.txt' 624 | ``` 625 | 626 | The user tells Git to remove the `data/letter.txt` file. 627 | 628 | First, `data/letter.txt` is deleted from the working copy. 629 | 630 | Second, the entry for `data/letter.txt` is deleted from the index. 631 | 632 | 633 |
After `data/letter.txt` `rm`ed from working copy and index
634 | 635 | ```bash 636 | ~/alpha $ git commit -m '13' 637 | [master 836b25c] 13 638 | ``` 639 | 640 | The user commits. As part of the commit, as always, Git builds a tree graph that represents the content of the index. Because `data/letter.txt` is not in the index, it is not included in the tree graph. 641 | 642 | 643 |
`13` commit made after `data/letter.txt` `rm`ed
644 | 645 | ## Copy a repository 646 | 647 | ```bash 648 | ~/alpha $ cd .. 649 | ~ $ cp -r alpha bravo 650 | ``` 651 | 652 | The user copies the contents of the `alpha/` repository to the `bravo/` directory. This produces the following directory structure: 653 | 654 | ``` 655 | alpha 656 | └── data 657 | └── letter.txt 658 | └── number.txt 659 | bravo 660 | └── data 661 | └── letter.txt 662 | └── number.txt 663 | ``` 664 | 665 | There is now another Git graph: 666 | 667 | 668 |
New graph created when `alpha` `cp`ed to `bravo`
669 | 670 | ## Link a repository ta another repository 671 | 672 | ```bash 673 | ~ $ cd alpha 674 | ~/alpha $ git remote add bravo ../bravo 675 | ``` 676 | 677 | The user moves back into the `alpha` repository. They set up `bravo` as a remote repository on `alpha`. This adds some lines to the file at `alpha/.git/config`: 678 | 679 | ``` 680 | [remote "bravo"] 681 | url = ../bravo/ 682 | ``` 683 | 684 | These lines specify that there is a remote repository called `bravo` in the directory at `../bravo`. 685 | 686 | ## Fetch a branch from a remote 687 | 688 | ```bash 689 | ~/alpha $ cd ../bravo 690 | ~/bravo $ printf '14' > data/number.txt 691 | ~/bravo $ git add data/number.txt 692 | ~/bravo $ git commit -m '14' 693 | [master 6764cd8] 14 694 | ``` 695 | 696 | The user goes into the `bravo` repository. They set the content of `data/number.txt` to `14` and commit the change to `master` on `bravo`. 697 | 698 | 699 |
`14` commit on `bravo` repository
700 | 701 | ```bash 702 | ~/bravo $ cd ../alpha 703 | ~/alpha $ git fetch bravo master 704 | Unpacking objects: 100% 705 | From ../bravo 706 | * branch master -> FETCH_HEAD 707 | ``` 708 | 709 | The user goes into the `alpha` repository. They fetch `master` from `bravo` into `alpha`. This process has four steps. 710 | 711 | First, Git gets the hash of the commit that master is pointing at on `bravo`. This is the hash of the `14` commit. 712 | 713 | Second, Git makes a list of all the objects that the `14` commit depends on: the commit itself, the objects in its tree graph, the ancestor commits of the `14` commit and the objects in their tree graphs. It copies all the objects that are in this list but that `alpha` does not have to `alpha/.git/objects/`. 714 | 715 | Third, the content of the concrete ref file at `alpha/.git/refs/remotes/bravo/master` is set to the hash of the `14` commit. 716 | 717 | Fourth, the content of `alpha/.git/FETCH_HEAD` is set to: 718 | 719 | ``` 720 | 132c6a5ba1bb9e0d89c45dc50ba4553f5edd19dc branch 'master' of ../bravo 721 | ``` 722 | 723 | This indicates that the most recent fetch command fetched the `14` commit of `master` from `bravo`. 724 | 725 | 726 |
`alpha` after `bravo/master` fetched
727 | 728 | Graph property: objects can be copied. Git behavior: history can be shared between repositories. 729 | 730 | Graph property: a repository can store remote branch refs like `alpha/.git/refs/remotes/bravo/master`. Git behavior: a repository can have a record of the state of a branch on a remote repository. Though correct at the time it is fetched, it will go out of date if the remote branch changes. 731 | 732 | ## Merge FETCH_HEAD 733 | 734 | ```bash 735 | ~/alpha $ git merge FETCH_HEAD 736 | Updating 836b25c..6764cd8 737 | Fast-forward 738 | ``` 739 | 740 | The user merges `FETCH_HEAD`. `FETCH_HEAD` is just another ref. It resolves to the `14` commit, the giver. `HEAD` points at the `13` commit, the receiver. Git does a fast-forward merge and points `master` at the `14` commit. 741 | 742 | 743 |
`alpha` after `FETCH_HEAD` merged
744 | 745 | ## Pull a branch from a remote 746 | 747 | ```bash 748 | ~/alpha $ git pull bravo master 749 | Already up-to-date. 750 | ``` 751 | 752 | The user pulls `master` from `bravo` into `alpha`. Pulling is shorthand for fetching and merging `FETCH_HEAD`. Git does these two commands and reports that `master` is `Already up-to-date`. 753 | 754 | ## Clone a repository 755 | 756 | ```bash 757 | ~/alpha $ cd .. 758 | ~ $ git clone alpha charlie 759 | Cloning into 'charlie' 760 | ``` 761 | 762 | The user moves into the directory above. They clone `alpha` to `charlie`. Cloning to `charlie` has similar results to the `cp` the user did to produce the `bravo` repository. Git creates a new directory called `charlie`. After that, it inits `charlie` as a Git repo, adds `alpha` as a remote called `origin`, fetches `origin` and merges `FETCH_HEAD`. 763 | 764 | ## Push a branch to a checked out branch on a remote 765 | 766 | ```bash 767 | ~ $ cd alpha 768 | ~/alpha $ printf '15' > data/number.txt 769 | ~/alpha $ git add data/number.txt 770 | ~/alpha $ git commit -m '15' 771 | [master 8b35db5] 15 772 | ``` 773 | 774 | The user goes back into the `alpha` repository. They set the content of `data/number.txt` to `15` and commit the change to `master` on `alpha`. 775 | 776 | ```bash 777 | ~/alpha $ git remote add charlie ../charlie 778 | ``` 779 | 780 | They set up `charlie` as a remote repository on `alpha`. 781 | 782 | ```bash 783 | ~/alpha $ git push charlie master 784 | Writing objects: 100% 785 | remote error: refusing to update checked out 786 | branch: refs/heads/master because it will make 787 | the index and work tree inconsistent 788 | ``` 789 | 790 | They push `master` to `charlie`. 791 | 792 | All the objects required for the `15` commit on the `master` branch are copied to `charlie`. 793 | 794 | At this point, the push process stops. Git, as ever, tells the user what went wrong. It refuses to push to a branch that is checked out on the remote. This makes sense. A push will update the current commit and index of the remote. This will cause confusion if someone is editing the working copy on the remote. 795 | 796 | At this point, the user could make a new branch and push that branch to `charlie`. But, really, they want a repository that they can push to whenever they want. They want a central repository that they can push to and pull from, but that no one commits to directly. They want something like a GitHub remote. They want a bare repository. 797 | 798 | ## Clone a bare repository 799 | 800 | ```bash 801 | ~/alpha $ cd .. 802 | ~ $ git clone alpha delta --bare 803 | Cloning into bare repository 'delta' 804 | ``` 805 | 806 | The user clones `delta` as a bare repository. This is an ordinary clone with two differences. The `config` file indicates the repository is bare. And the files that are normally stored in the `.git` directory are stored in the top of the repository: 807 | 808 | ``` 809 | delta 810 | ├── HEAD 811 | ├── config 812 | ├── objects 813 | └── refs 814 | ``` 815 | 816 | 817 |
`alpha` and `delta` graphs after `alpha` cloned to `delta`
818 | 819 | ## Push a branch to a bare repository 820 | 821 | ```bash 822 | ~ $ cd alpha 823 | ~/alpha $ git remote add delta ../delta 824 | ``` 825 | 826 | The user goes back into the `alpha` repository. They set up `delta` as a remote repository on `alpha`. 827 | 828 | ```bash 829 | ~/alpha $ printf '16' > data/number.txt 830 | ~/alpha $ git add data/number.txt 831 | ~/alpha $ git commit -m '16' 832 | [master 02d1bb2] 16 833 | ``` 834 | 835 | They set the content of `data/number.txt` to `16` and commit the change to `master` on `alpha`. 836 | 837 | 838 |
`16` commit on `alpha`
839 | 840 | ```bash 841 | ~/alpha $ git push delta master 842 | Writing objects: 100% 843 | To ../delta 844 | 8b35db5..02d1bb2 master -> master 845 | ``` 846 | 847 | They push `master` to `delta`. Pushing has three steps. 848 | 849 | First, all the objects required for the `16` commit on the `master` branch are copied from `alpha/.git/objects/` to `delta/.git/objects/`. 850 | 851 | Second, `refs/heads/master` is updated on `delta` to point at the `16` commit. 852 | 853 | Third, `alpha/.git/refs/remotes/delta/master` is set to point at the `16` commit. This means `alpha` has an up to date record of the state of `delta`. 854 | 855 | 856 |
`16` commit pushed from `alpha` to `delta`
857 | 858 | ## Summary 859 | 860 | Git is built on a graph. Almost every Git command manipulates this graph. To understand Git deeply, focus on the properties of this graph, not workflows or commands. 861 | 862 | To learn more about Git, investigate the `.git` directory. It's not scary. Look inside. Change the content of files and see what happens. Create a commit by hand. Try and see how badly you can mess up a repo. Then repair it. 863 | 864 | [^1]: In this case, the hash is longer than the original content. But, all pieces of content longer than the number of characters in a hash will be expressed more concisely than the original. 865 | 866 | [^2]: There is a chance that two different pieces of content will hash to the same value. But this chance is low. 867 | 868 | [^3]: Content can be lost if the runs `git prune`. This command deletes all objects that cannot be reached from a ref. 869 | 870 | [^4]: `git stash` stores all the differences between the working copy and the current commit in a safe place from which they can be retrieved later. 871 | 872 | [^5]: The `rebase` command can be used to add, edit and delete commits in the history. 873 | -------------------------------------------------------------------------------- /gitfromtheinsideout/images/1-a1-tree-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/1-a1-tree-graph.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/10-a3-detached-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/10-a3-detached-head.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/11-a3-on-deputy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/11-a3-on-deputy.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/12-a3-on-master-on-a2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/12-a3-on-master-on-a2.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/13-a3ondeputy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/13-a3ondeputy.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/14-a3-on-master-on-a2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/14-a3-on-master-on-a2.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/15-a3-on-master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/15-a3-on-master.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/16-a4-b3-on-deputy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/16-a4-b3-on-deputy.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/17-a4-b3-on-deputy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/17-a4-b3-on-deputy.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/18-b4-on-deputy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/18-b4-on-deputy.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/19-b6-on-master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/19-b6-on-master.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/2-a1-commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/2-a1-commit.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/20-b6-on-master-with-merge-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/20-b6-on-master-with-merge-head.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/21-b13-on-master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/21-b13-on-master.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/22-b13-with-objects-wc-and-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/22-b13-with-objects-wc-and-index.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/23-b13-letter-removed-from-wc-and-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/23-b13-letter-removed-from-wc-and-index.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/24-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/24-13.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/25-13-cp-alpha-to-bravo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/25-13-cp-alpha-to-bravo.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/26-14-bravo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/26-14-bravo.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/27-14-fetched-to-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/27-14-fetched-to-alpha.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/28-14-merged-to-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/28-14-merged-to-alpha.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/29-15-alpha-cloned-to-delta-bare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/29-15-alpha-cloned-to-delta-bare.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/3-a1-refs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/3-a1-refs.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/30-16-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/30-16-alpha.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/31-16-pushed-to-delta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/31-16-pushed-to-delta.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/4-a1-wc-and-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/4-a1-wc-and-index.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/5-a1-wc-number-set-to-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/5-a1-wc-number-set-to-2.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/6-a1-wc-and-index-number-set-to-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/6-a1-wc-and-index-number-set-to-2.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/7-a2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/7-a2.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/8-a2-just-objects-commits-and-refs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/8-a2-just-objects-commits-and-refs.png -------------------------------------------------------------------------------- /gitfromtheinsideout/images/9-a2-detached-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maryrosecook/DEPRECATED-essays/83c31fcd57ec5a9ad4642cda01df1f4b5809936d/gitfromtheinsideout/images/9-a2-detached-head.png --------------------------------------------------------------------------------