Working with Git branches

Command Line – Git Branches

© Lead Image © Rachael Arnott, 123RF.com

© Lead Image © Rachael Arnott, 123RF.com

Article from Issue 243/2021
Author(s):

Git makes version control as simple as possible. To manage your Git branches successfully, you need to learn the ins and outs of git branch and git merge.

In a previous issue of Linux Magazine [1], I outlined how to set up a Git Repository (Table 1). Once a repo is set up, you are ready to use Git [2] for version control.

Table 1

Basic Commands for Creating a Repository

git clone URL

Copy remote repository to your local hard drive.

git pull URL

Sync a local repository with the remote original.

git init

Create a local repository in the current directory.

git add FILE1 FILE2

Stage (prepare) files in the repository.

git commit -m "MESSAGE"

Add staged files to the repository.

Note: Each of these commands has other options, as well as its own man page. These are only the basic commands.

Version control in Git is about managing and creating branches (collections of files that are variations of each other). By making a branch, you can edit files without altering the original. Later, if you choose, you can merge branches to create a more advanced copy.

The process of managing branches is so simple that branches tend to proliferate in projects that use Git, with branches being created for different users, subsystems or hardware architectures, each release, experiments, or any other criteria that may useful. In fact, while other version control systems also use branches, using Git repos is so flexible that it is widely considered Git's defining feature. Two Git sub-commands are the main tools for managing branches: git branch [3], which sets up and edits branches, and git merge [4], which combines branches.

A Basic Overview

When a repository is created, a default called master is created. It is the top-level branch, analogous to the root directory on a filesystem, with its commits the equivalent of the root directory's files. Otherwise, master is no different from any other branch. However, ordinarily, the commits in master are not edited – the whole point, after all, is to have a clean set of files in case a recovery is needed. The most common workflow is to create a branch below master and edit the files there.

Git manages the branch tree with a series of pointers. The current branch is kept track of with a pointer called HEAD. You create a new branch locally with the command:

git branch NAME

If you want to move to the new branch immediately after creating it, instead use

git checkout -b NAME

or

git switch -c

Otherwise, use git checkout NAME, a basic navigational command for a repo. A new alternative for navigation is git switch NAME, which has the advantage of allowing you to return to your previous repo with git switch.

To transfer a local branch to a new remote repository, the remote repository must first be recognized by the local one with:

git remote add REMOTE-REPO-URL://LOCAL-HOST/USER/repo.git

Then a local branch can be uploaded remotely with:

git push REMOTE-REPO-URL LOCAL-BRANCH

The new branch is automatically created as a sub-branch of the current one. At the same time that you move to the new branch, so does HEAD (the current branch pointer). Keep in mind, too, that when you change branches, you change the versions of the files available to you. Should you forget, your Git repository can abruptly become a puzzling place.

Especially with large projects or numerous contributors, Git repo trees can have considerable depth and breadth. In such cases, navigating – just knowing where you are – can be a challenge. One solution is to use the command git branch --list (Figure 1), which marks the current local repository with an asterisk and prints any checked out local repositories in cyan. Use -r with --list, and remote repositories are listed, while -a lists both local and remote branches. Another navigational tool is to install the git-big-picture utility [5], which opens a map of the repository in a separate window (Figure 2).

Figure 1: A color-coded list of branches.
Figure 2: The git-big-picture utility provides a handy navigational aid, especially for large repositories.

Especially when merging (see below), you may also want to use git tag to give each commit a human-friendly name and refer to Git's log. The log has an effective search function, and you can filter the branches with:

git log INCLUDED-BRANCH..EXCLUDED-BRANCH

Editing Branches

A commit's actual content is edited elsewhere – generally in a text editor. However, branches can also be edited and managed using the command:

git branch OPTIONS STRING

In this structure, STRING can be a branch name or a commit, depending on the context. For instance, if a regular expression is used by itself, rather than a single branch name, then you could possibly create other branches – which could cause a lot of unwanted branches. To guarantee that you simply filter with a regex, --list must be used as well. Another way to filter is to use --contains to include only branches that contain the named commit (i.e., branches that are descendants of the commit) or --no-contains to exclude descendant branches. Similarly, --merged lists only branches merged into the named commit, while --no-merged excludes merged branches.

One of the more common ways to edit branches is with deletion. The simplest choice is --delete (-d), but it only works if the branch is merged in its upstream branch, in HEAD, or has a branch marked as its upstream (see below). If you are sure you want to remove the branch, use -D instead, or combine --delete with --force (-f).

Branches can also be copied with --copied (-c) or moved with --move (-m). The --move option has the same restrictions as --delete, but it can be forced with -M or by being accompanied by --force. If you want to rename a branch, you can use -m (-M) NEW-BRANCH OLD-BRANCH.

A more complicated edit is to add --track when a new branch is created. This option marks the current branch as being upstream from the new branch and is the default when working from a remote branch. In effect, it is a navigational marker, shown in git status and git branch -v. After a branch is created, you can give it an upstream with --setupstream-to BRANCH (-u BRANCH) or remove an upstream with --unset-upstream.

More trivially, you can set how output is displayed. --color=WHEN color-codes current, local, and remote repos, defaulting to always but also taking never or auto as a value. To ignore whether characters are lowercase or uppercase, use --ignore case. Another option is to display output with --column or to use the verbose modes (-v, --verbose, or -verbose) to see more information – although at the cost of having no columns.

Merging Branches

Merging is the joining of branches and the resolving of any differences between them. Before you merge, use git fetch to make sure that any local or remote repos are in sync, and check that all changes are committed. Then check out the branch into which you want to merge and run git pull to make sure it has the latest updates. Then enter the command:

git merge branch OTHER-BRANCH

If only one branch is specified, it will be merged into the current branch. When one branch is newer than the other, it will be marked as Fast-forward, meaning it is a simple two-way merge (Figure 3) that will mark the differences in the branch being merged into and use minus signs to note differences in the branch being merged. In other words, the results are shown much as they are in the results of the diff command.

Figure 3: A merge where Git has figured how to merge two branches, each containing one file.

Git does its best to resolve any conflicts, and, all going well, the result is a new commit into the parent branch that contains the original commits plus a log message detailing the changes. However, if there is no direct connection, Git tries to create one with a three-way merge, assigning a third merge as a route between the other two, which makes conflicts more likely. This is why a clear map of a repo can be useful. If you think a three-way merge is likely, you can add the option --no-commit as a dry run to see what problems may emerge.

Since conflicts can be tedious to fix, especially in bulk, experts also suggest that you merge frequently. You may also decide to stop the merge with git merge --abort, and Git will try to reconstruct the original change to all branches, although any uncommitted changes may not be restorable.

To fix conflicts:

1. Run git status (Figure 4) to get a list of files that need to be resolved. In the files, <<<<<<< marks the start of a conflict and >>>>>>> marks the end. Use ======= to mark the start and end of your manual changes as you work. Contents from the first branch are marked in plus signs and from the second batch in minus signs. Delete the conflict markers when you finish editing.

Figure 4: The command git status reports the merge results.

2. Run the git add command on the conflicting files when ready to merge.

3. Run git commit -m "MESSAGE" or git merge --continue to generate the merge commit.

If the conflicts are numerous or complicated, you may need to try a merge more than once to be successful.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Remote Git Repositories

    Software projects often comprise several code branches, some of which exist in parallel. Git supports community code development through remote repositories and code branching.

  • Tree View

    Complex Git projects sometimes require a better view of the dependencies and branches. Several tools offer GUI options for Git. We take a look at gitk, gitg, git-gui, and GitAhead.

  • Git Ready

    If you develop open source software, you need to know how to use Git. Information on Git fills books, but this basic overview will get you started with a vital open source development tool.

  • Perl: Collaborate with GitHub

    GitHub makes it easier for programmers to contribute to open source projects by simplifying and accelerating communications between project maintainers and people willing to contribute.

  • Git Essentials

    Once you've started using Git, these seven utilities can help you get the most out of this essential version control system.

comments powered by Disqus