Skip to content
academia.sh

Lesson 03 / 15

Creating and Configuring a Repository

Turning an empty directory into a repository, the contents of the `.git` directory, and the precedence of the system, user, and repository configuration layers.

Contents

The previous two lessons built the model: history is a directed acyclic graph, and in a distributed system the whole of this graph stands locally. This lesson makes the model concrete — the course’s example repository, the sozluk project, is created, and the repository’s counterpart on disk is examined.

It is necessary to start with configuration, because a commit’s author is read from configuration, and the author information enters the commit’s identity.

Three Configuration Layers

Settings are kept in three separate files, and the narrower scope overrides the wider one:

Layer Scope Option
System All users on the machine --system
User All of a user’s repositories --global
Repository Only the repository currently in --local

If the same key is defined in more than one layer, the repository-level value takes effect. This makes possible the distinction “I generally work under this identity, but in this repository I use a different one.”

Three settings are made at the user level:

git config --global user.name "Deniz Kaya"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main

The first two fill in commits’ author field; if either is undefined, an attempt to write a commit stops with an error. The third sets the name of newly created repositories’ first branch. The branch concept is the subject of the Branching and Collaboration course; here it will appear only as a name visible in output.

Where settings are written can be read:

git config --list --global
user.name=Deniz Kaya
[email protected]
init.defaultbranch=main

Notice that a key name’s section and name parts are case-insensitive: init.defaultBranch was written, init.defaultbranch was listed. Values, however, are preserved letter for letter.

Creating the Repository

A repository is set up inside an existing directory:

mkdir sozluk
cd sozluk
git init

The command writes a single-line confirmation: the phrase Initialized empty Git repository in is followed by the full path of the created .git directory. Because the path depends on the directory the command was run in, it differs on every system.

From this moment on, the directory is a repository. The directory’s visible content has not changed; the only thing added is a hidden subdirectory named .git. The repository is that subdirectory itself: if .git is deleted, the files remain, history is gone.

The Contents of the .git Directory

ls .git
HEAD
config
description
hooks
info
objects
refs

Four of the seven entries will be in constant use throughout this course:

  • objects — the object database. The content-addressed storage covered in the previous lesson takes place here: file contents, directory images, and commits sit in this directory as files named by their hash values. It is empty in a new repository.
  • refs — refs that bind human-readable names to object identities. refs/heads holds branch tips, refs/tags holds tags. Both are empty at the start.
  • HEAD — a single-line file pointing to the ref currently being worked on.
  • config — the repository’s own configuration; the narrowest of the three layers.

The remaining three are used more rarely: hooks holds scripts to be run on certain events, info holds repository-specific helper files, description holds a description text that only some server interfaces read.

The HEAD file can be read directly:

cat .git/HEAD
ref: refs/heads/main

The content is not an object identity but a reference to a reference. Because no commit has been written yet, the refs/heads/main file does not exist either; HEAD points to a target that does not exist. This temporary inconsistency will be resolved once the first commit is written.

The Repository’s Own Configuration

cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true

These values are read from the system and written when the repository is created. repositoryformatversion states the repository format’s version, bare whether the repository has a working directory, logallrefupdates whether ref changes are logged. The last two depend on the file system: ignorecase is true on file systems that do not distinguish case in file names (the usual configurations of macOS and Windows); precomposeunicode is written only on macOS. Most Linux file systems do not have these two lines.

To write a setting at the repository level, the command is run from inside the repository, with the --local option:

git config --local user.email "[email protected]"

This line affects only commits in the sozluk repository; the user-level value stays in effect in other repositories.

How the Repository’s Root Is Found

Commands are not required to be run from the repository’s root directory. When a command runs, .git is searched for upward, starting from the directory currently in; the first .git found determines the repository’s root.

git rev-parse --show-toplevel
<parent-dir>/sozluk

The output is the repository’s root directory’s full path; above, the parent directory’s name has been abbreviated. Run from a subdirectory, it returns the same value; where the root is does not change based on where you are. The relative path between the root and where you are can also be asked for separately:

git rev-parse --show-prefix
temp/sub/

Because the search goes upward, running a second git init inside a repository does not give the expected result: a new .git is created, and that subtree breaks off from the outer repository. Separate mechanisms exist for cases that require nested repositories; this course will use a single repository.

A command run outside a repository gives a clear error:

fatal: not a git repository (or any of the parent directories): .git

Finding Where a Value Comes From

Which layer an unexpected setting comes from can be asked directly:

git config --list --show-origin --global
file:<home-dir>/.gitconfig	user.name=Deniz Kaya
file:<home-dir>/.gitconfig	[email protected]
file:<home-dir>/.gitconfig	init.defaultbranch=main

At the start of every line is the file the value was read from; in the output above the home directory’s path has been abbreviated, the real output shows the full path. If the layer option is removed, all three layers are listed merged together, and it is possible for the same key to appear on more than one line; in that case, the last line is the one that takes effect.

A single key’s effective value is asked for like this:

git config user.name
Deniz Kaya

Initial Status

git status
On branch main

No commits yet

nothing to commit (create/copy files and use "git add" to track)

Three lines give three separate pieces of information. The first is the name of the ref that the HEAD file points to. The second says that the refs/heads/main ref has not yet been bound to an object. The third reports that nothing in the working directory is ready to be recorded.

git status is the most frequently run command in this course. It answers the same question every time: what differences exist between the working directory, the staging area, and the last commit? The next topic will define these three regions one by one.

Summary

  • Configuration is kept in system, user, and repository layers; a narrow scope overrides a wide one.
  • If user.name and user.email are not defined, a commit cannot be written; these values enter the commit’s identity.
  • git init creates the .git subdirectory in an existing directory; the repository is that subdirectory.
  • .git/objects holds the object database, .git/refs holds named refs, .git/HEAD holds the ref currently being worked on.
  • --show-origin shows which file a setting comes from.

Next Step

The repository is set up, but empty. What happens when a file is created — does it go straight into history, or is there an intermediate stage? The next lesson will define the staging area that stands between the working directory and the object database, and show that area’s counterpart inside .git.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close