Initializing your git repository

Introduction

Initializing git repository

% git init
hint: Using ‘master’ as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of ‘master’ are ‘main’, ‘trunk’ and
hint: ‘development’. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git

As you can see above, to initialize the git repository, you can simply enter into the directory and type git init. Git will use “master” as the name of the initial branch, you can change that but we don’t need to get into this topic right now.

Once the repository is initialized, you can check the files which are created on the repository, you can check it by using ls .git/ within the repository you just created.

% ls .git/
HEAD config description hooks info objects refs

One thing to note here is, as you start work on your repository this directory folder structure will change by adding few other files such as logs, info, index and commit_editMSG, look at my repository structure after committing few changes:

% ls .git/
COMMIT_EDITMSG config hooks info objects
HEAD description index logs refs

We will go through each of the files here and explain their meaning too.

HEAD

if you want to check where the HEAD is pointing to within your current branch, you can see by doing the following command, and you see that in this case, the HEAD is pointing to the MASTER and not to any specific commit_id:

% cat .git/HEAD                  
ref: refs/heads/master

ref is basically a reference where you can find where the HEAD is pointing to, you can compare that with the git log and see where the head is compared to the head from the log:

% git log --oneline
317c930 (HEAD -> master) second commit
e7bde04 new file added

As you can see above, the HEAD is on commit 317c930 and now you can compare with the HEAD from the refs.

% cat .git/refs/heads/master     
317c930d9aa7cc66c77958d8945dcd201ee59fb4

To summarize this, HEAD is the pointer of your branch, you can move the HEAD around commits depending on your needs but bit extra careful when doing this to don’t mess up the changes on the files.

CONFIG

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

Git stores configuration options in three separate files, which lets you scope options to individual repositories (local), user(Global), or the entire system (system). Let’s have a look at each of them:

  • — local: /.git/config — This is repository specific configuration. By default, git config will write to a local level if no configuration option is passed. Local level configuration is applied to the context repository git config gets invoked in.
  • Global: /.gitconfig — User-specific configuration, this is where options set with — global flags are stored. User-Specific here means the configuration applies to an operating system user. Global configuration values are store in the user’s home directory.
  • System: $prefix/etc/gitconfig — This is system wide settings which is applied across an entire machine. This covers all users on an operating system and all repositories. The system level configuration file lives in a gitconfig file off the system root path as showed above.

When git looks for a configuration value, it will start at the local level going to global and then system level configuration, so it will be local > global > system.

DESCRIPTION

HOOKS

% cat .git/hooks/commit-msg.sample    
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

Git Hooks are local to a repository and they are not copied over to a newly cloned repository. Because they are local, they can be modified by anyone who has access to the repository, which means that you would need to ensure the hooks are updates within your team.

Info/exclude

There are 3 ways of excluding files in git.

  1. .gitignore: this applies to every clone of this repository (versioned)
  2. .git/info/exclude: only applies to your local copy of this repository, local not shared with other developers)
  3. ~./gitignore: it will apply to all the repositories on your local computer and it will not be shared with others.

The advantage of gitignore is you can have multiple gitignore files, one inside each directory/subdirectory for directory specific ignore rules, unlike git/exclude. Another advantage is that gitignore is applied across all clones, which means that in large teams all developers are ignoring the same kind of files, while if you’re using .git/exclude you would have to set this up locally.

LOGS

% cat .git/logs/HEAD             
e7bde048443ef6e641851f8edebd74b60dc86b29 Renato Gentil <email@email.com> 1616434985 +0000 commit (initial): new file added
317c930d9aa7cc66c77958d8945dcd201ee59fb4 Renato Gentil <email@email.com> 1616538559 +0000 commit: second commit

INDEX

OBJECT

% git ls-tree master .
100644 blob e5695bc8dc652b66c02f15b5bc8396c5c884a045 file.txt

As you can see above, this is a blob object. Blob object is a file which contains/stores content of the committed file. You can also see this is a blob object by using git cat-file -t hash_id:

% git cat-file -t e5695bc8dc652b66c02f15b5bc8396c5c884a045
blob

Blob object is just the sequence of bytes and git blob object will contain the same data as the file. The main difference here is the blob object is stored in the git object database where the file is stored on the file system. This means that if you create a file into your git repository “test.txt”, you will have two copies of the same file, one of the in the filesystem and the second one as a blob object in git object database. you can actually see the file content if you do a git cat-file commit_id.

Final Words

Hope you have enjoyed this post and feel free to commend and send me a message if you like it.

Senior Devops Cloud Support Engineer at AWS