Git From the Command Line — Example Workflow

Gabriel Casullo
Major League
Published in
7 min readJul 25, 2016

--

People usually prefer the use of graphical applications in order to manage Git repositories. They allow us to have an intuitive vision of the state of the repository and different branches involved. These applications are basically interfaces that execute different Git commands depending on user actions.

We can also avoid the use of a graphical application and execute Git directly from the command line. It seems complex and sometimes unnecessary, since through the graphical applications, we can resolve almost all everyday problems.

So, why we should spend time and effort learning Git from the command line if we can choose the “easier way”? I think because Git commands are not just strings that one has to remember or copy-paste from somewhere. They have a syntax that lets you understand how things work and you can combine commands and arguments to resolve more complex or specific problems.

First I’ll start with a brief introduction of the flow we follow in the development process. Then, I’ll explain Git in terms of how we normally work following that flow, and then I’ll go in more detail with common problems we can face during the development/review process.

Our development flow

At Lateral View, we follow a “feature” oriented workflow, keeping a direct relation between the versioning flow and the project flow.

Let’s start with a little introduction of the workflow we follow, in order to be in the same page.
We always work around three main branches:

  • development: This is the less-stable branch, where all finished features are merged in. Every time we start a feature, we start from this branch. Once finished, that feature is merged into development so it gets updated.
  • staging: When a sprint is closed and everything is properly tested by us on development, we merge development to this branch and usually deploy to a staging server where the customer can do further testing.
  • master: When everything is reviewed by the customer and he wants to publish a new release, we merge into this branch and deploy the changes to production environment.

As commented above, we generally start from development when we create a new feature, but what if we’re reported about a bug in production? In this case we can’t start from development because it’s in a different state than production. Here we must branch from master, fix the bug and merge (or make a pull request) into master and also into staging and development too, so we have all versions updated accordingly. The same applies to bugs found on staging by the customer.

Git commands applied to everyday general workflow

Git has a set of commands that let us work on the repository.

The command that I personally use a lot is:

git status

Before I do almost everything, I run this command to have a quick overview of where I am and in which state is my working directory.

Suppose we have to work in some new issue, the first step is to fetch latest changes from development branch:

git pull origin development

The pull command fetches the new changes of specified branch and merges it to a local branch that tracks the state of remote version. We usually call this command with the " — rebase" argument. This tells Git to do a rebase instead of a merge: check-out to the common ancestor state, applies new remote changes and then applies the new local commits. This way we avoid to have automatic merge commits that makes the history more difficult to read:

git pull --rebase origin development

Now that we have updated, we create our feature branch to work in:

git checkout -b 324-profile-screen

The checkout command updates the working directory with the specified branch version. Using it with -b option we’re telling Git to create a new branch. So basically here we’re doing two things: create the "324-profile-screen" branch, and switch to it.

So now, we can work on this new feature until we think it’s ready for review.

When we close some functionality, we create a commit, so we have a “snapshot” of the state of the project in that moment:

git add .
git commit -m “[#324] - Profile screen services”

And later some other functionality:

git add .
git commit -m “[#324] - Profile screen layout and styles”

When we finish the feature, we usually push our branch:

git push origin 324-profile-screen

then create a Pull Request to development and assign a reviewer to it. This way only the reviewers modify development branch by merging developers feature-branches when approving the pull requests.

Once the branch is merged, we can safely remove it.

If the review isn't part of your workflow, you should merge to development and push the changes to remote:

git checkout development
git pull --rebase origin development
git merge 324-profile-screen
git push origin development
git branch -d 324-profile-screen

Note that before we merge, we must ensure that we have the latest changes on development. The last command removes the feature branch.

Some hints that could be useful

Although we usually use the above commands in the development process, Git also allows to do some more interesting stuff.

The double dash ` — ` option

In git, the double-dash ` — ` is mostly used to separate branches references and filenames. This can be very handy sometimes as I explain below.

Sometimes we need to work in a thinner granularity. For example, suppose you’re working in a feature branch “433-feature-1”, and another developer is working at the same time in another feature “440-feature-2”. You need an updated file that is modified within your partner’s branch but not yet merged into development.

You could just copy the content of that file in “440-feature-2” version and paste it on your ‘433-feature-1" branch. The problem with this approach is that Git will complain with a conflict when both branches are being merged to the main branch (development).

From your branch, you can checkout only the file (or files) you need from another branch instead of checkout the entire project:

git checkout 440-feature-2 -- src/services/profileService.js

So, in the above example, we “bring up” only the specified files from branch “440-feature-2” to our “433-feature-1” branch, and then commit the changes.

This way, when both branches are merged into development, Git will have tracked these changes and there won’t be conflicts in those files :-)

We can also use this option on other Git commands, for example, if we want to see the history of the current branch, we just type:

git log

And if we want to also see the diff of the changes made, we specify the -p option:

git log -p

But what if we want to see what happened with a specific file? For example, I could be working on a file where I previously wrote some code that now is gone, or has been modified again and you’re not sure what have happened there.

You can see the history of that specific file with the double-dash option:

git log -p -- src/config.js

Then Git will display the commits (hashes and messages) and the diffs with the changes made in each commit for that specific file.

The double-dash separator is also very handy if you want discard all changes in the working directory, keeping everything as set in the last commit:

git checkout -- .

"travelling" to previous versions

Another common issue is when we want to do a rollback to a previous stable version of the project. With git log select the hash of the commit you want to go and reset the HEAD to that commit.

git reset --hard 50352e6

This will do a rollback of the project to specified commit version. If you have pushed the branch before, you'll have to force-push it again

git push --force origin branch

Sometimes you just want to just take a look to some previous versions to test something. For example, the application is not working and you're not sure if is because your changes or something else. So you can go to a previous stable version, test whatever there and come back to current version.
In this case, instead of a reset we should use checkout:

git checkout 7dfc677

In this point you're in the specified commit version.
Note that from here you could create another branch and do changes you need and commit them without affecting the original branch.
You can also make changes to test, then discard those changes and go back to the current state:

git checkout -- .
git checkout your-branch

Conclusion

Obviously there are a lot of more interesting things we can do with git. I just mentioned the most used for me in my daily workflow.
Git is a powerful tool. It allowed me to be clearer in my code too. For example, I started to avoid leaving commented code that could use later or make a copy of a file with some "old_" prefix to test something. If you need something that you've done earlier you simply checkout to that version and get what you need.

It is also a great tool for the team workflow and the project management. Indeed it's hard at this time to imagine to work in some project without this kind of tool.

If you want to know more about technology and innovation, check us out at Lateral View!

--

--