Skip to content

Instantly share code, notes, and snippets.

@mtbulut
Forked from blackfalcon/git-feature-workflow.md
Created March 28, 2020 17:17
Show Gist options
  • Select an option

  • Save mtbulut/ab01dccff7bb45c0f044a2fde6ce811d to your computer and use it in GitHub Desktop.

Select an option

Save mtbulut/ab01dccff7bb45c0f044a2fde6ce811d to your computer and use it in GitHub Desktop.
Git basics - a general workflow

There are many Git workflows out there, I heavily suggest also reading the atlassian.com Git Workflow article as there is more detail then presented here.

The two prevailing workflows are Gitflow and feature branches.

The other prevailing Git workflow is Gitflow, but being more of a subscriber to continuous integration, the feature branch workflow is better suited.

When using Bash in the command line, it leaves a bit to be desired when it comes to awareness of state. I would suggest following these instructions on setting up GIT Bash autocompletion.

Basic branching

When working with a centralized workflow the concepts are simple, master represented the official history and is always deployable. With each now scope of work, aka feature, the developer is to create a new branch. For clarity, use descriptive names like transaction-fail-message or github-oauth for your branches.

#Protip: Although you may have a feature like 'user login and registration`, this is not considered appropriate to create a feature branch at this level, there is too much work to be done. It is better to break these large deliverables down to smaller bits of work that can be continuously integrated into the project. Remember, commit early and often.

Before you create a branch, be sure you have all the upstream changes from the origin/master branch.

Make sure you are on master

Before you pull, make sure you are on the right branch. If you have GIT Bash autocompletion installed, this will tell you. Otherwise the following command is good to know to list out the branches you have locally as well designate which branch you are currently on.

$ git branch

The branch you are on will have a * before the name. If the return designates anything other then master then switch to master

$ git checkout master

Once on master and ready to pull updates, you can use the following:

$ git pull origin master

The git pull command combines two other commands, git fetch and git merge. When doing a fetch the resulting commits are stored as remote branch allowing you to review the changes before merging. Merging on the other hand can involve additional steps and flags in the command, but more on that later. For now, let's stick with git pull.

Now that you are all up to date with the remote repo, let's create a branch. For efficiency, you want to use the following:

$ git checkout -b my-new-feature-branch

This command will create a new branch from master as well checkout out that new branch at the same time. Doing a git branch should list out the branches in your local repo and place a * before the branch that is checked out.

  master
* my-new-feature-branch

Do you have to be on master to branch from master?

No. There is a command that that allows you to create a new branch from any other branch while having checked out yet another branch. WAT?!

$ git checkout -b transaction-fail-message master

In that example, say I was in branch github-oauth and I needed to jump to create a new branch, by adding master at the end of that command Git will create a new branch from master and then move me (checkout) that new branch.

This is a nice command, but make sure you understand what you are doing before you do this. Creating bad branches can cause a real headache when trying to merge back into master.

Branch management

As you are working on your new feature branch, it is a good idea to commit often. This allows you to move forward without fear that if something goes wrong or you have to back out for some reason, you don't lose too much work. Think of committing like that save button habit you have so well programed into you.

Each commit also tells a little bit about what you just worked on. That's important when other devs on the team are reviewing your code. It better to have more commits with messages that explain the step versus one large commit that glosses over important details.

Commit your code

As you creating changes in your project, these are all unseated updates. With each commit there most likely will be additions, and there will also be deletions from time to time. To get a baring of the updates you have made, lets get the status.

$ git status

This command will give you a list of all the updated, added and deleted files.

To add files, you can add them individually or you can add all at once. From the root of the project you can use:

$ git add .

In order to remove deleted files from the version control, you can again either remove individually or from the root address them all like so:

$ git add -u

I'm lazy, I don't want to think, so the following command I make heavy use of to address all additions and deletions.

$ git add --all

All the preceding commands will the stage your updates for commitment. If you run a git status at this point, you should see a updates presented differently, typically under the heading of Changes to be committed:. At this point, the changes are only staged and not yet committed to the branch. To commit, do the following:

$ git commit -m "a commit message in the present tense"

It is considered best to illustrate your comment in the tense that this will do something to the code. It didn't do something in the past and it won't do something in the future. The commit is doing something now.

A bad example would be:

$ git commit -m "update fixed bug with login feature"

A good example would be:

$ git commit -m "update app config to address login bug" 

Comments are cheap. For more on how to write expressive commit messages, read 5 Useful Tips For A Better Commit Message.

Push your branch

When working with feature branches on a team, it is typically not appropriate to merge your own code into master. Although this is up to your team as how to manage these expectations, but the norm is to make use of pull requests. Pull requests require that you push your branch to the remote repo.

To push our new feature branch to the remote repo, simply do the following:

$ git push origin my-new-feature-brach

As far as Git is concerned, there is no real difference between master and your feature branch. So, all the same Git features apply.

My branch was rejected?

This is a special case when you are working on a team and the branch you are pushing to is out of sync with your local version outside of the changes you made. To address this, it's simple, pull the latest changes:

$ git pull origin my-new-feature-branch

This will fetch and merge any changes on the remote repo into your brach with the changes, thus now allowing you to push.

Working on remote feature branches

When you are creating the feature branch, this is all pretty simple. But when you are needing to work on a co-workers branch, there are a few additional steps that you need to know.

Tracking remote branches

Your local .git/ directory will of course manage all your local branches, but your local repo is not always aware of any remote branches. To see what knowledge your local branch has of the remote branch index, adding the -r flag to git branch will return a list.

$ git branch -r

To keep your local repo 100% in sync with deleted remote branches, it's good to make use of this command:

$ git fetch -p

The -p or --prune flag, after fetching, will remove any remote-tracking branches which no longer exist.

Switching to a new remote feature branch

Doing a git pull or git fetch will update your local repo's index of remote branches. As long as your co-worker as pushed their branch, your local repo will have knowledge of that feature branch. By doing a git branch you will see a list of your local branches. And by doing a git branch -r you will see a list of remote branches. There is a good chance that the new feature branch is not on your list of local branches.

The process of making this remote branch a local branch to work on, simply checkout the branch.

$ git checkout new-remote-feature-branch

This command will pull it's knowledge of the remote branch and create a local instance for you to work on.

The Pull request

The pull request is where the rubber meets the road. As stated previously, one of the key points of the feature branch workflow is that the developer who wrote the code does not merge the code with master until there has been a peer review. Leveraging Github pull request features, once you have completed the feature branch and pushed it to the repo, there will be an option to review the diff and create a pull request.

In essence, a pull request is a notification of the new code in an experience that allows a peer developer to review the individual updates within context of the update. For example, of the update was on line 18 of header.haml, then you will only see header.haml and a few lines before and after line 18.

This experience also allows the peer reviewer to comment each line within the update that will be communicated back to the editor or origin. This review experience really allows for everyone on the team to be actively involved in each update.

Once the reviewer has approved the editors updates, there are two ways to merge in the code. One from the Github interface and another from the command line.

Merging the code

Although you can merge from the Github interface, it is preferred to do it from the command line. After all, what happens if Github merging tools are broken? It can happen.

So let's assume that you created a feature branch, you edited code and pushed it to the repo. You initiated a pull request and the code update was approved. Here are the steps I will go through to merge the new code. Keep in mind, this illustration is simply managing code, this is not including running tests, while it can be worked into this workflow, that is a separate concern.

  1. Make sure that you have the latest version of the feature branch from the remote repo

     $ git checkout my-feature-branch
     $ git pull origin my-feature-branch
    
  • Make sure that the feature branch is up to date with master, while in the feature branch, execrate the following command:

      $ git pull origin master
    

    If there are any conflicts, best to address them here.

  • Now that we know that the feature branch is up to date with the remote repo and that it has the latest code from master, we can now merge these branches. We also need to make sure that our local master is up to date as well.

      $ git checkout master
      $ git pull origin master
      $ git merge --no-ff my-feature-branch
    

    Notice the --no-ff flag in the merge command. This flag keeps the repo branching history from flattening out. If you were to look at the branching history of this repo, using GitX for example, when using the --no-ff flag, you will see the appropriate bump illustrating the history of the feature branch. This is helpful information. If you do not use this flag and use the default Git fast forward commit, then Git will move the commit pointer forward.

    You can either enter the --no-ff flag each time you merge or you can set this as your default. I prefer the default myself. Running the following command will update your global gitconfig.

      $ git config --global merge.ff false
    

    And of course, setting the but back to true will return the default setting to fast forward with merging.

  • Now that we have merged the code, the feature branch by definition is obsolete. First, delete the branch from the local repo.

      $ git branch -d my-feature-branch
    

    The -d flag for delete will typically delete any branch. Remember, you can't delete a branch you have checked out.

    If you happen to see this following error when deleting a branch, then simply replace the -d with -D to force the delete.

      error: The branch 'name-of-branch' is not an ancestor of your current HEAD.
    
  • If the feature branch was pushed to the repo, as it should have been per the workflow we described, you will want to delete this from the remote repo as well.

      $ git push --delete origin/my-feature-branch
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment