Why use Git, How it Works and what’s going on behind the scenes?

Cloud with Chris Logo
Cloud with Chris Logo

Introduction

Setting some context

About Git

Getting started with Git

git --version
git version 2.31.1.windows.1
mkdir mynewfolder
cd mynewfolder

pwd

Path
----
D:\temp\mynewfolder

chris@reddobowen-home
❯ ls
git init
Initialized empty Git repository in D:/temp/mynewfolder/.git/
cd .\.git\
❯ ls

Directory: D:\temp\mynewfolder\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:12 hooks
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:12 objects
d---- 31/03/2021 10:12 refs
-a--- 31/03/2021 10:12 156 config
-a--- 31/03/2021 10:12 73 description
-a--- 31/03/2021 10:12 21 HEAD
  • The hooks folder contains a set of scripts that perform actions when a given Git action is performed. There are a series of example scripts in this folder that you can review if interested.
  • The info folder contains additional information about the repository. This can include information on refs for dumb transports, grafts, attributes, and sparse-checkout patterns. It also contains the exclude file inside it. This is a local file used for excluding some specific patterns in code that you don’t want Git to read or execute. This is different to the .gitignore file, as the .gitignore file is committed to the repository and therefore shared between contributors. The info folder is personal to your local repository.
  • The objects folder is likely what you would consider some of the magic behind Git. We’ll explore this further in the blog post, but this contains a series of folders named with with two hexadecimal characters. This relates to the first two characters of a Git hash. The remainder of the hash is then a file within the folder. That file may represent either a commit, tree or blob.
  • The refs folder is used for storing the ‘references’. Refs are user-friendly names that point to a commit hash, representing a branch of a tag. The commit contains a hash to a tree, and the tree will contain information about other trees or blobs. (Start seeing how all of this comes together?)
  • The config file contains any local git configuration overrides for this repository. Global configuration will be held elsewhere in the system, which will be different depending upon your OS.
  • You shouldn’t need to worry about the description file according to the Git Homepage.
  • The HEAD branch contains a pointer to the current HEAD of the ….. e.g. after running git init, the HEAD file in my .git folder is ref: refs/heads/main
<?php
echo "Helloworld";
?>
  1. Stage the changes by using git add. This is effectively saying "Hey Git, these are the files that I want to add to my local repository as part of my next set of updates".
  • You can use git add . to add the entire contents (and subdirectories) of the folder which you're currently in.
  • Alternatively, you can use git add helloworld.php to add only the helloworld.php file to the staging area.
  • There are tools such as Visual Studio Code which also have Git integration built in, and take away some of the overhead of working on the command line.
  1. Commit the changes by using git commit -m "Your Commit Message Here". This is the step that adds the staged files to the local Git repository.
  • It is a common practice to make smaller commits often. If you’re working on a feature update, make incremental changes with a larger amount of commits. This will give you the opportunity to revert to previous versions of the codebase if needed at a later point. When you combine this with a Continuous Integration (CI) system, this also allows you to get quick feedback through approaches like unit testing.
git status
On branch main

No commits yet

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

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

git add helloworld.php
warning: CRLF will be replaced by LF in helloworld.php.
The file will have its original line endings in your working directory

git status
On branch main

No commits yet

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

git commit -m "Initial version of helloworld.php file"
[main (root-commit) e927bdc] Initial version of helloworld.php file
1 file changed, 3 insertions(+)
create mode 100644 helloworld.php
  • There is a newly created logs folder. As we create additional commits, those logs are added into the relevant section. So for our commit a moment ago, it will be in logs/refs/heads/main. Yours may be logs/refs/heads/master depending upon what your initial branch is called. As you create additional branches, you will see additional files pop up in logs/refs/heads.
cd .\.git\
❯ ls

Directory: D:\temp\mynewfolder\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:12 hooks
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:57 logs
d---- 31/03/2021 10:12 objects
d---- 31/03/2021 10:12 refs
-a--- 31/03/2021 10:57 39 COMMIT_EDITMSG
-a--- 31/03/2021 10:57 156 config
-a--- 31/03/2021 10:12 73 description
-a--- 31/03/2021 10:12 21 HEAD
-a--- 31/03/2021 10:57 145 index

cd logs
❯ ls

Directory: D:\temp\mynewfolder\.git\logs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:57 refs
-a--- 31/03/2021 10:57 223 HEAD

cat HEAD
0000000000000000000000000000000000000000 e927bdcf4408d045c195c3cc4c39c04f94b7835f Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617184670 +0100 commit (initial): Initial version of helloworld.php file

cd refs
ls

Directory: D:\temp\mynewfolder\.git\logs\refs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:57 heads

cd heads

ls

Directory: D:\temp\mynewfolder\.git\logs\refs\heads

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 31/03/2021 10:57 223 main

cat main
0000000000000000000000000000000000000000 e927bdcf4408d045c195c3cc4c39c04f94b7835f Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617184670 +0100 commit (initial): Initial version of helloworld.php file
  • Next, let’s focus on the refs folder. You will see that when you navigate to the refs/heads folder and cat the branch that you committed into, the output is a hash! How interesting!
cd .\.git\
❯ ls

Directory: D:\temp\mynewfolder\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:12 hooks
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:57 logs
d---- 31/03/2021 10:12 objects
d---- 31/03/2021 10:12 refs
-a--- 31/03/2021 10:57 39 COMMIT_EDITMSG
-a--- 31/03/2021 10:57 156 config
-a--- 31/03/2021 10:12 73 description
-a--- 31/03/2021 10:12 21 HEAD
-a--- 31/03/2021 10:57 145 index

cd refs
❯ ls
Directory: D:\temp\mynewfolder\.git\refs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:57 heads
d---- 31/03/2021 10:12 tags

cd heads
❯ ls

Directory: D:\temp\mynewfolder\.git\refs\heads

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 31/03/2021 10:57 41 main

cat main
e927bdcf4408d045c195c3cc4c39c04f94b7835f
  • Let’s focus on the objects folder. When we navigate into the objects folder, we see multiple folders with two hexadecimal characters as their name. Navigating into the e9 folder, we see that there is a file with additional set of hexadecimal characters. Compare those initial two characters and the file name to the commit from the previous output. Notice anything interesting? That’s it! The folder uses the first two characters of the commit hash, and the file name is the remainder of the hash. As you’ll see from the output below, you can’t just cat that file though. Instead, you need to use the command git cat-file with the -p (pretty print) flag passing in the entire commit hash. This allows you to see the contents of the file, which looks similar to a commit message!
  • Notice that in the commit file, there is another hash for a tree? If you navigate back to the objects folder, you’ll see another subfolder that begins with the first two hexadecimal characters from the tree hash. You can run the git cat-file -p using the tree hash as well. This time, you should get a directory listing... and you've guessed it! Another hash, but this time relating to a blob.
  • You can go ahead and look in the objects folder for another subdirectory with a two hexadecimal character name. When you run git cat-file -p on the hash for the blob, you'll notice that this is the file that you version controlled a little earlier!
  • There are additional flags that you can use with git cat-file. For example, -t is used to understand the type of file that the hash relates to. I'll leave this as an exercise for you to explore!
cd .\.git\
❯ ls

Directory: D:\temp\mynewfolder\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:12 hooks
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:57 logs
d---- 31/03/2021 10:12 objects
d---- 31/03/2021 10:12 refs
-a--- 31/03/2021 10:57 39 COMMIT_EDITMSG
-a--- 31/03/2021 10:57 156 config
-a--- 31/03/2021 10:12 73 description
-a--- 31/03/2021 10:12 21 HEAD
-a--- 31/03/2021 10:57 145 index

cd objects
❯ ls
Directory: D:\temp\mynewfolder\.git\objects

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:57 4c
d---- 31/03/2021 10:56 72
d---- 31/03/2021 10:57 e9
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:12 pack

cd e9git l
❯ ls
Directory: D:\temp\mynewfolder\.git\objects\e9

Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 31/03/2021 10:57 169 27bdcf4408d045c195c3cc4c39c04f94b7835f

cat .\27bdcf4408d045c195c3cc4c39c04f94b7835f
x☺��A♫� ►=�§{oB�▬�&Ƙx��☼(l♂ ��R��↨/���L2↓���↨�¶?�L♦ˆ��G�☻�B��� �?↓��∟♠Mh;�F�ť♀7��♠☼��ǹgu�Rt������}����2���f_�>2��♂p�§▼�-򚮴> §�O��G_�♫�C�▲� ∟��^)�V���♥5▼�↕[�

git cat-file -p e927bdcf4408d045c195c3cc4c39c04f94b7835f
tree 4c4fc3540401700de06c00ab39c0d3688ae0d200
author Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617184670 +0100
committer Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617184670 +0100

Initial version of helloworld.php file

git cat-file -p 4c4fc3540401700de06c00ab39c0d3688ae0d200
100644 blob 72430935d88f3884816e3f9386184baee9649722 helloworld.php

git cat-file -p 72430935d88f3884816e3f9386184baee9649722
<?php
echo "Hello World";
?>
Create a GitHub repository
Create a GitHub repository
  • You can use existing tools like GitHub Desktop
  • You can create a new repository on the command line and push that up
  • You can push an existing repository from the command line (that’s what we’ll be doing here!)
  • You can import code from another repository, such as Subversion, Mercurial or TFVC.
  • Add a remote location to our local repository called origin, with the GitHub Repository URL
  • Origin and Upstream are a couple of standard naming conventions that you may see for the remote repository locations. You don’t have to use these names, though they are very commonly used!
  • Rename the current working branch to main
  • Main is considered a more friendly name than master due to the connotations of the word, so is now becoming a standard to adopt. For new repositories, GitHub adds in this line to encourage standardisation of the main terminology. When you install the Git client, there is also an option to override the default branch away from master. For my setup, I chose main (as you eagled-eyed readers may have already noticed!).
  • Finally, push the main branch to the origin’s remote location.
  • You may be challenged by the Git Credential Manager for credentials to authenticate, depending on the remote repository’s permissions and whether you already have any cached credentials.
git remote add origin https://github.com/chrisreddington/potential-garbanzo.git
git branch -M main
git push -u origin main
  • The logs folder is updated. Under the refs subdirectory of the logs folder, there is now a remotes folder, containing an origin subdirectory. This contains a file called main, which represents the current state of our remote repository.
cd .\.git\
❯ ls

Directory: D:\temp\mynewfolder\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:12 hooks
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:57 logs
d---- 31/03/2021 10:57 objects
d---- 31/03/2021 12:11 refs
-a--- 31/03/2021 10:57 39 COMMIT_EDITMSG
-a--- 31/03/2021 10:57 156 config
-a--- 31/03/2021 10:12 73 description
-a--- 31/03/2021 12:11 21 HEAD
-a--- 31/03/2021 10:57 145 index

cd logs
❯ ls

Directory: D:\temp\mynewfolder\.git\logs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 12:11 refs
-a--- 31/03/2021 12:11 223 HEAD

cat HEAD
0000000000000000000000000000000000000000 e927bdcf4408d045c195c3cc4c39c04f94b7835f Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617184670 +0100 commit (initial): Initial version of helloworld.php file
e927bdcf4408d045c195c3cc4c39c04f94b7835f 0000000000000000000000000000000000000000 Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617189090 +0100 Branch: renamed refs/heads/main to refs/heads/main
e927bdcf4408d045c195c3cc4c39c04f94b7835f e927bdcf4408d045c195c3cc4c39c04f94b7835f Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617189090 +0100 Branch: renamed refs/heads/main to refs/heads/main

cd refs
❯ ls

Directory: D:\temp\mynewfolder\.git\logs\refs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 12:11 heads
d---- 31/03/2021 12:11 remotes

cd remotes

ls

Directory: D:\temp\mynewfolder\.git\logs\refs\remotes

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 12:11 origin

cd origin
❯ ls

Directory: D:\temp\mynewfolder\.git\logs\refs\remotes\origin

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 31/03/2021 12:11 181 main

cat main
00000000000000000000000000000000000000 e927bdcf4408d045c195c3cc4c39c04f94b7835f Chris Reddington <791642+chrisreddington@users.noreply.github.com> 1617189095 +0100 update by push
  • Now for the refs folder in the .git folder. Once again, we will see a newly created remotes folder, which has an origin subdirectory (as that’s what we called our remote location, with thanks to the handy set of commands from GitHub). Inside of that folder, there is a file called main which contains a hash relating to our initial commit once again.
cd .\.git\
❯ ls

Directory: D:\temp\mynewfolder\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 10:12 hooks
d---- 31/03/2021 10:12 info
d---- 31/03/2021 10:57 logs
d---- 31/03/2021 10:57 objects
d---- 31/03/2021 12:11 refs
-a--- 31/03/2021 10:57 39 COMMIT_EDITMSG
-a--- 31/03/2021 10:57 156 config
-a--- 31/03/2021 10:12 73 description
-a--- 31/03/2021 12:11 21 HEAD
-a--- 31/03/2021 10:57 145 index

cd refs
❯ ls

Directory: D:\temp\mynewfolder\.git\refs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 12:11 heads
d---- 31/03/2021 12:11 remotes
d---- 31/03/2021 10:12 tags

cd remotes
❯ ls

Directory: D:\temp\mynewfolder\.git\refs\remotes

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 12:11 origin

cd origin
❯ ls

Directory: D:\temp\mynewfolder\.git\refs\remotes\origin

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 31/03/2021 12:11 41 main

cat main
e927bdcf4408d045c195c3cc4c39c04f94b7835f
  • Because we pushed the existing objects to a remote repository, there were no changes to the objects folder that we need to be concerned about.
Edit the Hello World File
Edit the Hello World File
git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
git remote update
Fetching origin
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 681 bytes | 4.00 KiB/s, done.
From https://github.com/chrisreddington/potential-garbanzo
e927bdc..609a83f main -> origin/main

❯ git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)

nothing to commit, working tree clean
git pull
Updating e927bdc..609a83f
Fast-forward
helloworld.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
cd D:\temp
git clone https://github.com/chrisreddington/potential-garbanzo
ls -Force

Directory: D:\temp\potential-garbanzo

Mode LastWriteTime Length Name
---- ------------- ------ ----
d--h- 31/03/2021 14:59 .git
-a--- 31/03/2021 14:57 36 helloworld.php
cd .git
❯ ls

Directory: D:\temp\potential-garbanzo\.git

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 14:57 hooks
d---- 31/03/2021 14:57 info
d---- 31/03/2021 14:57 logs
d---- 31/03/2021 14:57 objects
d---- 31/03/2021 14:57 refs
-a--- 31/03/2021 14:57 312 config
-a--- 31/03/2021 14:57 73 description
-a--- 31/03/2021 14:57 21 HEAD
-a--- 31/03/2021 14:59 145 index
-a--- 31/03/2021 14:57 112 packed-refs

cd refs
ls

Directory: D:\temp\potential-garbanzo\.git\refs

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 14:57 heads
d---- 31/03/2021 14:57 remotes
d---- 31/03/2021 14:57 tags

ls

Directory: D:\temp\potential-garbanzo\.git\refs\remotes

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 31/03/2021 14:57 origin

cd origin
ls

Directory: D:\temp\potential-garbanzo\.git\refs\remotes\origin

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 31/03/2021 14:57 30 HEAD

cat HEAD
ref: refs/remotes/origin/main

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Cloud With Chris

Exploring Cloud concepts with Chris Reddington (Welsh Tech Geek, Cloud Advocate, Musical Theatre Enthusiast and Improving Improviser!)