Thursday, October 22, 2020

1.8 Branching with Git

 Take a look at a real-world scenario. You decide to work on a new feature for your automation project by making some changes to existing code and creating some new configuration files. After an hour of programming, you receive an email that a critical issue exists in production and you need to fix it. You should provide a fix to the current production code as soon as possible, but you already did some changes to the code and do not want to lose these changes What should you do?

The next example is a typical real-world scenario. The solution to this scenario is branching and merging.

$ git branch
*  master
   feature-1
   bug-fix-1

The "*" sign is an indication of the current branch.

Git allows you to create different instances of your repository called branches. By default, there is only one instance of your repository called master branch.

Considering the example here, you have a master branch in your automation project repository that corresponds to the production code. The master branch contains production code, so this branch should contain only the code that is stable.

The following workflow should be used in Git to be able to apply fixes to your code and develop new features:

  • Never develop new features or apply bug fixes directly to the master branch.

  • Always create separate branch for a new feature or bug fix.

  • Apply frequent merges of the master branch to your feature or bug fix branch to avoid merge conflicts.

  • When the feature or bug fix is ready, merge it back to the master branch.

Typical real-world development workflow introduces an additional branch, usually called the develop branch. This branch is used when developing new features. Developers usually do not create new feature branches from the master branch but from the develop branch. Once features are developed, they are merged into the develop branch, and once a new software release is being prepared, the develop branch is merged into the master branch. However, for urgent fixes, developers usually create a bug fix branch directly from the master branch. Once the bug fix branch is merged back to the master branch, it must also be merged into the develop branch.



Creating separate branches for new features and bug fixes provides an isolated environment for every change in your codebase. Code changes in other branches do not affect the production code running in the master branch. Once new features and bug fixes are tested, the corresponding branch can be merged into the master branch, and code can be deployed to production.

Git Command

Description

git branch <parameters>

Manipulate branches.

git checkout <parameters>

Navigate through branches.

git merge <parameters>

Merge branches.

git diff <parameters>

Compare changes between branches.

The git branch command lets you manipulate with branches. Using the command without additional arguments will list all the branches in your local repository, while using a single argument will create a new branch by that name.

$ git branch my-new-branch
$ git branch
*  master
    my-new-branch

You can use the -D option to delete a branch from your local repository.

$ git branch -D my-new-branch
$ git branch
*  master

The git checkout command lets you navigate through branches. By default, you have only the master branch available. Once you create a new branch with the git branch command, you can use the git checkout command to navigate to the newly created branch.

$ git branch my-new-branch
$ git checkout my-new-branch
Switched to a new branch 'my-new-branch'
$ git branch

my-new-branch
Master

If you need to fix a bug that could be a configuration file or code, you can create a specific branch. You can create this new branch and automatically navigate to it as follows:

$ git checkout -b fix_aaa_bug
Switched to a new branch 'fix_aaa_bug'
$
$ git branch
*  fix_aaa_bug
    Master

As its starting point, the branch has all files from the master branch. Once you update the files with the fix, commit them and push them back using a command such as git push origin fix_aaa_bug. This command will push changes to the fix_aaa_bug branch on the remote repository.

At this moment, though, you have not made any file changes, so there is no difference between contents of the master and fix_aaa_bug branches.

Using the ls command, you can check which files and folders currently exist in this branch.

$ ls
aaa.cfg    s1.cfg    s2.cfg

Use your favorite text editor to edit the aaa.cfg file to fix a bug. Once you fix the bug, use the git status command to verify which files were changed.

$ git status
On branch fix_aaa_bug
Your branch is up to date with 'upstream/fix_aaa_bug'.
 
Changes 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:   aaa.cfg
 
no changes added to commit (use "git add" and/or "git commit -a")

Use the git add command to move your changes to the staging area and the git commit command to move changes to your local repository.

$ git add aaa.cfg
$ git commit -m "AAA bug fixed"
[fix_aaa_bug 9e188ea9d0] AAA bug fixed
1 file changed, 1 insertion(+), 1 deletion(-)

Finally, use the git push origin fix_aaa_bug command to push changes from your local repository to the remote repository.

Your changes are now available to other developers on the remote repository in the fix_aaa_bug branch. Once you verify that your changes solved the issue, you can merge your changes back to the master branch.

Use the git merge command to merge changes from fix_aaa_bug to the master branch and the command git push origin master to push the code to the remote repository.

$ git branch
*  fix_aaa_bug
    Master
$ git checkout master
$ git branch
*  master
    fix_aaa_bug
$ git merge fix_aaa_bug
$ git push origin master

Git Branches

Git branch workflow:

$ git branch
*  master
$ git checkout -b fix_aaa_bug
Switched to new branch 'fix_aaa_bug'
$
$ git branch
*  fix_aaa_bug
   master
$ git commit
$ git checkout master
$ git merge fix_aaa_bug

This figure shows using the commands that are previously reviewed, but all in a single workflow.

Handling Merge Conflicts

Merge conflicts are common when using Git. They can arise in these scenarios:

  • Two developers changed the same line or lines in the same file.

  • One developer deleted the file, while the other developer changed it.

  • One developer moved the file to other directory, while the other developer changed it.

  • Both developers moved the file to different directories.

Most conflicts arise from the first option. Git has a very good merge conflict resolution algorithm that can automatically solve most of the merge conflicts, but in the aforementioned examples, Git cannot know which change is correct. In these cases, you have to solve merge conflicts manually.

Assume that you and your coworker were both assigned to fix two separate authentication, authorization, and accounting (AAA) bugs. Both of you created your own branch, made the changes to the aaa.cfg file, committed them, and pushed them to the remote repository. When you decide to merge your changes to the master branch, your coworker had already merged their changes. Because you both changed the same line in a file, you will get a merge conflict.

$ git branch
*  master
    fix_aaa_bug
$
$ git pull
$ git merge fix_aaa_bug
Auto-merging aaa.cfg
CONFLICT (content): Merge conflict in aaa.cfg
Automatic merge failed; fix conflicts and then commit the result.

By opening the aaa.cfg file with your favorite text editor, you can see the following content:

<... output omitted ...>

<<<<<<< HEAD
    <content present in master branch>
=======
    <your changes>
>>>>>>> fix_aaa_bug

<... output omitted ...>

By observing the conflicting file, you can see that Git already marked the conflicting lines. The "HEAD" section contains the content of the file that already exists in the branch that you wanted to merge to (master branch). Similarly, the "fix_aaa_bug" section contains changes that you made in the fix_aaa_bug branch that you want to merge to the master branch. Use your favorite text editor and merge changes manually. By merging changes, also remov the HEAD and fix_aaa_bug section marks as well as the ======= mark. The merged file should contain only relevant AAA configuration.

The following output shows an actual merge conflict that you need to solve. As you can observe from the output, your coworker already configured the TACACS+ server using an IP address. You used a hostname to configure the TACACS+ server.

<... output omitted ...>

<<<<<<< HEAD
    tacacs-server host 10.2.1.2
=======
    tacacs-server host tacacs.cisco.com
>>>>>>> fix_aaa_bug

<... output omitted ...>

Decide which is the correct configuration, and modify the changes.

<... output omitted ...>

    tacacs-server host tacacs.cisco.com

<... output omitted ...>

Once you have made the changes to the file, use the git add command to move changes to the staging area, the git commit command to move changes to your local repository, and the git push command to move changes to the remote repository.

git branch

$ git branch
*  master
    fix_aaa_bug
$
$ git add aaa.cfg
$ git commit -m "Solve merge conflict"
$ git push origin master

Note

Some organizations may disallow changes directly on the master branch like it is done here. If this is the case, you must first merge the master branch into your branch (fixing the conflicts), and then merge back into the master branch.

git diff Command

You can use the git diff command to view the differences of files in your working directory—that is, compare the same files in your staging area or in your local repository (last snapshot commit). You can also use the git diff command to show differences between two commits, branches, or tags.

Assume that you started working on an AAA bug, and you already made some changes to some files, but you have not staged or committed anything yet. You want to know which changes you have made to the file so far. By observing the following git diff command output, you can see the changes between your working directory and staging area. A minus ("-") sign at the beginning of the line refers to the state in your local repository, and a plus ("+") sign at the beginning of the line refers to currently made changes.

$ git diff
diff --git a/aaa.cfg b/aaa.cfg
index 488506a..7fccdd5 100644
--- a/aaa.cfg
+++ b/aaa.cfg
@@ -1,5 +1,5 @@
AAA configuration line 1
-AAA configuration line 2
+New AAA configuration line 2
AAA configuration line 3
AAA configuration line 4
AAA configuration line 5

By applying the --cached option to the git diff command, you can see the changes between your staging area and local repository.

By applying the HEAD option to the git diff command, you can see the changes between your working directory and local repository

By applying additional options to the git diff command, you can also check the changes between two commits.

$ git diff <commit-hash-1>..<commit-hash-2>

You can obtain Git commit hashes by executing the git log command.

$ git log
commit 739e0c8eb0d33bc5c4331d1f35012e6a4e68e7dc (HEAD -> master, origin/master)
Merge: 281a739 b310ba5
Author: John Smith <john.smith@cisco.com>
Date:   Mon Aug 12 20:35:03 2019 +0200
 
    Merge branch 'aaa_bug_fix'
 
commit b310ba57019c7e271fd5006af72951d1125ddccd
Author: Jane Doe <jane.doe@cisco.com>
Date:   Mon Aug 12 20:33:51 2019 +0200
 
    Fix AAA bug
$ git diff 739e0c8eb0d33bc5c4331d1f35012e6a4e68e7dc..b310ba57019c7e271fd5006af72951d1125ddccd

Content Review Question

Which command is used to create and navigate to branch "my-new-branch"?

No comments:

Post a Comment