• Labs icon Lab
  • Core Tech
Labs

Guided: Advanced Merge Strategies

In this Git lab, you will deal with complex merging scenarios, common in collaborative development environments. The lab focuses on deepening understanding and practical skills in utilizing Git's advanced merging strategies, including how to use ours and theirs merge options. You will walk away with a nuanced understanding of each merge strategy's implications and best-use cases, enhancing your capability to manage code merges in a collaborative setting with precision and efficiency.

Labs

Path Info

Level
Clock icon Advanced
Duration
Clock icon 29m
Published
Clock icon Apr 04, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    Welcome!

    In this guided Git lab, you will be put into a scenario that will help you learn some advanced merge strategies and options, and more importantly, when to use each one.

    Tip: Before you jump in You should already be familiar with the essentials of using `git merge` and committing files. Additional information or context is provided with tips like this to dive deeper or help remind you how to use Git commands.

    The demo form is written in plain JavaScript, HTML, and CSS but you don't need to know the languages to complete the lab. Instead, you'll have to handle each merge scenario using the appropriate strategy and the lab will verify the files look correct.

    info> Since this lab relies on the file system and Git for validation, some Checks depend on previous steps and cannot re-run later in the lab. It would be best to fully complete each step before continuing on.

    info> If you are stuck, you can refer to the solution/INSTRUCTIONS.md file for complete solution steps. You can also reset the environment under Settings to get the file system back to the default state.

    Your First Command

    Before you start, let's make sure the lab is set up correctly. ## You've Been Promoted

    Throughout the lab, you will play the role of a lead engineer and be put into a scenario working on a user profile form that your team has been enhancing with new features and bug fixes for a major release.

    Feel free to view the profile form in the Web Browser tab in the lab, or explore the files in the Filetree.

    Once you're ready, it's time to integrate their changes and get the new form deployed out to production!

  2. Challenge

    Creating a Merge Conflict

    The Last Minute Avatar Picker

    You just got a phone call from your boss who said there needs to be a way for a user to upload a file to be their avatar photo.

    Gosh, you have to deploy this tomorrow morning! Better get it done quick. ## A Plea for Help

    Oh darn, you don't have any more time to work!

    You're going to need to cut it short and ask a teammate to help.

    Luckily, Henri is working and still has a few hours left.

    You tell him what's going on and he says, "No problem!"

    An hour passes...

    Henri tells you the code is ready and he pushed it into a branch named henri/picker.

    Fantastic, now all you need to do is merge his changes into the current master branch. Uh-oh, what's that message saying in the Terminal?

    CONFLICT (content): Merge conflict in index.html

    There's a conflict with our local changes and Henri's new changes.

    Let's see how you can resolve this...

  3. Challenge

    Resolving Conflicts Using Their Version

    A State of Conflict

    When you ran the git merge command, Git attempted to merge Henri's commits into your working tree.

    However, since you both worked on the index.html file in the same place, you created a merge conflict.

    What exactly is the problem? When the diff is displayed, you will see Git merge conflict markers like this:

    ++<<<<<<< HEAD
     +              <label for="avatar">Upload a file...</label>
     +              <input type="file" name="avatar">
    ++=======
    +               <label for="avatar-picker">Upload a file...</label>
    +               <input type="file" name="avatar-picker">
    +             </form-group>
    +             <form-group>
    +                 <label for="username">Username</label>
    +                 <input type="text" name="username" required>
    ++>>>>>>> henri/picker
    

    The first section is your HEAD branch changes which are "our" changes, and the second section are the henri/picker changes which are "their" changes.

    Different merge tools can visually display these changes side-by-side and provide quick and easy ways to go through each change to accept or reject changes.

    However, you trust Henri's changes and it's okay if it overwrites your own. In this case, you can tell Git to skip any conflicts with your code and simply take theirs (the bottom section).

    Let's try it out.

    Aborting a Merge

    First, you have to abort the current merge operation.

    Use "Their" Changes

    Next, you'll retry the merge but this time you'll pass a new argument:

    -X theirs

    You could also pass the longer form, --strategy-option theirs but -X is the short form.

    This strategy option will tell Git to resolve any conflicts automatically by taking the other branch's code over ours (that's why it's called "theirs"). ## What Did This Do?

    When you originally made your change, you replaced the Username input with an avatar picker. This was a mistake, but now if you check the index.html file, you will see that the missing Username form input is back in place because it was in Henri's branch. You prioritized Henri's changes over yours when merging which fixed your form.

    When Should You Use theirs?

    You may use the theirs merge strategy option when you are certain you don't care about your own changes to the branch and simply want to take whatever is from the other branch.

    There could be many reasons this might make sense:

    • When taking a teammates changes that redid your work
    • When merging in a hotfix or other high-priority update
    • When writing scripts that should be non-interactive

    However, theirs isn't the only merge strategy option available. What if we'd like to prioritize our changes?

  4. Challenge

    Resolving Conflicts Using Our Version

    Don't Forget to Validate

    After getting a good night's sleep, you wake up to a message from your boss:

    Boss: Hey team, the new avatar picker looks great, but it's missing validation. Can you add that quick before release?

    OK, fair enough -- you should run validation for a user's avatar. Your code is ready! Now you are ready to submit it for review and get the team's sign-off.

    A Case of Miscommunication

    But wait -- what's this?

    Henri just sent the following message to the team:

    Henri: Finished the avatar validation, it's in the henri/picker-validation branch. Take a look please!

    Oh gosh! You just duplicated work because you forgot to tell people you were working (it was an honest mistake, usually Henri's asleep)!

    OK, let's take a look at Henri's changes. You should see a diff like this:

    --- a/index.js
    +++ b/index.js
    @@ -16,7 +16,8 @@ function onSubmit(e) {
     function validateAvatarPicker(avatarFilename) {
       // Note: The server will double-check the content and MIME type
       if (avatarFilename.endsWith(".png") || 
    -      avatarFilename.endsWith(".jpg")) {
    +      avatarFilename.endsWith(".jpg") ||
    +      avatarFilename.endsWith(".jpeg")) {
         return true;
       }
       return false;
    

    In this case, it actually looks like Henri forgot to add support for the "JPEG" file extension. But otherwise, the validation logic is mostly the same (great minds think alike, you say to yourself).

    Preferring Our Changes

    You could perform a regular merge, but then you'll have to manually resolve the conflicts. You also don't want to merge using the theirs strategy, because you want to keep your .jpeg validation changes.

    Instead, you'll pass the -X ours merge strategy option. This will tell Git to resolve any conflicts with your code instead of their code.

    Let's try it out. ## What Did This Do?

    When you made your validation change, you checked for the following file extensions:

    • .png
    • .jpg
    • .jpeg

    But when Henri wrote their validation logic, they forgot to add .jpeg.

    Now if you check index.js, you will see your changes are preserved with the correct file extension checks. In addition, if Henri had added any new files, you would have merged those in as well. It's only in the case of a conflict that our changes are preferred over theirs.

    When Should You Use ours?

    You may use the ours merge strategy option when you are certain you don't care about the other branch's changes and simply want to take whatever is from your branch.

    There could be many reasons this might make sense:

    • When taking a teammates changes and extending their work
    • When merging in a hotfix or other high-priority update
    • When writing scripts that should be non-interactive

    You've now successfully used both the theirs and ours advanced merge strategy options.

    Hopefully this is the last merge you'll have to do before the major release.

    And as soon as you think this, your phone's incoming message sound dings again...

  5. Challenge

    Creating an Audit Trail with `Ours` Merge Strategy

    Making Auditors Happy

    As a bead of sweat trickles down your forehead, you squint to read the new message from your other teammate, Janice who is on the Compliance team:

    Janice: Hey team, remember that when we initiate the release we need to document the change in the audit branch.

    Ah yes, the hoops you have to jump through for compliance purposes.

    Since it's time to push the new release, you'll need to switch to the audit branch. Did you notice something weird? There are no files in the audit branch!

    The audit branch is a formal placeholder for compliance reasons. It is supposed to be a reference for the legal team to keep track of a "clean" release history. This means it doesn't need to contain any files but the Git history needs to match master and it's standard process of your team to update it during a release. (Even though it sounds strange, you've learned not to ask too many questions when it comes to legal compliance.)

    To mirror master's history, how can you do that without changing any files?

    The Default Merge Strategy

    If you look at the output in the Terminal after having done the last merge, you should have seen this message:

    Auto-merging index.html
    Merge made by the 'ort' strategy.
    

    This is the default Git merge strategy. This is what you use day-to-day without thinking and it performs a 3-way merge.

    History Lesson: `recursive` used to be the default
    There is an older merge strategy named `recursive` which was the default until Git v2.33.0. That's why `ort` is actually an acronym that stands for "Ostensibly Recursive's Twin".
    

    ort adds some additional features which is why it's now the default.

    You can still pass the -s recursive merge strategy along with some additional parameters that can result in less merge conflicts (but might be less accurate).

    Only Merging Commit History

    In this case, you don't want to actually take any files from the other branch -- you just want the commit history.

    To handle this, you can switch the merge strategy to ours instead of ort. You can change the merge strategy using the -s <NAME> or --strategy <NAME> command-line switch. Notice how the output has changed to say:

    Merge made by the 'ours' strategy.
    

    You'll also notice the working tree has remained unchanged -- no files were modified or added.

    Now that you've merged in master to the audit branch using the ours merge strategy, let's see how this impacts the commit history by viewing the history of the branch. In the commit history, you should see a commit like this:

    commit <sha>
    Author: PS User <psuser@labs.pluralsight.com>
    Date:   <date>
    
        Committed validation changes
    

    Git merged in the history of master but did not modify the working tree or files in the branch. It effectively preserves the working tree of the current branch.

    Even though it's rare, hopefully you can see how the -s ours merge strategy might be useful in very specific situations like legal compliance.

    Terminology: Merge Strategies vs. Merge Strategy Options

    You may wonder what the difference is between using the -s ours argument vs. the previous -X ours argument. Aren't they the same?

    The -s (or --strategy) argument specifies a merge strategy and each strategy may take different options, which are passed by the -X (or --strategy-option) argument.

    The ort merge strategy is the default so in previous steps you did not need to explicitly pass -s ort but effectively that's what you were doing.

    In this step, you switched to a different merge strategy, ours which can also take options.

  6. Challenge

    Next Steps

    Congratulations, you've finished all the tasks needed for the new user profile release and your customers (and boss) are happy with the results! 🎉

    Here's a Recap

    • The default merge strategy is ort and it replaces the original recursive merge strategy.
    • There are two advanced merge strategy command-line switches for Git:
      • -s, --strategy -- The merge strategy to use (default: ort)
      • -X, --strategy-option -- The merge strategy option to use
    • You can pass two merge options to the default ort strategy, theirs and ours using the -X or --strategy-option switch.
    • The theirs merge strategy option will resolve conflicts using "their" version of changes.
    • The ours merge strategy option will resolve conflicts using "our" version of changes.
    • You can switch the merge strategy from ort to ours to ignore changes in the other branch while merging. This will copy history but maintain the current branch's working tree, effectively "mirroring" history. This can be useful in specific situations like legal compliance.

    You can read and learn more about the available merge strategies in the official Git handbook.

    Bonus Challenge: Merging Multiple Branches at Once

    You can pass multiple branches to git merge and it will use the octopus merge strategy. Reset the lab and try merging both henri/picker and henri/picker-validation at once into master on Step 5 to see what happens.

Kamran Ayub is a technologist specializing in full-stack web solutions. He's a huge fan of open source and of sharing what he knows.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.