My current branch/pipeline strategy is as follows:
Feature branches are created off of the development branch and merged back in. On commits to the development branch, I've configured pipelines to automatically create a release/* branch off of the dev branch and commit to it. Then, on the release branch, pipelines deploys to a staging environment. Subsequently merging a PR from release/* to master will trigger a deploy to production.
This final commit/merge causes the master branch and the dev branch to become out of sync, forcing me to manually, within the Bitbucket UI, click "sync" from the dropdown menu on the dev branch.
I'd like to be able to automate this step with pipelines if possible. Ideally, a commit to master and a successful production deployment would automatically sync the dev branch with the master branch. Is something like this possible? It seems to be treated as a typical commit in the UI, but i was unable to re-create this functionality in pipelines using my intuition.
Hi @Brady ,
This should be possible. A sync is basically a merge operation which you can perform during the Pipelines build and then push to dev branch.
I would just like to ask for clarification: the pipeline that deploys to production (and where you also want to sync dev with master), is it configured to run for commits on master? I.e. is it defined in the
branches:
master:
part of the bitbucket-pipelines.yml file?
If so, what you can do is add the following commands in the script for master, after the command(s) that does the deployment:
- git fetch origin "+refs/heads/*:refs/remotes/origin/*"
- git checkout -b dev origin/dev
- git merge master
- git push origin dev
This should sync dev branch with master.
Is this something that works for you?
Kind regards,
Theodora
Sorry for the delay in getting back to you. I finally merged a PR to master for the repo in question today. Your understanding is correct and your solution worked great! Thank you so much for the help.
I have a few more questions about the solution you provided if you are able to help further or point me in the right direction..
First, I'd like to be able to add some sort of tailored commit message to that `merge` so that I can skip CI when merging into dev (I don't want to trigger a staging deployment based on code that was already deployed to staging). In the Bitbucket Cloud UI this is possible and sort of required when clicking sync (see image). I tried adding the -m option (per git docs):
git merge -m '[skip ci] Merged master into dev' master
(as is what seems to work in the UI) to the merge command but this didn't appear to have any effect, and the commit message from my merge of
release/* -> master
was used, thus triggering the `dev` branch pipeline.
Second, this all assumes that no changes occur in the dev branch between when a staging deployment occurs e.g.:
dev -> release/*
and this merging operation of
master -> dev
However, if a feature branch merges into dev during this time, I imagine this could lead to merge conflicts. Would the protocol then be to manually resolve conflicts? Could this potentially cause any serious issues (other than headaches)?
Lastly (and I guess less importantly of the three), I wouldn't say I'm a noob when it comes to git, but I don't really understand what is happening in that fetch. What exactly is "+refs/heads/*:refs/remotes/origin/*"? I've been using git for about 4 years now and I've never come across anything like that.. What's happening here?
Thank you again for your very helpful response and in advance for any continued support!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Brady,
Thank you for the update, you are very welcome and it's good to hear that this worked for you!
Regarding your questions:
1. Merge commit message
I believe that the git merge command in the script is doing a fast forward merge, so no merge commit is actually created like when you do a sync from the UI.
After the fast forward merge, the last commit of master becomes the last commit of dev as well, and since this doesn't have [skip ci] in its message, a build gets triggered for dev.
To avoid this, you can add the option --no-ff in the merge command, which will force a merge commit to get created and add the commit message as well:
git merge master --no-ff -m '[skip ci] Merged master into dev'
2. Merge conflicts
A merge conflict could indeed arise and since this can only be resolved manually, I believe the step will fail in this case and the sync won't happen.
If you want to avoid failure of the step because of a merge conflict, you could add the commands in an after-script section of this step.
Please note that the after-script section will run anyway, whether the step succeeds or fails. So, if you want to sync only in case the previous commands of the step have succeeded, you may want to leave the commands for sync inside the script.
If you want to sync the branch regardless, you can use the after-script section. In this case, if the sync fails, the build status won't get affected, but you will need to resolve the conflicts locally, merge and push.
You can check our doc for the after-script keyword and example here, it's quite a long doc, so you can search the page for after-script to find the relevant section.
3. Fetch command
When you run Pipelines builds on a branch, only that branch is cloned in the Docker container where the build runs.
For builds that run e.g. on master, the .git/config file that is created in that clone includes the following:
[remote "origin"]
url = http://bitbucket.org/<workspace-id>/<repo-slug>
fetch = +refs/heads/master:refs/remotes/origin/master
You can check that if you add the command cat .git/config in your yml file in the definition for master.
So if you do a git fetch, only master refs will be fetched and you won't be able to check out another branch during the build.
git fetch origin "+refs/heads/*:refs/remotes/origin/*" is going to fetch all refs in that clone so you can then check out dev branch.
Since you only want to check out dev branch, you could actually use the following command instead, in order to fetch only dev refs:
git fetch origin "+refs/heads/dev:refs/remotes/origin/dev"
I hope this helps, please feel free to let me know if you have any other questions!
Kind regards,
Theodora
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Theodora Boudale Thank you so much for all of the help! I really appreciate you taking the time to write out such an in depth answer. I had no idea the after-script keyword existed (guess I need to dig into the docs more). --no-ff worked beautifully, and I even learned something new about git.
Endless thanks to you :) !!!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.