Skip to content

Instantly share code, notes, and snippets.

@markreid
Created January 17, 2017 04:30
Show Gist options
  • Star 76 You must be signed in to star a gist
  • Fork 30 You must be signed in to fork a gist
  • Save markreid/12e7c2203916b93d23c27a263f6091a0 to your computer and use it in GitHub Desktop.
Save markreid/12e7c2203916b93d23c27a263f6091a0 to your computer and use it in GitHub Desktop.
git flow with rebasing

Git Flow (with rebasing)

See http://nvie.com/posts/a-successful-git-branching-model/

Features

A feature is based off the develop branch and merged back into the develop branch. It will eventually get into master when we make a release.

Working Locally

# checkout develop, fetch the latest changes and pull them from remote into local
git checkout develop
git fetch
git pull origin develop

# create a feature branch that is based off develop
git checkout -b feature/XX-123/some-description

# do your work
git add something
git commit -m "first commit"
git add another
git commit -m "second commit"

# rebase against develop to pull in any changes that have been made
# since you started your feature branch.
git fetch
git rebase origin/develop

# push your local changes up to the remote
git push

# if you've already pushed changes and have rebased, your history has changed
# so you will need to force the push
git fetch
git rebase origin/develop
git push --force-with-lease

GitHub workflow

  • Open a Pull Request against develop
  • When the Pull Request has been approved, merge using squash and merge, adding the ticket number and a brief description: ie, MQ-330 enable users to order a pizza from the dashboard.
  • This squashes all your commits into a single clean commit.

If you are unable to squash merge because of conflicts, you need to rebase against develop again:

# in your feature branch
git fetch
git rebase origin/develop
git push --force-with-lease

Releases

A release takes the changes in develop and applies them to master.

Working locally

# create a release branch from develop
git checkout develop
git fetch
git pull origin develop
git checkout -b release/3.2.1

# finalise the change log, local build, etc
git add CHANGELOG.md
git commit -m "Changelog"

# rebase against master, which we're going to merge into
git fetch
git rebase origin/master
git push --force-with-lease

Usually at this point you will want to deploy the release branch to the staging server for final QA. If there are any issues, fixes should be committed to the release branch.

Github workflow

  • Open a Pull Request against master
  • When the PR is approved and the staging deploy has been verified by QA, merge using rebase and merge.
  • DO NOT SQUASH MERGE. We don't want a single commit for the release, we want to maintain the feature commits in the history.
  • Repeat the steps above against develop (may need to rebase first).
  • Tag a release on master. Use the version number and put the changelog in the description.

Hotfixes

A hotfix is a patch that needs to go directly into master without going through the regular release process. The most common use case is to patch a bug that's on production when develop contains code that isn't yet ready for release.

Working locally

# create a hotfix branch based on master, because master is what will be deployed to production
git checkout master
git fetch
git pull origin master
git checkout -b hotfix/describe-the-problem

git add patch.fix
git commit -m "fix the problem"
git push

Github workflow

  • Open a Pull Request against master
  • When the PR's approved and the code is tested, squash and merge to squash your commits into a single commit.
  • Open a Pull Request against develop (may need to rebase first).
  • Tag a release on master. Describe the issue in the name, feel free to put details in the description.
@SmartDroidDeveloper
Copy link

While doing rebase
git rebase origin/develop
If we get conflicts, then What's the procedure to follow?

@riveryc
Copy link

riveryc commented Nov 8, 2019

While doing rebase
git rebase origin/develop
If we get conflicts, then What's the procedure to follow?

That's why I prefer "pull request", same way to merge dev -> feature, so no more magic rebase on the git server for collaboration. haha

@mohsenoid
Copy link

mohsenoid commented Jun 4, 2020

Based on gitflow a release branche should be merged into master and develop, what you explained here is about release into master branch. how should we update develop with release branch?
Should we rebase develop on top of master?!

@markreid
Copy link
Author

markreid commented Jun 4, 2020

^ at that point you’d merge master back into develop. You don’t want to be rebasing on “shared” branches that other members of your team might be working from or on because it changes the commit history. The purpose of rebasing on your feature or release branches is just to be able to pull in the latest changes from other branches without creating extra merge commits. But it’s really just a personal preference.

@markreid
Copy link
Author

markreid commented Jun 4, 2020

What’s described here is just a process that a team I was working with agreed upon for a particular project we were doing. It might not be the best approach for everyone! We just needed to document it somewhere so we had something to refer to.

@meenie
Copy link

meenie commented Jun 30, 2020

@markreid What's quite cool is that our teams' software development lifecycle is pretty much exactly this and we kind of organically fell into it. It's good to see another team doing similar things.

And optimization I recently made was creating a small CLI tool which helps in creating the release branches and provides for an easy way to essentially cherry-pick the commits in develop (we actually call it release-ready) into master so you don't have to manually go through and use git rebase interactive to remove the commits that are not ready for production. You use a git command like this:

git log --reverse --format=' - [ ] %s by %an' origin/master..

while you are on the develop branch and it generates a list like this:

 - [ ] JIRA-921 Add a thing to do X feature. (#1234) by The Joker
 - [ ] JIRA-946 This enables whatever for whoever (#1325) by Batman
 - [ ] JIRA-1065 Fix a bug that was bad (#1437) by Commissioner Gorder
...

and in markdown it looks like this:

  • JIRA-921 Add a thing to do X feature. (#1234) by The Joker
  • JIRA-946 This enables whatever for whoever (#1325) by Batman
  • JIRA-1065 Fix a bug that was bad (#1437) by Commissioner Gorder

Then in the PR you can check off any of the commits that are ready to go and use the cli tool to pull down the PR description, go through the list of commits and remove anything that is not checked off and then force-push the release branch back up. If there is a conflict with the rebase, it probably means you shouldn't release because a previous commit is required for the commit you are trying to keep is required. And you can decide if you'd like to add that previous commit or drop the current one.

The reason I really like the flow we both use is that it frees up the team to continually release without getting held back by other teams/team members. And it allows for the latest code to be deployed to our staging server and have automated smoke tests be run on the code altogether.

The one thing that is annoying is that when you rebase and merge your release branch into master and then having to then rebase master back into your develop branch, you need to force-push the develop branch and we are using GitHub's branch protection to require reviews and also passing tests. That means you can't actually force-push into the branch unless you temporarily remove the branch protections. Have you run into this issue as well? If so, any suggestions on how to get around it? I have also enabled the option that the rules are required for Admins as well.

One thing I could suggest in your flow above is combining two commands into one:

git fetch
git rebase origin/develop

You can cut that down to just one command by doing:

git pull --rebase origin develop

@khauser
Copy link

khauser commented Jun 24, 2022

@meenie: He is not rebasing master back into develop. Instead he creates a PR to merge his release also back into develop after he has done it for master. But that's only needed if the release contains changes made only there (maybe fixes, changelog, version-numbers). In case of hotfix-branches you always have to bring their changes also into develop.

But another problem we encountered is that the rebase and merge into master via PR always results in conflicts in the next PR (see: https://github.com/khauser/test_gitflow_with_rebase/pull/9). As far as I understand it rebase and merge also changes history. That's why develop and master get incompatible. Then indeed master needs to be merged into develop, or better develop needs to be reset to master. Merge might be worser than reset..
With normal merges from hotfix- or release-Branches into master the problem disappeared. And still squash and merge could be used when bringing features into develop.

Please tell me your thoughts about this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment