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.

Revisions

  1. @blackfalcon blackfalcon revised this gist Dec 15, 2019. 1 changed file with 155 additions and 133 deletions.
    288 changes: 155 additions & 133 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -1,259 +1,281 @@
    There are many Git workflows out there, I heavily suggest also reading the atlassian.com [Git Workflow][article] article as there is more detail then presented here.
    # Git-workflow or feature branching

    The two prevailing workflows are [Gitflow][gitflow] and [feature branches][feature]. IMHO, being more of a subscriber to continuous integration, I feel that the feature branch workflow is better suited.
    When working with Git, there are two prevailing workflows are [Gitflow][gitflow] and [feature branches][feature]. IMHO, being more of a subscriber to continuous integration, I feel that the feature branch workflow is better suited, and the focus of this article.

    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][git-auto].
    If you are new to Git and Git-workflows, I suggest reading the [atlassian.com Git Workflow][article] article in addition to this as there is more detail there than presented here.

    I admit, using Bash in the command line with the standard configuration leaves a bit to be desired when it comes to awareness of state. A tool that I suggest using follows these instructions on [setting up GIT Bash autocompletion][git-auto]. This tool will assist you to better visualize the state of a branch in regards to changes and being in sync with the remote repo.

    ## 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, make sure to use descriptive names like `transaction-fail-message` or `github-oauth` for your branches.
    When working in a decentralized workflow, the concepts can be simple. `master` represents the official history and should always deployable. With each new scope of work, aka feature, a developer creates a new branch. For clarity, make sure to use descriptive names like `transaction-fail-message` or `github-oauth` for your branches.

    Although you may have a feature like 'user login and registration`, it may not be appropriate to create a feature branch at this level, there is too much work to be done. It may 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.

    **#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.
    That being said, there are times when a single branch will be needed to deliver a large feature or prepare for a release. In this scenario, I'd suggest reading over the [Git Commit Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit) created by the Angular team at Google. As they put it, it is a series of '... precise rules over how our git commit messages can be formatted'. As of late, I make heavy use of these commit message guidelines in all the projects I am working on.

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

    ### Make sure you are on master

    Before I pull, I make sure I am on the right branch. I have GIT Bash autocompletion installed, this tells me the branch in the prompt. Otherwise, the following command is good to know to list out the branches I have locally as well designate which branch I am currently on.
    Before I pull, I make sure I am on the right branch. I have GIT Bash autocompletion installed, so this is clear from the prompt. Otherwise, the following command is good to know to list out the branches I have locally as well as designate which branch I am currently on.

    $ git branch
    $ git branch
    The checked out branch will have a `*` before the name. If the return designates anything other then `master` then switch to master

    $ git checkout master
    $ git checkout master
    Once on master and ready to pull updates, I 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, I'll stick with `git pull`.
    $ git pull origin master

    Depending on your setup, you may even be able to run only the following:

    $ git pull

    The `git pull` command combines two other commands, `git fetch` and `git merge`. When doing a `fetch` the resulting commits are stored as a 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, I'll stick with `git pull`.

    Now that I am all up to date with the remote repo, I'll create a branch. For efficiency, I will 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` will list out the branches in my local repo and place a `*` before the branch that is checked out.
    $ git checkout -b my-new-feature-branch
    This command will create a new branch from `master` as well as check out out that new branch at the same time. Doing a `git branch` here again will list out the branches in my local repo and place a `*` before the branch that is checked out.

    master
    * my-new-feature-branch
    master
    * my-new-feature-branch

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

    No. There is a command that that allows me to create a new branch from any other branch while having checked out yet another branch. WAT?!
    No. There is a command that allows me 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 create a new branch and then checkout the new branch? By adding `master` at the end of that command, Git will create a new branch from master and then move me (checkout) to that new branch.
    $ git checkout -b transaction-fail-message master
    In that example, say I was in branch `github-oauth` and I needed to create a new branch and then check out the new branch? By adding `master` at the end of that command, Git will create a new branch from master and then move me (check out) to 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.

    ## Some files should be ignored

    In any Git project, you will find a .gitignore file. This is a simple registry file where you can list the files you DO NOT want to commit to the repo. This would be any files that contain secret information like keys and tokens or any sensitive server configurations.

    To read more about the basics of a .gitignore file, read [ignoring files][ignorefiles] from the Github site.

    The only thing I want to mention is if a resource has already been added to Git's control, adding it later to the .gitignore file will not ignore that file. The thing to remember here is that the intention is to remove the file from Git control, but not from disk. To do this, use the following command:

    $ git rm --cached <filename>

    For example, say we had a directory with the filed `index.html` and then the file `config.yml`, but the config file had a lot of secret info and it was accidentally added to the Git version control.

    In the `.gitignore` file, first we would add `config.yml` then in the command prompt, run the following command:

    $ git rm --cached config.yml

    After running the command, you should see that `config.yml` is still in the directory, but running the following command, you would see that it is NOT being tracked by Git:

    $ git ls-tree -r master --name-only

    ## Branch management

    As I am working on my new feature branch, it is a good idea to commit often. This allows me to move forward without fear that if something goes wrong, or you have to back out for some reason, I don't lose too much work. Think of committing like that save button habit you have so well programed into you.
    When I am working on my new feature branch, it is a good idea to commit often. This allows me to move forward without fear that if something goes wrong, or you have to back out for some reason, I 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 I just worked on. That's important when other devs on the team are reviewing my code. It's better to have more commits with messages that explain the step versus one large commit that glosses over important details.

    ### Commit your code

    As I am creating changes in my 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 I have made, lets get the status.
    As I am creating changes in my 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 I have made, let's get the status.

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

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

    $ git add .
    $ git add .
    In order to remove deleted files from the version control, I can again either remove individually or from the root address them all like so:

    $ git add -u
    $ 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.
    I'm lazy, I don't want to think, so I make heavy use of the following command to address all additions and deletions.

    $ git add --all
    All the preceding commands will stage the updates for commitment. If I run a `git status` at this point, I will see my 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 add --all
    All the preceding commands will stage the updates for commitment. If I run a `git status` at this point, I will see my 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. The next step is to commit with a message. Here is where I lean on the Angular style commit messages linked to above. To commit, do the following:

    $ git commit -m "a commit message in the present tense"
    $ git commit -m "<type>(<scope>): <subject>"
    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:
    A bad subject example would be:

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

    A good example would be:
    A good subject example would be:

    $ git commit -m "update app config to address login bug"
    $ 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][thoughtbot].


    ## 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.
    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 to best manage, the norm is usually to make pull requests. Pull requests require that you push your branch to the remote repo.

    To push the 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 a feature branch. So, all the same Git features apply.
    $ git push origin my-new-feature-branch
    As far as Git is concerned, there is no real difference between `master` and a feature branch. So, all the identical Git features apply.

    ### My branch was rejected?

    This is a special case when working on a team and the branch I am are pushing is out of sync with the remote. To address this, it's simple, pull the latest changes:
    There is a special case when working on a team and the feature branch being pushed is out of sync with the remote. To address this is pretty simple with the following command:

    $ git pull origin my-new-feature-branch
    This will fetch and merge any changes on the remote repo into my local brach with the changes, thus now allowing you to push.
    $ git pull origin my-new-feature-branch
    This will fetch and merge any changes on the remote repo into the local feature branch with all the changes addressing any issues with diffs in the branch's history, now allowing you to push.

    ## Working on remote feature branches

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

    ### Tracking remote branches

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

    $ git branch -r
    $ git branch -r

    To keep my local repo 100% in sync with deleted remote branches, I make use of this command:

    $ git fetch -p
    $ 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 my local repo's index of remote branches. As long as co-workers have pushed their branch, my local repo will have knowledge of that feature branch. By doing a `git branch` you will see a list of my local branches. By doing a `git branch -r` I will see a list of remote branches. There is a good chance that the new feature branch is not in my list of local branches.
    Doing a `git pull` or `git fetch` will update my local repo's index of remote branches. As long as co-workers have pushed their branch, my local repo will have knowledge of that feature branch.

    The process of making this remote branch a local branch to work on is easy, simply checkout the branch.
    By doing a `git branch` you will see a list of your local branches. By doing a `git branch -r` you will see a list of remote branches.

    $ git checkout new-remote-feature-branch

    This command will pull it's knowledge of the remote branch and create a local instance for me to work on.
    The process of making a remote branch a local branch to work on is easy, simply check out the branch.

    ## The Pull request
    $ git checkout new-remote-feature-branch

    This command will pull its knowledge of the remote branch and create a local instance to work on.

    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's 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.
    ## Keeping current with the master branch

    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, if 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.
    Depending on how long you have been working with your feature branch and how large your dev team is, the `master` branch of your project may be really out of sync from where you created your feature branch.

    This experience also allows the peer reviewer to place a comment on any line within the update. This will be communicated back to the editor of origin. This review experience really allows for everyone on the team to be actively involved in each update.
    When you have completed your update and prior to creating a pull request, you not only have to be up to date in order to merge your new code but also be confident that your code will still work with the latest version of `master`.

    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.
    It's here where there are two very different schools of thought. Some teams don't mind if you PULL the latest version from `master`, by simply doing the following.

    ## Merging the code
    $ git pull origin master

    This will fetch and merge any changes on the remote repo into the local branch with all the changes, now allowing your feature branch able to be merged. This works for the purpose of merging, but it's kind of gross on the branch's history graph.

    Although I can merge from Github's interface, it is preferred to do it from the command line. After all, what happens if Github merging tools are broken? It can happen.
    Then there are teams who are not a fan of this process, simply because pulling from origin can really screw up the feature branch's history and make it harder to perform more advanced Git features if needed. So, in these situations, it's best to REBASE O_O.

    So let's assume that I created a feature branch, edited code and pushed it to the repo. I 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.
    Rebasing a feature branch is not as scary as most make it seem. All a rebase really is, is taking the updates of the feature branch and moving them to a new spot in the history as to be on top of the latest version of `master`. It's as if you just created that feature branch and made the updates. This creates a very consistent branch history that is easy to follow and easy to work within all situations.

    1. Make sure that I have the latest version of the feature branch from the remote repo
    To rebase your local feature branch off of the latest version of `master`, following these steps will be a guarantee every time.

    $ git checkout my-feature-branch
    $ git pull origin my-feature-branch
    ```
    $ git checkout master /* ensure you are on the master branch
    $ git pull /* pull the latest from the remote
    $ git checkout my-feature-branch /* checkout the feature branch
    $ git push origin my-feature-branch /* update your copy in the repo
    $ git rebase master /* rebase on the master branch
    $ git push origin my-feature-branch --force /* force update the remote
    ````
    1. Make sure that the feature branch is up to date with `master`, while in the feature branch, execrate the following:
    And that's it. This process will ensure that you have the latest version of `master` then take the commits from your feature branch, temporarily unset them, move to the newest head of the `master` branch and then re-commit them. As long as there are no conflicts, there should be no issues.
    $ git pull origin master
    If there are any conflicts, best to address them here.

    1. Now that I know that the feature branch is up to date with the remote repo and that it has the latest code from `master`, I can now merge these branches. I also need to make sure that my local `master` branch is up to date as well.
    ### Force push? But ...
    $ 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 I were to look at the history of this branch, using GitX for example, when using the `--no-ff` flag, I will see the appropriate bump illustrating the history of the feature branch. This is helpful information. If I didn't use this flag, then Git will move the commit pointer forward.

    I can either enter the `--no-ff` flag each time I merge or I can set this as my default. I prefer the default option. Running the following command will update the global gitconfig.

    $ git config --global merge.ff false
    And of course, setting the bit back to `true`, will return the default setting to fast forward with merging.

    **NOTE:** there is a mild side-effect that will happen when you set this flag to `false`. Every time you do a `pull` this will not fast forward your local repo and basically make this a new commit. That's ok, but you will see this in the commit logs

    Merge branch 'master' of github.com: ...
    and

    # Your branch is ahead of 'origin/master' by 1 commit.
    If you are ok with this, then keep the flag. If this annoys or bothers you, do not use the flag and set `--no-ff` manually with each merge.

    1. Now that I have merged the code, the feature branch by definition is obsolete. First, delete the branch from the local repo.
    Yes, there are those who are not fans of force pushing, but in the case of a feature branch, this is ok. Now force pushing to `master`, well, that's a really bad idea.
    $ 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 the 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.
    1. 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.
    When performing operations like rebasing you are in effect changing the branch's history. When you do this, you can't simply push to the remote as the histories are in conflict, so you will get rejected. To address this, adding the `--force` flag to force push tells the remote to ignore that error and replace the previous history with the new one you just created.
    $ git push origin --delete my-feature-branch
    ## Shortcuts using aliases
    ### Conflicts
    There are some steps in there that we should just be doing all the time. What about making a single command alias that will cycle through all these commands just so we know things are always in good shape? Yup, we can do that.
    In the worst-case scenario, there is a conflict. This would happen even if you did the pull directly from `master` into the feature branch. To resolve a conflict, read the error report in the command prompt. This will tell you what file has a conflict and where.
    ### In Bash
    When opening the file you will see a deliberate break in the file's content and two parts that are essentially duplicated, but slightly different. This is the conflict. Pick one of the versions and be sure to delete all the conflict syntax injected into the document.
    Using Git and Bash is like using a zipper and pants. They just go together. Creating a Bash alias is extremely simple. From your Terminal, enter
    Once the conflict(s) is/are resolved, back in the command line you need to add this correction.
    $ open ~/.bash_profile

    This will open a hidden file in a default text editor. If you have a shortcut command for opening in an editor like Sublime Text, use that to open the file. In the file add the following:
    $ git add .
    alias refresh="git checkout master && dskil && git pull && git fetch -p"

    The alias `dskil` is useful for removing annoying `.DS_Store` files. You should have a `.gitignore` file that keeps these out of version control, but I like to keep a clean house too. To make that work, add the following:

    alias dskil="find . -name '*.DS_Store' -type f -delete"
    Once the new updates are staged, you can't commit again as this process is inside a previous commit. So you need to continue with the rebase, like so:
    With this in your `.bash_profile`, you simply need to enter `refresh` in the command line and POW!
    $ git rebase --continue
    ### In Powershell
    If for any reason you get stuck inside a rebase that you simply can't make sense of, you can abort the rebase;
    If you are on Windows and using Powershell, you can use the same aliases, but the set up is different. The article [Windows PowerShell Aliases][WinPower] is a good tutorial of the process.
    $ git rebase --abort
    ## Summary
    As long as there are no other issues, the rebase will continue and then complete with an output of the updates.
    Following this simple workflow has helped keep my projects clean and `Git hell` free. I hope it serves you well too.
    ## The Pull Request
    But ... the story doesn't end here. Well, the post does, but the story does not. There are many more advanced features that your team can use. I am sure some of you reading this will say "What about [rebasing][rebase]?" This is a perfectly practical addition to this workflow and many teams use it. But out of all the teams I have ever worked for, only one has ever made use of this feature. Just saying.
    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 through a peer review. Leveraging Github's 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.
    Outside of that, for more in-depth learning on Git, I invite you to read the [Git book][book], it's free and contains awesome learning.
    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 the context of the update. For example, if the update was on line 18 of `header.html`, then you will only see `header.html` and a few lines before and after line 18.
    This experience also allows the peer reviewer to place a comment on any line within the update that will be communicated back to the editor of origin. This review experience really allows everyone on the team to be actively involved in each update.
    Once the reviewer has approved the editor's updates, the next step is to merge the code. While it used to be preferred to merge locally and push master, Git has really grown into this feature and I would argue today it is most preferred to simply use the GUI took in Github.
    Now the question is, how to merge? Github has three options;
    Create a merge commit
    Squash and merge
    Rebase and merge
    Creating a merge commit is ok, this will simply merge in the new feature branch code into the `master` branch as long as there are no conflicts. Github will not allow you to merge if it already knows there will be conflicts.
    The squash and merge process is interesting as this will compact all the commits to this feature branch into a single commit to the `master` branch. This may or may not be an issue depending on how your team want's to preserve history. If you are a user of the Angular commits, you may not want to use this feature.
    Lastly, there is the rebase and merge. Showing my preference for rebasing earlier, I am definitely a fan of this merge action. This will do exactly what I explained earlier. It will take all the commits of the feature branch and reset them to the latest head of the `master` branch. If you did a rebase on the feature branch prior to creating a pull request, this process will be seamless and in the end, the most healthy for the project's history.
    ## Shortcuts using aliases
    There are some steps in there that we should just be doing all the time. What about making a single command alias that will cycle through all these commands just so we know things are always in good shape? Yup, we can do that.
    ### In Bash
    Using Git and Bash is like using a zipper and pants. They just go together. Creating a Bash alias is extremely simple. From your Terminal, enter
    $ open ~/.bash_profile
    This will open a hidden file in a default text editor. If you have a shortcut command for opening in an editor like Sublime Text or VS Code, use that to open the file. In the file add the following:
    alias refresh="git checkout master && dskil && git pull && git fetch -p"
    The alias `dskil` is useful for removing annoying `.DS_Store` files. You should have a `.gitignore` file that keeps these out of version control, but I like to keep a clean house too. To make that work, add the following:
    alias dskil="find . -name '*.DS_Store' -type f -delete"
    With this in your `.bash_profile`, you simply need to enter `refresh` in the command line and POW!
    ### In Powershell
    If you are on Windows and using Powershell, you can use the same aliases, but the set up is different. The article [Windows PowerShell Aliases][WinPower] is a good tutorial of the process.
    ## Summary
    Following this simple workflow has helped keep my projects clean and `Git hell` free. I hope it serves you well too.
    But ... the story doesn't end here. Well, the post does, but the story does not. There are many more advanced features that your team can use. Outside of that, for more in-depth learning on Git, I invite you to read the [Git book][gitbook], it's free and contains awesome learning.
    [git-auto]: https://gist.github.com/ivanoats/1823034
    [article]: https://www.atlassian.com/git/workflows
    [feature]: https://www.atlassian.com/git/workflows#!workflow-feature-branch
    [ignorefiles]: https://help.github.com/en/github/using-git/ignoring-files
    [article]: https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
    [feature]: https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow
    [gitflow]: https://www.atlassian.com/git/workflows#!workflow-gitflow
    [thoughtbot]: http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message
    [rebase]: http://git-scm.com/book/en/Git-Branching-Rebasing
    [book]: http://git-scm.com/book/en
    [gitbook]: http://git-scm.com/book/en
    [WinPower]: http://www.powershellpro.com/powershell-tutorial-introduction/tutorial-powershell-aliases/
  2. @blackfalcon blackfalcon revised this gist Jan 26, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -197,7 +197,7 @@ So let's assume that I created a feature branch, edited code and pushed it to th
    1. 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
    $ git push origin --delete my-feature-branch
    ## Shortcuts using aliases

  3. @blackfalcon blackfalcon revised this gist Jan 24, 2014. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -175,6 +175,16 @@ So let's assume that I created a feature branch, edited code and pushed it to th
    And of course, setting the bit back to `true`, will return the default setting to fast forward with merging.

    **NOTE:** there is a mild side-effect that will happen when you set this flag to `false`. Every time you do a `pull` this will not fast forward your local repo and basically make this a new commit. That's ok, but you will see this in the commit logs

    Merge branch 'master' of github.com: ...
    and

    # Your branch is ahead of 'origin/master' by 1 commit.
    If you are ok with this, then keep the flag. If this annoys or bothers you, do not use the flag and set `--no-ff` manually with each merge.

    1. Now that I 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
  4. @blackfalcon blackfalcon revised this gist Jan 16, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -203,7 +203,7 @@ This will open a hidden file in a default text editor. If you have a shortcut co

    alias refresh="git checkout master && dskil && git pull && git fetch -p"

    The alias `dskil` is useful for removing annoying `.DS_Store` files. You should have a `.gitignore` file that keeps these out of version control, but I like to keep a clean out too. To make that work, add the following:
    The alias `dskil` is useful for removing annoying `.DS_Store` files. You should have a `.gitignore` file that keeps these out of version control, but I like to keep a clean house too. To make that work, add the following:

    alias dskil="find . -name '*.DS_Store' -type f -delete"

  5. @blackfalcon blackfalcon revised this gist Jan 16, 2014. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -189,6 +189,30 @@ So let's assume that I created a feature branch, edited code and pushed it to th

    $ git push --delete origin/my-feature-branch
    ## Shortcuts using aliases

    There are some steps in there that we should just be doing all the time. What about making a single command alias that will cycle through all these commands just so we know things are always in good shape? Yup, we can do that.

    ### In Bash

    Using Git and Bash is like using a zipper and pants. They just go together. Creating a Bash alias is extremely simple. From your Terminal, enter

    $ open ~/.bash_profile

    This will open a hidden file in a default text editor. If you have a shortcut command for opening in an editor like Sublime Text, use that to open the file. In the file add the following:

    alias refresh="git checkout master && dskil && git pull && git fetch -p"

    The alias `dskil` is useful for removing annoying `.DS_Store` files. You should have a `.gitignore` file that keeps these out of version control, but I like to keep a clean out too. To make that work, add the following:

    alias dskil="find . -name '*.DS_Store' -type f -delete"

    With this in your `.bash_profile`, you simply need to enter `refresh` in the command line and POW!

    ### In Powershell

    If you are on Windows and using Powershell, you can use the same aliases, but the set up is different. The article [Windows PowerShell Aliases][WinPower] is a good tutorial of the process.

    ## Summary

    Following this simple workflow has helped keep my projects clean and `Git hell` free. I hope it serves you well too.
    @@ -222,3 +246,4 @@ Outside of that, for more in-depth learning on Git, I invite you to read the [Gi
    [thoughtbot]: http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message
    [rebase]: http://git-scm.com/book/en/Git-Branching-Rebasing
    [book]: http://git-scm.com/book/en
    [WinPower]: http://www.powershellpro.com/powershell-tutorial-introduction/tutorial-powershell-aliases/
  6. @blackfalcon blackfalcon revised this gist Jan 15, 2014. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -155,13 +155,13 @@ So let's assume that I created a feature branch, edited code and pushed it to th
    $ 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:
    1. Make sure that the feature branch is up to date with `master`, while in the feature branch, execrate the following:

    $ git pull origin master
    If there are any conflicts, best to address them here.

    * Now that I know that the feature branch is up to date with the remote repo and that it has the latest code from `master`, I can now merge these branches. I also need to make sure that my local `master` branch is up to date as well.
    1. Now that I know that the feature branch is up to date with the remote repo and that it has the latest code from `master`, I can now merge these branches. I also need to make sure that my local `master` branch is up to date as well.

    $ git checkout master
    $ git pull origin master
    @@ -175,7 +175,7 @@ So let's assume that I created a feature branch, edited code and pushed it to th
    And of course, setting the bit back to `true`, will return the default setting to fast forward with merging.

    * Now that I have merged the code, the feature branch by definition is obsolete. First, delete the branch from the local repo.
    1. Now that I 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
    @@ -185,7 +185,7 @@ So let's assume that I created a feature branch, edited code and pushed it to th

    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.
    1. 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
  7. @blackfalcon blackfalcon revised this gist Jan 15, 2014. 1 changed file with 35 additions and 37 deletions.
    72 changes: 35 additions & 37 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -1,47 +1,45 @@
    There are many Git workflows out there, I heavily suggest also reading the atlassian.com [Git Workflow][article] article as there is more detail then presented here.

    The two prevailing workflows are [Gitflow][gitflow] and [feature branches][feature].

    The other prevailing Git workflow is [Gitflow][gitflow], but being more of a subscriber to continuous integration, the feature branch workflow is better suited.
    The two prevailing workflows are [Gitflow][gitflow] and [feature branches][feature]. IMHO, being more of a subscriber to continuous integration, I feel that 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][git-auto].

    ## 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.
    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, make sure to 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.
    Before I pull, I make sure I am on the right branch. I have GIT Bash autocompletion installed, this tells me the branch in the prompt. Otherwise, the following command is good to know to list out the branches I have locally as well designate which branch I am 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
    The checked out branch 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:
    Once on master and ready to pull updates, I 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`.
    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, I'll 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:
    Now that I am all up to date with the remote repo, I'll create a branch. For efficiency, I will 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.
    This command will create a new branch from `master` as well checkout out that new branch at the same time. Doing a `git branch` will list out the branches in my 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?!
    No. There is a command that that allows me to create a new branch from any other branch while having checked out yet another branch. WAT?!

    $ git checkout -b transaction-fail-message master

    @@ -51,31 +49,31 @@ This is a nice command, but make sure you understand what you are doing before y

    ## 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.
    As I am working on my new feature branch, it is a good idea to commit often. This allows me to move forward without fear that if something goes wrong, or you have to back out for some reason, I 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.
    Each commit also tells a little bit about what I just worked on. That's important when other devs on the team are reviewing my code. It's 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.
    As I am creating changes in my 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 I 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:
    To add files, I can add them individually or I can add all at once. From the root of the project I 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:
    In order to remove deleted files from the version control, I 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 stage your updates for commitment. If you run a `git status` at this point, you should see your 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:
    All the preceding commands will stage the updates for commitment. If I run a `git status` at this point, I will see my 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"

    @@ -96,49 +94,49 @@ Comments are cheap. For more on how to write expressive commit messages, read [5

    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:
    To push the 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.
    As far as Git is concerned, there is no real difference between `master` and a 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:
    This is a special case when working on a team and the branch I am are pushing is out of sync with the remote. 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.
    This will fetch and merge any changes on the remote repo into my local 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 need to work on a co-workers branch, there are a few additional steps that you need to know.
    When I am are creating the feature branch, this is all pretty simple. But when I need to work on a co-workers branch, there are a few additional steps that I follow.

    ### 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.
    My local `.git/` directory will of course manage all my local branches, but my local repo is not always aware of any remote branches. To see what knowledge my 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:
    To keep my local repo 100% in sync with deleted remote branches, I 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 has 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. 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.
    Doing a `git pull` or `git fetch` will update my local repo's index of remote branches. As long as co-workers have pushed their branch, my local repo will have knowledge of that feature branch. By doing a `git branch` you will see a list of my local branches. By doing a `git branch -r` I will see a list of remote branches. There is a good chance that the new feature branch is not in my list of local branches.

    The process of making this remote branch a local branch to work on is easy, 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.
    This command will pull it's knowledge of the remote branch and create a local instance for me 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.
    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's 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, if 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.

    @@ -148,11 +146,11 @@ Once the reviewer has approved the editors updates, there are two ways to merge

    ## 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.
    Although I can merge from Github's 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.
    So let's assume that I created a feature branch, edited code and pushed it to the repo. I 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
    1. Make sure that I have the latest version of the feature branch from the remote repo

    $ git checkout my-feature-branch
    $ git pull origin my-feature-branch
    @@ -163,27 +161,27 @@ So let's assume that you created a feature branch, you edited code and pushed it
    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.
    * Now that I know that the feature branch is up to date with the remote repo and that it has the latest code from `master`, I can now merge these branches. I also need to make sure that my local `master` branch 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 history of this branch, 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.
    Notice the `--no-ff` flag in the merge command. This flag keeps the repo branching history from flattening out. If I were to look at the history of this branch, using GitX for example, when using the `--no-ff` flag, I will see the appropriate bump illustrating the history of the feature branch. This is helpful information. If I didn't use this flag, 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.
    I can either enter the `--no-ff` flag each time I merge or I can set this as my default. I prefer the default option. Running the following command will update the global gitconfig.

    $ git config --global merge.ff false
    And of course, setting the bit 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.
    * Now that I 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.
    If you happen to see the 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.
    @@ -193,9 +191,9 @@ So let's assume that you created a feature branch, you edited code and pushed it
    ## Summary

    Following this simple workflow as helped keep my projects clean and `Git hell` free. I hope it serves you well too.
    Following this simple workflow has helped keep my projects clean and `Git hell` free. I hope it serves you well too.

    But ... the story doesn't end here. Well, the post does, but the story does not. There are many more advanced features that your team can use. I am sure some of you reading this will say "What about [rebasing][rebase]?" This is a perfectly practical addition to this workflow and many teams use it. But out of all the teams I have ever worked for, only one has ever made use of this feature.
    But ... the story doesn't end here. Well, the post does, but the story does not. There are many more advanced features that your team can use. I am sure some of you reading this will say "What about [rebasing][rebase]?" This is a perfectly practical addition to this workflow and many teams use it. But out of all the teams I have ever worked for, only one has ever made use of this feature. Just saying.

    Outside of that, for more in-depth learning on Git, I invite you to read the [Git book][book], it's free and contains awesome learning.

  8. @blackfalcon blackfalcon revised this gist Jan 15, 2014. 1 changed file with 22 additions and 13 deletions.
    35 changes: 22 additions & 13 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -45,13 +45,13 @@ No. There is a command that that allows you to create a new branch from any othe

    $ git checkout -b transaction-fail-message master

    In that example, say I was in branch `github-oauth` and I needed to create a new branch and then checkout the new branch, by adding `master` at the end of that command Git will create a new branch from master and then move me (checkout) to that new branch.
    In that example, say I was in branch `github-oauth` and I needed to create a new branch and then checkout the new branch? By adding `master` at the end of that command, Git will create a new branch from master and then move me (checkout) to 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.
    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.

    @@ -75,15 +75,15 @@ I'm lazy, I don't want to think, so the following command I make heavy use of to

    $ 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:
    All the preceding commands will stage your updates for commitment. If you run a `git status` at this point, you should see your 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"
    $ git commit -m "fixed bug with login feature"

    A good example would be:

    @@ -112,7 +112,7 @@ This will fetch and merge any changes on the remote repo into your brach with th

    ## 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.
    When you are creating the feature branch, this is all pretty simple. But when you need to work on a co-workers branch, there are a few additional steps that you need to know.

    ### Tracking remote branches

    @@ -128,9 +128,9 @@ The `-p` or `--prune` flag, after fetching, will remove any remote-tracking bran

    ### 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.
    Doing a `git pull` or `git fetch` will update your local repo's index of remote branches. As long as your co-worker has 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. 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.
    The process of making this remote branch a local branch to work on is easy, simply checkout the branch.

    $ git checkout new-remote-feature-branch

    @@ -140,9 +140,9 @@ This command will pull it's knowledge of the remote branch and create a local in

    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.
    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, if 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.
    This experience also allows the peer reviewer to place a comment on any line within the update. This will be communicated back to the editor of 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.

    @@ -157,7 +157,7 @@ So let's assume that you created a feature branch, you edited code and pushed it
    $ 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:
    * Make sure that the feature branch is up to date with `master`, while in the feature branch, execrate the following:

    $ git pull origin master
    @@ -169,13 +169,13 @@ So let's assume that you created a feature branch, you edited code and pushed it
    $ 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.
    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 history of this branch, 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.
    And of course, setting the bit 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.

    @@ -190,6 +190,14 @@ So let's assume that you created a feature branch, you edited code and pushed it
    * 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
    ## Summary

    Following this simple workflow as helped keep my projects clean and `Git hell` free. I hope it serves you well too.

    But ... the story doesn't end here. Well, the post does, but the story does not. There are many more advanced features that your team can use. I am sure some of you reading this will say "What about [rebasing][rebase]?" This is a perfectly practical addition to this workflow and many teams use it. But out of all the teams I have ever worked for, only one has ever made use of this feature.

    Outside of that, for more in-depth learning on Git, I invite you to read the [Git book][book], it's free and contains awesome learning.


    @@ -214,4 +222,5 @@ So let's assume that you created a feature branch, you edited code and pushed it
    [feature]: https://www.atlassian.com/git/workflows#!workflow-feature-branch
    [gitflow]: https://www.atlassian.com/git/workflows#!workflow-gitflow
    [thoughtbot]: http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message

    [rebase]: http://git-scm.com/book/en/Git-Branching-Rebasing
    [book]: http://git-scm.com/book/en
  9. @blackfalcon blackfalcon revised this gist Jan 15, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -45,7 +45,7 @@ No. There is a command that that allows you to create a new branch from any othe

    $ 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.
    In that example, say I was in branch `github-oauth` and I needed to create a new branch and then checkout the new branch, by adding `master` at the end of that command Git will create a new branch from master and then move me (checkout) to 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.

  10. @blackfalcon blackfalcon revised this gist Jan 15, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,7 @@ Before you pull, make sure you are on the right branch. If you have GIT Bash aut

    $ git branch

    If the return says anything other then `master` then switch to master
    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

  11. @blackfalcon blackfalcon created this gist Jan 15, 2014.
    217 changes: 217 additions & 0 deletions git-feature-workflow.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,217 @@
    There are many Git workflows out there, I heavily suggest also reading the atlassian.com [Git Workflow][article] article as there is more detail then presented here.

    The two prevailing workflows are [Gitflow][gitflow] and [feature branches][feature].

    The other prevailing Git workflow is [Gitflow][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][git-auto].

    ## 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

    If the return says 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][thoughtbot].


    ## 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


















    [git-auto]: https://gist.github.com/ivanoats/1823034
    [article]: https://www.atlassian.com/git/workflows
    [feature]: https://www.atlassian.com/git/workflows#!workflow-feature-branch
    [gitflow]: https://www.atlassian.com/git/workflows#!workflow-gitflow
    [thoughtbot]: http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message