Making Git easier

Introduction

We are going to cover some of the challenges that occur when using git version control during the software development process.

They include:

  1. How to resolve a merge conflict

  2. How to rename master branch to main

  3. How to undo pushed commits

  4. How to co-author commits

How to resolve a merge conflict

A merge conflict occurs when there is/are conflicting change(s) made on different or the same files from the main branch or different branches. To resolve a merge conflict you have to accept changes to incorporate from different branches in a new commit.

We will cover how to solve this on the command line:

  1. Open the command line and navigate to the local repository that has a merge conflict

  2. Get a list of files affected by the merge conflict. In this example the file example.md has a merge conflict:

$ git status
> # On branch example-b
> # You have unmerged paths.
> #   (fix conflicts and run "git commit")
> #
> # Unmerged paths:
> #   (use "git add <file>..." to mark resolution)
> #
> # both modified:      example.md
> #
> no changes added to commit (use "git add" and/or "git commit -a")
  1. Open your favorite text editor and navigate to the file that has a merge conflict

  2. To find where a merge conflict has occurred in your file, search for the following markers <<<<<<<. In your file, you will see changes from HEAD or base branch after the line <<<<<<< HEAD. Next, you will see ====== that separates changes from other branches, followed by >>>>>> BRANCH-NAME. In this example, one person wrote "Git is a version control software" in the base or HEAD branch and another person wrote "you need to install." in the compare branch or example-a.

Changes made
<<<<<<< HEAD
Git is a version control software
=======
you need to install.
>>>>>>> example-a
  1. Decide on the changes you want to keep then delete the conflict markers <<<<<<<, =======, >>>>>>>. Make changes you want in the final merge. In our example, we incorporate both changes:
Git is a version control software which you need to install on your local system in order to use it
  1. Add or stage your changes.
git add .
  1. Commit you changes
git commit -m "Resolved merge conflict by incorporating both suggestions."
  1. Finally, push your changes
git push

Removed file merge conflicts

This occurs when there are competing changes to a file. For example, if a person deletes a file in one branch and another person edits the same file, you must choose whether to delete or keep the removed file in a new commit.

  1. Open Terminal. Navigate into the local Git repository that has the merge conflict.

  2. Get a list of files affected by a merge conflict. In this example, the file README.md has a merge conflict.

     $ git status
     > # On branch main
     > # Your branch and 'origin/main' have diverged,
     > # and have 1 and 2 different commits each, respectively.
     > #  (use "git pull" to merge the remote branch into yours)
     > # You have unmerged paths.
     > #  (fix conflicts and run "git commit")
     > #
     > # Unmerged paths:
     > #  (use "git add/rm <file>..." as appropriate to mark resolution)
     > #
     > #    deleted by us:   README.md
     > #
     > # no changes added to commit (use "git add" and/or "git commit -a")
    
  3. Open your favorite text editor and navigate to the file that has merge conflicts.

  4. Decide if you want to keep the removed file. You may want to view the latest changes made to the removed file in your text editor.

    To add the removed file back to the repository:

git add README.md

To remove this file from the repository:

$ git rm README.md
> README.md: needs merge
> rm 'README.md'
  1. Commit your changes.
$ git commit -m "Resolved merge conflict by keeping README.md file."
  1. Push your changes.
git push

How to rename master branch to main

The default branch in most Git repositories was named "master". Fortunately, many people have become aware that this terminology should be replaced as the tech industry moves to a more inclusive, open culture - and removing language like "master/slave" is an important step in this journey.

Several alternatives for "master" have come up, "default" and "primary" being some of them. But the most popular term seems to be "main".

To rename your branch to main follow these steps:

  1. Checkout the master branch :
git checkout master
# Make sure you have the latest changes
git pull origin master
  1. Rename the local branch with the following command:
git branch -m main
  1. Note that this change is only in your local repository, what you need to do next is to push this the remote, using this command:
git push origin -u main

Change the default branch

At this point, you have both master and main on your remote, and before you can delete the master branch, you need to go to the repository settings on your Github account, On the General section, scroll to Default branch then click on the pen icon. If it’s master you should change it to your new main branch

Once you have switched the default branch, you can safely delete the remote master branch:

git push origin --delete master

How to undo pushed commits

Ever made a commit or checked your commit history and thought "Oops! My commit history is wanting!". Git provides various ways to undo pushed commits.

Method 1: Reverting a Commit

This is a great method, especially if you're working in a team. Reverting doesn't delete any commits; it adds a new commit that undoes the changes.

Single Commit

# Show commit history
git log

# commit <commit-hash>

# Create a new commit that undoes the previous one
git revert <commit-hash>

# Push the new commit
git push

Before pushing, consider creating a new branch and running your tests. It's just safer that way.

Multiple Commits

# Show commit history
git log

# commit <commit-hash>

# Revert a range of commits
git revert OLDEST_COMMIT_HASH^..NEWEST_COMMIT_HASH

# Push the new commits
git push

Method 2: Resetting a Commit

Use this when you absolutely need to, because it rewrites commit history.

# Show commit history
git log

# commit <commit-hash>

# Move the HEAD and branch pointer to a specific commit
git reset --hard <commit-hash>

# Force push to apply the changes to the remote repository
git push --force-with-lease

Note: Coordinate with your team before using --force-with-lease, or you risk causing mayhem.

Method 3: Interactive Rebase

This method is complex however it gives you the most control.

# Show commit history
git log

# commit <commit-hash>

# Start an interactive rebase
git rebase -i <commit-hash>^

# Vim (or your default editor) will open. Make your changes.
# Save and exit the editor.

# Force push the changes
git push --force-with-lease

Note: Don't do this on shared branches without coordinating with your team.

How to co-author commits

When you are pair programming (or if someone's been helpful to you), you may want to be able to give them credit in a commit you make in a Git repository.

To achieve this from the command line, you just have to add this to your commit message:

Co-authored-by: name <someemail@example.com>

In a situation where you don't know that person's email address configured in Git, you can just run

git log

and then scroll through until you find it (which works well on small teams or when that person has a branch that you can check out and run this on). You could also get a bit more adventurous and run

git show <commit-hash> --format=email

to get just their email. Or you can be less adventurous and just ask them.

This is fairly easy to do, but in case you like to use the command line, this is how you'd write it:

git commit -m "Regular commit message" -m "Co-authored-by: name <someemail@example.com>"

And then, once you push, GitHub will credit that person with the commit alongside you!

Happy coding!