Skip to content

Merging branches

Bernardo Ramos edited this page Dec 16, 2018 · 13 revisions

Types

  • Merge
  • Rebase
  • Forward Merge

Options

  • With conflict detection (default, slower)
  • Without conflict detection (using --force)

Due to its nature, there are no conflicts on a forward merge. So no conflict detection is used.

Commands

Merge

PRAGMA branch_merge [--check|--force] {source} [{dest}]

Rebase

PRAGMA branch_rebase [--check|--force] [{to_rebase}] {new_base} [{new_branch}]

Where to_rebase can be:

  • a branch name
  • a single commit, like branch.commit
  • a commit range, like branch.start-end

If to_rebase is omitted then it rebases the current branch.

When rebasing a single commit or a range of commits to an internal commit we must supply the name for the new_branch that will be created.

We can also rebase them to the end of a branch. In this case if no new_branch name is supplied, the commit(s) will be rebased onto the destination branch.

Forward Merge

PRAGMA branch_merge --forward {parent} {child} [{num_commits}]
PRAGMA branch_merge --forward {parent} {child.commit}

Examples

Merge

Merging the test branch into the master branch:

PRAGMA branch=master
PRAGMA branch_merge test

Merging the test branch up to commit 25 into the master branch:

PRAGMA branch=master
PRAGMA branch_merge test.25

Rebase

Rebasing the test branch onto the end of the master branch:

PRAGMA branch=test
PRAGMA branch_rebase master

Rebasing the test branch onto commit 20 of the master branch:

PRAGMA branch=test
PRAGMA branch_rebase master.20

Moving the commits 25 thru 27 from the master branch to the dev branch:

PRAGMA branch_rebase master.25-27 dev

Moving the commits 25 thru 27 from the master branch to a new branch named test that will start at the dev branch:

PRAGMA branch_rebase master.25-27 dev test

Moving the commits 25 thru 27 from the master branch to a new branch named test that will start at the master branch's commit 20:

PRAGMA branch_rebase master.25-27 master.20 test

Forward Merge

Advancing the master branch 3 commits in the direction of the test branch:

PRAGMA branch_merge --forward master test 3

Advancing the master branch in the direction of the test branch up to commit 25:

PRAGMA branch_merge --forward master test.25

Advancing the master branch in the direction of the test branch all the way up to (and including) the last commit:

PRAGMA branch_merge --forward master test

Conflict Detection

LiteTree performs will perform conflict detection by default on merge and rebase operations.

If you want to omit it, use the --force parameter, like this:

PRAGMA branch=master
PRAGMA branch_merge --force test
PRAGMA branch=test
PRAGMA branch_rebase --force master

If you want to perform just a conflict detection you can use the --check parameter on both merge and rebase operations. eg:

PRAGMA branch=master
PRAGMA branch_merge --check test
PRAGMA branch=test
PRAGMA branch_rebase --check master

On these cases no merge or rebase is performed.

Conflict Resolution

LiteTree will not implement conflict resolution. The conflicts must be resolved manually, either by:

  • Choosing another point for merge or rebase
  • Editing existing commits
  • Adding or removing commits

Implementation

Option 1:

Use the stored SQL commands from the source branch and run them in the destination branch.

Problem: if a previous merge was already done (from previous or the same commit)

Solution 1: use the SQL commands starting at the last merge

This implies storing merge info/history.

Pros:

  • Easy to implement

Cons:

  • No conflict detection
  • Merging can take a long time to be processed if the SQL commands are complex (because they are re-executed)

Option 1b:

Store a modified SQL command on each execution, in which do not depends on previous values.

eg:

UPDATE t1 SET count = count + 1 WHERE id=3

becomes:

UPDATE t1 SET count = 10 WHERE id=3

if count was previously 9.

UPDATE t1 SET count = count + 1

becomes:

UPDATE t1 SET count = 15 WHERE id=1
UPDATE t1 SET count = 12 WHERE id=2
UPDATE t1 SET count = 10 WHERE id=3
...

And

UPDATE t1 SET col1 = col2 WHERE col3 > 10

becomes:

UPDATE t1 SET col1 = "John" WHERE id=11
UPDATE t1 SET col1 = "Mary" WHERE id=17
UPDATE t1 SET col1 = NULL   WHERE id=19
...

Note: using the session / changeset feature is better suited to execute these commands because we don't need to parse each of them.

Note 2: maybe in some cases the user wants that a command like UPDATE products SET active = 1 affect all the rows, even the ones included from the merging process. So it could have an option to use the plain/original command (affecting all rows) or affect just the ones from that commit.


Option 2:

Compare all the rows from source and destination branches.

Detect duplicated and modified rows as conflicts that must be resolved in some way.

Pros:

  • Conflict detection
  • Maybe faster at the merge stage

Cons:

  • Maybe slower at the scan stage

Note:

Rows that exist on source but not on the destination can be due to:

  • They were inserted in the source
  • They were deleted in the destination

How to detect the difference?


Option 3:

Use the Session / Changeset feature

Pros:

  • Conflict detection

Cons:

  • Does not deal with schema differences

Option 4:

Use a modified Session / Changeset feature with these changes:

  1. Detect schema differences

  2. Copy rows directly instead of generating SQL commands

Pros:

  • Conflict detection
  • Deals with schema differences

Cons:

  • Maybe hard to implement

Option 5:

Just like option 4 but automatically choosing the best / faster merge approach (run SQL or copy rows directly)

Pros:

  • Conflict detection
  • Deals with schema differences

Cons:

  • Maybe hard to implement

Copying rows "directly"

Either by:

  1. Using our code in C

  2. Using the SQLite VDBE

Notice that the SQL commands from option 1 come from the log / history and the others are generated by code. So the complexity and speed of execution may vary a lot.


Notes

(you can add your notes here bellow or participate in the discussion here)