Branches

Learning Objectives

By the end of this chapter, you will be able to:

  • Explain the feature-branch workflow
  • Create, navigate, and delete branches
  • Manage changes in the working directory
  • Merge changes through pull requests
  • Identify and resolve issues with pull requests

This chapter describes the working of branches, workflows and conflict resolution.

Introduction

In the previous chapter, we explored how local repositories are able to connect to a remotely hosted repository. We covered the git push, git fetch, and git pull commands, which facilitate the retrieval of changes and uploading of changes to the shared repository. Lastly, we explored the git revert and git reset commands, which rescind changes.

In this chapter, we'll look at a common workflow that's utilized in version control, the feature-branch workflow. In doing so, we will also learn about branches and how changes are affected through the merging of branches and shipping the work to the user-facing product on your live environment. The topics covered in this chapter are geared toward demonstrating how version control fits into the picture, from when you start building a feature to when it's shipped.

Utilizing Workflows

Workflows refer to the approach a team takes to introduce changes to a code base. A workflow is characterized by a distinct approach in the use of branches, or lack thereof, to introduce changes into a repository.

Gitflow Workflow

This uses two branches: master and develop. The master branch is used to track the release history, while the develop branch is used to track feature integration into the product.

To introduce a feature, first, you must create a feature branch from the develop branch and then make changes in the created branch and commit those changes. Next, you should push the changes to the remote feature branch. Additionally, you must raise a pull request against the develop branch, and then follow up by resolving the feedback provided in the pull request. Afterward, merge the feature branch to the develop branch and create a release branch once an agreed number of features are merged to develop. Next, you should raise a pull request against the master. Lastly, you need to merge the pull request once it's been approved.

Hotfix workflow

To make a hotfix, first you must create a branch off the branch master, make changes, and commit them. Next, you can push the changes to the remote hotfix branch. Follow this up by raising a pull request against the master. Lastly, merge the pull request once it's been approved.

Centralized Workflow

This approach uses the master branch as the default development branch. The changes are committed to the master branch. It's a suitable workflow for small size teams and teams transitioning from Apache Subversion. In Apache Subversion, the trunk is the equivalent of the master branch.

Creating a Centralized Workflow

To commission work and conduct development on a project, you need to initialize the central repository, host the central repository on GitHub, and clone the central repository. The next step is to make the desired changes and commit. Finally, push the changes to the central repository and manage the emergent conflicts by using the rebase utility of Git.

Feature Branch Workflow

In this workflow, feature development is carried out in a dedicated branch. The branch is then merged with the master once the intended changes are approved.

To introduce a feature into an application, you should first initialize a repository with the default master branch. Then, you must clone the repository or pull changes from the remote master branch in the event that you have the repository locally. Next, create a new branch, make changes, and commit the changes. Then, push the feature branch to the remote repository and raise a pull request. Lastly, resolve the feedback provided in the pull request review and merge the pull request.

Forking Workflow

A forking workflow takes the following approach in the development of features or in the general introduction of a change to the code base. Initially, you must fork an official product repository to your account on GitHub and clone the forked repository to your local environment. Then, create a new branch for the feature, make changes, and commit the changes. Next, you should push the changes to the remote cloned repository and raise a pull request against the official repository. Finally, resolve the feedback provided and merge the PR into the original/official repository. Merging is done by an authorized repository owner.

Feature-Branch Workflow

In this workflow, feature and maintenance-oriented development is carried out in a dedicated branch. The branch is then merged to the master once the intended changes are approved.

To ensure ease in the tracking of changes being introduced to the branch master, a naming convention is required for the branches that are created off of the branch master. The branch name should have an appropriate description, in a manner that indicates the change being introduced by a branch.

The following sample notation demonstrates the form a branch name assumes:

branch_type-task_description

Given that a project is undertaken using an issue tracking tool such as Jira, Trello, or PivotalTracker, the branch name should be suffixed by the issue number corresponding to the change the branch seeks to introduce.

Branch types include feature, bug, fix, and chore. Take a look at their abbreviations in the following table:

Branch Type

Abbreviation

feature

ft

bug

bg

fix

fx

chore

ch

To introduce a feature into an application, you should initialize a repository with the default master branch. Then, clone the repository or pull changes from the remote master branch in the event that the repository is local. Next, you need to create a new branch, make changes, and commit those changes. Then, follow up by pushing the feature branch to the remote repository and raising a pull request. Finally, round up by resolving the feedback provided in the pull request review and merge the pull request.

Exercise 24: Feature-Branch Workflow-Driven Delivery

To roll out a feature using the feature-branch workflow, follow these steps:

  1. Navigate to the abacus repository of your GitHub account, as shown in the following screenshot:
    Figure 4.1: The abacus repository
  2. Select the Projects tab and click the Create a project button in the window you're directed to, as shown in the following screenshot:
    Figure 4.2: Organizing your issues
  3. In the resultant window, specify a name and description for the project's issue tracking board, as shown in the following screenshot:

    Note

    Templates for task organization are available and may be used for scenarios where a bespoke ordering of tasks isn't required. For the purpose of this demonstration, we shall use the Basic kanban template.

    Figure 4.3: Creating a new project
  4. Click the Create project button pictured in step 3. The result is the board shown in the following screenshot:
    Figure 4.4: Resulting output
  5. Create an issue to add support for exponents arithmetic operations by selecting the Issues tab and clicking the New Issue button to create a feature request, as shown in the following screenshot:
    Figure 4.5: New issue
  6. We will now utilize the issues templates we configured earlier. Click the Get started button to the right of the Feature request text, as shown in the following screenshot:
    Figure 4.6: Getting started
  7. Provide the feature request specification and click Submit new issue, as shown in the following screenshot:
    Figure 4.7: Submitting a new issue
  8. Navigate to the abacus-aims board and click the Add cards option on the top pane of the board, as shown in the following screenshot:
    Figure 4.8: Adding cards
  9. On the resultant panel, click the Support exponents issue:
    Figure 4.9: Support exponents issue
  10. Allot an assignee and project to the issue and click Back to Add cards, as shown in the following screenshot:
    Figure 4.10: Back to Add cards
  11. Click and drag the issue to the To do column and to In progress thereafter.
  12. Launch the terminal and navigate to the location of the abacus repository.
  13. Create a branch off ft-support-subtraction-arithmetic for the feature of the exponents arithmetic that you will add to the application, as seen in the following screenshot:

    git branch ft-support-exponents

    git checkout ft-support-exponents

    Figure 4.11: Creating a branch
  14. Add the following function to support exponents using the following code, and as seen in the following screenshot:

        def exponent(self):

            num_exponent = self.operands[0] ** self.operands[1]

            print(num_exponent)

    Figure 4.12: Adding the function
  15. Persist the change and push it to a remote branch using the following code, and as seen in the following screenshots:

    git add src/lib/compute.py

    git commit -m "Add support for exponents"

    git push origin ft-support-exponents

    Figure 4.13: Persisting the change
    Figure 4.14: Pushing to a remote branch
  16. Raise a pull request to merge the change and navigate to the new pull request page, as seen in the following screenshot. Use the following template as an example: https://github.com/[username]/abacus/pull/new/ft-support-exponents. My page link is as follows: https://github.com/TrainingByPackt/Version-Control-with-Git-and-GitHub:
    Figure 4.15: Raising a pull request

    Note

    Add an apt title and description. In the description, indicate the issue that the pull request (PR) is meant to resolve. GitHub establishes the issue number when the said digit(s) is prefixed with a #. Conclude the process by clicking the Create pull request button, as shown in the following screenshot:

    Figure 4.16: Raising a pull request
  17. Merge the changes to the branch master by clicking the Merge pull request button presented in the window you're directed to.

Outcome

By using the steps outlined in this exercise, you should be able to demonstrate the feature-branch process of change incorporation.

Creating, Renaming, Deleting, and Listing Branches

In git reset, we examined how Git stores a commit and the contents of a commit. The commit object stores a snapshot of the directories and files that constitute a repository at a given point in time. In addition, the commit specifies auxiliary information, which includes the parent commit of the created commit, the author, the committer date and time, and the commit message:

Figure 4.17: Snapshots of repository branches

A branch is therefore a pointer to a snapshot of the repository. This pointer refers to the commit at the tip of the branch. These tips are the commit hashes stored in .git/refs/heads/. HEAD is the pointer that references the commit at the tip of the current branch. This commit is imperative because it's based on the fact that git is able to navigate the history of a repository with the help of the parent-child association between commits. The creation of a branch, in turn, creates a pointer and the head, which bears a branch's name. Navigating from one branch to another updates the HEAD to refer to the tip of the branch you switch to – or in Git terms, check out to.

Creating:

git branch [branch_name]

git branch --set-upstream-to [remote_branch_name]

e.g. git branch --set-upstream-to origin/ft-support-exponents

git branch --unset-upstream [branch_name]

git branch [branch_name] [start_point]

Renaming:

git branch -m [old_branch_name] [new_branch_name]

git branch -M [old_branch_name] [new_branch_name]

This is similar to invoking git branch with the --move and --force options.

git branch -c [old_branch_name] [new_branch_name]

Copy:

git branch -C [old_branch_name] [new_branch_name]

This is similar to invoking git branch with the --copy and --force options.

Deleting:

git branch -d [branch_name]

Delete a branch, granted that it's fully merged into its upstream branch or the HEAD, in the event that the upstream branch is not specified.

git branch -D [branch_name]

This forces the deletion of a branch.

It's similar to using --delete --force.

Listing:

git branch --list

git branch --list [pattern]

For example, you can use git branch --list 'ft*'.

git branch --contains [commit]

For example, you can use git branch --contains 8354043.

git branch --no-contains [commit]

git branch --merged [commit]

For example, you can use git git branch --merged 8354043.

This lists branches that have been merged into a given commit, that is, commits whose tip is reachable from the given commit.

git branch --no-merged [commit]

This is used for branches that are not merged into the given commit.

git branch -a

This is used to get all branches:

git branch -r

This is used for the remote tracking of branches.

Switching to New and Existing Branches

The process of moving from one branch to another is done by switching to [branch] and then setting the files in the index and working tree to reflect [branch]'s latest commit. Lastly, you must set the HEAD to branch:

Note

Modifications to the working tree are retained in case you wish to commit them in [branch].

git checkout [branch_name]

git checkout -b [branch_name]

git branch -B [branch_name] [start_point]

Create a new branch and set its tip to [start_point]. If the branch exists, then reset it to [start_point].

Switching to a Detached Head

Consider a rookie-day-one branch with the commits a-->b-->c. Commit a is the initial/first commit.

HEAD refers to a named branch. In this case, branch rookie-day-one refers to commit c.

a-->b-->c-->d

In adding a new commit, d, to the branch, HEAD refers to branch rookie-day-one, which is updated to refer to commit d:

Example:

git checkout b

HEAD now points to commit b:

echo 'Test HEAD' >> a.txt

git add a.txt && git commit -m "Test"

echo 'Test HEAD' >> a.txt

git add a.txt && git commit -m "Test 2"

Adding changes and commits by extension changes HEAD to refer to commit f.

git checkout rookie-day-one

e-->f

a-->b-->c-->d

The preceding command shifts HEAD back to a named branch, rookie-day-one.

As such, changes in commits e and f are discarded, given that no reference is created to point to the commit, for example, via the following:

git checkout -b sample

git branch sample

git tag v1.0

git checkout [commit_hash]

git checkout [tag]

git checkout --detach [branch]

This detaches HEAD from the specified branch and switches to the specified branch.

git checkout --detach [commit]

The preceding code detaches HEAD from the [commit] and updates the working tree and index to match the state at [commit].

Switching to a Specific Version of a File

When switching, the git check out command takes the following syntax:

git checkout [commit] -- [path]

Other uses of git checkout are as follows:

git checkout -b --orphan [new_branch] [start_point]

This creates a branch whereby the first commit has no parent. This is necessary when certain information contained in the repository's history needs to remain unexposed for privacy reasons.

Incorporating Changes with Stashing

In the book of development work, emerging requests are a typical occurrence, including in scenarios where you are attending a planned work stream over a specific period of time. The book of action in this scenario, normally, is to put aside what you're working on and attend to this request, be it an emergency or not.

How does Git enable you to "put away" what you're working on without losing the progress you'd achieved on a certain task? Ask no more.

In comes git stash. The git stash command temporarily moves staged, unstaged, or untracked modifications made to a repository, to and from the index and working directory.

To achieve this with git stash, use the following subcommands:

git stash push -m [message] or git stash push —message [message]

This saves modifications to a stash list and reverts the index and the working tree to the state reflected by HEAD.

The —keep-index option retains changes made to the index. This means that the modifications in the index are not reverted.

The —include-untracked option includes untracked files in the stash entry made to the stash list.

The —all option stashes ignored files in the stash entry made to the stash list.

Note

git stash save was deprecated in favor of this command.

git stash list

This command lists the entries in the stash list. These are all of the created stashes:

Git stash show [stash_id]

This command displays the changes introduced by the stash identified by [stash_id].

git stash apply [stash_id]

This updates the working directory with the changes stored in [stash_id].

git stash pop [stash_id]

This updates the working directory with the stash [stash_id] and removes it from the stash list.

git stash drop [stash_id]

This removes the specified stash from the stash list.

git stash clear

This removes all stashes from the stash list.

git stash branch [branchname] [stash_id]

Note

The stash list is available from every branch.

Merging

The order that the introduction of a change to a repository entails is as follows:

  1. Creating a change branch off the main branch
  2. Building the change
  3. Unifying the change with the main branch

The exercise of merging is one of unifying the change into the main branch. This involves reconciling the divergent histories of the change branch and the feature branch, and creating a snapshot referenced by a commit to indicate the emergent result of incorporating the change branch.

A merge takes one of two modes, namely:

  1. Fast-forward merge
  2. Three-way merge

Where a merge is required from, branch-a to split, branch-b; in the event that there have been no changes in branch-a, Git adds the commits from branch-a to branch-b and updates the tip of branch-b (HEAD) to be the commit at the tip of branch-a. This is a fast-forward merge.

In merging two branches, that is, branch-a into branch-b, where there have been changes introduced into branch-b in the form of commits since branch-a was created off branch-b, that is, their shared ancestor, Git does the following:

  1. Compares the files in the two branches from the point where they diverged
  2. Reconciles the changes from both branches and merges incoming changes into the current branch by updating the index and working directory
  3. Retains changes from both branches where differences cannot be resolved for the purpose of merge conflict resolution
  4. Once the merge conflict (if any) is resolved, a merge commit is created to represent the incoming changes

This is a Three-way merge.

Merging is achieved by using the git merge command. This command uses the following syntax:

git merge [options] [branch_name]

--no-commit

This option merges changes into the current branch. However, the command does not create a merge commit in order to leave room for evaluating the result of the merge.

--edit

This option launches the editor to allow for editing of the generated commit message.

--no-edit

This conducts the merge using the message generated by the command.

--no-ff

This option creates a merge commit in all merge scenarios, including when the merge resolves to a fast-forward merge.

--squash

This option instructs git merge to update the index and working directory to reflect the incoming changes without creating a commit. Using this option enables you to create a commit as part of the current branch, thus referencing the incoming changes. With this option, the HEAD is not changed and the MERGE_HEAD ref is not recorded. As a result, the subsequent commit is not a merge commit.

--strategy=[strategy]

This specifies the merge strategy to be used for the merge.

The supported [strategy] includes

--strategy-option=[strategy_option]

This sets the option that's specific to the provided strategy.

Cherry-Pick

The git cherry-pick command takes a commit from one branch and applies the specified commit to another branch.

git cherry-pick is useful when you wish to check the effects of certain changes that have been introduced to a branch you're working on.

The syntax of the git cherry-pick command is a follows:

git cherry-pick [options] [commit].

git cherry-pick supports options that dictate how the introduced commits are handled. This includes the following:

-x: This option adds a standardized message to the commit of the form "cherry picked from commit ..." to specify the commit that introduces the incoming change.

--edit: This allows you to edit the commit message for the incoming changes.

--no-commit: You may wish to integrate changes from a specific commit without creating a corresponding commit. The --no-commit command integrates changes from a commit without creating a commit.

--mainline [parent_number]: Since a parent commit possesses two parents, running a cherry-pick against a merge commit requires that a parent is specified. The given parent is compared to the merge tree of the merge commit and the resulting difference is introduced into the branch where git cherry-pick is invoked from.

Consider two branches, namely branch-1 and branch-2.

Branch-1 implements the add-to-cart feature, while branch-2 implements a system-wide refactor.

From branch-1, you can merge branch-2:

git checkout branch-1

git merge branch-2

This creates a merge commit.

The merge commit corresponds to a merge tree that combines the changes implemented by branch-1 and the changes introduced by branch-2. This merge commit, as is the case with all merge commits, has two parents. Each parent represents the series of changes implemented in each branch.

The --mainline option requires that a parent is specified in order to indicate which of the two sets of changes should be incorporated when a merge commit is specified:

parent-1 is the last commit made in branch-1, that is, the add-to-cart implementation.

parent-2 is the last commit made in branch-2, that is, the refactor.

Consider branch-3.

In this branch, we would like to test the effects of changes introduced by the merge commit in git check out branch-3.

Scenario 1

git cherry-pick -m 1 merge_commit

By specifying -m 1, we choose parent-1.

This is the difference, or diff in Git terms, between the merge tree of merge_commit and commit parent-1. This is the refactor.

As such, this command will introduce the changes that refactor the code base in branch-3.

Scenario 2

git cherry-pick -m 2 merge_commit

By specifying -m 2, we choose parent-2.

This is the difference, or diff in Git terms, between the merge tree of merge_commit and commit parent-2. This is the add-to-cart implementation.

As such, this command will introduce, the changes that add the add-to-cart feature in branch-3.

Pull Request (PR)

A pull request (PR) is the culmination of a piece of work undertaken on a branch. A PR is an intent to merge. Pull requests are intended to avail the forum where changes that are to be made to a repository's main branch are accorded scrutiny. Consensus is arrived upon the completion of a satisfactory discussion on the modifications that are borne by the branch that seeks to introduce changes.

To gain a clear picture of the changes that a PR seeks to introduce, we need to check the diff between two branches. Let's take a look at how you can achieve this.

Exercise 25: Examining Branch Differences

To compare branches to establish impending changes, follow these steps:

  1. Navigate to the abacus repository of your GitHub account, as shown in the following screenshot:
    Figure 4.18: Abacus repository
  2. On the branch selection drop down, select the ft-support-addition-tasks branch, as shown in the following screenshot:
    Figure 4.19: Branch selector
  3. Click the New pull request button.
  4. GitHub will redirect you to https://github.com/TrainingByPackt/Version-Control-with-Git-and-GitHub.
  5. GitHub will display additions using the + sign and deletions using the - sign, as shown in the following screenshot:
Figure 4.20: Branch selector

Outcome

By following the preceding steps, you should be able to identify the changes that a branch introduces into another branch through a merged pull request.

Pull Request Templates

In Chapter 1-Introduction to Version Control, we looked at the usage of issue templates to aid in the contribution process by setting a guideline for the process of the resolution of bug and feature requests. To ensure the seamless integration of changes being introduced to the primary branch of a repository, GitHub supports standardized pull requests by providing means for stating a format for pull requests. A template seeks to ensure that each pull request raised on the repository is clear in communicating what the potential change seeks to resolve. This lends itself to the appropriate discourse and comprehensive scrutiny, which in turn ensures that the result of the PR review process is a change that has been agreed upon by the relevant stakeholders. We shall now proceed and define a template that is to be used for raising a pull request.

Note

The pull request template must adhere to the following canons:

1. The template should be stored in a repository's default branch.

2. The template should be stored in the repository's root directory, the docs directory, or the hidden.github directory.

Exercise 26: Standardizing Procedures through Ordered Templates

To demonstrate the usage of templates in raising pull requests and organizing the application's pipeline, follow these steps:

  1. Navigate to the abacus repository on your computer and check out to the branch master.
  2. Create a branch called ch-add-pr-template and switch to it using the following code:

    git branch ch-add-pr-template

    git checkout ch-add-pr-template

  3. Add the template to the root directory by using the touch PULL_REQUEST_TEMPLATE.md command:
    Figure 4.21: Branch selector
  4. Open the PULL_REQUEST_TEMPLATE.md template on your editor of choice.
  5. Add the earlier template text to the file and save it.

    Note

    What issue does this pull request correspond to?

    What is the acceptance criteria for the proposed solution?

    #### Merging Checklist

    - [ ] PR approved

    - [ ] All checks pass

    - [ ] Manual tests approved

  6. Stage the file, and commit and push it to the remote branch using the following code:

    git add PULL_REQUEST_TEMPLATE.md

    git commit -m "Add pull request template"

    git push origin ch-add-pr-template

    Figure 4.22: Staging the file
  7. Raise a pull request and merge it as shown in the following screenshots:
    Figure 4.23: Raising a pull request
    Figure 4.24: Adding a pull request
  8. To observe the template in action, retrieve the changes from the remote branch master, check out a new branch, and make the following edit in the README.md file using the following code:

    git checkout master

    git pull origin master

    git checkout -b ch-add-usage-instructions

    Figure 4.25: Adding a pull request
  9. Use the following sub-steps:

    Note

    Getting started:

    1. git clone [email protected]:[username]/abacus.git.

    2. Navigate to the repository location.

    3. Run python bin/runner.py.

    Figure 4.26: The README.md file
  10. Stage the change, and commit and push it to the remote branch using the following code:

    git add READ.md

    git commit -m "Add usage instructions"

    git push origin ch-add-usage-instructions

    Figure 4.27: Staging the change
  11. Raise a pull request. On the page where you provide details of the pull request, add the usage instructions, as seen in the screenshots below:
Figure 4.28: Opening a pull request
Figure 4.29: Adding usage instructions

Outcome

By following this exercise, you should be able to outline the steps that need to be adhered to for a pull request to be merged. Additionally, you should be able to lay out the format that a pull request's description follows.

Identifying and Fixing Merge Issues

As part of incorporating changes, certain checks need to pass for a pull request to be merged. These checks vary from repository to repository. In this section, we will explore failed status checks and merge conflicts.

Failed Status Checks

A PR may execute unit tests as part of a pre-merge sanity check. To proceed with the merging of PR, you need to ensure that the set checks pass. In this scenario, this means ensuring that unit and integration tests pass in the CI/CD builds.

As demonstrated in the following screenshot, failed checks need to pass for a merge to be conducted:

Figure 4.30: Failed check status
Figure 4.31: Passed check status

In Chapter 6: Automated Testing and Release Management, we will look into configuring tests that are to be triggered when we create pull requests and rectify failed builds when they occur.

Merge Conflicts

A merge conflict is a term that depicts an issue whereby modifications made in separate branches can't be amalgamated into one unit of change or modification.

A merge conflict will occur when:

  1. Modifications are made on the same line of a file.
  2. Changes are made to a file on one branch and the same file is deleted on another branch.

Merge conflict resolution encompasses picking which of the differing sets of changes should be used in a merge process.

Exercise 27: Merge Conflict Resolution

To demonstrate merge conflicts that are the result of multiple contributors changing the same line in a file, follow these steps:

  1. Navigate to the location of the abacus repository. Ensure that you are on the master branch.
  2. Create a branch and check out to it using the git checkout -b conflict-branch-1 command, as shown in the following screenshot:
    Figure 4.32: Creating a branch
  3. Open the PULL_REQUEST_TEMPLATE.md file and add the following text between line 7 and line 8. Line 8 should read - [ ] Architecture changes approved:
    Figure 4.33: Opening the pull request template
  4. Stage and commit the change using the following code:

    git add PULL_REQUEST_TEMPLATE.md

    git commit -m "Add PR instructions"

    Figure 4.34: Staging and committing the change
  5. Switch to the branch master. Create a branch called conflict-branch-2 and check out to this branch using the following code:

    git checkout master

    git checkout -b conflict-branch-2

    Figure 4.35: Switching to the branch master
  6. Open the PULL_REQUEST_TEMPLATE.md file and edit line 8 to read "- [ ] Manual tests approved and test screenshots attached" as follows:
    Figure 4.36: Opening the pull request
  7. Stage and commit the change using the following code:

    git add PULL_REQUEST_TEMPLATE.md

    git commit -m "Modify PR checklist"

    Figure 4.37: Staging and committing the change
  8. Switch to the conflict-branch-1 branch and merge the changes from conflict-branch-2 using the following code:

    git checkout conflict-branch-1

    git merge conflict-branch-2

    Note

    On the terminal, you will see the following message, indicating conflicting sets of changes:

    Figure 4.38: Switching to the branch
  9. Open PULL_REQUEST_TEMPLATE.md in your editor, as shown in the following screenshot:
    Figure 4.39: Opening the pull request template

    Note

    Take a look at the format to be used:

    <<<<<<< HEAD

    Content in current branch

    =======

    Content from the incoming branch

    >>>>>>>

  10. Edit the file to accept either of the sets of changes or both sets of changes, shown as follows:
    Figure 4.40: Editing the file
  11. Stage the file and commit the change using the following code:

git add PULL_REQUEST_TEMPLATE.md

git commit -m "Merge conflicting edits"

Figure 4.41: Staging the file

Outcome

Having followed these steps, you should be able to resolve a merge conflict that encompasses competing changes on the same line of a single file.

Exercise 28: Resolving Conflicts

To demonstrate merge conflicts that are the result of the removal of a file in one branch and the changing of a file's content in another branch, follow these steps:

  1. Navigate to the location of the abacus repository. Ensure that you are on the master branch.
  2. Create a new branch and check out to it using git checkout -b conflict-branch-3 as shown in the following screenshot:
    Figure 4.42: Staging the file
  3. Open the PULL_REQUEST_TEMPLATE.md file and add the following text between line 7 and line 8. Line 8 should read "- [ ] Architecture changes approved":
    Figure 4.43: opening and pulling the request template
  4. Stage and commit the change using the following code:

    git add PULL_REQUEST_TEMPLATE.md

    git commit -m "Add PR instructions"

    Figure 4.44: Opening the pull request template
  5. Switch to the branch master. Create a branch called conflict-branch-3 and check out to this branch using the following code:

    git checkout master

    git checkout -b conflict-branch-4

    Figure 4.45: Switching to the branch master
  6. Stage and commit the change using the following code:

    git checkout conflict-branch-3

    git merge conflict-branch-4

    Note

    In the Terminal, you will see the following message, indicating conflicting sets of changes:

    Figure 4.47: Switching the branch
  7. Stage the file and commit the change using the following code, and as seen in the following screenshot:

git add PULL_REQUEST_TEMPLATE.md

or git rm PULL_REQUEST_TEMPLATE.md

then git commit -m "Merge conflicting edits"

Figure 4.48: Stage the file

Outcome

Following the preceding steps should enable you to resolve a merge conflict where the competing changes are the removal of a file in one branch and the modification of the same file in another branch.

Merging and Reverting Pull Requests

With the prospective changes approved and all of the checks having been successful, a PR may be merged.

There are three modes available for merging pull requests, as shown in the following screenshot:

Figure 4.49: Available modes

Consider a PR merging the feature-1 branch to the master branch:

Figure 4.50: PR Merging

Merge Commit

This mode adds commits c4 and c5 to the branch master using a unifying commit, c6, referred to as a merge commit. This is a non-fast-forward mode:

Figure 4.51: Merge Commit

Squash and Merge Commits c4 and c5 are combined into a single commit, c6. The c6 command is then merged in the fast-forward mode:

Figure 4.52: Squash and Merge

Rebase and Merge

In this mode, each commit from the feature-1 branch is added to the branch master without the use of a merge commit:

Figure 4.53: Rebase and Merge

Exercise 29: Pull Request Reversal

To establish the process of reversing a merged pull request, follow these steps:

  1. Navigate to the location of the abacus repository locally.
  2. Switch to the conflict-branch-1 branch and push the branch to the remote repository using the following code:

    git checkout conflict-branch-1

    git push origin conflict-branch-1

    Figure 4.54: Switching the branch
  3. In your browser, go to https://github.com/kifeh-polyswarm/abacus/compare/conflict-branch-1?expand=1 to raise a pull request:
    Figure 4.55: Raising a pull request
  4. Merge the pull request.
  5. To revert the pull request, go to a pull request. In this case, this is https://github.com/kifeh-polyswarm/abacus/pull/12.
  6. Click the Revert button, as shown in the following screenshot:
    Figure 4.56: Revert button

    Note

    Clicking this button redirects you to a page so that you can create a revert commit.

  7. Create the revert PR and merge it as shown in the following screenshot:
Figure 4.57: Creating the revert PR

Outcome

Having followed these steps, you should be able to create a pull request and reverse changes once a pull request has been merged.

Activity 4: Managing Branches and Experimentation with Selective Changes

You have been tasked with adding capabilities for computing speed and distance to your company's application. The features need to be handled separately and merged as a single work stream. You need to raise a pull request of the release-candidate branch you created in the activity in Topic 1: Utilizing Workflows. Merge the pull request once the changes have been approved. This is required since the tasks in this activity are a continuation of the work done in the activity in Topic 1: Utilizing Workflows.

The aim of this activity is to demonstrate being able to handle branches.

To start this activity, you need to have the Git command-line tool installed on your computer. Then, you need to have an account on https://github.com/. You should be logged into your account on GitHub. Lastly, you should have the abacus application repository on GitHub and your computer:

  1. Open the browser and navigate to the abacus repository to raise a pull request.
  2. Provide the appropriate description of the purpose of the pull request.
  3. Edit the rule associated with the branch master and save the changes.
  4. Merge the pull request on the page you're directed to.
  5. Open the terminal on your computer and navigate to the location of the abacus repository.
  6. Retrieve the changes for the remote master branch.
  7. Create a branch called ft-speed to implement the speed computation feature.
  8. Edit the speed method as required.
  9. Stage the changes made on src/lib/util/util.py / and commit the changes.
  10. Create a branch to compute the distance, given a speed and time.
  11. Retrieve the available stash list entries and apply the changes of the relevant stash to the working directory.
  12. Delete the stash from the stash entry.
  13. Stage the changes and commit them.
  14. List the branches to obtain the names
  15. Switch to the ft-compute-speed branch and create a branch called bg-speed-calc to resolve the bug and switch to the branch.
  16. Edit the speed method.
  17. Switch to the ft-compute-distance branch and create a branch called ft-distance-arguments to resolve the bug and switch to the branch.
  18. Edit the distance method.
  19. Rename bg-speed-calc and fx-distance-arguments.
  20. Delete the ft-compute-distance and ft-compute-speed branches.
  21. To explore the difference in the distance method, check out to the revision prior to the point at which you introduced the fix in the method.
  22. Switch back to the ft-compute-calc branch and create a branch named util-milestone.
  23. In src/lib/util/util.py, edit the file as required.
  24. Integrate the functionality to compute speed.
  25. Resolve the merge conflict by editing src/lib/util/util.py to adopt the incoming change.
  26. Merge the changes.
  27. To conclude this task, we need to include a function to calculate time.
  28. Stage the changes and commit them.
  29. Obtain the hash commit for use in the next step.
  30. Push the change to the remote repository.
  31. Visit https://github.com/ [username]/abacus/compare/util-milestone?expand=1 to raise a pull request.

Outcome

The activity in the culmination of this topic should enable you to navigate branches as well as the snapshots represented by their respective commits.

Note

For detailed steps for this activity, refer to the Appendix section on page 294.

Summary

In this chapter, you used the feature-branch workflow to implement units of work through branches. This workflow has also introduced you to the naming convention utilized to identify the nature of work a branch delivers. Using the git branch command, you've created, listed, and deleted branches. We've explored how to navigate different revisions of a repository and utilized the same revisions to selectively integrate changes into branches. We then looked at how to manage unstaged changes in the working directory. Lastly, we shipped the changes we've introduced by comparing branches, raising pull requests to merge desired changes, and reverting the changes where necessary.

In the next chapter, you will develop collaboratively on a remote repository, build application artifacts, and automate testing on GitHub. Additionally, you will develop new software version releases.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.124.244