Crates.io | shrink-conflicts |
lib.rs | shrink-conflicts |
version | 0.1.0 |
created_at | 2025-07-25 09:46:06.357363+00 |
updated_at | 2025-07-25 09:46:06.357363+00 |
description | Tries to minimise diff3-style git conflicts |
homepage | |
repository | https://github.com/asayers/shrink-conflicts |
max_upload_size | |
id | 1767353 |
size | 19,062 |
shrink-conflicts
is a program which tries to minimise diff3-style git
conflicts.
As I work on resolving a conflict, I slowly make all three parts (left,
right, and centre) more and more similar. As I do this, I repeatedly pass
the conflict through shrink-conflicts
to have it automatically simplified
(and possibly elliminated). It's pretty nice.
shrink-conflicts
reads data on stdin and prints it to stdout (ie. it's a
"filter"). This means you can easily use it from within your text editor:
just pipe the buffer through it.
I got the idea from git-mediate. shrink-conflicts
is a re-implementation
of (part of) git-mediate's functionality.
Here's lib.rs:
impl Conflict {
<<<<<<<
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
// TODO: Should we be handling the common part too?
self.left.is_empty() && self.right.is_empty()
}
|||||||
fn is_resolved(&self) -> bool {
self.left.is_empty() && self.right.is_empty()
}
=======
fn is_resolved(&self) -> bool {
self.left.is_empty() && self.common.is_empty() && self.right.is_empty()
}
>>>>>>>
}
Running this file through shrink-conflicts
will have no effect yet.
Let's copy the doc comment from the left part into the common and right parts.
impl Conflict {
<<<<<<<
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
// TODO: Should we be handling the common part too?
self.left.is_empty() && self.right.is_empty()
}
|||||||
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
self.left.is_empty() && self.right.is_empty()
}
=======
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
self.left.is_empty() && self.common.is_empty() && self.right.is_empty()
}
>>>>>>>
}
Now when we run this through shrink-conflicts
it detects that all
three have a common prefix, and pulls it out:
$ shrink-conflicts <lib.rs
impl Conflict {
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
<<<<<<<
// TODO: Should we be handling the common part too?
self.left.is_empty() && self.right.is_empty()
|||||||
self.left.is_empty() && self.right.is_empty()
=======
self.left.is_empty() && self.common.is_empty() && self.right.is_empty()
>>>>>>>
}
}
Now, let's delete the TODO.
impl Conflict {
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
<<<<<<<
self.left.is_empty() && self.right.is_empty()
|||||||
self.left.is_empty() && self.right.is_empty()
=======
self.left.is_empty() && self.common.is_empty() && self.right.is_empty()
>>>>>>>
}
}
This time, when we run the file through shrink-conflicts
, it detects that
the left and common parts are identical, and so selects the right part.
$ shrink-conflicts <lib.rs
impl Conflict {
/// Is this conflict resolved?
fn is_resolved(&self) -> bool {
self.left.is_empty() && self.common.is_empty() && self.right.is_empty()
}
}