One of the things I remember the most about my early days as a web developer is that time when I was working on a new website and I got the blue screen of death. I had been making multiple changes throughout the day and when I restarted my computer they were all gone. If only I had been saving and tracking changes in my code, I wouldn’t have had to spend the entire weekend rebuilding what I lost.
You might be familiar with similar situations if you’ve started your journey in software development without learning about version control first. Perhaps you’ve even fallen into the “final” naming trap and have created multiple copies of your project folders with names like “website_final”, “website_final_v2”, or “website_final_REALLY_FINAL”.
Most of us have been there at some point in our journey and if you are still there let me tell you there’s a better way! In this article I’ll explain a few basic details about version control with a focus on Git, the most used version control system today. Version control has changed over the years and adapted to the development needs of globally distributed teams and individual programmers alike.
We’ll explore how version control works, why it’s essential, and how you can start using it in your projects. Not only this we will also focus on its evolution to understand how Git’s current landscape took shape.
Table of Contents
Brief History of Version Control
Quick Introduction to Git’s Basics
Common Issues and Troubleshooting
Brief History of Version Control
I like to think of version control as a time machine for my code. This analogy is very fitting because just as a time machine would allow me to visit different points in history, version control lets me view and restore code from different points in the development process.
Traditional Methods
Before version control, developers used several different approaches. In the early days some used timestamps when naming their files and, if they were working in teams, they took turns in editing.
For decades, simple methods like naming files “project_v1” or “project_final” have been commonly used. However, these approaches often result in confusion and versioning chaos. Without a structured system, projects can quickly become cluttered with duplicate files and unclear labels.Centralized Version Control
Once software teams started growing, actual version control systems began to emerge. The first ones were centralized. Famous systems like SVN (Subversion) were quickly adopted but they had important limitations.
We could think of SVN like a library with a central card catalogue. Developers would check out code from the same central server, make changes, and check them back in.
Subversion achieved the goal of tracking changes but most developers who worked with it would probably tell you how frustrating it was to use on a daily basis. When the central server went down, teams were left stuck, unable to save their work or access the project’s history. Merging conflicts also happened frequently, and if someone locked a file and forgot to unlock it, an admin had to step in to resolve the issue.
Distributed Version Control
Given the limitations of centralized version control, the arrival of distributed systems like Git marked a real breakthrough. Now, instead of relying on a single central repository, every single developer maintains an entire copy of the project’s history on their local machine.
To expand on the library analogy, imagine if instead of depending on a single central library, every single person had their own complete collection of books, including all previous editions and revisions.
This solved the major pain points that everyone faced with centralized systems:
- Developers now could work offline and commit changes locally
- The system could handle multiple working on the same files simultaneously
- The complexities of merging were handled automatically
- Every developer’s computer effectively served as a backup of the entire codebase
Quick Introduction to Git’s Basics
Moving from basic file naming (like “project_final_FINAL”) to Git was truly transformative. It completely changed how I manage my code and turned me into a more efficient developer, giving me capabilities I didn’t even know I needed in my workflow.
Git takes snapshots of your entire project each time you commit changes, instead of just tracking differences between files. This means that every commit preserves the exact state of all your files at that precise moment, which makes for very efficient project history management.
Using Git’s distributed nature along with Github was a game-changer for me. Instead of relying on a single copy of my project stored in one place, I now had the complete history both on my laptop and securely backed up online. This shift meant I could work from anywhere. I could commit changes, create branches, and review my project’s history right from my local copy offline. Then, the moment I was back online, syncing my changes was as simple as pushing them to GitHub. This flexibility not only streamlined my workflow but also gave me a newfound confidence in version control.
To really be able to appreciate how Git revolutionized version control, it’s important to understand a few core concepts that work together seamlessly in Git:
Repositories
We can think of a repository as a project’s timeline. It’s where Git stores your project’s complete history. When I create a new Git repository, I’m essentially starting a new history book that will track every change, big or small. I can keep this repository locally on my machine, ensuring I have full control over my project’s evolution. But when I need a secure backup or want to collaborate with others, I can easily push it to platforms like GitHub or GitLab.
Commits
Commits are the actual “snapshots” of the code at specific points in time. I make a point of creating a commit whenever I complete a meaningful change in the codebase, like when I fix a bug or add a new feature.
Each commit stores details of what was changed and when. It also allows me to add a message explaining why I made those changes. These messages are a wonderful thing to have when revisiting code months later or collaborating with others.
This is what a commit looks like when we use Git’s command line interface:
# Stage changes for commit
git add index.html
# Create a commit with a descriptive message
git commit -m “Fix navigation menu alignment”
Staging Area
The staging area (or index) is a concept that took me some time to appreciate. It basically is a preparation zone where you can carefully select which changes you want to include in your next commit.
This granular control helps create clean, logical commits that are easier to understand and review:
# See what files have changed
git status
# Stage specific files or changes
git add file1.js file2.css
# Review what’s staged
git diff –staged
Branches and Merging
After becoming more familiar with them, branches became one of my favorite Git features. They can be seen as parallel versions of the project where you can safely experiment with new features or bug fixes without risking your working code.
When I create a new branch, I can make all the changes I want, and if everything works, I can merge those changes back into my main code. If my changes just create a bunch of issues, I can simply delete the branch and try a different approach.
# Create and switch to a new branch
git checkout -b feature/login-system
# Make some changes and commit them
git add login.html
git commit -m “Add login form”
In this example, the login form page (login.html) exists only in the feature/login-system branch. The main branch remains untouched, protecting the stable code while I’m experimenting.
Once I’m confident my new feature works well, I can bring those changes back to my main branch. This is where merging comes in. Merging combines the changes from one branch into another:
# Switch to the branch you want to merge INTO
git checkout main
# Merge your feature branch
git merge feature/login-system
# If everything works, you can delete the feature branch
git branch -d feature/login-system
Remote Repositories
Remote repositories are great because they can serve both as backups for individual developers and as central points where teams can share their changes.
There are a few platforms online that provide hosting for remote repositories. Github is the most popular one but GitLab, and Bitbucket are good alternatives.
Using one of these platforms allows you to use collaboration features like pull requests and code review tools.
# Add a remote repository
git remote add origin https://github.com/username/project.git
# Push changes to remote
git push origin main
# Get latest changes from remote
git pull origin main
Remote repositories are fantastic when working in teams. Everyone has their own complete copy of the project which means every single team member can work individually and upload their code to the remote repository when the changes are ready. Git takes care of merging the changes together and if any conflict occurs, it actually provides clear tools for resolving them.
Git in Practice
Once I grasped Git’s core concepts, I dove into learning the actual commands. The command-line interface was a bit intimidating back then but after playing around a bit, it all quickly fell into place. Let me walk you through setting up Git and the commands I use in my workflow.
Installing Git
First, if you haven’t already, you’ll need to install Git on your computer. There are a few methods for installing Git but the easiest is to visit https://git-scm.com/downloads and download the installer for your operating system.
After installation, the first thing you should do is use the terminal in your operating system to set your user name and email address. This is important because this information is added to every commit you create:
# Configure your identity
git config –global user.name “Your Name”
git config –global user.email “your.email@example.com”
Using Git on a Test Project
Practicing Git commands on a personal project will help you understand the concepts and basic commands without the pressure of working with others’ code.
This is how you can take your first steps with Git in your local machine. Try the following in the terminal:
# Create a new project directory
mkdir my-first-project
# Change into the directory we’ve just created
cd my-first-project
# Initialize Git in the directory
git init
# Create a dummy file
touch index.html
# Add the file to the staging area
git add index.html
# Create the first commit!
git commit -m “Create initial project structure”
# See the commits log
git log
With this simple exercise you’ve used the most common Git commands. You’re ready to start using version control in your own projects.
As you keep using Git, one of the most valuable habits you can develop is to check your repository status frequently. For that, the git status command is your best friend as it tells you exactly what’s going on in your repository:
# It’s a good idea to check status before and after commands
git status
# Make some changes
echo “<h1>Hello World</h1>” > index.html
# Check status again
git status # Shows you have uncommitted changes
Typical Git Workflow with Remote Repositories
As you grow more comfortable with Git, you’ll want to explore remote repositories. When I first pushed code to GitHub, it felt like a major milestone.
Let’s assume that you have a GitHub repository that you want to push code to. First you need to add your repository to Git:
# Add a remote repository
git remote add origin https://github.com/username/repository.git
After you’ve added the remote repository, all you have to do is use the push command to upload your code to your remote repository on GitHub.
# Push your code
git push -u origin main
If you are working with other developers in a team, you’ll all be pushing and pulling from the same remote repository. Let me walk you through a typical workflow that you’d follow if you worked collaboratively:
1. Start the workday by getting the latest changes:
# If you’re working with others, always start by pulling latest changes
git pull origin main
2. Create a branch for a new feature or bug fix:
# Create and switch to a new branch
git checkout -b feature/user-profile
# Check which branch we’re on
git branch
3. Make changes and commit them regularly:
# I like to check status frequently to see what I’ve modified
git status
# Stage all files
git add .
# Commit changes
git commit -m “Add user profile page layout”
4. Share changes with others:
# Push changes to the remote repository
git push origin feature/user-profile
If I ever need to revisit a previous version of my code, Git makes it simple to find any commit and restore files or the entire project to that earlier state:
# View commit history
git log
# Restore a file from a previous commit
git checkout <commit-hash> — path/to/file
# Or revert an entire commit
git revert <commit-hash>
Common Issues and Troubleshooting
Now that we’ve covered the basics of working with Git, let’s talk about some challenges you might encounter along the way. While Git is incredibly powerful, using some of its sophisticated features can sometimes lead to challenging situations.
In my experience, many common issues arise when managing branches and merging code. The good news is that Git’s robust design means every problem has a solution. Let’s take a look at the most frequent challenges I’ve faced and how to resolve them.
Merging Conflicts
Merge conflicts occur when Git can’t automatically reconcile different changes to the same part of a file. This typically happens when two developers modify the same lines of code in different ways. While they might seem intimidating at first, Git’s conflict resolution system is quite sophisticated and helps you make informed decisions about which changes to keep.
When a conflict occurs, Git modifies the affected files to show both versions of the conflicting code, separated by special markers:
<<<<<<< HEAD
const taxRate = 0.08;
=======
const taxRate = 0.085;
>>>>>>> feature/update-tax
In this example, the section between <<<<<<< HEAD and ======= shows your current branch’s version, while the section between ======= and >>>>>>> feature/update-tax shows the incoming changes.
To resolve the conflict, you’ll need to edit the file to keep the correct version (or combine both versions if appropriate), remove the conflict markers, and then commit the resolved changes.
Undoing Changes
Git provides several ways to undo changes, each serving a different purpose depending on where you are in your workflow.
To completely remove any modifications you’ve made to a file since your last commit this is what you’d do:
# Discard changes in a file that hasn’t been staged
git checkout — filename.txt
You can also remove the file from the staging area while preserving your changes in the working directory.
# Unstage a file you accidentally added
git reset filename.txt
If you made a commit but changed your mind about it you can move your commit’s changes back to the staging area to modify what you need before committing again.
# Undo your last commit while keeping the changes
git reset –soft HEAD~1
If you really wanted, you could also undo your last commit. You should be careful with this, though. This command will permanently remove all the changes you made in the commit.
# Completely undo your last commit and all changes
git reset –hard HEAD~1
Wrong Branch Issues
Realizing you’ve made changes in the wrong branch is a common situation, especially when juggling multiple new features in a project. Git’s stash feature provides a clean way to move your changes to the correct branch:
First we need to create a temporary save point and clean the working directory. For that, we use the stash command.
# Save your current changes without committing
git stash
Now we’d need to switch to the correct branch with a clean working directory.
# Switch to the correct branch
git checkout correct-branch
And finally we’d restore the changes in the new branch.
# Apply your saved changes
git stash pop
We could also use git stash list to see all the stashed changes and git stash apply if we wanted to keep the changes in the stash after applying them.
Fixing Commit Messages
If you notice a typo or want to improve your last commit message, Git allows you to modify it without creating a new commit.
To modify the most recent commit and replace its message we would do this:
# Edit the last commit message
git commit –amend -m “Your corrected message”
If the commit already has been pushed to a remote repository, we can still modify its message but it’s important to be careful with force pushing, especially on shared branches, as it can lead to certain unexpected issues.
# If you’ve already pushed the commit
git push –force origin branch-name
Beyond the Command Line
I believe that learning Git through the command line is essential for understanding how version control works, but I also appreciate that there are excellent visual tools that can make daily work with Git more intuitive and efficient.
In my experience, most developers eventually develop a workflow that combines both command line and visual tools. You might find yourself using the command line for quick operations like committing and pushing changes, while turning to GitHub Desktop when you need to carefully review changes before a commit. Or you might primarily use VS Code’s Git integration while coding but switch to Sublime Merge when you need to resolve a particularly tricky merge conflict.
GitHub Desktop
Let’s start with what I consider the most beginner-friendly option. GitHub Desktop offers an excellent starting point for visual Git interaction, especially if you’re just beginning to move beyond the command line.
I particularly appreciate how it shows exactly which files have changed and lets me see those changes side by side. Creating commits becomes more intuitive since you can see exactly what you’re including, and tasks like switching branches or resolving conflicts feel much more manageable through its visual interface.
VS Code Git
If you’re using Visual Studio Code as your code editor, you already have access to excellent Git integration right in your development environment. VS Code’s Git features allow you to track changes, create commits, and resolve conflicts without ever leaving your editor.
I find this integration particularly helpful during active development. The color-coded changes in the editor’s margin instantly show me what I’ve modified, added, or deleted.
Sublime Merge
Sublime Merge, from the creators of the popular Sublime Text editor, provides another excellent option for visual Git interaction.
What sets it apart is its speed. Even with large repositories, operations feel instantaneous. Its interface does a good job balancing power and simplicity so it’s super useful for handling complex merges or when you need to search through your repository’s history.
Which One to Choose?
While other tools like GitKraken, Sourcetree, and Tower offer their own unique features, the three tools mentioned above provide an excellent foundation for most developers looking to complement their command line Git usage.
I personally would recommend you to start with GitHub Desktop to have a more visual understanding of what every Git operation does and then slowly transition into using the Git tool integrated within Visual Studio Code in your workflow, if that’s your editor of choice.
Wrapping Up
When I think back to my early days of manually copying project folders and losing track of changes, I’m grateful for how Git has transformed my development workflow.
With version control we can code with confidence, collaborate effectively, and maintain a clear history of any project’s evolution. Getting comfortable with Git is essential if you want to become a developer. Whether you are working on personal projects or collaborating with a global team, version control will become a big part of your daily workflow which is a good thing, as it will inevitably save you from disaster more than a few times during your career.
If you are ready to go deeper, check out Udacity’s Version Control with Git course where you’ll learn advanced Git and GitHub concepts. If you are interested in web development, you might want to take a look at the Full Stack Web Developer Nanodegree program where you will get to use Git in real-world projects.



