Version Control with Git and Github

Jadesola AdeagboJadesola Adeagbo
15 min read

Just last month, I experienced what you could call every developer’s worst nightmare. I woke up one morning, ready to dive into work and hit my daily targets, but all efforts in trying to start my laptop were to no avail, as it refused to come on. Panic began to creep in, but remembering the popular Nigerian slang, “Them go whine you, but no panic," I quickly got my sister’s laptop, re-cloned my project from GitHub, and picked up right where I left. Thankfully, I had pushed my code to GitHub just the day before, so even though my laptop wouldn’t turn on, I still had access to everything I needed. Github saved me from what could have been a major setback!

Your story might be a little different, but one thing remains the same for all of us—version control is essential. In this article, we'll explore two crucial tools that go hand-in-hand with version control and enhance collaboration: Git and GitHub.

I can confidently say that GitHub has saved me more times than I can count. Its possibilities are endless, and it could be the key to taking your projects and teamwork to new heights.

Defining Git and GitHub

Git is a distributed version control system that tracks the version of your files. In other words, git takes a picture of what all your files look like at the moment and stores a reference to that snapshot. It helps manage different versions of code, collaborate with others, and, more importantly, ensure that different people can work on a project without any conflicts.

GitHub is a web-based platform for hosting git repositories.

People often mistake git for GitHub; if you have been wondering, they are not the same. Git is the local version control system installed on your machine, while GitHub is the remote service that stores git repositories and allows collaboration.

GitHub Terminologies

  • Repository (Repo): is a file tracked by git, where your project files and complete history of changes are stored, which may be local or remote.

    A local repository is on your computer. A remote repository is on GitHub.

  • Commit: A commit is a snapshot of the current state of your project.

  • Merge: A merge integrates changes made from one branch into another

  • Clone: Creates a local copy of a git repository

  • Push: Sends local changes to a remote repository.

  • Pull: Fetches changes from a remote repository to a local repository. It combines git fetch (to download changes) and git merge (to incorporate them).

  • Fork: A fork allows you to make a copy of another user’s repository and make changes without directly affecting the original repository, unless you make a pull request and it is merged.

  • Branch: A branch is a separate line of development. Allows collaborators on a project to make different changes to the same project without affecting the main code base

  • Pull Request: A pull request is a request to merge changes from a featured branch into another branch (usually the main branch) in the same repository or another.

  • GitHub issues: are used to track bugs, enhancements, or other tasks related to the repository. Issues can be assigned to team members, labeled, and discussed within the community.

Basic Git commands

  • git init initializes a git repository

  • git add [file_name] stages changes for the next commit. This command tells git what changes you want to include in the next commit but does not actually commit them. You can specify a file or use “*” to add all files.

    Example: git add . (stages all changes)

  • git commit -m “[message]” commits files and creates a snapshot of the current repository.

    Example: git commit -m Added button functionality”

  • git remote add [remote_name] [repo_url] adds a remote repository (like on GitHub) that allows you to sync changes between your local and remote repositories.

    Example: git remote add origin https://github.com/user/repo.git

  • git push [remote_name] [branch_name] pushes committed changes to a specified branch on a remote repository.

    Example: git push origin main (pushes committed changes to the main branch).

  • git pull [remote_name] [branch_name] fetches and merges changes from a specified branch on your remote repository to your current branch on your local repository.

    Example: git pull origin development (Pulls changes from the development branch)

  • git branch lists all local branches in your repository. The current branch is marked with an asterisk (*).

  • git checkout [branch_name] allows you to switch to another branch, making it the current branch.

    Example: git checkout development (switches to the development branch).

  • git merge [branch] merges the specified branch into your current branch, integrating the changes from one branch into another.

  • git clone [URL] creates a copy of a repository on your local machine

  • git status shows the current state of the working directory and staging area. Shows files that are untracked, modified, or staged for commit

  • git stash temporarily stores the changes in your working directory that you are not ready to commit in order to allow you to switch to another branch without losing your progress.

Setting up Git and GitHub

Step 1: Install Git

  • On Windows: You can download Git from Git’s official website

  • On MacOS: You can install Git using Homebrew (if you have it installed):

      brew install git
    

    Alternatively, you can download Git from Git's official website.

  • On Linux: Open the terminal and install Git using your package manager. For example:

      sudo apt install git     # For Ubuntu/Debian
      sudo yum install git     # For Fedora/Red Hat
      sudo pacman -S git       # For Arch
    

Step 2: Configure Git

Once Git is installed, you’ll need to configure it with your name and email. This information will be used in your commits.

Open the terminal or Git Bash (for Windows) and run the following commands:

  • Set up your identity globally across all repositories on your machine.
git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"
  • Verify your configuration by running:
git config --global --list

Step 3: Set Up GitHub

  • Create a GitHub Account: If you don’t have a GitHub account yet, sign up at GitHub.

  • Authenticate GitHub on your system: You can securely authenticate your GitHub account on your local machine using either HTTPS or SSH. SSH is recommended for easier use and more security.

Option A: Setting up SSH Authentication

  1. Generate an SSH Key

  • Open your terminal and generate an SSH key (if you don't have one already) using the following command:

      ssh-keygen -t ed25519 -C "your-email@example.com"
    

    If your system doesn’t support the ed25519 algorithm, you can use:

      ssh-keygen -t rsa -b 4096 -C "your-email@example.com"
    
  • When prompted to enter a file to save the key, press Enter to accept the default path.

  • You'll then be prompted to set a passphrase for the SSH key. You can press Enter to skip, but it's more secure to create one.

  1. Add the SSH Key to Your SSH Agent

  • Start the SSH agent on your system:
eval "$(ssh-agent -s)"
  • Add your SSH private key to the agent:
ssh-add ~/.ssh/id_ed25519   # For ed25519 key
ssh-add ~/.ssh/id_rsa       # For RSA key
  1. Add the SSH Key to GitHub

  • Copy the contents of your public key to the clipboard:
cat ~/.ssh/id_ed25519.pub   # or ~/.ssh/id_rsa.pub for RSA
  • Go to GitHub > Settings > SSH and GPG keys.

  • Click New SSH key, give it a title, and paste your public key into the "Key" field.

  • Click Add SSH key.

Option B: Using HTTPS Authentication

  1. When you push changes to GitHub, you'll be prompted to enter your GitHub username and password. Alternatively, you can use a personal access token (PAT) instead of your password.

  2. To create a Personal Access Token (PAT):

    • Go to GitHub > Settings > Developer settings > Personal access tokens.

    • Click Generate new token, give it a name, select scopes like repo for repository access, and generate the token.

    • Use this token in place of your password when pushing/pulling from a remote repository.

Step 4: Verify GitHub Connection

For SSH Authentication:

  1. To verify that your SSH setup is correct, run:

     ssh -T git@github.com
    
  2. You should see a message like:

     Hi username! You've successfully authenticated, but GitHub does not provide shell access.
    

For HTTPS Authentication, you’ll need to enter your credentials (or access token) when pushing or pulling from GitHub.

Linking a sample local git repository with a remote Github repository

Prerequisites: Before you do this, ensure you have git and github properly set up on your system.

Step 1: Create the local repository and commit changes

  1. Create a directory for your project:

    • Open a terminal and run:

        mkdir sample-project
        cd sample-project
      
  2. Initialize the repository:

    • Inside the sample-project directory, initialize Git with:

        git init
      

This creates a new, empty Git repository in your local folder.

  1. Add files to the project:

    • Create a sample file:

        echo "# Sample Project" >> README.md
      
    • Stage the file:

        git add README.md
        # You could also use git add . to stage all changes
      
    • Commit the file:

        git commit -m "Initial commit with README"
      

Step 2: Create a Remote Repository on GitHub

  1. Go to GitHub:

    • Navigate to GitHub and ensure you are signed in.
  2. Create a new repository:

    • Click on the + icon in the top right corner and select New repository.

    • Name your repository something like sample-project.

    • You can leave the repository public or private depending on your preference.

    • Do not initialize with a README or .gitignore since you already have one in your local repository.

    • Click Create repository.

Once the GitHub repository is created, you’ll see a URL (usually something like this: https://github.com/username/sample-project.git)

  1. Add the remote repository:

    • In your terminal, link your local repository with the remote GitHub repository:

        git remote add origin https://github.com/username/sample-project.git
      

This sets the remote repository (origin) to point to your GitHub repository URL.

  1. Push your changes to GitHub:

    • Push your local commits to the remote repository:

        git push -u origin main
      

This command pushes the local main branch to the origin repository and sets it as the default upstream branch. If your local branch is named something else (e.g., master), replace main with that branch name.

Step 4: Verify on GitHub

  • Go to the repository URL on GitHub (e.g., https://github.com/username/sample-project).

  • You should now see your README.md file and the initial commit reflected in the repository.

Collaborating on github

1. Cloning the Repository

To collaborate, you’ll need a local copy of the project:

  • Clone the repository from a remote platform like GitHub:

      git clone https://github.com/user/repo.git
    
  • This creates a local copy of the repository and sets up a remote connection called origin to the repository.

2. Creating and Using Branches

Branches allow developers to work independently on different features or fixes.

  • Create a branch for your new feature or bug fix:

      git checkout -b new-feature-branch
    
  • After switching to the new branch, you can start working on your feature. Each developer typically works in their own branch, keeping the main branch stable.

3. Making Changes and Committing

As you make changes to your code:

  1. Stage your changes:

     git add <file-name>   # Stage specific file
     git add .             # Stage all changes
    
  2. Commit your changes with a descriptive message:

     git commit -m "Add feature X or fix bug Y"
    

4. Fetching and Pulling Changes

Before pushing your changes, it’s important to update your local copy to include changes others may have made:

  1. Fetch updates from the remote repository without merging:

     git fetch origin
    
  2. Pull updates and merge them into your current branch:

     git pull origin <branch-name>
    

    This ensures that your branch includes the latest changes from others.

5. Pushing Changes to the Remote Repository

Once your feature or fix is ready, push your branch to the remote repository:

  • Push your branch to the remote repository:

      git push origin new-feature-branch
    

6. Opening a Pull Request (PR)

A Pull Request (PR) is a request to merge your changes into another branch, typically the main or development branch.

  1. Go to your repository’s hosting service (e.g., GitHub).

  2. Open a pull request from your feature branch to the desired branch (e.g., main).

  3. Add a description of what you did, and request reviewers to review your code.

7. Reviewing and Merging Pull Requests

When collaborating, it’s common to review each other’s pull requests:

  • Reviewers can comment on the changes, suggest improvements, or request additional changes.

  • If approved, the pull request can be merged into the main branch.

Once your PR is approved, you can:

  • Merge your branch into the main branch.

  • Delete your feature branch if it's no longer needed (either locally or on the remote).

Troubleshooting Common Git Head-Aching Issues

1. Merge Conflicts

Merge conflicts occur when two people change the same lines in a file on different branches and Git doesn’t know which changes to keep when merging.

Solution:

  • Git will indicate which files have conflicts. Open the conflicting files, and you’ll see markers like this:

      <<<<<<< HEAD
      // Your changes
      =======
      // Changes from the other branch
      >>>>>>> branch-name
    
  • Manually edit the file to keep the desired changes, then remove the markers.

  • After resolving the conflicts, run:

      git add .
      git commit
    
  • You should be able to successfully merge your changes now.

2. Detached HEAD

A detached HEAD occurs when you check out a specific commit rather than a branch. Any changes you make won’t be associated with a branch.

Solution:

  • If you want to keep the changes, create a new branch and commit your changes there:

      git checkout -b new-branch-name
      git add .
      git commit -m "Your message"
    
  • If you don’t need the changes, switch back to a branch:

      git checkout <branch-name>
    

3. Accidental Commit to the Wrong Branch

Solution:

  • Run the following command to view the commit history and find the commit hash of the commit:

      git log --oneline
      # Alternatively, for a more detailed log, you may run "git log"
    

    This will display a list of commits with their corresponding hashes in abbreviated form (e.g., a1b2c3d Fix typo in ReadMe). The hash is the first part of each line.

    Copy the commit hash.

  • Switch to the correct branch and use git cherry-pick to apply the commits from the wrong branch to the correct one:

      git checkout correct-branch
      git cherry-pick <commit-hash>
    
  • To undo the commit on the wrong branch, go back and reset:

      git checkout wrong-branch
      git reset --hard HEAD~1
    

4. Mistakenly Pushed Sensitive Data (e.g., API keys)

Solution:

  • First, remove the sensitive data from the commit history using the git filter-branch or the BFG Repo-Cleaner tool. For example:

      git filter-branch --force --index-filter \
      'git rm --cached --ignore-unmatch <file>' \
      --prune-empty --tag-name-filter cat -- --all
    
  • Force-push the changes:

      git push origin --force --all
    
  • Invalidate and regenerate the compromised credentials.

5. Pushed changes to the Wrong Remote Branch

Solution:

  • To remove the changes from the wrong branch:

      git push origin :wrong-branch
    
  • Then push the changes to the correct branch:

      git push origin correct-branch
    

6. Failed to Push Due to Non-Fast-Forward Updates

Error: This is when you try to push your changes, but the remote branch has new changes, causing a conflict.

Solution:

  • First, pull the latest changes from the remote branch:

      git pull origin <branch> --rebase
    
  • Resolve any conflicts, if they arise, then continue the rebase:

      git rebase --continue
    
  • After resolving, push your changes:

      git push origin <branch>
    

7. Forgot to Add a File to the Last Commit

Solution:

  • You can amend the last commit to include the forgotten file:

      git add <file>
      git commit --amend --no-edit
    
  • If you’ve already pushed the commit, you’ll need to force-push:

      git push --force
    

8. Undoing the Last Commit

Solution:

  • To undo the last commit but keep the changes in your working directory:

      git reset --soft HEAD~1
    
  • To undo the commit and discard the changes:

      git reset --hard HEAD~1
    

9. Pulling with Uncommitted Changes

Error: When you try to pull changes but have uncommitted changes in your working directory.

Solution:

  • You can either:

    • Stash your changes:

        git stash
        git pull origin <branch>
        git stash pop
      
    • Or, commit your changes first:

        git add .
        git commit -m "Save changes"
        git pull origin <branch>
      

10. Git Refusing to Merge Unrelated Histories

Error: This happens when you’re trying to merge two repositories that don’t share a common commit history.

Solution:

  • Use the --allow-unrelated-histories flag to force Git to merge them:

      git pull origin <branch> --allow-unrelated-histories
    

11. Rewriting Commit Messages

Error: You want to change the message of a previous commit.

Solution:

  • To change the most recent commit’s message:

      git commit --amend -m "New commit message"
    
  • To change older commit messages, use interactive rebase:

      git rebase -i HEAD~n
    

    Replace n with the number of commits you want to edit. Mark the commit message with reword to edit it.

12. Corrupted .git Directory

Error: Your Git directory becomes corrupted.

Solution:

  • If your .git directory gets corrupted, you can try running:

      git fsck
    

    This command checks the integrity of the repository and identifies issues. To fix errors, use:

      git gc --prune=now
    

    This garbage-collects and cleans up the repository.

13. Git Reflog for Undoing Mistakes

Error: You reset, checkout, or rebase to the wrong commit and seem to have lost your work.

Solution:

  • Use Git’s reflog to recover commits or changes. Reflog records every change in HEAD:

      git reflog
    
  • Find the commit hash you want to recover and reset to it:

      git reset --hard <commit-hash>
    

14. Could not resolve GitHub host

Error: This issue is caused by a failure to resolve GitHub’s host; often due to network connection problems.

Solution: Check your internet connection and ensure that your network is functioning properly.

  • If your internet is working but the error persists, try the following:

    • Flush your DNS cache.

    • Check if you’re behind a proxy and configure Git to use the correct proxy settings.

    • Test your connection to GitHub using ping github.com or ssh -T git@github.com (if using SSH).

Conclusion

With git, you can safely experiment on your projects knowing that in the case of any issue, you can easily roll back to past versions of your code, and continue right where you left off with no hindrance. Additionally, GitHub offers more features beyond version control, including stars, gists, and so much more.

For further details, feel free to explore the GitHub documentation.

Thank you for reading! If you found this article helpful and informative, please subscribe and give it a like; it helps support the content and keep you updated with future posts.

11
Subscribe to my newsletter

Read articles from Jadesola Adeagbo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jadesola Adeagbo
Jadesola Adeagbo

Hi🙋🏽‍♀️, I'm Jadesola, a software developer based in Nigeria 🛠️. Driven by a passion for solving problems with code, I'm currently refining my skills as a front-end developer while delving into the world of back-end development. I am dedicated to sharing my knowledge and experience as I grow in the tech world. Join me on my journey and let's grow together!