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

Git in Practice

Common Issues and Troubleshooting

Beyond the Command Line


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.

Alan Sánchez Pérez Peña
Alan Sánchez Pérez Peña
Alan is a seasoned developer and a Digital Marketing expert, with over a decade of software development experience. He has executed over 70,000+ project reviews at Udacity, and his contributions to course and project development have significantly enhanced the learning platform. Additionally, he provides strategic web consulting services, leveraging his front-end expertise with HTML, CSS, and JavaScript, alongside his Python skills to assist individuals and small businesses in optimizing their digital strategies. Connect with him on LinkedIn here: http://www.linkedin.com/in/alan247