Git Good, Part 1: Configuration, Creating Repositories, and Committing Changes

Git Config, Init, Add, and Commit

Franco Posa


0. Prerequisites

0.1 Install Git

Most machines will already have git installed, but the Git official book provides install instructions as well.

1. Initialize Global Git Configuration

View Existing Global Git Configuration

The “global” Git config for a given user on a system is generally stored either in .gitconfig or in .config/git/config under the user’s home directory.

Run git config --global --list --show-origin to show any existing Git config we may have, including the origin of the configuration, which is usually just the path to the relevant config file.

A scrollable paging program in your terminal will open to show the config:

[~/repos/git-demo-repo] % git config --global --list --show-origin  # press q to exit the viewer

file:/home/franco/.gitconfig    user.name=francoposa
file:/home/franco/.gitconfig    user.email=[email protected]
file:/home/franco/.gitconfig    init.defaultbranch=main
file:/home/franco/.gitconfig    pull.rebase=true
file:/home/franco/.gitconfig    push.autosetupremote=true
lines 1-4/4 (END)

If we do not have any existing git configuration, we may see:

fatal: unable to read config file '/home/franco/.gitconfig': No such file or directory
lines 1-1/1 (END)

The configuration file will be created when we set the first config options.

Set Basic Global Git Configuration Options

Our first concern is to set the git user name and email, which are attached to all git “commits”, or recorded changes. Commonly, these are your full name or username and email associated with your account on GitHub or other remote git server.

% git config --global user.name francoposa
% git config --global user.email [email protected]

The changes will be saved in the global Git config file.

We can confirm these changes several different ways, including:

Bonus: Set the Default Branch Name to main

While Git was never intended to have a single “default” branch, usage of Git has largely settled on having one branch serve as the master record or source of truth for the state of the repository (or “repo”).

This branch generally is used to spawn all other branches, and changes from new branches may go through an approval process before being accepted and merged back into the main branch.

This branch was traditionally named the master branch, which has now fallen out of favor. Most new Git repos now start with main as the default branch and many older Git repos have migrated as well.

% git config --global init.defaultbranch main

2. Initialize a Git Repository

Initialize a Git repository in an existing (preferably empty) directory:

[~/repos] % mkdir git-demo-repo
[~/repos] % cd git-demo-repo
[~/repos/git-demo-repo] % git init
Initialized empty Git repository in /home/franco/repos/git-demo-repo/.git/

or have Git create the directory:

[~/repos] % git init git-demo-repo
Initialized empty Git repository in /home/franco/repos/git-demo-repo/.git/

Git maintains all the data essential to its operations in the .git subdirectory:

[~/repos/git-demo-repo] % ls .git/
branches  config  description  HEAD  hooks  info  objects  refs

Deleting or altering a .git directory which does not have a remote copy or backup can result in the loss of all metadata and history of the repository.

View Repository Git Configuration

The .git/config file holds the local config settings for the repo:

[~/repos/git-demo-repo] % cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true

Run git config --list --show-origin - note the --global flag is not used this time. This shows the Git config in effect for the current repository, a merging of the global with the local config.

file:/home/franco/.gitconfig    user.name=francoposa
file:/home/franco/.gitconfig    user.email=[email protected]
file:/home/franco/.gitconfig    init.defaultbranch=main
file:/home/franco/.gitconfig    pull.rebase=true
file:/home/franco/.gitconfig    push.autosetupremote=true
file:.git/config        core.repositoryformatversion=0
file:.git/config        core.filemode=true
file:.git/config        core.bare=false
file:.git/config        core.logallrefupdates=true
lines 1-9/9 (END)

Local Git config options will override the global options when using Git within the configured repository. If a project requires different configuration than your global defaults, we can override that option just for the current repository:

[~/repos/git-demo-repo] % git config pull.rebase false  # no --global flag

Commit to a Git Repository

At this point, the Git repo should be empty (except for the .git directory).

Check Git status to confirm:

[~/repos/git-demo-repo] % git status
On branch main

No commits yet

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

Changes to a Git repository can be discarded without any record of their existence until they are committed. Each commit in a Git history is simply a record of what is different from the state of the repository at the previous commit. These commits are also relatively interchangeably referred to as changesets, deltas, or patches.

Create the First Changes

It is standard for a repo to have a markdown file in the root directory titled README.md, containing information that pertains to the project, as whole. The README generally starts with the repo or project name as the first line, formatted as a title or h1 header with a preceding #

Create this file in your editor:

# git-demo-repo

Check your Git status again:

[~/repos/git-demo-repo] % git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	README.md

nothing added to commit but untracked files present (use "git add" to track)

Now Git is aware that something is in the repository, but it is not yet actively tracking changes to it. We can add any amount of changes to the README, and still all Git will know is that there is some untracked file named README.md sitting there. If we delete the file, the changes will be gone forever.

We can change this by adding the file to Git’s index, then checking the status again:

[~/repos/git-demo-repo] % git add README.md
[~/repos/git-demo-repo] % git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md

Now we have not committed our change yet, but Git is tracking the changes to the file. Changes and files that have been added but not yet committed are said to be staged changes.

Change the file, say we decide we want to use are more proper project name instead of the hyphenated, lowercase repo name. Remove the text git-demo-repo and replace it with Git Demo Repository.

Check Git status again:

[~/repos/git-demo-repo] % git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   README.md

So nothing has been committed, but Git is tracking README.md, and it are aware that something has changed since the README was last added or staged.

Use Git’s diff command to review what has changed:

[~/repos/git-demo-repo] % git diff  # press q to exit the viewer

diff --git a/README.md b/README.md
index 5676235..8f8bd34 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-# git-demo-repo
+# Git Demo Repository
lines 1-7/7 (END)

With color-coded output and the +/- signs prefixing each line, Git shows us the difference between the staged changes and the unstaged changes.

If we stage the latest changes, Git no longer outputs a diff:

[~/repos/git-demo-repo] % git add README.md
[~/repos/git-demo-repo] % git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md

[~/repos/git-demo-repo] % git diff  # press q to exit the viewer

byte 0/0 (END)

If we have nothing further to change, we are ready to submit this changeset to the Git history

Record the First Commit

Git Commit

The primary requirement for a Git commit is that it has a commit message. While this can be overridden, it is not recommended.

The easiest way to provide a commit message is via the Git commit command’s --message/-m option:

[~/repos/git-demo-repo] % git commit -m "initial commit"
[main (root-commit) e1fd443] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

When a commit messages is not provided via the --message/-m option, Git will prompt for a message by opening the system default terminal text editor. For most Linux and Mac users, this is likely to be the notoriously-non-beginner-friendly Vi or Vim editors - so you may want to learn the very basics of Vim in short order.

View the Change Log

Git Log

[~/repos/git-demo-repo] % git log  # press q to exit the viewer

commit e1fd443f48ac0f4729fdf6cc931fb941bdda0bf8 (HEAD -> main)
Author: francoposa <[email protected]>
Date:   Tue Nov 21 17:20:01 2023 -0600

    initial commit
lines 1-5/5 (END)

VoilĂ !