Showing posts with label GIT Merge. Show all posts
Showing posts with label GIT Merge. Show all posts

Thursday, 8 August 2019

5 STEPS TO MERGE A GIT BRANCH

If you are working in development for a long time, you should know what version control system and a GIT is. In this post, we will see what a GIT branch is and how to merge a branch to other branch or a master in git repository.

WHAT IS A GIT BRANCH?

GIT store all the files and data in a repository. This repository is a centralized location where we store all data by versioning controlling them. A branch is nothing but a complete replica of a repository which effectively forks within your repository. At the time of new branch creation, the branch is similar to the repository main branch(many times it will be a master branch) or from which branch it is forked.
Once the branch is created we can start working on a new branch with out modifying master branch content this way any bugs we introduce is with in your working branch. In this post, we will see how to merge a branch to a master branch after we are confident about the changes.
In this post, we will use two branches
first_branch: This is actual changes which we do and need to merge these changes to another branch.
second_branch: This is the branch where we merge our first_branch changes.

STEPS TO MERGE A GIT BRANCH TO MASTER

STEP1: CHECK OUT TO AN EXISTING BRANCH

First, check what branches are available to you.
git branch
Example:
surendra@linuxnix:~/code/sh/gittraining$ git branch
first_branch
second_branch
* master
From the above output, the * with a name indicates your present branch. So the current branch is a master.
Checkout into first_branch branch.
git checkout branchname
Example:
surendra@linuxnix:~/code/sh/gittraining$ git checkout first_branch
Switched to branch 'first_branch'
surendra@linuxnix:~/code/sh/gittraining$ git branch
* first_branch
second_branch
master

STEP2: COMMIT AND PUSH CHANGES TO A BRANCH

Update your files and commit those changes locally and then push those changes to sync remote repository.
git commit -am “First commit.”
git push
Example:
Check if any changes already exists or not
surendra@linuxnix:~/code/sh/gittraining$ git status
On branch first_branch
Your branch is up-to-date with 'origin/first_branch'.
nothing to commit, working directory clean
Edit your files and check status.
surendra@linuxnix:~/code/sh/gittraining$ vi abc.sh
surendra@linuxnix:~/code/sh/gittraining$ git status
On branch first_branch
Your branch is up-to-date with ‘origin/first_branch’.
Changes are not staged for commit:
(use “git add <file>…” to update what will be committed)
(use “git checkout — <file>…” to discard changes in working directory)
modified: abc.sh
no changes added to commit (use “git add” and/or “git commit -a”)
Commit changes
surendra@linuxnix:~/code/sh/gittraining$ git commit -am “Updated abc.sh script”
[first_branch f564909] Updated abc.sh script
1 file changed, 1 insertion(+)
surendra@linuxnix:~/code/sh/gittraining$ git push
Username for ‘https://github.com: linuxnix
Password for ‘https://linuxnix@github.com
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 342 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/linuxnix/gittraining.git
e4a48b6..f564909 first_branch -> first_branch

STEP3: CHECKOUT TO THE DESIRED BRANCH

Example:
surendra@linuxnix:~/code/sh/gittraining$ git checkout second_branch
Switched to branch 'second_branch'

STEP4: PULL CHANGES TO LOCAL DIRECTORY

surendra@linuxnix:~/code/sh/gittraining$ git pull
Already up-to-date.

STEP5: MERGE CHANGES TO PRESENT BRANCH.

It is a syncing your first branch data with your second branch.
git merge desired_branch_to_merge
Example:
surendra@linuxnix:~/code/sh/gittraining$ git merge first_branch
Updating 075ca41..f564909
Fast-forward
abc.sh | 2 ++
1 file changed, 2 insertions(+)
Check status if the local changes are synced to remote branch or not.
surendra@linuxnix:~/code/sh/gittraining$ git status
On branch second_branch
Your branch is ahead of 'origin/second_branch' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
If remote second_branch and local second_branch are not synced, sync them by using git push command.
surendra@linuxnix:~/code/sh/gittraining$ git push
Username for 'https://github.com': linuxnix
Password for 'https://linuxnix@github.com': 
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/linuxnix/gittraining.git
 075ca41..f564909 second_branch -> second_branch
Hope this helps in understanding How to merge branches. In our next post, we will see how to delete a git branch locally and remotely.

Friday, 28 December 2018

GIT: Git Merge Therapy

Git merge conflicts are normal and okay.
They are supposed to happen and, most likely, will happen regularly. They don’t happen because you did something wrong. They happen because Git is trying to protect you from losing your hard work.
If you’re new to Git or haven’t done extensive work with it in a team environment then you probably haven’t had the experience of a lot of merge conflicts.
In a future article I will share how you can resolve conflicts but right now, let’s talk about prevention.
We can do some things to prevent conflicts; here’s a list of a few:
  • Ignore generated files
  • Ignore cache or other runtime directories and files
  • Have a good branching strategy
  • Avoid whitespace errors

GIT: How to Integrate Branches

Separating different topics into different branches is a crucial practice for any serious developer. By not mixing up code from one feature / bugfix / experiment with another, you avoid a lot of problems - and don't have to worry about breaking things in your development branches.
But at some point your code will (hopefully) reach a state where you'll want to integrate it with the rest of the project. This is where the "git merge" command comes in.

A Simple Example

Let's assume a very simple example scenario:
Our goal is to integrate the changes from "contact-form" back into "master".

Preparing to Merge

Before merging your code into one of your project's long-running branches (like a "development" or "master" branch), make sure that your local repository is up to date. Both your local feature / bugfix / <topic> branch and the receiving branch should be updated with the latest changes from your remote server.
Start with a "git fetch", followed by a "git branch -va":
$ git fetch
...

$ git branch -va
  master             87eab46 [behind 1] Fix #332
* contact-form       b320ab3 Ensure safe login
The [behind 1] remark tells us that "master" has received new changes on the remote. We must update "master" before we can integrate our own changes.
If properly configured, a plain "git pull" should suffice (after making "master" our active branch):
$ git checkout master
$ git pull
The last thing to check before actually starting the merge process is our current HEAD branch: we need to make sure that we've checked out the branch that should receivethe changes.
But since we just updated "master" and already performed a "git checkout master", we're good to go!

Starting the Merge

With such perfect preparation, the actual merge process itself is easy as pie:
$ git merge contact-form
Looking at our project's commit history, we'll notice that a new commit was created: a so-called "merge commit" that represents the actual "melting knot" that combines the two branches.
Our integration was successful and, if our feature work on "contact-form" is finished, we could safely delete that branch.

Dealing with Conflicts

Git will do what it can to make merging as easy as in our example. And in many cases, a merge will indeed be a walk in the park.
In some cases, however, the integration will not go as smoothly: if the branches contain incompatible changes, you will have to face (and solve) a "merge conflict". If you want to learn more about how to handle such a situation, have a look at Dealing with Merge Conflicts.

GIT: Using git rebase Instead of git merge

Using the "git merge" command is probably the easiest way to integrate changes from one branch into another. However, it's not your only option: "git rebase" offers another, slightly different way of integration.

An Example Scenario

Let's take a simple scenario with the following two branches. Our goal is to integrate "branch-B" into "branch-A":

git rebase Avoids Merge Commits

Before we look at the exact steps that occur during a rebase, let's illustrate the differences between merge and rebase.
Using "git merge", the result of our integration would look like this:
Using "git rebase", the end result looks quite different - especially because no extra merge commit will be created. Rebase results in a "straight-line" commit history:
Neither of these scenarios is "better" or "worse" than the other. It's rather a matter of taste and convention in your team!

git rebase in Slow Motion

There's quite a lot happening behind the curtains when a rebase is performed.
In step 1, Git will prepare the receiving branch, in our case "branch-A": all commits that came after the two branches' common ancestor commit (C1) will be removed - just temporarily, of course! Think of them as being parked, ready to be reapplied later.
Step 2 is very easy: Git now integrates the commits from "branch-B". At the end of this step, both branches look exactly the same.
It's the third, final step that gives "rebase" its name: the parked commits from "branch-A" are now reapplied, on top of the just integrated commits. These commits are literally re-based, their new parent commit now being C4.

Be Careful with git rebase

The rebase command is a wonderful and very powerful tool for integrating changes. Keep in mind, though, that it rewrites your commit history.
Let's revisit our above example to illustrate this: before starting the rebase, C3's parent commit was C1. After the rebase, however, C3 is now based on C4!
A revision's parent commit is crucial information. When a commit is rebased onto a new parent, it will also receive a new commit hash. This effectively makes it a completely new commit!
Trouble begins when you rebase commits that have already been published on a remote server. These commits might already be part of your colleagues' work - and should not change their identities! Therefore, please never rebase published commits!

Using git rebase

Actually executing a rebase is dead simple. Make sure you are on the branch that should receive the changes and then simply type...
$ git rebase branch-B

GIT: Rebase as an Alternative to Merge

While merging is definitely the easiest and most common way to integrate changes, it's not the only one: "Rebase" is an alternative means of integration.
NOTE
While rebasing definitely has its advantages over an off-the-shelf merge, it's also a matter of taste to a great extent: some teams prefer to use rebase, others prefer merge.
As rebasing is quite a bit more complex than merging, my recommendation is that you skip this chapter unless you and your team are absolutely sure you want to use it. Another option is to return to this chapter after you've had some practice with the basic workflow in Git.

Understanding Merge a Little Better

Before we can dive into rebase, we'll have to get into a little more detail about merge. When Git performs a merge, it looks for three commits:
  • (1) Common ancestor commit
    If you follow the history of two branches in a project, they always have at least one commit in common: at this point in time, both branches had the same content and then evolved differently.
  • (2) + (3) Endpoints of each branch
    The goal of an integration is to combine the current states of two branches. Therefore, their respective latest revisions are of special interest.
Combining these three commits will result in the integration we're aiming for.

Fast-Forward or Merge Commit

In very simple cases, one of the two branches doesn't have any new commits since the branching happened - its latest commit is still the common ancestor.
In this case, performing the integration is dead simple: Git can just add all the commits of the other branch on top of the common ancestor commit. In Git, this simplest form of integration is called a "fast-forward" merge. Both branches then share the exact same history.
In a lot of cases, however, both branches moved forward individually.
To make an integration, Git will have to create a new commit that contains the differences between them - the merge commit.

Human Commits & Merge Commits

Normally, a commit is carefully created by a human being. It's a meaningful unit that wraps only related changes and annotates them with a comment.
A merge commit is a bit different: instead of being created by a developer, it gets created automatically by Git. And instead of wrapping a set of related changes, its purpose is to connect two branches, just like a knot. If you want to understand a merge operation later, you need to take a look at the history of both branches and the corresponding commit graph.

Integrating with Rebase

Some people prefer to go without such automatic merge commits. Instead, they want the project's history to look as if it had evolved in a single, straight line. No indication remains that it had been split into multiple branches at some point.
Let's walk through a rebase operation step by step. The scenario is the same as in the previous examples: we want to integrate the changes from branch-B into branch-A, but now by using rebase.
The command for this is very plain:
$ git rebase branch-B
First, Git will "undo" all commits on branch-A that happened after the lines began to branch out (after the common ancestor commit). However, of course, it won't discard them: instead you can think of those commits as being "saved away temporarily".
Next, it applies the commits from branch-B that we want to integrate. At this point, both branches look exactly the same.
In the final step, the new commits on branch-A are now reapplied - but on a new position, on top of the integrated commits from branch-B (they are re-based).
The result looks like development had happened in a straight line. Instead of a merge commit that contains all the combined changes, the original commit structure was preserved.

The Pitfalls of Rebase

Of course, using rebase isn't just sunshine and roses. You can easily shoot yourself in the foot if you don't mind an important fact: rebase rewrites history.
As you might have noticed in the last diagram above, commit "C3*" has an asterisk symbol added. This is because, although it has the same contents as "C3", it's effectively a different commit. The reason for this is that it now has a new parent commit (C4, which it was rebased onto, compared to C1, when it was originally created).
A commit has only a handful of important properties like the author, date, changeset - and who its parent commit is. Changing any of this information effectively creates a completely new commit, with a new hash ID.
Rewriting history in such a way is unproblematic as long as it only affects commits that haven't been published, yet. If instead you're rewriting commits that have already been pushed to a public server, danger is at hand: another developer has probably already based work on the original C3 commit, making it indispensable for other newer commits. Now you introduce the contents of C3 another time (with C3*), and additionally try to remove the original C3 from the timeline with your rebase. This smells like trouble...
Therefore, you should use rebase only for cleaning up your local work - but never to rebase commits that have already been published.

GIT: How can I fix & solve merge conflicts?

A merge conflict is not the end of the world. Actually, if you keep a couple of things in mind, solving conflicts is easy as pie:
  1. Keep Calm
    Above all, you need to realize that you cannot break anything: Git always allows you to go back to the state before the conflict occurred. With a simple "git merge --abort", you can always undo the merge and start over again. This makes it almost impossible to severely screw things up.
  2. How do I Know I Have a Conflict?
    When calling "git status", you'll see a special Unmerged paths category. All of the items in this category are in a conflict state and need to be dealt with:
    $ git status
    # On branch contact-form
    # You have unmerged paths.
    #   (fix conflicts and run "git commit")
    #
    # Unmerged paths:
    #   (use "git add <file>..." to mark resolution)
    #
    #       both modified:   contact.html
    #
    no changes added to commit (use "git add" and/or "git commit -a")
    
  3. Understand When & Why a Conflict Happens
    Conflicts occur when the same file was changed in contradictory ways. Most modifications don't fall into this category: if two people just work on the same file, Git can most likely figure things out on its own.
    The most common situation when it cannot do this is when the exact same lines were edited in that file. In that case, Git has no way of knowing what's correct - you'll have to look at the changes and decide how you want the file to finally look.
  4. A Conflict is Just an Annotation
    It helps to realize that a conflict is nothing magical. In the concerned file, Git simply marks the areas that were edited in contradictory ways:
    This helps you understand which edits were made - and even on which branches.
  5. Solving Means Choosing & Editing
    Your job now is to condition the file to its desired state. There are a couple of ways to do this:
    (a) You can simply open the file in an editor, search for the conflict markers (see above image) and make any necessary modifications. When you're done, the file needs to look exactly as you want it to look.
    (b) Alternatively, you can tell Git that you'll simply go with one of the edited versions, called "ours" or "theirs".
    git checkout --ours path/to/conflict-file.css
    
    Note that there are lots of dedicated "Merge Tool" applications that help you with this process. Especially in complex situations with multiple conflicts in the same file, a good tool can be of tremendous value. We've compiled a list of merge tools.
  6. Wrap Up
    When you've successfully solved all conflicts, you need to do two more things:
    (1) Mark each conflicted file as solved. A simple "git add <filepath>" does this for you.
    (2) Commit the resolution just as you would commit any other change with the "git commit" command.