DEV Community

Cover image for GIT Essentials
Import Sys
Import Sys

Posted on

GIT Essentials

You've been crunching day and night making sprite animation and finally you got it. Smooth and pleasant. With sight of relief you run your build... to find out that the character movement is broken!
You checked the movement code and... it is gone!

Before you go inventing a time machine stay awhile and listen. I will tell you how to do it.

Table of content


Luckily for us development is not always like running Diablo on hardcore without saves. You can and should save your progress during development, especially when you are working in team with other developers.
This is the point where version control system (VCS) becomes handy. Today we are going to talk about git.
Git is a distributed version control system that track file changes over time, allowing you to become time and space traveler.


Installing git

Installing git is very straight forward. Just visit the official web site downloads section https://git-scm.com/install/linux and follow the instructions for your operating system.

Once git installed let's check its version to verify installation

git --version
Enter fullscreen mode Exit fullscreen mode

Ok, everything seems fine.


Init repository

Let's start new project

mkdir newgame
cd newgame

nvim main.py
Enter fullscreen mode Exit fullscreen mode
if __name__ == "__main__":
    print("This will be the next Diablo")
Enter fullscreen mode Exit fullscreen mode

For git, to be able to track changes in your project you have to init repository first.
It can be done running init command

git init
Enter fullscreen mode Exit fullscreen mode

This will create an empty repository inside your project folder. If you will list folder content you will find that .git folder was created

ls -la 
Enter fullscreen mode Exit fullscreen mode

So what, you will ask?


Repository trees

Yes, currently git did not track anything.
But let's run status command.

git status
Enter fullscreen mode Exit fullscreen mode

As you can see the main.py file is listed in the "Untracked files" section. At least we track that we do not track anything so far :)

But what does it mean?
Now is the most crucial part to understand what git is and how it actually work.

Git is a file system with three states trees:

  • Working tree
  • Index
  • HEAD

and in any moment in time git tracks your project state in all three trees.

Most command you will run will move your changes between this three states.

Let's start unrolling all of this from the "Working tree".
As it names suggests working tree is where work happens. You can edit, remove, move files and folders and git mostly does not care at all.

But when you are good with work you have done you can stage the changes into the "Index" tree using add command

git add main.py
Enter fullscreen mode Exit fullscreen mode

and now if you will check the status

git status
Enter fullscreen mode Exit fullscreen mode

you will see that main.py is moved from the "Untracked files" to the "Changes to be commited".

Let's add some code to the main.py file

from dataclasses import dataclass

@dataclass
class NPC():
    name: str
    greetings: str

if __name__ == "__main__":
    decard = NPC(name="Deckard Cain", greetings="Stay awhile and listen")

    print("You see an old man")
    print(f"{decard.name}: {decard.greetings}")

Enter fullscreen mode Exit fullscreen mode

Let's see what git thinks about this update

git status
Enter fullscreen mode Exit fullscreen mode

Now you see another section: "Changes not staged to commit".
It means that now you have both staged version in the Index tree as well as new changes in Working tree.

You can always check what has been changed by running diff command

git diff
Enter fullscreen mode Exit fullscreen mode
diff --git a/main.py b/main.py
index 5f7d3db..d9211a3 100644
--- a/main.py
+++ b/main.py
@@ -1,3 +1,13 @@
+from dataclasses import dataclass
+
+@dataclass
+class NPC():
+    name: str
+    greetings: str
+
 if __name__ == "__main__":
-    print("This will be the next Diablo")
+    decard = NPC(name="Deckard Cain", greetings="Stay awhile and listen")
+
+    print("You see an old man")
+    print(f"{decard.name}: {decard.greetings}")

Enter fullscreen mode Exit fullscreen mode

As you can see git is watching you.

If you are good with the changes you can stage it once again

git add main.py
Enter fullscreen mode Exit fullscreen mode

and checking the status you can see that there are no unstaged changes and also the diff is empty, meaning that all the changes are now in the Index tree.

git status
Enter fullscreen mode Exit fullscreen mode


Commits

So far so good. But I've promised you a time machine.
This is the point where HEAD tree enters the scene.

You sure that you are done with greeting logic and want to make a save that you can load later if things will go wrong.
You can move your staged changed to the HEAD tree using commit command

git commit 
Enter fullscreen mode Exit fullscreen mode

If you run commit for the first time git will ask you to identify yourself, since every change should have it author

Git will ask you to write the commit message. Usually in the commit message you describe features or fixes you have made so later you can easily find your save point.

feat: Deckard Cain said hello!
Enter fullscreen mode Exit fullscreen mode

Save the commit message, and there you have it, your first commit!
Let's take a quick look at the status

git status
Enter fullscreen mode Exit fullscreen mode

it says nothing to commit, working tree clean which means that now we starting with clean Working and Index trees.


Let's go a bit crazy and delete the whole file!

rm -f main.py

ls -l
Enter fullscreen mode Exit fullscreen mode

The code is gone... Diff renders all red...

diff --git a/main.py b/main.py
deleted file mode 100644
index d9211a3..0000000
--- a/main.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from dataclasses import dataclass
-
-@dataclass
-class NPC():
-    name: str
-    greetings: str
-
-if __name__ == "__main__":
-    decard = NPC(name="Decard Cain", greetings="Stay awhile, and listen")
-
-    print("You see an old man")
-    print(f"{decard.name}: {decard.greetings}")

Enter fullscreen mode Exit fullscreen mode

But now we have the time machine!

git reset --hard HEAD

ls -l
Enter fullscreen mode Exit fullscreen mode

Deckard is back!

This particular command reset all trees to their states on the time of commit! But, we will get back to it later.


Commits history

Let's quickly make another commit

#... 
akira = NPC("Akira", "Wanna some heal, adventurer?")
#...
Enter fullscreen mode Exit fullscreen mode

Add changes to the commit

git add main.py
Enter fullscreen mode Exit fullscreen mode

And commit them

git commit -m "feat: add Akira"
Enter fullscreen mode Exit fullscreen mode

Now you have a new save point. But it doesn't mean that your previous commit is lost, you still can reset everything to the gold era of Deckard Cain!

You can look at yours commit history using log command

git log
Enter fullscreen mode Exit fullscreen mode
commit 035e7ecf82bc3966332320c405b34645b5e7b591 (HEAD -> master)
Author: import sys <import.sys.dev@gmail.com>
Date:   Wed Mar 4 21:26:03 2026 +0200

    feat: add Akira

commit 6d5d2d1d8c1d7c67b08f85067724c515b3534ef0
Author: import sys <import.sys.dev@gmail.com>
Date:   Wed Mar 4 20:51:02 2026 +0200

    feat: Deckard Cain said hello!
Enter fullscreen mode Exit fullscreen mode

You see both commits, and every commit has it unique ID.
The HEAD tree is now pointing to the latest commit.

Let's try to reset Akira changes.

Usually you do not need the whole commit information, but only the ID and the commit message, so you can run log with --oneline prefix

git log --oneline
Enter fullscreen mode Exit fullscreen mode
035e7ec (HEAD -> master) feat: add Akira
6d5d2d1 feat: Deckard Cain said hello!
Enter fullscreen mode Exit fullscreen mode

When executing reset command you can specify target commit id

git reset --soft 6d5d2d1
Enter fullscreen mode Exit fullscreen mode

Soft reset means that we reset only HEAD tree, leaving changes staged at Index tree, so you can re-commit them if you want to. But this is the story for another time


Remotes

For now everything is happening on your local machine, and if you will accidentally delete .git folder you will lost all your commits and history. This is no good.

To address this issue remotes exists.

Remotes are basically servers where you can publish and store your commits. This can be literally any machine running git and accessible by the network. Or it can be platform like Github, GitLab, Bitbucket and so on.
We will talk about Github specifically, but the overall flow is identical to the every other platform.
Also I will not cover github account registration and setup, because I will never finish this tutorial otherwise :)

First of all let's check if we have any remotes configured for our repository

git remote -v
Enter fullscreen mode Exit fullscreen mode

As expected there are none of them, so let's go to the github.com and create remote repository.

Now, as you have repository URL you can add remote to your local repository

git remote add origin git@github.com:import-sys/fantastic-fishstick.git
Enter fullscreen mode Exit fullscreen mode

Origin is just a default name for the default remote.
Now if you check remotes

git remote -v
Enter fullscreen mode Exit fullscreen mode

you will find that you have origin remote with two endpoints, for fetching and pushing commits.

origin  git@github.com:import-sys/fantastic-fishstick.git (fetch)
origin  git@github.com:import-sys/fantastic-fishstick.git (push)
Enter fullscreen mode Exit fullscreen mode

Ok, now the fun part.

git push origin main
Enter fullscreen mode Exit fullscreen mode

You just pushed all your commits to the remote, so you can access your work history even if you will burn your computer (don't do it). As a bonus you can share code with other developers to collaborate on the project. Hello FOSS.

Let's actually wipe everything, to prove the point

cd ..
rm -rf newgame
Enter fullscreen mode Exit fullscreen mode

Your code is gone, you local git history is gone, but you can restore everything with a single command!

git clone git@github.com:import-sys/fantastic-fishstick.git newgame

ls -l newgame
Enter fullscreen mode Exit fullscreen mode

You've just cloned remote repository into local repository.
Let's quickly check it

cd newgame && ls -l 

git log --oneline
Enter fullscreen mode Exit fullscreen mode

All the files and commits are there as if I have never delete them!

If someone make another commits to the remote repository you can pull remote changes using following command

git pull origin main
Enter fullscreen mode Exit fullscreen mode

Now you are up to date with remote server, and in the log you will see the new commit

git log --oneline
Enter fullscreen mode Exit fullscreen mode

That's it, your remote is all set up.


I know, it was tough. But understanding how you can manipulate git tree states is a key to more advanced git topics. Next time I will touch git topic we will discuss why trees are actually trees, cover branches, merging, rebasing and other cool stuff.

Top comments (0)