shrink-conflicts 0.1.0

Tries to minimise diff3-style git conflicts
Documentation
  • Coverage
  • 0%
    0 out of 2 items documented0 out of 1 items with examples
  • Size
  • Source code size: 19.06 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 258.27 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 22s Average build duration of successful builds.
  • all releases: 22s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • asayers/shrink-conflicts
    3 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • asayers

Shrink git conflicts

shrink-conflicts is a program which tries to minimise diff3-style git conflicts.

Workflow

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.

Credit

I got the idea from git-mediate. shrink-conflicts is a re-implementation of (part of) git-mediate's functionality.

Example

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()
    }
}