Git for Development and Operations

GIT

  • Git for Development and DevSecOps
  • 19 MAR 2023
  • blog

Git Merge

After posting the first article on Git and how its not scary at all, Git is your best friend and whether you love it or hate it - you're going to be using it! I thought it would be useful to follow up with a post about what scares people the most, mergeing and merge conflicts.

As we all know git is a distributed Version Control System (VCS) and while your everyday use of Git can sometimes feel like you are using a file system sitting happily sitting on a remote drive - its not, and that's when you're expectations and reality differ.


Reality always wins.

Does this sound familiar? After happily working for the last 2 months on the worlds newest and best mouse trap, committing your code regularly and generally being a happy and tidy developer. The Test Lead throws a defect across the desk and says how many times are they going to have to repeat the same failing test case, and why don't you believe them when they say its broken?

After much investigation you determine there's nothing wrong in fact you dont even know why this is a problem, its not even your code! It works fine in your dev environment and every-time you deploy it works, then fails, then works .... finally in frustration you beg access to source code in the Test environment - hook up your debugger to the running executable and discover ..... the code isn't even there!

Welcome to merging in git.


Why do we need to Merge?

Merging is the process used to apply changes from a source branch to a destination branch. In most cases if your developing in a non SaaS platform this means usually means a master branch or release candidate branch. In Salesforceland this is not always the case, using Copado for example, the destination branch is almost certainly a promotion branch on its way to an environment branch.


How do we Merge?

The git merge command is used to merge changes from one branch into another branch. It's a powerful tool that allows developers to combine code changes from several projects with multiple contributors into a single, cohesive code-base.

Here's the basic syntax of the git merge command:


                                git merge 
                            

This command tells Git to merge the changes from the specified branch (in this case, ) into older version of the current branch. Before you run this command, you'll need to make sure that you're on the branch where you want to merge the changes.

When you run the git merge command, Git will attempt to automatically merge the changes from the specified branch into the current branch. If the changes don't conflict with each other, Git will merge them automatically and create a new merge commit.

If there are conflicts between the changes, Git will pause the merge process and ask you to resolve the conflicts manually. You'll need to open the affected files in your code editor and make the necessary changes to resolve the conflicts. Once you've resolved all the conflicts, you can save the changes and commit them to git repository in Git using the git commit command.

Here are a few additional options that you can use with the git merge and command line:

  • --no-commit:
    This option tells Git to perform the merge, but not to create a new merge commit. This can be useful if you want to review the changes before committing them to Git.
  • --squash:
    This option tells Git to merge the changes from the specified branch into the current branch, but to squash all the changes into a single commit. This can be useful if you want to keep the commit history of your code-base clean and organized.
  • -X :
    This option allows you to specify a merge conflict resolution strategy. There are several strategies to choose from, including "ours" (which keeps the changes from the current branch) and "theirs" (which keeps the changes from the specified branch).


Overall, the git merge command is an essential tool for collaborating on code with other software developers. It allows you to easily merge changes from multiple contributors into a single code-base, while also giving you fine-grained control over how conflicts are resolved.

Sounds fantastic but ..... this implies that the merge is an overwrite operation, and that is not the case!

If you're after the physical TL;DR on how do I merge in detail, head over to Atlassian as there's a great tutorial that takes you through the fine grain detail. Meanwhile if you're confused and want to impress your friends and know why, read on!


Merge in detail

Whatever your target branch the merge process is basically the same with subtle differences applied by your strategy option (more on that later),

  • BOTH branches are wound back to a common ancestor
  • Each commit on the branches are applied to the destination branch in the order they occurred
  • Any conflicts are identified and the merge will not be committed, its up to you to now resolve these merges

If your are after more detail, try Stackoverflow or the github documentation, but here's the kicker - if your change also introduces a revert of previous code, or worse a revert on top of a change - git just assumes you're happy with that!

Remember when I said git pull origin master now you know why.


I'm not a Muppet, I know that - but now I have conflicts!

Okay all jokes aside if you're at this point and trying to figure out what to do the first thing to remember are conflicts are normal, don't panic - all that has happened is that two or more changes have been applied to the same file and git can't decide which one is correct.

The simplest and often best course of action at this point is to open each file in your merge target branch and fix the problem;

  • Identify the merge conflict
    This is actually pretty easy as git will add some formatting to assist this, look for
    
                                            a 
                                            <<<<<<< ours 
                                            b 
                                            ======= >>>>>>> theirs 
                                            c
                                        
  • Find your favorite text editor, IDE, git cli, whatever - go eyeball the difference and manually edit the file.
  • Stage and commit as normal
    
                                            git add filename
                                            git commit
                                            git push
                                        

If you're at this point and still panicking,


                                git merge --abort
                            

Will reset the current branch and undo any changes in your working directory, if its still looking like its all gone south on you try git reset and a few calming breaths.


                                git reset: --mixed, --soft, and --hard
                            
  • --mixed
    This mode is the default option for git reset. It updates the current branch tip to the specified commit and un-stages changes, which means that changes in the working directory are preserved but are not marked for commit.
  • --soft
    This mode updates the current branch tip to the specified commit and preserves the changes in the index (staging area). This means that changes in the working directory are not affected, and the changes in the index can be committed later.
  • --hard
    This mode updates the current branch tip to the specified commit and discards any changes in the working directory and index. This means that changes made since the specified commit are permanently lost.

The git reset --hard origin command will always help as it will move the repositories current branch to the state of the remote repository named "origin". This is the equivalent to performing a git fetch followed by a git reset --hard origin/master command, there's a couple of caveats however.


Panic over - I reset everything now what?

If you're at this point, you've given up trying to edit your merge conflicts, you have no idea who changed what and why and you're starting to get desperate ..... remember conflicts are normal, don't panic we can always reset everything so lets try a couple of things - remember we discussed merge strategy options?

Git has several merge strategies that can be used to combine changes from multiple branches. Here are the most commonly used merge strategies and what they do:

Fast-forward merge strategy: This is the default strategy used by Git. It applies when the branch you are merging into has no new commits since the branch you want to merge in was created. In this case, Git simply moves the pointer of the branch you are merging into to the same commit as the other branch. This results in a linear history without any additional merge commits.

  • Recursive merge strategy:
    This strategy is used when the branches being merged have diverged from a common ancestor, resulting in a merge commit. Git creates a new commit that combines the changes from both branches. The recursive strategy works by considering each individual change made on each branch and trying to merge them together in a new commit.
  • Octopus merge strategy:
    This strategy is used to merge multiple branches simultaneously. It creates a single merge commit that combines changes from multiple branches at once.
  • Sub-tree merge strategy:
    This strategy is used when merging a sub-directory of a repository instead of the entire repository. It allows you to merge changes from one sub-directory in one branch into another sub-directory in another branch.
  • Our and Theirs merge strategy:
    These strategies are used to resolve conflicts that arise during a merge. The "ours" strategy resolves conflicts by keeping the changes from the current branch, while the "theirs" strategy keeps the changes from the branch being merged in.

Overall, the choice of merge strategy depends on the specific circumstances of your project and your goals for the merge.

If you want some pretty pictures to help for your next Tech Brown Bag session, head over to PlasticSCM, they really get into the detail in a couple of posts here and here.

So now all you need to do is perform the git merge again, this time choose a merge strategy that works the way you want. If you know your changes are good BUT you don't want to break anything, try a merge strategy of theirs;


                                git merge -s recursive -X theirs 
                            

In this command:
  • -s recursive specifies the recursive merge strategy, which is the default strategy for most cases.
  • -X theirs specifies that, in case of a conflict, Git should automatically choose the changes from the branch being merged in (i.e., "theirs") instead of prompting you to manually resolve the conflict.

Replace <branch-to-merge> with the name of the branch that you want to merge into your current branch. This command will perform the merge using the "theirs" strategy and automatically choose the changes from the branch being merged in if any conflicts occur.


More CLI Stuff

Okay, now for some more helpful cli commands, because I need a place to keep them!

Find the point that you created your branch (based on master)


                                git merge-base master 
                            
This will find the common ancestor between the master branch and your branch - this will be the commit ID that you last had in common.

View the details of any commit id


                                git show 
                            
If you just want date and time

                                git show --pretty=format:%ci 
                            

Find all changes made on master since commit-id


                                git log --oneline --since= master
                            
As an extension to the above (and since I'm using Copado that adds a bunch of messages) I want to ignore anything containing "All conflicts were solved"

                                git log --oneline --since=commit-id master | grep -v "All conflicts were solved"
                            
or for those non bash users

                                git log --oneline --since=commit-id master | findstr /V "All conflicts were solved"
                            
will do the same in windows.


Congratulations, you made it!

That was a lot of tech stuff for a post, I hope it helps you out and, as always, reach out and let us know how we can help at AppGenie.com.au.


This is article 2 on GIT, in a series of 3. Please find links to each in the series.

footer-logo

If you want high performance, high availability, low operational costs we are here to help.