introducing the basics of git
Any Git project will consist of three sections: The Git directory, the working tree, and the staging area.
the Git directory is where we have the whole history of all files and changes, and that is the most important feature of a Version Control System, to keep track of all our previous snapshots of our project, so in case we have a bug or any malfunction we can easily roll back to a safe version of our project, in Git those snapshots are called ‘commits’. The working tree contains the current state of your project. And the staging area contains the changes that we decided to include in our next commit. It might be helpful to think of git in terms of files, our files can be either untracked, meaning they are not even in the staging area, or tracked which means they already have been staged.
If this is all don’t make sense, don’t worry, it will all become clear later with some practice, for now just keep in mind that a tracked file can be in one of three states: modified, staged or committed.
With all that jargon in mind, let’s dive in to some useful commands. To see Git commands in action let’s open a file and practice. I will use the README.md file in a simple python script, this is my README.md before we made any changes.
I highly recommend you follow along, open any file in a git repository if you already have one, if you don’t have one don’t worry, keep reading and I will guide you how to do it. for now just read and I will let you know when to go to your GitHub and create a new repo
to create a new git repo we can simply run:
This will initialize a git repo (repo is short for repository). To add your remote repo you can simply add the url, for example if you have github account you can create a new repo and copy it’s url and then go back to your terminal and run:
git remote add <remote_name> <remote_repo_url>
Usually the remote name is ‘origin’, that’s just a convention, alternatively if you want to copy an existing repo you can simply run git clone and add the url just like this:
git clone <repo url>
This will create a copy or clone of the remote repository into your local machine.
For now I recommend you create a new repo from scratch, that’s the best way to learn, so now it’s time to go online to your GitHub account, press the plus button to create a new repo, copy the URL. now from your desktop create a new folder, open it with your favorite text-editor ( I am using visual studio code because it is awesome! ).
now open the terminal and run:
echo “list of my python script to interact with the operating system” > README.md
git add README.md
git commit -m “first commit”
git branch -M main
git remote add origin <remote url exp:https://github.com/Sedki-Sghairi/awesomness>
git push -u origin main
echo is a bash (Linux’s shell) to write an input and display it in the standard output, if you don’t understand what that means that’s fine for now, in the first line we are basically writing a string , and creating a file called README.md and putting that string in the file. The rest of lines will make sense later when we visit each command one by one. now let’s run git status, which, as the name implies gives us the status of our project.
As you see git clearly tell us that we are on ‘branch main’ and that our branch is up to date with ‘origin/main’, this will become clear later when we understand branches, for now notice the message ‘nothing to commit, working tree clean’. let’s change something in our README.md file and run git status again. let’s change the first letter in ‘list’ to capital letter.
git tells us that README.md file was modified, and that we have no changes added to commit, and it also gives us the commands we can use to add our modified file to the staging area ‘use git add or git commit -a’. The only difference is that with git commit -a (-a for add) we can skip the adding part and go straight to commit, but we can only use it with existing files, and we can’t use it for a new file that we just created. give it a try later and see what output git gives you. You might have noticed as well the third line, which basically means that if we made those changes by mistake we can run ‘git restore README.md’ and the changes to README.md file will be discarded in the working directory. now let’s run git add and then git status again.
Now you see the README.md is highlighted in green, meaning it is staged and ready to be committed, and git also gives us the alternative, if we want to cancel and go back to previous state we can do that by running :
git restore --staged README.md
Try that for yourself to get a grasp of those commands you can also try and replace the filename, in this case README.md by ‘.’ (bash command that points to everything withing the directory we are currently in)and you will have the same result since we only modified one file,. Now let’s try and run git commit.
don’t freak out! that’s VIM, it is just a text editor, depending on your shell you might get VIM or nano. I highly recommend learning both not only because you find them by default in most Linux distributions but also because they are great tools, especially VIM, once you get to know how to use it, you will realize how powerful it is, I will definitely write an article about them in the future! for now let’s exit, if you have VIM (you have it if you see same output as shown above) you can exit by pressing ‘:q” and then hit enter, if it’s nano then press ‘ctr x’. Now as you might have guessed, git opened a text editor as soon as we ran git commit, to remind us to write something that describe the change we are making, you will see how powerful these comments once you start working with large projects. writing a detailed comment is a good practice and it will save you so much time when you need to debug the same code in the future, for now let’s keep things simple and write a short message. we can do that by adding a ‘-m’ and a string containing our message. something like this:
git commit -m'capitalize the first letter of the second line in README.md file'
And there we go, we just created a snapshot for our project! git shows us that 1file changed, 1insertion and one deletion, let’s run git status.
what does ‘Your branch is ahead of origin/main by 1 commit’ mean?
Is it a good time to visit branches in Git? not yet! let’s first push our changes to GitHub by running git push
Go back to your GitHub page and refresh and you should see the changes updated. It’s cool right!
Now let’s dive a little deeper. run:
git config -l
This display the configuration list (-l for list), you can scroll down using the down arrow of your keyboard, and you can notice details like user.name and user.email, now exit by pressing ‘q’ (for quit). to change your username or email you can run
git config --global user.name "My new name"
git config --global user.email "My new email"
Time to make some more changes. let’s write something in the next line of our README.md file, something like this:
now let’s use the short commit plus add command by running git commit -a
If we ran git log at any stage, it gives us a nice summary of our logs (history), let’s give it a try. run:
You see that each commit it given a Hash (a unique number), and you see some useful information about each commit like the author and his/her email and the date it was created. You also notice that our last commit is listed on the top. And the HEAD is pointing to it(and also telling us that we are in the main branch). HEAD is nothing but an alias used by Git to represent the currently checked-out snapshot of our project. Think of it like a bookmark to keep track of where you are, for example we will see later that we can go back in time, to an older version of our project and HEAD will point to that point in time. now you can exit with ‘q’ . Sometimes we need to see more information than that summary displayed by log. we can run git log -p ( p for patch since it gives us the patch that was created). let’s give it a try! run: git log -p
This format show us much more info, like added lines with a + sign and in green color and the removed one with a minus sign in red, and you can scroll down as well to see the rest of history and exit with ‘q’, to see just one line of each commit you can run :
git log --oneline
It gives you an even shorter output than log and only the first 7digits of the hash-key. Try and experiment with these commands to get a good grasp of how they work, try
git log --stat
to see some statistics , you can also jump to see a specific commit in the log by running :
git show <commit id>
You don’t need to remember all these commands, you will get used to them by practice and you can always check the manual and reference docs if you need to.
Let’s say we made a change by mistake and we want to revert or cancel it, we can do that by running git revert HEAD. git revert will create a commit that is the opposite of the previous commit, for example if we mistakenly added a file, git revert will delete the file, the advantage of git revert is that we can nicely keep a history of everything even undone commits. let’s try it out!
git revert HEAD
This will open the default text editor again, so let’s write something to describe why we are reverting. to write in VIM press i and then write, when you are done press Esc then ‘:wq’ to save (in nano you can write and then to save press ‘ctr o’ and exit by pressing ‘ctr x’)
once we save we the output bellow, which is similar to the commit output, that’s because the git revert command creates a commit for us:
It’s cool right!
let’s look only at the last 2 commit by adding -2 to git log -p
git log -p -2
You can clearly see that git revert created the exact opposite commit of the previous one (you can scroll down to see the previous one) .
As a practice exercise make some changes, add and commit then try revert to a specific commit (not the last one). you guessed right!! you can use
git revert <commit id>
I think it’s time to address the elephant in the room: branches. Now it’s a good opportunity for you take a break if you need, may be revisit the previous commands and get used to them and then come back!
A branch is nothing but a pointer to a particular commit, but it also represent an independent branch of development for the project (and it points to the last commit in that line of development). If this sounds complicated don’t worry, with a practical example it will all make sense.
Git by default gives you a default branch when you create a repo and it’s usually called master or main, everything we have done so far was in the main branch. let’s run git branch to see all our branches.
we see that we have only one branch and the * in front of main means that we are in that branch. You might think why do we need other branches? think of the main branch as the safe/good version of your project and let’s say you wanna try some other features, then creating a new branch (a copy of main) that is independent of main, will allow you to test new features without messing up with the safe version of your project. The best way to understand is try it out:
let’s create a new branch, we can do so by running git branch <branchname>, let’s create a branch called my_new_branch and then run git branch to see the list of all branches.
git branch my_new_branch
As I mentioned earlier the * points to the branch we are currently in, and as you can see it still points to main since we haven’t moved from main,to change to a different branch we can run git checkout <branchname>(git checkout -b <branchname> will create a new branch with that name and moves to it). now let’s move to my_new_branch
git checkout my_new_branch
notice Git moves the * to point to my_new_branch and it changes its color to tell us we are there. Lets create a new file and name it my_cool_file, we can do that in bash by running:
let’s add and commit this file
now let’s log the last two commits
git log -2
Notice that HEAD is pointing at my_new_branch in the last commit, and notice that main still in the previous commit, that means my_new_branch is ahead of main by one commit
Now let’s go back to main
git checkout main
Now HEAD point to main, and if you check your files now, you will not find my_cool_file, that’s because git updates files when we move from one branch to another and my_cool_file only exists in my_new_branch
Starting to see the power of git!
If we wanna delete a branch we can simple run git branch -d <banchname>try to remove my_new_branch and Git will ask you if you are sure, because our branch was not merged, merging is basically combining both histories of both branches together. let’s try it out. since we are in main we can run git merge <name_of_branch_we_want_to_merge_with>
git merge my_new_branch
Et voila! it’s cool right! now if you check your file you will find my_cool_file. you can see see git message telling us about the update and it also tells us that it is a Fast-forward merge. this will make sense very shortly!
Lets run git log -p
We can see that HEAD points at main and my_new_branch and main both point to the same last commit. this type of merge is call fast-forward merge which basically means that the commit history of both branches doesn’t diverge. the other type is called a three way merge, it’s performed when the history of the merging branches has diverged and can not longer be combined by a fast-forward, an example of this would be if we committed a new change in main before merging with my_new_branch, then if we try to merge git will combine the branch histories with a new commit, and merge both commits with the most recent ancestor (commit before divergence) . if git cannot figure out how to merge two opposite commits, it will ask you to resolve the conflict, which means chose one of the changes to keep and modify the one you don’t want to keep (or delete it) and then merge again.
Try creating a merge conflict and then resolve it as a challenge!
There is so much more to learn in git, but at least we saw the fundamentals, we saw how to initialize a git repo, how to add changes , stage them and commit, then we practiced to the most important aspect of Version Control which is the ability to roll back to an older commit. Finally we tapped into the world of Git branching. It might still feel overwhelming when you just starting but rest assured that once you put what you learned into practice you will master it in no time!