Skip to content

Gira Custom Git Merge Driver

Gira includes a custom Git merge driver that intelligently handles conflicts in JSON files, preventing data loss during concurrent modifications.

Overview

The merge driver provides semantic merging for: - Ticket files (handles status changes, field updates) - State files (manages counters and lists) - Configuration files - All other Gira JSON data

Features

Intelligent Conflict Resolution

  1. Three-Way Merge: Compares base (ancestor), ours, and theirs versions to detect actual changes, not just differences.

  2. Latest-Write-Wins Strategy: When the same field is modified in both branches, the version with the most recent updated_at timestamp is used.

  3. Field-Level Merging: Each field is merged independently, allowing non-conflicting changes to be combined.

  4. Entity Validation: Verifies UUID/ID match before merging to prevent merging different entities.

  5. State File Merging:

  6. Numeric counters take the maximum value
  7. Lists are merged with unique values
  8. Handles mixed data types intelligently

Conflict Tracking & Audit Trail

When conflicts are automatically resolved using the latest-write-wins strategy: - A merge_notes field is added to the merged file - Each note includes timestamp, type ("auto-merge"), and affected fields - Provides full transparency for automated conflict resolution - Only added to files with an id field (tickets, epics, etc.)

Installation

Automatic Setup

Run the setup script from your project root:

.gira/scripts/setup-merge-driver.sh

Manual Setup

  1. Configure Git to recognize the merge driver:
git config merge.gira-json.name "Gira JSON merge driver"
git config merge.gira-json.driver "python3 '.gira/scripts/merge-driver.py' %O %A %B"
git config merge.gira-json.recursive binary
  1. The .gitattributes file is already configured to use this driver for all Gira JSON files.

How It Works

During a merge, Git calls the merge driver with three versions of each conflicting file: - %O: The common ancestor (original) - %A: Our version (current branch) - %B: Their version (branch being merged)

The driver: 1. Parses all three JSON files 2. Identifies changes in each branch relative to the ancestor 3. Applies semantic rules to merge changes 4. Writes the merged result back to the working directory

Examples

Example 1: Field Conflict

If two users update the same ticket's priority: - User A: Changes priority from "medium" to "high" at 10:00 AM - User B: Changes priority from "medium" to "low" at 10:30 AM

Result: Priority will be "low" (User B's change is more recent)

Example 2: Status Movement

If two users move the same ticket: - User A: Moves from "todo" to "in_progress" - User B: Moves from "todo" to "review"

Result: The ticket location depends on which change has the latest timestamp.

Example 3: State File

If two users create tickets concurrently: - User A: Creates tickets, next_ticket_id becomes 105 - User B: Creates tickets, next_ticket_id becomes 103

Result: next_ticket_id will be 105 (maximum value)

Limitations

  1. Binary Conflicts: The merge driver only handles JSON files. Binary files (images, etc.) still require manual resolution.

  2. Structural Changes: Major structural changes to JSON schemas may require manual intervention.

  3. Deletion Conflicts: If one branch deletes a ticket while another modifies it, manual resolution is needed.

Troubleshooting

Verify Installation

Check if the merge driver is configured:

git config --get merge.gira-json.driver

Test the Merge Driver

Create a test conflict:

# Create two branches that modify the same ticket
git checkout -b test-branch-1
gira ticket update GCM-1 --priority high
git add . && git commit -m "Update priority to high"

git checkout main
git checkout -b test-branch-2
gira ticket update GCM-1 --priority low
git add . && git commit -m "Update priority to low"

# Merge to see the driver in action
git checkout test-branch-1
git merge test-branch-2

Debug Mode

To see detailed merge information, check the merge notes added to tickets after automatic conflict resolution.

Best Practices

  1. Commit Frequently: Smaller, more frequent commits reduce the chance of conflicts.

  2. Pull Before Major Changes: Update your local repository before starting significant work.

  3. Use Descriptive Commit Messages: Include ticket IDs in commits for better tracking.

  4. Review Merge Results: After automatic merges, review the changes to ensure the resolution makes sense for your workflow.