Good merge, bad merge

Posted on

Some time ago, I got excited about a new VCS called Pijulhttps://pijul.org/ whose distinctive feature is that it's based on a theoretical foundation around patches.

I tried to read the paperA Categorical Theory of Patches at the time and failed miserably. I have extremely limited knowledge of category theory.

The fascinating property of Pijul in my opinion is that merge conflicts have an actual representation in the way it represents files with contents in disks. If you think of a file in terms of lines with a partial ordering, then for regular files the ordering is also total: The blog A new version does a much better job at explaining the theory behind Pijul. The posts Merging and patches and Merging, patches, and Pijul are recommended. any two lines have an order in the file. Files with merge conflicts however do not have a total ordering of their lines, as there are at least two lines (from different changes) where the VCS cannot immediately infer which should come before the other.

This is something that’s been worked on extensively in Darcs.

Here I want to retrace an existing demonstration of the “bad merge” This is based on an example that shows how Darcs can resolve merges correctly where Git, Subversion, Mercurial, and Bzr all fail. There is both an abstract and a concrete example. and perform the equivalent steps with Pijul side-by-side and look at the end result.

Git

Let’s create a simple bad merge with Git:

$ git --version
git version 2.35.1
$ git init merge-git
$ cd merge-git

# Create and record our initial change (a)
$ python -c "print('\n'.join(c for c in 'ABCDE'))" > file.txt
$ git add file.txt
$ git commit -m 'a'

# Creates changes b1 and b2
$ git checkout -b b

# Change b1
$ python -c "print('\n'.join(c for c in 'GGGABCDE'))" > file.txt
$ git commit -a -m 'b1'

# Change b1
$ python -c "print('\n'.join(c for c in 'ABCDEGGGABCDE'))" > file.txt
$ git commit -a -m 'b2'

# Create change c1
$ git checkout -b c master

$ sed -i -e 's/C/X/' file.txt
$ git commit -a -m 'c1'

# Now we merge c1 into b2
$ git checkout -b merge b


$ git merge c
Auto-merging file.txt
Merge made by the 'ort' strategy.
 file.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

$ cat file.txt
A
B
X
D
E
G
G
G
A
B
C
D
E

Pijul

Let’s try the same sequence with Pijul.

$ pijul --version
pijul 1.0.0-beta.2
$ pijul init merge-pijul
$ cd merge-pijul


$ python -c "print('\n'.join(c for c in 'ABCDE'))" > file.txt
$ pijul add file.txt
$ pijul record -m 'a'


$ pijul fork b
$ pijul channel switch b

$ python -c "print('\n'.join(c for c in 'GGGABCDE'))" > file.txt
$ pijul record -m b1


$ python -c "print('\n'.join(c for c in 'ABCDEGGGABCDE'))" > file.txt
$ pijul record -m b2


$ pijul fork c --channel main
$ pijul channel switch c
$ sed -i -e 's/C/X/' file.txt
$ pijul record -m 'c1'


$ pijul fork merge --channel b
$ pijul channel switch merge

$ pijul apply "$(pijul log --channel c |head -1 | cut -d' ' -f2)"





$ cat file.txt
A
B
C
D
E
G
G
G
A
B
X
D
E

See the X towards the bottom of the file? Here’s the diff:

$ diff -Naur merge-git/file.txt merge-pijul/file.txt
--- merge-git/file.txt	2022-08-04 12:09:49.054364728 +0200
+++ merge-pijul/file.txt	2022-08-04 11:56:16.251548521 +0200
@@ -1,6 +1,6 @@
 A
 B
-X
+C
 D
 E
 G
@@ -8,6 +8,6 @@
 G
 A
 B
-C
+X
 D
 E

With Git, the X ended up towards the top of the file, but for Pijul it was able to track that the modification with X applied to the lines at the bottom. This outcome is not affected by the merge direction, so merging c into b is not different from merging b into c (although the output from “git merge” will look different).

Git to Pijul

If you, like me, is a day-to-day Git user, I’ve written up a rough command translation table:

git init pijul init
git commit -a -m pijul record -m
git checkout -b foo start-point pijul fork foo --channel start-point
pijul channel switch foo
git merge bar pijul log --channel bar (to find hashes to apply)
pijul apply hash

Pijul doesn’t operate with commits, branches, or merges, instead the terminology is changes (or patches), channels and apply. The implies in particular that you will never see something like a “merge conflict”—if the application of one change introduces a conflict, Pijul will warn about it just move on.Pijul by itself does not have a simple way to recall and list conflicts in the current file graph, but I have created a pijul-conflicts to provide a way to identify them. The conflict is tracked internally, but it doesn’t prevent you from applying or recording other unrelated changes.


Articles from blogs I follow around the net

In praise of Plan 9

Plan 9 is an operating system designed by Bell Labs. It’s the OS they wrote after Unix, with the benefit of hindsight. It is the most interesting operating system that you’ve never heard of, and, in my opinion, the best operating system design to date. Even …

via Drew DeVault's blog November 12, 2022

Making Hare more debuggable

Hare programs need to be easier to debug. This blog post outlines our plans for improving the situation. For a start, we’d like to implement the following features: Detailed backtraces Address sanitization New memory allocator DWARF support These are rou…

via Blogs on The Hare programming language November 4, 2022

bloat

the actual problem with bloat

via orib.dev September 26, 2022

Generated by openring