/spork

AST-based structured merge tool for Java, fully Git compatible https://doi.org/10.1109/TSE.2022.3143766

Primary LanguageJavaMIT LicenseMIT

Build Status Code Coverage Supported Platforms

Spork - AST based merging for Java files

Spork is an AST based structured merge tool for Java. This means that instead of merging Java files by their raw text, it resolves the abstract syntax trees and merges based on them instead.

Academic use

If you use Spork in an academic context, please cite the related research paper:

S. Larsen, J. -R. Falleri, B. Baudry and M. Monperrus, "Spork: Structured Merge for Java with Formatting Preservation," in IEEE Transactions on Software Engineering, doi: 10.1109/TSE.2022.3143766.

You may export a citation in various formats using the Cite this repository button to the right. See the GitHub docs for more info.

Master's thesis

Spork was created as part of a master's thesis project. If you want to learn more about Spork in terms of theory and design, the thesis is freely available.

Attribution

Spork is built on top of a few pieces of fantastic software, most notably:

The merge implementation in Spork is based on the 3DM merge algorithm by Tancred Lindholm.

Quickstart

Want to just try out Spork on a small merge scenario? Below are a few shell commands that will download Spork along with a sample merge scenario, and then run it!

# Download Spork
wget https://github.com/KTH/spork/releases/download/v0.5.0/spork-0.5.0.jar -O spork.jar

# Download a sample merge scenario
wget https://raw.githubusercontent.com/KTH/spork/fe906f537d1bb7205256d1fe81fda9f323849a60/src/test/resources/clean/both_modified/move_if/Left.java
wget https://raw.githubusercontent.com/KTH/spork/fe906f537d1bb7205256d1fe81fda9f323849a60/src/test/resources/clean/both_modified/move_if/Base.java
wget https://raw.githubusercontent.com/KTH/spork/fe906f537d1bb7205256d1fe81fda9f323849a60/src/test/resources/clean/both_modified/move_if/Right.java
# You should now have spork.jar, Left.java, Base.java and Right.java in your local directory

# a line based-merge is not possible
diff3 Left.java Base.java Right.java -m -A

# an AST-merge with Spork does
java -jar spork.jar Left.java Base.java Right.java

It should print the result of the merge to stdout. See Base.java for the original version, and Left.java and Right.java for the respective changes. They should all be neatly integrated into the resulting merge. For more on using Spork, see Usage.

Usage

You can find a pre-built jar-file under relases. The jar-file includes all dependencies, so all you need is a Java runtime. Download the jar and run it like so:

Important: Spork requires a Java runtime version 8 or higher to run.

java -jar path/to/spork/jar <left> <base> <right>

The left, base and right arguments are required, and represent the left, base and right revisions, respectively. The base revision should be the best common ancestor of the left and right revisions.

For a full listing of the command line options, supply the -h option. It will produce the following output.

Usage: spork [-eghlV] [-o=<out>] LEFT BASE RIGHT
The Spork command line app.
      LEFT              Path to the left revision.
      BASE              Path to the base revision.
      RIGHT             Path to the right revision.
  -e, --exit-on-error   Disable line-based fallback if the structured merge
                          encounters an error.
  -g, --git-mode        Enable Git compatibility mode. Required to use Spork as
                          a Git merge driver.
  -h, --help            Show this help message and exit.
  -l, --logging         Enable logging output.
  -o, --output=<out>    Path to the output file. Existing files are overwritten.
  -V, --version         Print version information and exit.

Naturally, if you want the absolute latest version, you will have to build Spork yourself.

Build

Maven can be used to build the latest version of Spork.

Note: Requires JDK8+ to build.

mvn clean compile package -DskipTests

This will produce a jar-file in the target directory called something along the lines of spork-x.x.x.jar. Run the jar with java -jar path/to/spork/jar.

Configure as a Git merge driver

When Git performs a merge and encounters a file that has been edited in both revisions under merge, it will invoke a merge driver to merge the conflicting versions. It's a very simple thing to configure Spork as a merge driver for Java files, all you need is to add a couple of lines to a couple of configuration files. First, let's create a .gitattributes file and specify to use Spork as a merge driver for Java files. Put the following content in your .gitattributes file (you may all ready have one, check your home directory):

*.java merge=spork

spork doesn't mean anything to Git yet, we need to actually define the merge driver called spork. We do that in the .gitconfig file, typically located in your home directory. You should put the following content into it:

[core]
	attributesfile = /path/to/.gitattributes

[merge "spork"]
    name = spork
    driver = java -jar /path/to/spork.jar merge --git-mode %A %O %B -o %A

Then replace /path/to/.gitattributes with the absolute path to the .gitattributes file you edited/created first, and replace /path/to/spork.jar with the absolute path to the Spork jar-file. With that done, Spork will be used as the merge driver for Java files!

Important: The --git-mode option is required to use Spork as a Git merge driver. If you find that Spork always reverts to line-based merge, then that option is probably missing in the driver option that invokes Spork.

License

Unless otherwise stated, files in Spork are under the MIT license.

Experimental: compile as a native image

Spork can be compiled to a native executable file using GraalVM. To do so, you need to first install GraalVM's JDK for Java 17 (Spork does not support Java 21 yet, see #479). Running mvn package -P native will then generate a native image in target/spork.

Note: the native image is known to behave differently to the .jar file, producing different conflict resolution results. Help to debug this would be welcome.