Bridge-Branch Strategy with GitHub Actions
Tags: github, githubactions, agile, tutorial
Published: 2024-02-05 06:08:07

## Problem: 
As a developer, you want to merge small, file imports into your remote repository's development branch to share with your team incrementally, but, your workflow is bottlenecked by opening and closing PRs every time.

## Solution:
Create a "Bridge-Branch" in parallel to `main` or your _development_ branch that has Actions watching it and will automatically merge changes into `main`.

Here is the [Bridge-Branch Template Repo with PR and Issue Templates](https://github.com/colinwilliams91/helpful-gh-automations) I created to solve this problem. Feel free to Fork ( and Star 🌟😉) if you find yourself in a similar scenario.

## Caveats:
Typically, Rules and Rulesets on GH exist for a reason, and it is not best practice to build ways to circumvent them. However, when you find a reasonable case to do so, you MUST ENSURE:
- Small Incremental Changes (Easy to revert without loss)
- Consistently syncing the source branch with the target branch to avoid conflicts
- Good communication and notifications for your team, as changes will be going into your remote on a branch that other developers depend on MORE FREQUENTLY.

## Thoughts:
There are other ways of handling this but this is a strategy that I developed while working on a collaborative Unity project. In our case, we wanted to be able to incrementally import Sprites into our Unity code base and check them into our remote repository so the entire team could pull them down and review them in an Editor or Image Viewer tool so that they can make accurate suggestions early in their design process.

The nature of Sprites in a Unity project are that they will sit inside a specific directory (away from any scripts/code) until they are plugged in as components to Game Objects. For this reason, upon their creation they can be merged into the development branch of our remote repo without any risk of merge conflicts (for the most part).

## The "Bridge-Branch" Strategy
This may or may not exist elsewhere, and may arguably be an anti-pattern in some git workflows, but for ours I theorized and executed a strategy. I configured our repository's permissions and runner, then designed two Actions: 
1. To watch the "Bridge-Branch" and merge changes to `main` automatically on push, **removing the bottleneck.**
2. To watch "Main" and ensure all the code in the "Bridge-Branch" stays in sync with it, **preventing any merge conflicts during automation**.
Both listen for pushes and then checkout and merge the desired changes to the specified target.

🔁`auto_merge_bridge_to_main.yaml` 1
```yaml
name: Auto Merge Bridge Branch to Main

on:
  push:
    branches:
      - your-bridge-branch

jobs:
  merge-to-main:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      # this ensures all histories are fetched for runner, avoiding `unrelated histories` merge error
      with:
        fetch-depth: 0

    - name: Merge to main
      # GH actions/checkout requires git identity to be configured for security, top two commands handle that
      run: |
        git config user.name "${{ github.actor }}"
        git config user.email "${{ github.actor }}@users.noreply.github.com"

        git fetch origin
        git checkout main
        git merge --no-ff -m "auto merge bridge changes to main" ${{ github.ref }}
        git push origin main
```

🔁`auto_sync_main_to_bridge.yaml` 2
```yaml
name: Auto Sync bridge-branch with main

on:
  push:
    branches:
      - main

jobs:
  sync-with-main:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      # this ensures all histories are fetched for runner, avoiding `unrelated histories` merge error
      with:
        fetch-depth: 0

    - name: Merge changes into sprite-branch
      # GH actions/checkout requires git identity to be configured for security, top two commands handle that
      run: |
        git config user.name "${{ github.actor }}"
        git config user.email "${{ github.actor }}@users.noreply.github.com"
        git config pull.rebase false

        git fetch origin
        git checkout your-bridge-branch
        git pull origin main
        git merge --no-ff -m "auto sync main changes to bridge branch" main

        git push origin your-bridge-branch
```

The purpose of this "Bridge-Branch" is to act as an intermediary between feature development and `main`. When I was first drafting up how to achieve this I was thinking: "I want a connection from my local feature-branch to main like a web socket, something that stays open so I can push in changes any time" 🤔🤔🤔

And, because Unity converts Sprites to YAML if these changes go into our remote repository they would require a PR to be opened, reviewed, approved, merged and then closed. A lot of extra work and bottlenecking for a change that will have no significant impact on the code. All of the review of the actual design occurs in the Unity Editor where the Sprite can actually be viewed (as a `.png` or checked out inside our Team's sprite editor Aseprite as a `.ase` or `.aseprite` per our workflow for art prototypes)

## How to Use:
- Bootstrap a repository from [my template](https://github.com/colinwilliams91/helpful-gh-automations) OR create a `.github/workflows` directory in your project root and copy/paste the two files I list below into it.
- Navigate to your projects "Settings" view on Github
- Click the "Actions" dropdown-section in the left-side toolbar
- Scroll to "Workflow permissions" and toggle "Read and write permissions" and "Allow GitHub Actions to create and approve pull requests"
  - You may need to perform this in the "Organization Settings" level above your repository if it is inside of one to establish default permissions across the group's repositories first
- Create a branch parallel to `main` (like a `development` or `staging` branch) (this will be your "Bridge-Branch") on the remote
- Plug the name of that branch into the places where `your-bridge-branch` exists in the [auto_merge_bridge_to_main.yaml](https://github.com/colinwilliams91/helpful-gh-automations/blob/main/.github/workflows/auto_merge_bridge_to_main.yaml) file
- Plug the name of that branch into the places where `your-bridge-branch` exists in the [auto_sync_main_to_bridge.yaml](https://github.com/colinwilliams91/helpful-gh-automations/blob/main/.github/workflows/auto_sync_main_to_bridge.yaml) file

## Test:
- Create a new feature branch
  - Make a small change like a "hello world" `.md`, `.sh` or any extremely simple file
  - Push it to the remote
  - Merge it into `main`
- Checkout the "Bridge-Branch" you created to ensure those new changes are reflected on this branch as well
- While checked out on the "Bridge-Branch"
  - Make another small change
  - Push that change to the remote "Bridge-Branch"
- Checkout `main` to ensure those changes are reflected here

You should also be able to view the Actions working here: https://github.com/your-organization?/your-repo/actions or by clicking the Actions tab on the view for your repo on GH.