Tag: checkout

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).

How to: Undo changes with Git (Part III)

How to: Undo changes with Git (Part III)

Sometimes, you f*ck up. I f*ck up, you f*ck up, everyone f*cks up at some point, we all do it, it’s natural. F*ck, some people actually even make a living out of it and sadly, it is often the same people we look up to or those who run the country. But f*ck it. This section is still all about Git and Git is the magical land where f*ckups are undoable.


However, in most situations it is probably more preferable to just log the mistakes too and make new commits that fix them to reflect an accurate change history.

But no matter the weather, even in dire situations where there have been more commits in the meanwhile, on top of the ones we’re trying to undo, we have a few options:

git checkout

Even though git checkout can help restore peace and order in your working directory, we’ll have to talk about it later too when we reach branching, as it’s primary purpose is way greater. Here we can use it to replace files in the working area with the files stored in the repository (at the current HEAD pointer or any ref pointer really). But note that, when not using branches, it is good practice to include a double bare dash -- to avoid confusion and any unforeseen consequences:

To restore a file in the working directory with the file located at the current HEAD in the repository:

git checkout -- <file>

To restore a file with the file located in the repository at a specific commit pointer:

git checkout 24f6daf6f -- <file>

Looks like we’re going to need to talk about the checksums anyway… Git generates a checksum for each change set, using the SHA-1 hash algorithm, which helps maintaining data integrity. It is the checksum that can be used to refer to a specific commit.

Typically, a SHA1 hash value is rendered as a 40 digits long hexadecimal number, but because of how unique they all are, it is considered safe to address them by only their first few characters (8 characters for instance is way safe).

git revert

This command is used to revert an entire commit. Well, in actuality it creates a new commit which mirrors the targeted one (i.e. everything that was added gets deleted, everything that was deleted gets added, thus all changes undone).

git revert 24f6daf6f

So, using the above command creates the new commit and opens your editor so you can customize the commit message.

git reset

Most commonly, you could find yourself using the reset command to do one of the following two things:

  • Unstage files: say you’re trying to build up a nice commit, stating multiple files and then by accident, a file that’s not supposed to be there just slips in and your staging area is ruined…
git reset HEAD

There we go, that command had the sole purpose of unstaging that file.

  • Undo multiple commits: using the following commands will actually move the HEAD pointer to a previous commit. We have three useful options for three different types of resets, as follows:

The soft reset is the safest reset there is, as it doesn’t change the staging area or the working directory:

git reset --soft 24f6daf6f

The mixed reset is the default option, it changes the staging area but not the working one:

git reset --mixed 24f6daf6f

The hard reset can be destructive as it changes files in all three areas – USE WITH CAUTION.

git reset --hard 24f6daf6f

Thing is, once the HEAD pointer moves back in time, all the other commits after it might seem lost, but they’re not – you can run the same command again, referencing any future commit you can think of (you can first output a git log to a plain text file to still have access to those checksums).

By now I assume you’re old enough to know that not every project is made of candy and each one of them is totally worth tracking and just as important as the next one. There will always be such things as small OS-specific temp files, cache files, logs, dumps and stuff that constantly changes just enough to make git flip out on every commit you make. In the next post, we’ll have a serious grown-up talk on How to: Ignore files in Git (Part IV).