Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git flow vs cherry-picks

Tags:

git

workflow

We have branches prod for production releases and dev for ongoing development.

Our current flow:

We work mainly in dev branch and from time to time, customer decides which features/bugfixes he wants to come to prod and we cherry-pick them.

From my understanding, cherry-picks contradict to git flow model.

And so far I don't see how to adapt our flow to avoid it.
git flow assumes that you know beforehand should the change go to prod or not

Does community see any way around it?

UPDATE: I found that my question requires a better clarification of terms

What we use now

To implement a issue #12345

git fetch
git checkout origin/dev -B issue-12345 # new branch for issue #12345 from bug tracking system
# ... do many atomic commits
git fetch
git checkout origin/dev -B dev
git merge issue-12345 --no-ff -m "Bug #12345 - Bug title from bug tracking system"
# ... fix merge conflicts if any and commit
git branch -D issue-12345
git push
NOTES
  1. We use atomic commits for each commit to have a clear intent. This simplifies review/blame/bisect processes
  2. We use custom message for merge as it is way more descriptive than default Merge 'issue-12345' into 'dev'
  3. We force non-fast-forward merges via --no-ff because we want all issue to be represented as a merge. So git log dev --first-parent returns high-level view of the tasks completed
  4. We don't use git merge --squash and its rebase analogues. We want whole task history to be preserved

When client decides that he wants to get issue #12345 into production

git fetch
git checkout origin/prod -B issue-12345
git log origin/dev --grep "#12345" --oneline --reverse # get all commits that have to be cherry-picked, usually that's only one merge commit (abcd1234)
git cherry-pick abcd1234 -x -m 1 # '-m 1' required for cherry-picking merge commit
# ... fix merge conflicts if any and commit
# ... repeat for other commit if any
git checkout origin/prod -B prod
git merge issue-12345-prod --no-ff -m "Bug #12345 - Bug title from bug tracking system"
# ... fix merge conflicts if any and commit (although that's unlikely for them to occur)
git branch -D issue-12345
git push

What git flow told us to do

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

In terms of that article our dev branch corresponds to develop, prod corresponds to master, release branches are not used

According to git flow, only feature branches should be based on dev branch, and they are never merged to prod.

However hotfix branches should be based on prod and then merged to both prod and dev.

Why git flow is not applicable for us

  1. We don't know beforehand if the task will need to go to prod branch or not.
  2. If we base feature branch from dev, we won't be able to merge it to prod later on if that will be requested (possibly much-much later)
  3. If we base feature branch from prod, we won't be able to benefit from other tasks completed before.

Example 1

Let's say we have a task #12345 to implement a new Contact Us page. And then we have a task #23456 to change the page's background color from white to yellow.

We based our issue-12345 branch from prod and then merged it into dev and waiting for approval to merge it into prod.

Then we start working on issue-23456 and based on prod again. But prod code doesn't even have any mentions of Contact Us page yet. So we'll have to do some quirks such as merging issue-12345 branch into issue-23456 first.

That's complicated enough for even that simple case. And you can imagine it will be much more difficult if you want to use some code introduced in other task.

Example 2

Task #34567 asks to implement Feedback page. This page is very similar to Contact Us page so it has similar css. We would like to reuse it. But how? It's not fair to say that #34567 depends on #12345. So it would be illogical to base issue-34567 on issue-12345. So what? Rewrite code manually? Copy-paste? Or still cherry-picks?

I don't see any reasonable solution for such issue.

like image 596
mnaoumov Avatar asked Feb 08 '23 04:02

mnaoumov


2 Answers

git-flow (seen here translated as regular git commands) is based on merging branches (features into dev, dev into master)

git cherry-pick is not compatible with merge because of:

  • duplicating commits on merge,
  • functional dependencies

So if your current workflow based on cherry-picking works, you ought to keep it.
However, as explained in "If you cherry pick, your branch model is wrong":

Their insight is that, with git (or any DAG-based SCM), if you can anticipate where a commit may/will be need to applied, you can put it on it’s own branch, and merge it into those various places as needed.

This will get the change applied to all the necessary branches (you can merge it into release as well as master), but not result in the commit getting copy/pasted. Instead, new merge commits will be recorded, so no new commit ids, and the history (what branches have this commit?) is tracked nicely in the DAG.

Yet:

The con to not cherry picking is that you’ll need to know up front that you want your commit applied into multiple places, so that you can place it on it’s own branch.

In your case, that would involve multiple separate feature branches, merged into master only after approval by the client.


Regarding git-flow, it is true it is not a good fit for you. An integration model is more accurate:

It is simpler to have an integration branch which starts from master and with:

  • features branches created from the integration branch
  • those same feature branches rebased on top of the updated integration branch each time other features have been merged to integration: that involve communicating with the team in charge of that feature branch as they will have to reset their own copy of the feature branch each time it is rebased (since its history would change)
  • the merge commit from a feature, result of the merge of a feature branch to integration, can be reverted at any time if that feature is dropped: all other feature branches not yet merged need to rebase themselves on top of the updated integration branch.

Once the integration branch is feature complete and has passed user acceptance tests, it would be merged to master (or prod)


From the OP's scenario, when features can go individually into prod at any time, you don't need dev or integration:

Day 1. prod=dev=integration

Let's consider only prod and integration here, and feature or issue branches.

Day 2. Issue #1 raised. Here it is obvious. All branches are the same. So we can git checkout prod -B issue-1

Day 3. Issue #1 fixed. Do we merge issue-1 branch anywhere?

Merge --no-ff to integration

Day 4. Issue #2 raised. Basing from integration branch again?

Here based on prod. Especially if it is an issue (detected in prod).
If it is a feature, you can consider starting it from integration, but since features will be dropped from integration, the benefit of an early integration won't be a guaranty.

Day 5. Issue #2 fixed. Merging anywhere?

To integration (merge --no-ff), to check if issue 2 works with issue 1.

Day 6. Issue #2 approved to get into prod. What do we do?

First, rebase issue-2 on top of prod (in case of prod have evolved since then)
Then merge --no-ff issue-2 to prod.

Reset integration to prod, and merge all the other features branches back into integration, in order to validate if they play well together on top of the new prod (which now includes issue-2).

Day 7. Issue #1 approved to get into prod. What do we do?

First, rebase issue-1 on top of prod: that will validate that issue-1 is still working, even when based on top of issue-2 (which was merged into prod previously).
Then, merge --no--ff.

Note the use of merge --no-ff, which generates a merge commit in prod or integration from a feature/issue branch: if said feature/issue needs to be dropped from prod, all you need to do is to revert that unique merge commit in prod or integration (instead of reverting a series of commits representing the branch to drop).

like image 161
VonC Avatar answered Feb 13 '23 03:02

VonC


Working with cherry-pick is a very decent way to do it.

But

The "problem" is that git flow merge you branches into each other (fully and then delete them as part of its flow) so using cherry-pick along with git-flow is some sort of abusing git flow.


How do deliver features to customer?

In my opinion you should consider developing feature toggle mechanism for choosing which features to turn/off per customer.

like image 43
CodeWizard Avatar answered Feb 13 '23 04:02

CodeWizard