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.
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.
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.
Spork is built on top of a few pieces of fantastic software, most notably:
- Spoon provides the AST representation used in Spork.
- GumTree provides the tree matching.
- gumtree-spoon-ast-diff
bridges the gap between
Spoon
andGumTree
.
The merge implementation in Spork is based on the 3DM merge algorithm by Tancred Lindholm.
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.
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.
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
.
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 thedriver
option that invokes Spork.
Unless otherwise stated, files in Spork are under the MIT license.
- The GumTreeSpoonAstDiff file is composed of code from gumtree-spoon-ast-diff and is therefore individually licensed under Apache License 2.0.
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.