How to: Use branches in Git (Part V)

How to: Use branches in Git (Part V)

So, essentially branches are the way to go when trying out new ideas or isolating features or sections of work. One can branch out of the master line and work on a feature, independently from what’s going on the outside, little introvert f*ckers branches are…

Git handles context switching very fast, meaning that switching branches replaces the files in the working directory with those of the selected branch without too much hassle. Eventually, branches can be either merged into the master branch or discarded completely.

git branch

By itself, the command displays the branches of the current repository:

git branch          # Show the local branches
git branch -v       # Show the remote branches 
git branch -a       # Show all branches, including remotes

To create a branch out of thin air, use this command and give it a nice name (no, Branchie is not a nice name):

git branch <significant-branch-name>

Of course, if you f*ck up, you can always rename it using:

git branch -m <old-branch-name> <new-branch-name>

It is also possible to delete the branch, but note that the more branches you remove, the more your git tree will start looking like a giant wooden buttplug:

git branch -d <delete-me>

Note that if a branch was not fully merged, that command won’t do it, but you can force it to do it anyway and it won’t even mind:

git branch -D <delete-me>

And now it’s probably the time to bring back our old pal, git checkout. Apart from replacing your local files, it can also switch branches, thus moving the pointer to the new currently active branch and replacing the contents of your working directory.

git checkout <branch-name>

It can also do super combos: create a new branch, make it reference another branch or tag and switch to it.

git checkout -b <new-branch> <parent-branch>

Another quick option that can come in real handy, git branch --merged will display branches that were merged and basically contain each other’s commits, more precisely it displays a list of all the branches that contain all the commits that the currently active branch has.

Note however, that Git will not allow branch switching if the current branch’s working directory is not clean, in the sense that there are no files in conflict – there’s no problem with new files or changed files that have not been altered in other branches. In the event of possible conflicts, either stage and commit the changes, or remove them.

git merge

To merge a branch, first checkout the branch you want to merge things into, then run the git merge command.

git checkout master
git merge <branch-name>

That command will add the commits from <branch-name>, on top of those on the master branch and then move the HEAD pointer at the top of the list. But, based on the level of their complexity, merges can be of two types: fast-forward merges and real merges.

Fast-forward merges occur when the parent branch doesn’t contain additional changes from the time of the branching, meaning that it’s absolutely safe to just move the source branch’s commits at the end of the parent branch and then simply update the HEAD pointer with the last position in the chain.

Real merges occur when the parent tree contains additional commits that were submitted in the meanwhile, between the times of branching and merging. Git tries to auto-merge branches using a recursive strategy. But there can always be such things as merge conflicts. 

Conflicts are usually handled automatically if the file differences are on different lines, but otherwise, put yourself in Git’s position. Without any knowledge of what any of those lines mean, how do you decide which version is more adequate or better yet come up with a hybrid solution that takes incorporates both changes?

When that happens, Git throws a conflict error and the merging operation is suspended until the conflicts are resolved. So, the files that are in conflict now contain both blocks of code, enclosed between lines of <<<<<< and ====== delimiters.

Manually reviewing those changes and removing the delimiters is preferable to using automatic merge tools as it is considered safer. After the conflicts are fixed, we can add the files to the staging index and perform a simple commit without any message – that will be prompted by the merging operation itself in a freshly opened editor.

Now that we talked about the two types of merges, here are a couple of useful options:

The first one inhibits fast-forward merges and forces git to copy all the commits from the branch to the parent tree, thus maintaining a detailed history log, even if fast-forwarding would have been possible, in which case only one commit would have been created on the parent branch to indicate the fact that there has been a merging operation:

git merge --no-ff <branch-name>

The other one will perform a merge only if fast-forwarding is possible and abort the operation otherwise:

git merge --ff-only <branch-name>

To reduce the probability of having conflicts occur when merging branches, we can merge the parent branches into the working branches, and do it often – this way when the working branches will pretty much contain the same thing as the parent ones, thus making it easy for git to perform successful auto-merges or even fast-forward merges. This strategy is called tracking and is commonly used when working with remotes.

Note: It is advisable to only perform merges with a clean working directory. Otherwise, things could get messy and we would have to talk about using stashes. Oh, what the hell – let’s get it over with:

git stash

I know it sounds like a porn term, but in actuality, the stash is a special fourth area in Git. It is separate from the repository, the staging area or the working directory and doesn’t have a checksum associated with it.

Stashes are commonly used when trying to switch into a branch while the working directory is not clean. Typically you would have two options: discard your changes or commit them. The third option would be to stash those changes and deal with them at a later time.

git stash save "Message goes here"

What the command really does, is it stores the changes into the stash with the specified message, so that they can be accessed later, and then performs a hard reset to HEAD e.g. git reset --hard HEAD, taking the pointer back to the previous commit.

Here’s another fun command, to display all the stashed entries, with their associated identifier and message.

git stash list

Just for future reference, a stash identifier looks something like this: stash@{<number-of-stash>}

This next one displays a diff between the changes in the stash and those in the HEAD.

git stash show -p <stash-identifier>

And well, here’s the rest of them:

git stash apply <stash-id>  # Apply <stash-id>
git stash pop <stash-id>    # Apply <stash-id> and remove it from stashes
git stash drop <stash-id>   # Remove <stash-id> from stashes
git stash clear             # Remove all stashes

That’s it for today. Marilyn Monroe once said “if you can make a woman laugh, you can make her do anything”, to which I must add that the same thing applies if you can make her branch. Next time we can already start talking about remotes, moving up in the world like that… Here you go: How to: Work with remotes in Git (Part VI).


One thought on “How to: Use branches in Git (Part V)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s