Mastering Git and GitHub
Mastering Git and GitHub
Ebenezer Don
* * * * *
This is a Leanpub book. Leanpub empowers authors and publishers with the
Lean Publishing process. Lean Publishing is the act of publishing an in-
progress ebook using lightweight tools and many iterations to get reader
feedback, pivot until you have the right book and build traction once you
do.
* * * * *
When I first encountered Git, I was, frankly, scared of it. The concept of
Version Control and the commands associated with Git seemed
intimidating. The term “Open Source” was a mystery, and I couldn’t
understand how a group of strangers around the globe could use GitHub to
efficiently collaborate on a project. However, my perspective changed
dramatically when I finally delved in and learned how to use Git. I came to
the startling realization of how many thousands of hours and years of lost
work I could have saved if I had embraced it earlier. Git became a tool that
empowered me to work confidently, giving me the freedom to
collaborate, experiment, and even break things, all while knowing I had a
reliable safety net.
In the pages of this book, we will take a journey. It’s a journey that begins
in the roots of version control, unfurling the basic concepts of Git. You’ll
learn how to initiate a new repository, stage and commit changes, manage
branches, and merge code—always with an eye on real-world application,
with plenty of examples to make the concepts come alive.
As we reach the final chapters, you’ll learn advanced Git features and
real-world troubleshooting techniques. From rebasing to cherry-picking,
from handling merge conflicts to recovering lost commits, you’ll acquire
skills that turn problems into opportunities for learning and growth.
In this journey, you’ll learn more than just commands and features. You’ll
understand the philosophy behind Git, GitHub, and open source—the why,
not just the how. Whether you’re a beginner hoping to grasp the basics, an
experienced developer aiming to hone your skills, or an open-source
enthusiast seeking to contribute more effectively, you’ll find “Git Prodigy,”
a valuable companion.
Then you realize that you’ve made a mistake. You’ve deleted a paragraph
that you wanted to keep. You try to undo your changes, but you’ve saved
over the same file multiple times, and you can’t go back to the previous
version. You’re stuck!
Now, if you have ever worked on a project and saved different versions at
different points with names like “first-draft”, “second-draft”, “final-draft”
or “final-final-draft-for-real”, to avoid this problem, instead of overwriting
only one saved file, you’ve actually done some kind of version control. You
did this so that you can always go back to a previous version in case you
don’t like your new changes.
In the following sections, we’ll dive into the fascinating world of Git and
learn how to harness its power for managing your projects efficiently and
collaboratively.
Imagine you roll out a new feature for your web app and immediately
receive messages about a critical bug. Version control allows you to swiftly
revert to a stable version of the code, effectively undoing the changes, so
you can address the issue.
For example, consider a scenario where you are developing an app and
want to add a new feature that you’re not sure will be enjoyable. Version
control allows you to create a separate copy of your code, known as a
branch, for experimentation. If your new feature proves to be successful,
you can merge it back into the main code. If it’s unsatisfactory, you can
simply discard the branch without affecting the main codebase.
Simplifying Collaboration
When working on a software project with a team, things can get messy if
you don’t have a good system in place. Imagine multiple people making
changes to the same files - it’s a recipe for disaster without version control.
Let’s say you and your colleague are both working on different features of a
mobile app. Version control enables you both to work on the same codebase
without interfering with each other’s work. When you’re both done, you
can combine your changes into the main project, and if there are any
conflicts, the version control system will help you resolve them.
Introduction to Git
Now that we’ve established how critical version control is for software
development let’s delve into Git. Git is a Distributed Version Control
System (DVCS) that has become an industry standard for both small and
large-scale projects. In this section, we will lay the groundwork for
understanding what Git is, how it differs from other version control
systems, and why it has become so popular among developers.
What is Git
The term “distributed” in its architecture means that each user’s working
copy of the codebase includes the full history of changes and commits.
Unlike Centralized Version Control Systems (CVCSs) where there’s one
central repository, in Git, every developer’s working copy is a repository.
A , often shortened to is a storage location where all the files of a project
and their history of changes are stored. A repository can be local, which
means it’s stored on your computer, or remote, which means it’s stored on a
server.
These snapshots are stored within a directory at the root of your project
called .git which is created when a new Git repository is initialized. This
directory is hidden by default on most systems and contains all the
information necessary for Git to manage your project’s history. To see the
contents of the .git directory, you might need to enable the option to show
hidden files in your file explorer.
Whenever you make a commit, Git saves a snapshot of what all your files
look like at that moment. This is different from some other VCSs, which
store data as a list of file-based changes.
Here are a few reasons you might want to use Git for your projects:
Speed: Git is fast. Since you have the entire repository and history on
your local machine, most operations are almost instantaneous.
Collaboration: Git’s distributed nature makes it easy for teams to
work together. Different members can work on different features in
parallel.
Open Source: Git is free and open source. It has a large, active
community of contributors, which means it’s continually being
improved and updated.
In Summary:
Git is not just an ordinary tool—it’s an entire ecosystem that stands on its
own. The combination of its decentralized structure, exceptional efficiency,
and flexibility makes it the favored version control system among many
developers. As we progress through this book, you’ll obtain hands-on
knowledge and understand how to harness Git’s potential to manage your
code effectively.
One of the common questions everyone new to version control has is the
distinction between Git and GitHub. Although they sound similar and are
closely related, they serve different purposes. Let’s demystify these two and
understand how they complement each other.
Understanding Git
As we discussed in the previous section, Git is a version control system. It
is a tool that manages the source code history and allows multiple
developers to work on a single project without stepping on each other’s
toes. Git is software that you install locally on your computer, and it works
primarily from the command line (though there are also graphical user
interfaces for Git).
Understanding GitHub
GitHub, on the other hand, is a web-based platform that uses Git for version
control. Think of it as a social networking site for coders and their code. It
allows you to upload your Git repositories online, making it easier to
collaborate with others. GitHub provides additional features such as Pull
Requests, Issues, and Wikis for your repositories.
Git is mainly a local tool; you use it to track changes on your computer. It is
powerful on its own, but its capabilities are magnified when you bring
GitHub into the mix. With GitHub, you can share your code with the world,
collaborate with other developers, and even integrate third-party apps and
services.
Use Git when you are working on a project (either alone or with a
team) and need to keep track of the changes in your code.
Use GitHub when you want to share your project with others,
collaborate more efficiently, or when you need a remote backup of
your repository.
In Summary:
Git is the tool, and GitHub is the service that hosts your repositories and
enhances collaboration. They are distinct but complementary. While you
can use Git without using GitHub, utilizing them together creates a more
powerful and efficient workflow, especially for collaboration on larger
projects or open-source contributions. Next, we’ll look at other version
control systems and how they compare to Git.
Subversion (SVN
Subversion, also known as SVN, is a centralized version control system
initially developed by CollabNet Inc in 2000, and now maintained by the
Apache Software Foundation. Unlike Git, which is a distributed system,
SVN follows a more linear approach to version control.
While SVN does support branching and merging, the mechanism is quite
different and can be more cumbersome compared to Git. SVN requires a
connection to the central repository for commits, but it can track changes
offline to some extent. Some teams find SVN straightforward and suitable
when transitioning from a no-VCS setup, but it lacks some of the robust
features offered by distributed systems like Git.
While Mercurial supports most of the basic features of Git, such as local
commits and easy branching, its simplicity does come at the cost of fewer
features by default. However, it does have a robust plugin system that
allows you to extend its functionality.
Unlike Git, Perforce lacks a distributed architecture and does not support
local repositories in the same way that Git does.
However, CVS is less efficient with large projects or binary files and has a
more error-prone branching and merging system compared to newer VCS
like Git or SVN. Development on CVS has slowed significantly, and it
lacks many features found in contemporary systems. Today, CVS is mostly
used in projects that adopted it before modern systems were available and
have not yet migrated to a newer VCS.
In Summary:
Different version control systems have different strengths and are suited to
different types of projects. While Git’s robustness, flexibility, and
widespread adoption make it the tool of choice for most software
development projects, other systems may be more suited to specific use
cases.
The key is to understand your project’s needs and the capabilities of each
VCS. Regardless of the specific system you use, the important thing is that
you use version control. It’s an essential tool for modern software
development. In the following chapters, we will focus on mastering Git, but
many of the principles and practices you’ll learn will apply to other version
control systems as well.
Installing
Now that we’ve learned what version control is and have a basic
understanding of Git, it’s time to start using Git practically. The first step is
to install Git on your computer. This section will guide you through the
process of installing Git on Windows, macOS, and Linux.
Installing Git on
Installing Git on
1. Git might be preinstalled on macOS. You can check this by typing git
--version in the terminal. If it’s already installed, you’ll see the Git
version displayed.
2. If you don’t have Git or want to install a newer version, the easiest
way to install Git is using Homebrew. If you don’t have Homebrew,
you can install it by visiting brew.sh and following the instructions.
3. After installing Homebrew, you can install Git by typing brew
install git in the terminal, and pressing Enter.
4. To check if Git was installed successfully, type git --version in the
terminal. It should display the installed Git version.
Installing Git on
1. On a Linux system, you can use the package manager that comes with
your distribution to install Git.
2. For Debian/Ubuntu-based systems, open a terminal and type sudo
apt-get update followed by sudo apt-get install git.
3. For Red Hat/Fedora-based systems, use sudo dnf install git.
4. Please note, other distributions might require different commands or
procedures.
5. To confirm that Git is installed, type git --version in the terminal.
This will show you the version of Git that’s installed.
Configuring
After installing Git, it’s a good idea to configure it with your information.
1. Open your terminal or Git Bash (on Windows).
2. Type git config --global user.name "Your Name" and press Enter.
3. Type git config --global user.email "[email protected]"
and press Enter.
This sets up your name and email as the author of your commits. It’s
important because every commit you make will include this information.
Wrapping Up
Basic Git
Before we dive into creating repositories and making commits, it’s essential
to familiarize yourself with some basic Git commands. These commands
form the bedrock of your interactions with Git and will be used frequently
throughout your Git journey.
Let’s start by looking at some of the most common Git commands you’ll
use. Remember, practice makes perfect. So, as you read, try to follow along
by typing the commands on your own computer.
git init
The git init command is used to create a new Git repository. When you
run this command in a directory, Git initializes a new repository in it. This
means that Git starts keeping track of your files and changes in that
directory. You can run this command in any directory to create a new
repository there:
$ git init
The dollar sign ($) is used to indicate the command prompt, so you don’t
need to type it too.
git clone
The git clone command allows you to create a copy of an existing Git
repository in your local machine. This is especially useful when you want to
work on a project that is hosted on a remote repository, like GitHub.
$ git clone <repository-url>
git add
The git add command is used to stage changes for a commit. It tells Git that
you want to include the updates to a particular file(s) in the next commit.
This includes new files, modifications to existing files, and the deletion of
files. Here, the term “staging” refers to the process of preparing files for a
commit. The “staging area” is where Git keeps track of the changes that are
to be included in the next commit.
$ git add <file-name>
To add all new and modified files in the current directory and its
subdirectories to the staging area, use the . (dot) as the file name:
$ git add .
The git add command also has a -A flag that allows you to stage all
changes, including all new, modified, and deleted files in the entire
repository, not just the current directory and its subdirectories:
$ git add -A
git commit
The git commit command is used to save your changes to the local
repository. This step takes the files as they are in the staging area and stores
a snapshot of these files as a commit. A in Git is like a checkpoint in your
project history that you can return to at any time. Each commit has a unique
ID, often referred to as a , which you can use to access it whenever you
need to.
$ git commit -m "Commit message"
The git commit command also has an -a flag that allows you to
automatically stage files that have been modified and deleted, but new files
that have not been tracked are not affected:
$ git commit -a -m "Commit message"
If there are new files that you’ve never added to the repository before, you
will need to add them using git add <file> or git add . before they can
be included in a commit.
If you need to write a longer commit message, you can omit the -m flag and
just run git commit. This will open a text editor where you can write your
commit message. When you’re done, save the file and close the editor to
complete the commit. We’ll discuss best practices for writing commit
messages in a later chapter.
git status
The git status command displays the state of the working directory and
the staging area. It lets you see which changes have been staged, which
haven’t, and which files aren’t being tracked by Git. This command gives
you a summary of all the changes that have been made since the last
commit, and which of these changes are ready to be committed.
$ git status
git log
The git log command shows a list of all the commits made to a repository.
The commits are displayed in reverse chronological order, so the most
recent commit is at the top. This command provides a history of your
project, showing the changes made in each commit, as well as the author of
the commit and the date it was made.
$ git log
These commands are just the tip of the iceberg when it comes to interacting
with Git, but they will get you started on your journey. As we move along
through the chapters, we’ll introduce more commands and dive deeper into
how Git works.
The Command Line Interface (CLI) is a text-based way to interact with Git.
As you’ve seen in the previous section, you issue commands by typing
them into a terminal or console. This is the original way of interacting with
Git, and it’s powerful because it gives you direct access to all Git
commands.
Advantages:
Disadvantages:
Steeper learning curve for those not familiar with a command line.
Requires memorizing commands and their options.
Might be more error-prone for beginners.
GUI tools for Git are applications that provide a visual interface for
interacting with repositories. These tools are often easier for beginners
because they don’t require memorizing commands.
Advantages:
Disadvantages:
Ultimately, many Git users find that a combination of both the command
line and a GUI tool is the most effective way to work. You might use a GUI
for day-to-day tasks and the command line for more complex operations.
In the next section, we will explore how to perform some basic Git
commands using a popular GUI tool: VSCode.
Before we begin, make sure you have both Git and VSCode installed on
your computer. VSCode should automatically detect Git, but if not, you can
set the path to Git in the VSCode settings.
Initializing a Git
1. Open the folder (or directory) you want to use as a Git repository in
VSCode.
2. Click on the Source Control icon in the Activity Bar on the side of the
window. You’ll recognize this as the icon with three connected circles,
similar to the Git logo.
3. Click on ‘Initialize Repository’. This will create a new Git repository
in the current folder.
Alternatively, you can also initialize a Git repository from the VSCode
Command Palette (Ctrl + Shift + P or Cmd + Shift + P on Mac). Type
‘Git: Initialize Repository’ and select the command.
Cloning a
Instead of using git clone in the command line, in VSCode you can:
Staging
1. After making changes to your files, go to the Source Control view (the
icon with three connected dots in the Activity Bar).
2. In the changes section, you’ll see a list of all the modified files. Click
on the “+” sign next to each file you want to stage, or click on the “+”
sign at the top to stage all changes.
Committing
Instead of using git commit in the command line, in VSCode you can:
In the command line, we used git status and git log. In VSCode, much
of this information is available visually:
1. In the Source Control view, you can see which files have changed.
2. For history, you can install an extension like Git History to view the
commit logs.
VSCode provides a visually intuitive and easy way to interact with Git,
especially for those who are not comfortable with the command line.
However, as you become more experienced, you may find it useful to use a
combination of the GUI and command line depending on the complexity of
the tasks you are performing. But in most cases, the GUI should be
sufficient for your day-to-day Git needs.
4. Stage the File: Use the git add command to stage the file, which
means you are preparing it to be included in the next commit.
$ git add README.md
5. Commit the File: Finally, use the git commit command to save the
staged changes. Make sure to include a descriptive message about
what changes the commit includes.
$ git commit -m "Add README file with pro\
ject title"
6. Check the Status: Use the git status command to see the state of
your repository. Since you’ve made a commit, it should tell you that
your working directory is clean.
$ git status
3. Open the Directory: Go to File > Open Folder and select the
directory you just created.
6. Stage the File: In the Source Control view, click the ‘+’ icon next to
the README.md file to stage it.
Nice! You’ve just created your first Git repository and made your first
commit. Whether you chose the command line or VSCode, you now have a
snapshot of your project that you can always revert back to if needed. As
you work on more complex projects, you’ll find that Git is an invaluable
tool for managing and tracking changes.
2. Commit the Change: Stage the file and commit the change with a
message indicating what you modified.
$ git add README.md
$ git commit -m "Add a new line to README"
3. Viewing the Commit History: Now, let’s view the commit history by
using the git log command. This will show you a list of all the
commits made in the repository in reverse chronological order.
$ git log
commit a4d5b8d8ed4b2e0b4567df2b2
Author: Your Name <[email protected]>
Date: Thu Jun 18 10:45:00 2025 +0000
The commit hash, author, date, and commit message are displayed for
each commit. You can navigate through the log using the arrow keys
and exit by pressing q.
Save and close the text editor if it pops up requesting a revert commit
message. This will effectively undo the changes made in the “Add a
new line to README” commit, bringing your README.md file back to
its initial state.
3. Commit the Change: Go to the Source Control view, stage the change
by clicking the ‘+’ icon next to the README.md file, enter a commit
message, and press Ctrl + Enter or Cmd + Enter on Mac to commit
the change.
And that’s it! Now you know how to view and revert commits in your
repository, and how you can use this powerful feature to undo mistakes or
simply explore what the project looked like at any point in its history.
Understanding these concepts is fundamental in using Git effectively for
version control. And whether you prefer the command line or VSCode, Git
has you covered.
3. Branching and Merging in
This chapter introduces the concepts of branching and merging, two
powerful features in Git that enable developers to work on different features
or bugs in isolation. You’ll learn how to create and switch between
branches, merge them, and resolve merge conflicts. You’ll also learn how to
do all these operations in Visual Studio Code.
Understanding Branches
If you think of your Git repository as a tree, your project starts as a single
trunk, growing taller with each commit you make. However, sometimes you
might want to try out new ideas, make some experimental changes, or work
on a new feature without affecting the main part of the project. In such
cases, branches come to the rescue.
Imagine your project as a tree again, but this time, besides the main trunk, it
has smaller branches sprouting out. Each branch represents a new timeline,
allowing for independent development and experimentation. This also helps
with collaboration, as multiple people can work on different branches
simultaneously without affecting each other’s work. Once you’re satisfied
with the changes in a branch, you can merge it back into the main trunk.
Main
By default, every Git repository has a main branch, often called the master
branch (or main in more recent repositories). This is usually considered the
definitive, stable version of your project. All other branches you create will
be based on this branch, or a branch that was based on this one, and so on.
Feature
In the following sections, we’ll learn how to create and switch between
branches both from the command line and using Visual Studio Code’s
graphical interface for Git. This is where Git starts showing its real power
in flexibly handling project versions. Let’s keep learning!
Creating a New
To create a new branch in Git from the command line, you can use the git
branch command followed by the name of your new branch:
In the above example, feature-x is the name of the new branch you have
created. Branch names should be meaningful and indicative of the work
being done on the branch. Running the command git branch without any
arguments will list all the branches in your repository:
$ git branch
Switching Between
Creating a branch does not automatically switch to it. To move from one
branch to another, you need the git checkout command. Let’s switch to
the feature-x branch we just created:
$ git checkout feature-x
Now, you’re working on the feature-x branch, and any commits you make
will be on this branch and not affect the main branch. You can switch back
to the main branch at any time using the same git checkout command:
$ git checkout main
Creating and Switching in One Step
Git also allows you to create a new branch and switch to it in one command
using the -b flag with the git checkout command:
$ git checkout -b feature-y
Let’s make a new commit on the feature-y branch and then switch back to
the main branch. First, add a new line to the README.md file with the text
Working on feature-y and save the file. Then, commit the changes to the
feature-y branch:
When you switch back to the main branch, you will notice that the new line
you added to the README.md file is no longer there. This is a good way to
keep your main branch clean and stable while you work on new features.
Let’s learn how to merge branches so that we can integrate the changes
from the feature-y branch into the main branch.
Merging
Once you’ve completed your work on a feature branch, the next step is to
incorporate those changes back into the main branch, or another branch if
needed. This is known as merging.
Let’s continue with our example. We made some changes in the feature-y
branch, and now we want to integrate those changes into the main branch.
To do this, you need to be on the main branch. That’s because when we
merge, the changes are applied to the currently active branch. If you’re not
already on the main branch, switch to it using the git checkout command.
With the main branch active, we can use the git merge command to merge
the changes from the feature-y branch:
$ git merge feature-y
This command combines the content of the feature-y branch with the main
branch.
Fast-Forward
In our example, since there were no new changes in the main branch after
we created the feature-y branch, Git performed a “fast-forward” merge.
This means that Git simply moved the main branch pointer to the last
commit of the feature-y branch, without needing to create a separate
merge commit.
Merge Commits
However, sometimes both the branch you are merging into and the branch
you are merging from might have changes that diverge. In such cases, Git
will create a new commit that brings together the changes from both
branches. This is known as a merge commit.
Handling Merge
There are times when changes in the branches involve the same lines in the
same files, and Git isn’t sure which version to use. This results in a merge
conflict. Git will need your help to resolve these conflicts. We’ll delve
deeper into resolving merge conflicts in the next section.
The --oneline flag displays each commit on a single line, making it easier
to read. HEAD is a pointer to the current branch - in this case, the main
branch.
This means that Git was not able to resolve the differences automatically,
and it’s waiting for you to step in and make the decision.
When a merge conflict occurs, Git will modify the affected files to visually
indicate the parts causing the conflict. Conflict markers are added to show
you the conflicting changes. These markers are:
Now that you understand how Git shows you the conflicts, you can resolve
them by manually editing the file. Essentially, you have to decide which
changes to keep or make a new change that resolves the conflict.
When editing the file, you might wonder if you need to keep the conflict
markers. The answer is no. The conflict markers are there to guide you in
locating and understanding the conflicts. Once you decide on the changes to
keep, you should remove the conflict markers.
For example, if you want to keep the change from the branch you’re
merging, your file should look like this after editing:
This is the conflicting change on the bra\
nch you're merging.
After you have made your changes and removed the conflict markers, you
need to tell Git that the conflict has been resolved. To do this, stage the file
by using the git add command:
$ git add README.md
Finally, it’s time to cement the resolution with a commit. This commit will
include the resolved changes:
$ git commit -m "Resolved merge conflict \
in README.md"
Editing files and removing conflict markers manually isn’t the only way to
resolve conflicts. There are various tools that provide a more visual or
guided interface to help you. For instance, VSCode has a built-in merge
conflict resolution tool that highlights conflicts and allows you to easily
choose which changes to keep. We will explore this in the last section of
this chapter.
1. Click on the current branch name at the bottom left corner again.
2. A window pops up showing a list of branches. Click on the branch you
want to switch to.
1. First, switch to the branch that you want to merge into (e.g., main).
2. Click on the ellipsis (…) on the Source Control title bar and select
“Branch”, then “Merge Branch”.
3. In the popup window, select the branch you want to merge from.
4. If there are no conflicts, the branches will merge automatically. If
conflicts arise, you’ll get a notification.
Remember that while VSCode provides these handy features for handling
Git operations, it’s essential to understand the underlying Git commands
and concepts to fully grasp what’s happening when you click these buttons.
This way, you’ll be more equipped to resolve any issues that might arise
and to use Git more effectively.
4. Introduction to GitHub
In this chapter, we’ll introduce GitHub, a popular platform for hosting Git
repositories. You’ll learn how to create a GitHub account, explore its
interface, and create your first GitHub repository.
What is GitHub
Wow, you’ve come a long way already! You’ve taken your first steps into
the world of version control, learned about Git, its core concepts like
commits, branching, and merging, and even used both the command line
and a graphical user interface with VSCode. That’s impressive, and you
should be proud of yourself!
Now it’s time to up the ante and dive into a platform that brings even more
power to your version control skills – GitHub. If you recall, we touched on
GitHub in the first chapter, but let’s dig a bit deeper and see why it’s such a
crucial tool for developers around the world.
GitHub is an online platform that utilizes Git for version control and
collaboration. It allows you to work on projects with other people, keep
track of issues, and even host web pages. Essentially, it takes all the version
control goodness from Git and wraps it in a user-friendly interface that’s
accessible from anywhere.
While Git is super powerful, it can be a bit isolated when working on your
own. GitHub takes your coding projects to the cloud, allowing for robust
collaboration features. This means that whether you’re a team of one or one
thousand, you can work together effectively. It’s especially popular in open-
source projects (projects where the code is available to the public and can
be modified and used by anyone).
Alternatives to
While GitHub is incredibly popular and widely used among developers for
hosting Git repositories, it’s not the only option available. There are other
platforms that offer similar functionalities, with some distinct advantages:
SourceForge has been around since the late 1990s, making it one of the
pioneers in code repository hosting. Like GitHub, it provides a web-based
interface for managing repositories, but in addition to Git, it also supports
other version control systems such as Subversion and Mercurial.
SourceForge is particularly popular among open-source projects and offers
features such as project web hosting, forums, and mailing lists. However, its
interface is dated compared to newer platforms like GitHub and GitLab,
and it does not offer the same level of integration with modern development
tools.
Let’s get you set up with GitHub and explore its powerful features! In the
next section, you’ll learn how to create a GitHub account. This will be the
first step in unlocking the collaborative power of version control with
GitHub.
Creating a GitHub
Alright, it’s time to create a GitHub account. This is a straightforward
process, and best of all, it’s free! Now, just a heads-up: website interfaces
tend to evolve, so the exact steps and the look of the pages might change.
However, the essential elements usually stay the same. So, if the GitHub
signup page looks a bit different from what’s described here, don’t worry!
You should still be able to follow along. Here’s a general guide to creating a
GitHub account:
1. Navigate to GitHub’s Website: Open your web browser and go to
GitHub’s official website - www.github.com. Typically, you can find
the option to create an account (or sign up) prominently displayed on
the homepage.
2. Sign Up: Look for a “Sign up” button or link, usually located at the
top-right corner or in the center of the page. Click on it to get started.
Next, we’ll get acquainted with the GitHub interface. Remember that
practice makes perfect, so don’t be afraid to click around and learn by
doing.
GitHub Homepage
Upon logging into GitHub, you land on your dashboard. Here you’ll find:
Navigation Bar
Pull Requests: An area where you can see your pull requests. We’ll
learn more about pull requests in a later lesson.
Issues: A section where your issues are listed. We’ll also cover issues
in a later lesson.
Notifications: An overview of all your notifications.
Profile and Settings: Click on your profile picture to find these
options.
Profile Page
Access your profile by clicking on your profile picture and selecting “Your
profile”. Your profile page is where you can:
Customize Your Profile: Add a profile picture, write a short bio, and
add a link to your website or portfolio.
View Your Repositories and Contributions: A summary of your
repositories and an overview of your contributions to GitHub projects.
Repository Page
Clicking on a repository, yours or someone else’s, will take you to its page.
This page usually contains:
Code: This is where the files and directories of the project are
displayed.
Issues: Here, users can report bugs, ask questions, or suggest
enhancements.
Pull Requests: Any proposed changes to the repository are listed here.
Actions: This is where you set up and monitor automated workflows.
Security: This tab provides an overview of any security issues
associated with your repository.
Insights: This gives you a detailed analysis of the repository, including
contributions and repository traffic.
Inside a repository, you can create new files or edit existing ones. Look for
options to add a file or edit an existing one.
Account Settings
To reach your account settings, click on your profile picture and select
“Settings”. This is where you can set your preferences, such as email
notifications and account security.
As you spend more time on GitHub, you’ll become more comfortable with
the platform. It’s a powerful tool, so take your time and explore its many
features. We’ll discuss creating your first GitHub repository and using
GitHub for version control in the next section. Get ready!
Log into your GitHub account and click on the “+” icon at the top right
corner of the page. From the drop-down menu, select “New repository.”
You’ll be taken to a page where you can set up your new repository. Here’s
what you need to do:
Once you’ve filled out this page, click on the “Create repository” button.
Nice! You’ve created your first GitHub repository. You will now be
redirected to your new repository’s main page, where you can see your
README file displayed.
Remember that your repository is more than a storage space for your files –
it’s also a space for managing your project. So, it’s important to get familiar
with the different features of your repository that GitHub provides.
Remote repositories work hand in hand with local repositories. When you
make changes to your project locally, you have to explicitly “push” those
changes to the remote repository to update it. Conversely, if someone else
has made changes to the remote repository, or if you have pushed changes
from a different machine, you would need to “pull” these changes into your
local repository.
While Git enables the use of multiple remote repositories, the typical
practice, particularly among smaller teams, is to maintain a single primary
remote repository. This primary repository often serves as the main hub for
the codebase, ensuring everyone has access to the most recent, stable
version of the project. However, having multiple remote repositories can be
beneficial in complex projects, for instance, when you want to have
separate repositories for development, staging, and production
environments.
Git also allows you to assign names to your remote repositories for easy
reference. By default, Git assigns the name “origin” to the primary remote
repository. This name can be changed as per your project needs or left as is
for consistency with common Git practices.
Now that you’ve understood what remote repositories are, let’s see how to
connect your local Git environment to a GitHub remote repository. In the
next section, you’ll learn how to connect Git with GitHub, push local
changes to a remote repository, and pull updates from it. We’ll be using
GitHub as our remote repository host, but the same principles apply to other
Git hosting services like GitLab and Bitbucket, even though the steps may
vary.
Assuming you have a GitHub account and a local Git repository (from
previous sections), here’s how you link the two:
You have now linked your local Git repository to a remote GitHub
repository! This connection is an important foundation for collaborating on
projects and syncing your work between your local machine and GitHub.
Connecting with
5. Verify the Remote Repository: You can confirm that the remote
repository has been successfully added by checking the bottom-left
corner of VSCode. You should see a cloud icon with an arrow pointing
upwards (push) and another pointing downwards (pull). These icons
indicate that VSCode is now connected to your remote repository on
GitHub.
And that’s it! You’ve now connected your local Git repository to GitHub
using VSCode.
Contributing to a Project:
Creating a Backup:
2. Clone the Repository: Open your command line or terminal, and use
the git clone command followed by the URL of the repository you
want to clone:
git clone https://github.com/username/rep\
ository.git
Replace the URL with the one you copied from GitHub. This
command creates a new directory with the same name as the repository
and downloads the code and version history into this new directory.
1. Open VSCode.
3. Choose a Location: VSCode will ask you to select a directory for the
repository. Navigate to where you’d like the cloned repository to be
located and confirm the location.
Once the clone is complete, VSCode will ask if you’d like to open the
cloned repository. Click ‘Open’ to start working on it.
You now have a good grasp of what cloning is, why it’s important, and how
to do it using both the command line and VSCode. In the next section, we
will tackle how to keep your local and remote repositories in sync by
pushing to and pulling from GitHub. Congrats on making it this far!
Pushing to and Pulling from GitHub
Now that we’ve explored cloning, it’s time to tackle two other crucial
operations that will ensure the synchronization between your local and
remote repositories: pushing and pulling. These operations allow your local
Git repository and your GitHub repository to communicate and share
changes, ensuring that both repositories are up-to-date with the latest
changes.
The git push command tells Git to push your commits to the remote
repository. The word ‘origin’ is an alias that stands for the URL of your
remote repository on GitHub. And ‘main’ is the branch that you’re pushing.
After running the git push command, your changes from the main branch
in your local repository are now also in the main branch of your remote
repository on GitHub.
While git push is used to send commits from your local repository to your
remote repository, git pull is used to fetch changes from the remote
repository and merge them into your current local working branch.
Let’s say you’re working on a project with a team, and one of your
teammates has pushed some changes to the repository on GitHub. To get
those changes into your local repository, you’d use the git pull command.
Here’s what that command looks like:
$ git pull origin main
The git pull command tells Git to fetch the changes from the remote
repository (origin) and merge them into your current local working branch
(main).
VSCode makes it easy to push and pull changes to and from GitHub
without having to leave your editor or use the command line. Here’s how to
do it:
1. Commit your changes: Make some changes to your code, then stage
and commit those changes using the Source Control panel.
2. Push the changes: Clicking the three dots at the top of the Source
Control panel will open a menu. Click on the ‘Push’ button to push
your changes to GitHub. Alternatively, After making your commit in
the Source Control panel, you might see a button that says “Sync
Changes”. Click it to push your changes to GitHub. You can also click
the circular button with an up arrow beside it at the bottom-left of
VSCode, where you have the branch name. This will either push or
pull depending on whether you have new commits in the local or
remote repository.
1. Open the Source Control Panel: On the left side of VSCode, click on
the ‘Source Control’ icon to open the Source Control panel.
2. Pull the changes: Clicking the three dots at the top of the Source
Control panel will open a menu with a ‘Pull’ button. You can also click
the circular button with an a down beside it at the bottom-left of
VSCode, where you have the branch name.
In addition to these two main types of permissions, there are also a few
other permissions that can be granted to users:
Triage users can view and manage issues and pull requests, but they
cannot make changes to the repository’s contents.
Note that the permissions for a repository are managed at the individual
repository level. This means that a user can have different access levels to
different repositories.
When you create a new repository on GitHub, you can choose to make it
either public or private. This setting determines who can see and access the
repository.
In the next section, we’ll discuss how you can invite collaborators to a
repository and manage their permissions.
5. Choose permissions. Once you’ve added the person, you can select
the level of access they should have from the dropdown menu. Make
sure to give only the necessary permissions based on what they need to
do.
6. Send the invitation. After you’ve selected the permissions, click the
“Add [username] to [repository name]” button. They will receive an
email with the invitation, and once they accept it, they will have access
to the repository with the permissions you’ve specified.
Forking a
Forking is one of the fundamental concepts on GitHub that allows you to
create a copy of a repository under your own account. This enables you to
experiment with changes without affecting the original project. It’s
especially popular in open-source projects, where it’s often used as a way to
contribute. Let’s dive into what forking is, why you might want to do it, and
how it’s done.
2. Click the Fork Button: In the top-right corner of the page, you will
see a button labeled “Fork.” Click this button. GitHub will create a
copy of the repository in your account.
3. Clone Your Fork: You can now clone this forked repository to your
local machine and work on it just like any other repository.
You can then pull changes from the original repository by running the
following command:
$ git pull upstream main
This will pull changes from the original repository’s main branch into your
forked repository. You can also pull changes from other branches by
replacing main with the name of the branch you want to pull from.
We used as the name of the remote in the above example instead of the
default “origin.” This is a common convention, but you can use any name
you want.
Pull
Pull requests are an essential part of the collaborative development process,
especially on GitHub. They are a way to propose changes from one
repository to another, typically from a fork back to the original repository,
or between branches in the same repository. They not only suggest changes
but also provide a way to review and discuss these proposed changes before
they are integrated.
Pull requests show the differences between the content in the two branches.
The changes are presented in a diff format, which shows what has been
added or removed from files.
2. Commits: All the commits that are included in the branch and thus in
the pull request. Each commit has a message explaining what it does,
making it easier for others to follow your work.
3. Make Your Changes: Make the changes to the code in your local
repository. Be sure to make small, focused commits with informative
commit messages that explain what each change does.
4. Push Your Branch to the Remote Repository: Once you are satisfied
with the changes, push your branch to the remote repository (your
fork, if you are contributing to someone else’s project) by using the
git push command.
9. Wait for Approval and Merging: Once all feedback has been
addressed, wait for the maintainers to review and approve your pull
request. They may merge it directly, or they may ask for further
changes.
10. Clean Up After Merge (Optional): After your pull request is merged,
you might want to delete the branch you created for it, both locally and
on the remote repository. This keeps your repository clean and
organized.
These steps should help you create and submit a pull request to either a
project you are contributing to or even to your projects when working with
branches.
Here are some best practices to follow when creating a pull request:
One of the most common issues with pull requests is merge conflicts These
occur when the same part of the code has been modified in both your
branch and the target branch. GitHub will alert you of the conflict, and you
will have to resolve it manually.
Another common issue is submitting a pull request too early. It’s best to
fully test your changes and ensure everything works as expected before
requesting others to review your code.
Pull requests are the heart of collaboration on GitHub. Understanding how to create and
manage them effectively will make you a better collaborator and open-source
contributor. They are a way to contribute to the projects you care about, improve your
coding skills, and collaborate with others in the developer community.
Now that we have a good understanding of pull requests and their
importance in proposing and reviewing changes, let’s discuss another
essential aspect of project collaboration on GitHub - Issues.
Issues are a great way to keep track of tasks, enhancements, and bugs for
your projects. They act like a conversation thread where you can discuss
these items with your team or contributors, assign people to tasks, and keep
track of progress.
To open an issue, you can navigate to the main page of the repository and
click on the “Issues” tab, then click on the “New Issue” button. Here, you
can write a title for your issue and a description. It’s good practice to be as
clear and descriptive as possible to help others understand the issue.
When creating an issue, you can assign it to one or more people, add it to a
milestone, or categorize it using labels.
One of the great things about issues and pull requests is that they can be
linked. This means when a pull request that resolves a particular issue gets
merged, the issue gets automatically closed, and vice versa.
To link an issue to a pull request, you can use certain keywords followed by
the issue number in the pull request description. Keywords include close,
closes, closed, fix, fixes, fixed, resolve, resolves, and resolved.
For example, if you have an “issue number 12” and you’ve created a pull
request that solves this issue, in your pull request description, you could
write Fixes #12. This will create a reference link in the issue, and once the
pull request is merged, issue number 12 will automatically be closed. The
issue number is different from the issue title. You’ll see the issue number
beside the title after you open an issue.
GitHub Issues integrate smoothly with your Git workflow. When you’re
ready to work on an issue, you might create a new branch with the issue
number in the name, make your changes, commit them referencing the issue
in your commit message, push the branch and open a pull request.
Using issues in this way helps maintain a clear connection between the
discussion about what should be done and the actual changes made in the
code. As a result, your project’s history becomes not only a record of what
changes were made but also why they were made.
By leveraging the combination of issues and pull requests, you can ensure a
more organized and efficient workflow, making collaboration on GitHub
more effective and enjoyable.
Code
Code reviews are a critical practice in modern software development,
designed to catch bugs, improve code quality, and spread knowledge among
team members. On GitHub, code reviews happen in the form of comments
on a pull request.
When a pull request is opened, it’s common for the maintainers of the
project or other collaborators to review the changes. This can involve
several steps:
Approving the Pull Request: Once the reviewers are satisfied with
the changes, they can approve the pull request. This indicates that the
pull request is ready to be merged.
Merging on
Once the code review is done and any necessary changes have been made,
it’s time to merge the pull request. Merging is the act of integrating the
changes from the pull request’s branch into the target branch.
On GitHub, merging a pull request is simple. If there are no conflicts
between the pull request’s branch and the target branch, you can just click
the “Merge pull request” button, and GitHub will do the rest.
Merge commit: This strategy combines all the commits from the
source branch into a single merge commit in the target branch. The
commit history of the source branch is preserved.
This strategy squashes all the commits from the source branch into one
and then merges that commit into the target branch. This leads to a
cleaner commit history but loses the context provided by individual
commits.
The right strategy to use depends on your project and how you want to
structure your commit history.
Code reviews and merging are the final steps in the collaborative development workflow
on GitHub. They are crucial practices for maintaining high-quality code and a healthy
project. By knowing how to review and merge code effectively, you can contribute more
efficiently to your projects or any open-source project on GitHub. Remember to be
considerate and constructive when reviewing people’s code; collaboration is all about
helping each other to grow and improve.
7. Best Practices for Git and
Throughout the journey so far, you’ve gained a solid understanding of Git
and GitHub. You’ve learned how to make commits, create branches, open
pull requests, manage issues and collaborate with others.
This chapter provides guidelines on how to use Git and GitHub effectively.
We’ll discuss best practices, such as writing good commit messages,
managing branches, organizing your repository, and other key points to
remember when working with Git and GitHub.
Take note that these aren’t to be followed blindly; they are guidelines that
have evolved based on the experiences of many developers. They might not
be a perfect fit for every case or preference, but they’re invaluable as a
starting ground to shape your code of practice.
Let’s learn some best practices for writing commit messages that
communicate effectively.
A clear, descriptive commit message can save a lot of time when you or
others are looking back through the project’s history. Compare a vague
message like “Updated code” with a descriptive one like “Fixed bug
causing application crash when user inputs negative numbers”. The second
example immediately conveys what the commit is about, reducing the need
to dig through the code to understand the changes.
For example, if you’ve fixed a bug, briefly explain the bug’s impact. If it’s a
new feature, describe what the feature adds to the application. The goal is to
provide context and make the commit message meaningful.
The subject line of a commit message (the first line) should ideally be kept
under 50 characters. This is not just a random rule; it’s about usability.
Many tools, including command-line tools and GitHub, are designed around
this convention and will truncate longer messages. Keeping messages short
ensures that they can be easily read at a glance.
If a commit is more complex and the subject line isn’t enough to fully
describe it, you can use the body of the message to elaborate. In the body,
focus on explaining what you changed and why you made those changes.
Remember, the code tells the story of how something was changed - the
commit message should provide context to understand these changes.
Example:
Add error handling for invalid user input
Code Reviews: During code reviews, reviewers can understand the context
of changes which leads to more insightful feedback.
Debugging: When you’re trying to find the source of an issue, being able to
read through the history effectively can often provide insights into where a
bug was introduced.
Good commit messages communicate your intentions. They are especially important in
a collaborative environment but can be just as valuable even when you’re working on
solo projects. Make it a habit to write meaningful commit messages; your teammates
(and your future self) will thank you for it.
Managing Branches
Branching is a fundamental aspect of Git and one that lends itself to a
multitude of strategies and approaches. With so much flexibility, how can
we ensure that we’re managing our branches effectively? Let’s explore
some guidelines to help maintain an efficient and organized branch
structure.
Every branch in your repository should have a clear and focused purpose. It
could be for adding a new feature, fixing a bug, or even experimenting with
some ideas. By keeping branches focused on a single task, you make it
easier to understand what changes are contained in each branch and reduce
the likelihood of conflicts when it’s time to merge.
Short-lived branches are also easier to work with. The longer a branch lives
separate from the main line of development (often the main or master
branch), the more likely it is to fall behind the current state of the project
and incur merge conflicts. Aim to merge branches back into the main line of
development as soon as their purpose has been fulfilled.
Branch names should convey the purpose of the branch. While Git doesn’t
impose any strict rules on naming branches, having a consistent and
descriptive naming convention makes it easier for you and others to
understand what’s going on in a repository.
You should frequently sync your branches with the main branch to prevent
them from becoming too far out of date. This can be achieved by either
merging the main branch into your branch or rebasing your branch onto the
main branch. Regular updates can help catch integration issues early and
reduce the scope of merge conflicts.
Once a branch has been merged and its changes are part of the main line of
development, it’s usually safe to delete the branch. This keeps the list of
branches in your repository clean and manageable.
On GitHub, you can easily delete branches after a pull request has been
merged. If you’re using the command line, the git branch -d command
can be used to delete branches that have been merged.
These rules can enforce certain policies like requiring pull request reviews
before merging, requiring status checks to pass before merging, and
preventing force pushes. With branch protection rules, it’ll be easier to
maintain the quality of code in your primary branches and avoid accidental
modification or deletion.
Branch management might seem like a lot to take in, but with consistent
practice, it’ll soon become second nature. It’s all about staying organized,
keeping communication clear, and maintaining the quality and
understandability of your project’s history.
Naming Conventions: Use clear and descriptive names for your files
and directories. This helps others understand what each file or
directory is for. Avoid using spaces in your file names as this can
sometimes cause issues. Instead, use hyphens (-), underscores (_) or
camel casing (myFile.js) to separate words. This usually depends on
the language or framework you’re using and the conventions that are
common in that community.
yarn.lock
package-lock.json
README
The README is one of the most important documents in your repository.
It serves as the first point of contact for anyone who stumbles upon your
project and as such, should be clear, informative, and inviting. Here are
some things you should include in your README:
Project Title and Description: Start with the name of your project
and a brief description. What does the project do? Why does it exist?
Creating a README that covers these areas helps make your project
inviting to both users and potential contributors. It shows that you care
about your project and the people who interact with it.
The way you organize your repository and craft your README can greatly
influence the accessibility and success of your project. Strive for clarity and
simplicity, and always consider the perspectives of different users.
2. Stay Synced: Ensure you’re always working with the most recent
version of the project by pulling changes from the remote repository
frequently. This is particularly important when collaborating with others to
avoid merge conflicts or working on outdated code.
Open source is not just a development model; it’s also a philosophy. The
open-source philosophy believes in the free exchange of ideas and
knowledge. It is built on the premise that when developers can read,
modify, and distribute source code, the software evolves. Through this
community-driven development model, open source fosters innovation and
creates more robust and reliable software.
The Open Source Initiative was formed to steward the Open Source
Definition (OSD), a document that specifies what criteria a software license
must meet to be considered open source. This definition was based on the
Debian Free Software Guidelines, with contributions from the Free
Software Movement. The OSD ensures that software can be freely
accessed, used, modified, and shared.
9. License Must Not Restrict Other Software: The license must not
place restrictions on other software that is distributed along with the
licensed software.
Now that you have an understanding of what open source means and its
core principles, let’s delve into how open-source licensing works and how
you can participate in or start your own open-source project.
Open Source
Licensing plays a key role in open-source software. It’s the legal
instruments through which the freedoms and rules associated with the
software are defined. Without an open-source license, the software, even if
its source code is publicly available, isn’t truly open source – it doesn’t
guarantee users the rights to study, change, and distribute the software to
anyone for any purpose.
There are many open-source licenses available, each with its own rules and
obligations. However, they all adhere to the Open Source Definition. Let’s
explore a few of the most common open-source licenses:
MIT
The MIT License is one of the most permissive and widespread open-
source licenses. It permits users to do almost anything with the code,
including using it in proprietary software, provided that the original
copyright notice and the license’s text is included in all copies or substantial
uses of the software.
Apache License 2.
The Apache License 2.0 is another popular choice. It’s permissive like the
MIT License but also provides an express grant of patent rights from
contributors to users.
These are just a few examples of the many licenses available. When
creating your open-source projects, it’s crucial to understand the licenses’
implications and choose one that aligns with your intentions for the project.
GitHub makes it easy to choose a license when creating a new repository,
and they provide a handy guide to understand the differences between the
licenses.
In the next section, we’ll discuss some best practices for contributing to
open-source projects. These practices will help you become an effective
participant in the open-source community and help you make meaningful
contributions.
Before diving in and making changes, spend some time understanding the
project and its community. Read the project’s documentation, check out its
issue tracker, and look at the project’s history and recent changes. Each
open-source community can have its own style, conventions, and norms,
and it’s important to understand these before contributing.
Communicate Effectively
Maintainers are usually very invested in the project, and they might not
always agree with the changes you propose. It’s important to respect their
decisions, even if they decide not to incorporate your contributions. Stay
open to feedback and be willing to make revisions as needed.
Before submitting your changes, make sure they work as expected and
don’t introduce new bugs. Add tests if appropriate. Projects often have
automated testing set up, and your changes should pass these tests.
As you work on your contribution, the main project may continue to evolve.
Regularly sync your fork and branch with the upstream project to ensure
that your changes can be merged without conflicts.
Contributing to open source isn’t just about code. You can also contribute
by improving documentation, helping with translations, reporting bugs, and
participating in discussions.
Conclusion
The open-source movement is a testament to the power of collaboration and
shared knowledge. It has shaped the software industry in unimaginable
ways and continues to be a driving force for innovation. As a contributor,
you have the opportunity to be a part of this change.
Remember, open source is not just code. It’s a community. It’s about mutual
respect, collaboration, and helping each other to achieve common goals. By
participating in open source, you are joining a global community of
individuals who believe in the power of openness and collaboration.
Whether you’re contributing to improve your coding skills, to give back to
tools you use, or to make a positive impact, your contributions are valuable.
Always be open to learning and adapting to the practices and conventions
of the community you are joining.
9. Advanced Git Features
Congratulations on making it this far! By now, you’ve gained a solid
understanding of the basics of Git and GitHub. You’ve mastered the art of
commits, branching, merging, and collaborating in open source. But the
beauty of Git is its depth - there’s always more to learn. In this chapter,
we’ll dive into some of the more advanced features of Git, such as stashing
changes, rebasing and rewriting history, using Git hooks, and tracking
changes with Git blame and bisect.
Stashing
Imagine you are in the middle of developing a new feature, and your
working directory is full of changes when a critical bug is reported. Now,
you need to switch branches to work on a fix. But you can’t switch
branches with uncommitted changes. You don’t want to commit half-done
work, and you don’t want to lose your changes either. What do you do?
This is where Git stashing comes in. Stashing allows you to temporarily
save changes that you have made but do not want to commit yet. It’s like
putting your changes in a drawer so you can work on something else, and
then taking them back out when you’re ready. Since you can’t switch
branches with a “dirty” working directory, stashing is a great way to save
your work so that you can come back to it later.
Or:
$ git stash push -m "optional stash messa\
ge"
This takes all the modified tracked files and stages them and saves them on
a stack of unfinished changes that you can reapply at any time. When you
stash your changes, Git resets your working directory to the last commit. At
first, it might look like you’ve lost all your changes, but don’t worry! They
are still there, and you can get them back whenever you want.
It’s important to note that the behavior of the git stash or git stash
push command can vary depending on the version of Git you are using and
your particular Git configuration. In many typical scenarios and newer
versions of Git, these commands will stash both staged and unstaged
changes, meaning you don’t necessarily need to stage your changes before
stashing.
If you are using an older version of Git (earlier than version 2.35), then the
git stash command will only stash staged changes by default. In this case,
you will need to stage your changes before stashing.
You can check the default behavior of the git stash command by running the
following command:
$ git config stash.default
# output
stash-all
You can also check the specific settings in your Git environment that affect
the behavior of the git stash command by running the following command:
$ git config --list | grep stash
# output
stash.default=stash-all
Your stashes are saved in a stack, which means the last stash you create is
the first one to come out. To see a list of all your stashes, use the following
command:
$ git stash list
This will show you a list of all your stashes, along with a unique identifier
for each stash. You can use this identifier to reapply or delete a specific
stash. The output will look something like this:
stash@{0}: WIP on <branch-name>: <last-co\
mmit-hash> <last-commit-message>
stash@{1}: WIP on feature-x: 50a6b7a add \
number to log
stash@{2}: On feature-x: custom stash mes\
sage
The template at the top is a general representation of what each entry in the
list might look like:
The stash@{2} entry shows what a stash message looks like when you
provide a custom message (custom stash message in this case) during
stashing.
Remember, stash@{0} represents the latest stash, stash@{1}, stash@{2},
etc., represent earlier stashes. The stash identifier is what you’ll use if you
want to apply, drop, or do other operations with a specific stash.
If you want to re-apply the changes from your most recent stash to your
working directory, you can use:
$ git stash apply
Alternatively, if you want to apply a specific stash from the list, you can
pass the stash name like this:
$ git stash apply stash@{2}
Once you have successfully reapplied a stash, you might want to remove it
from your stack. To do this, use the git stash drop command followed by
the stash name:
$ git stash drop stash@{2}
There’s also a handy command that applies the latest stash and immediately
drops it from the stack:
$ git stash pop
pop is a combination of apply and drop. It “pops” the latest stash off the
stack to your working directory.
Partial Stashing
Sometimes you might not want to stash all the changes in your working
directory. Git allows you to stash just the changes in certain files. Use the
following command and list the files you want to stash:
$ git stash push file1.txt file2.txt
Now that you have a good understanding of stashing in Git, you’re well-
equipped to manage your working directory more effectively. Up next,
we’ll dive into another advanced Git feature - rebasing.
What is Rebasing?
On the other hand, git rebase works a little differently. Rather than
creating a new commit that brings together the two branches, git rebase
moves or combines the changes onto the tip of the main branch.
Essentially, it takes the changes made in the feature branch, saves them as
temporary files, then reapplies them on top of the main branch, one by one,
in the order they were made.
This creates a new commit for each change, giving the impression that the
changes were made linearly on top of whatever is present in the main
branch.
Rebasing can be a powerful tool, but it also comes with a big warning: it rewrites
commit history. This can make it hard to follow what happened in the history of your
project, which is often the whole point of using a version control system! As such, it’s
generally recommended to use rebasing judiciously, particularly when collaborating
with others.
The commands above take the changes in feature-x, and reapply them on
top of the changes in main.
If conflicts occur between the changes you’ve made in feature-x and the
changes made in main since you branched off, Git will pause and allow you
to resolve those conflicts before continuing.
Rewriting History
Along with rebasing, Git also allows you to alter the commit history in
other ways. Using commands such as git commit --amend and git
rebase -i (interactive rebase), you can change commit messages, combine
commits, reorder commits, and even remove commits entirely.
Just like rebasing, rewriting history changes the existing commit history.
This can be dangerous and is not recommended if you’re working with
others, as it can create conflicting histories and make collaboration more
difficult.
$ git commit --amend -m "New commit messa\
ge"
The command above replaces the last commit with a new commit that has
the same changes but a new commit message.
$ git rebase -i HEAD~3
The command above starts an interactive rebase session for the last 3
commits. Git will open a text editor listing the last 3 commits and possible
commands. You can then choose to pick, reword, edit, squash, or fix up
each commit. When you save and close the editor, Git will apply the actions
you chose, altering the last 3 commits as you specified.
Rebasing and rewriting history can be complex, but they also offer precise
control over the commit history. As long as you understand their risks and
use them carefully, they can be powerful tools in your Git toolbox.
Using Git
Git hooks are an advanced feature that can make your life much easier by
automating tasks in your repository. They are scripts that Git executes
before or after events such as commit, push, and receive. These hooks
can be used to automate various tasks you might want to perform when
these events happen. For example, you might want to run tests before a
commit is applied, or send a notification after a push operation.
Git hooks reside in the hooks subdirectory of the .git directory in every
Git repository. By default, this directory contains some sample scripts that
are disabled (they have the .sample extension). To enable a hook script,
you must remove the .sample extension.
Let’s say you want to ensure all your commit messages follow a certain
format. You can create a commit-msg hook that checks the message and
rejects the commit if it doesn’t conform. Here’s a basic example:
#!/bin/sh
Now, every time you try to commit, this script will check the commit
message.
Note: Make sure your hook scripts are always tested and maintained. A
broken hook can cause problems with the repositories it’s installed in.
As powerful as Git hooks are, remember that they are local to your Git
repository and not versioned. This means they won’t be shared when you
push to or clone a repository. If you need to share automated tasks with
others, you’ll need to use a different method, such as continuous
integration/continuous delivery (CI/CD) pipelines, which are commonly
used for tasks like running tests or deploying code.
In the next section, we’ll dive into more advanced features to trace changes
and debugging in Git. These are essential skills for when things start to go
wrong.
Git
git blame is a command that helps you determine who made changes to a
file and what those changes were, line by line. This can be particularly
useful when you’re trying to understand why a line of code exists or who to
ask about it.
Let’s say you have a file called my_script.py, and you want to see the
revision history for this file. You can use the following command:
$ git blame my_script.py
This will print each line of the file, along with the commit hash, author,
timestamp, and the line number in the original commit.
While the term ‘blame’ might sound accusatory, remember that this tool is
not meant to point fingers but to aid understanding and collaboration.
Git
git bisect is another powerful debugging tool in Git, designed to help you
find the commit that introduced a bug into your project. It uses a binary
search algorithm, allowing you to efficiently pinpoint the problematic
commit, even among hundreds or thousands of commits. The binary search
algorithm operates by dividing the data set (in this case, your commits) in
half repeatedly until the search is narrowed down to one element.
Next, you need to tell Git which commit is known to be bad. This is
usually the current commit. Run:
$ git bisect bad
For example, if you know that the bug exists in commit with hash
abc123, you could also specify it explicitly:
Now, specify a commit where you know the code was still working as
expected. This should be a commit before the bug was introduced.
Use:
$ git bisect good <commit-hash>
5. Repeat as Necessary
Once you’ve found the problematic commit, you can use git bisect
reset to end the bisect session and return your HEAD and working
directory to the normal state:
$ git bisect reset
These tools, along with the others we’ve covered, can make managing even
large and complex projects much easier and more efficient. It’s okay if these
tools seem overwhelming at first. You might not need them right away, but
it’s good to know they’re there when you do.
10. Troubleshooting Common
Git and GitHub Issues
Now that you’ve delved into the more complex functionalities of Git and
GitHub, it’s time to look at how to tackle some common issues you may
encounter along the way. We’ve already addressed a common situation in
Chapter 3 - Merge Conflicts. In this chapter, we’ll explore other issues that
may arise when working with Git and GitHub, such as being in a detached
HEAD state, authentication problems, and how to recover lost commits.
You’ll learn solutions and preventive measures for each issue.
Detached HEAD
As you venture deeper into Git, you may sometimes come across a message
saying you are in a ‘detached HEAD’ state. This can happen when you
check out a commit that is not the latest on its branch. Let’s see what this
means and how to handle it.
When you’re in a detached HEAD state, you can still make commits.
However, since there’s no branch referencing those commits, you might
lose your work once you switch to a different branch.
You can end up in a detached HEAD state if you check out to anything
other than the latest commit on a branch. This could be a previous commit,
a tag, or a different branch. For example, running git checkout
<commit_hash> will put you into a detached HEAD state.
If you’ve made some commits in the detached HEAD state and want to
keep these changes, the simplest way is to create a new branch while still in
the detached HEAD state. You can do this using git checkout -b
<new_branch_name>. This will create and switch to a new branch that
includes your detached commits.
If you haven’t made any new commits in the detached HEAD state, or if
you don’t want to keep your changes, you can simply checkout to an
existing branch (like git checkout main). This will leave the HEAD
detached commits behind, and they will be cleaned up by Git’s garbage
collection eventually.
Next, let’s look at how to handle authentication issues in Git and GitHub.
Authentication Issues
When working with remote repositories, especially on platforms like
GitHub, authentication is a key aspect of ensuring that only authorized
users have access to certain repositories and operations. While it is crucial
for security, authentication can sometimes be a source of issues and
frustrations. In this section, we’ll explore common authentication issues and
how to resolve them.
1. SSH Keys: Secure Shell (SSH keys are a pair of cryptographic keys
that can be used to authenticate yourself without a password. The
private key stays with you and should be kept secret, while the public
key can be shared with GitHub or any other Git server.
Permission
Solution:
Double-check that your SSH key is added to your GitHub account (or
another Git server you are using).
Make sure you are a collaborator on the repository or are using an
account with sufficient permissions.
If using SSH, make sure your SSH agent is running and that your key
is added to the SSH agent.
Solution:
If you enter the wrong credentials too many times, you may be temporarily
locked out.
Solution:
Wait for a few minutes and then try again with the correct credentials.
Make sure to have them at hand to avoid another lockout.
Now that we’ve tackled authentication issues, in the next section, we’ll
explore how to recover lost commits - a lifesaver when you accidentally
delete or overwrite commits.
For example, let’s say you’ve accidentally deleted a branch that had some
critical bug fixes. To recover the branch:
$ git reflog
You will see a list of every change you’ve made, each with its index, and
the most recent operation at the top.
To recover a commit, find its SHA (commit hash in the list, and then create
a new branch with that commit as the head.
$ git branch recover-branch <sha-of-commi\
t>
Cherry-Picking a
Sometimes, you might want to apply a specific commit from one branch
into another without merging the entire branch. This is where the cherry-
pick command comes in handy. It allows you to apply a commit from one
branch to another.
Cherry-picking can be useful when, for example, when you make a hotfix
on a release branch and need to apply that fix to the main development
branch.
$ git checkout mybranch
$ git cherry-pick <commit-to-apply>
Resetting a
The reset command is a powerful tool that can be used to undo changes to
a branch. It can be used to revert commits, unstage files, and even reset the
entire branch to a previous commit.
For example, you can use reset to undo the last commit on a branch:
$ git reset HEAD~1
This will undo the last commit and move the HEAD pointer to the previous
commit. The --hard flag can be used to discard any changes in the working
directory.
$ git reset --hard HEAD~1
You can also reset a branch to a specific commit. This can be useful if you
want to discard all commits after a certain point. For example, if you want
to reset a branch to a commit with the hash abc123:
$ git reset --hard abc123
Commit early and often! Small, frequent commits are easier to manage
and troubleshoot.
Push to your remote repository regularly. This serves as an offsite
backup of your code.
Avoid using commands that alter commit history on public branches.
Dealing with lost commits can be intimidating, but remember that Git is
designed to preserve data integrity, making it difficult to lose committed
work.
Git provides the means to turn what could be a catastrophe into only a
temporary setback. However, use these powers wisely and again, make sure
to practice caution when using commands that can alter your repository’s
history.
11. Conclusion and Next Steps
What a journey it’s been! We’ve delved into Git and GitHub, starting from
the fundamental concepts and gradually making our way to some of the
advanced features. Before we talk about the future and where you can go
from here, let’s take a moment to reflect on what we’ve learned throughout
this book.
Now, as we stand at the end of this book, it’s essential to realize that this is
just the beginning of your journey. The world of version control and
collaboration is ever-evolving. With the foundation you’ve built here, you
are well-equipped to continue learning and growing.
In the next sections, we’ll talk about further resources and suggested
learning paths to continue on your journey.
While Git is the most popular version control system, it’s not the only one.
Understanding alternative systems can provide different perspectives and
might be useful in certain situations:
Contributing to Open
CI/CD Integration: Learn how Git integrates with CI/CD tools like
Jenkins, Travis CI, or GitHub Actions.
Integration with IDEs: Explore how Git can be used efficiently with
Integrated Development Environments like IntelliJ, Eclipse, or Visual
Studio.
Join a Community
Remember that the key to mastering any skill, including using Git and
GitHub, is practice and continual learning. Don’t be afraid to experiment,
break things and fix them again. That’s how you learn.
Staging Changes:
Stage a file
$ git add <file>
Viewing History:
Branches:
Delete a branch
$ git branch -d <branch_name>
Remote Repositories:
Stashing:
Undoing Changes:
Unstage a file
$ git reset <file>
Revert a commit
$ git revert <commit>
and its available options, always refer back to relevant chapters in this
book.
Appendix B: Glossary of Git
and GitHub Terms
Here is a collection of some common terms we’ve encountered throughout
this book:
Blame: A Git command that allows you to see who last modified each
line of a file and when, helping track the origin of changes.
Fetch: The process in Git of retrieving commits, files, and other data
from a remote repository to your local one.
Hook: A way to execute custom scripts when certain key events occur
in Git. They’re used for the automation of workflows.
Master: Traditionally the default branch name in Git for the initial
branch. However, many projects now use ‘main’ as the default branch
name.
Merge: The action in Git of integrating changes from one branch into
another. It keeps the commit history intact.
Origin: The default name Git gives to the server where your repository
was originally cloned from.
Upstream branch: The branch which was cloned from the remote
repository, or the branch that is synced with the remote repository.
Remember, the purpose of this glossary is to serve as a handy reference
when you come across a term you don’t recognize. Don’t worry if you don’t
have all these terms memorized right away. With time, they’ll will become
part of your everyday vocabulary as you use Git and GitHub more
frequently.