Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandJoin.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandJoin.java	(revision 31489)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandJoin.java	(revision 31489)
@@ -0,0 +1,55 @@
+package org.openstreetmap.josm.plugins.mapillary.commands;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.List;
+
+import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
+import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils;
+
+/**
+ * Command joined when joining two images into the same sequence.
+ *
+ * @author nokutu
+ *
+ */
+public class CommandJoin extends MapillaryExecutableCommand {
+
+  /**
+   * Main constructor.
+   *
+   * @param images
+   */
+  public CommandJoin(List<MapillaryAbstractImage> images) {
+    super(images);
+  }
+
+  @Override
+  public void execute() {
+    this.redo();
+  }
+
+  @Override
+  public void undo() {
+    MapillaryUtils.unjoin((MapillaryImportedImage) this.images.get(0),
+        (MapillaryImportedImage) this.images.get(1));
+  }
+
+  @Override
+  public void redo() {
+    MapillaryUtils.join((MapillaryImportedImage) this.images.get(0),
+        (MapillaryImportedImage) this.images.get(1));
+  }
+
+  @Override
+  public void sum(MapillaryCommand command) {
+    // TODO Auto-generated method stub
+
+  }
+
+  @Override
+  public String toString() {
+    return tr("2 images joined");
+  }
+}
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandUnjoin.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandUnjoin.java	(revision 31489)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandUnjoin.java	(revision 31489)
@@ -0,0 +1,54 @@
+package org.openstreetmap.josm.plugins.mapillary.commands;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.List;
+
+import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
+import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils;
+
+/**
+ * Command joined when joining two images into the same sequence.
+ *
+ * @author nokutu
+ *
+ */
+public class CommandUnjoin extends MapillaryExecutableCommand {
+
+  /**
+   * Main constructor.
+   *
+   * @param images
+   */
+  public CommandUnjoin(List<MapillaryAbstractImage> images) {
+    super(images);
+  }
+
+  @Override
+  public void execute() {
+    this.redo();
+  }
+
+  @Override
+  public void undo() {
+    MapillaryUtils.join((MapillaryImportedImage) this.images.get(0),
+        (MapillaryImportedImage) this.images.get(1));
+  }
+
+  @Override
+  public void redo() {
+    MapillaryUtils.unjoin((MapillaryImportedImage) this.images.get(0),
+        (MapillaryImportedImage) this.images.get(1));
+  }
+
+  @Override
+  public void sum(MapillaryCommand command) {
+    // IGNORE
+  }
+
+  @Override
+  public String toString() {
+    return tr("2 images unjoined");
+  }
+}
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/mode/JoinMode.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/mode/JoinMode.java	(revision 31488)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/mode/JoinMode.java	(revision 31489)
@@ -6,5 +6,5 @@
 import java.awt.Point;
 import java.awt.event.MouseEvent;
-import java.util.ArrayList;
+import java.util.Arrays;
 
 import org.openstreetmap.josm.Main;
@@ -15,5 +15,7 @@
 import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
-import org.openstreetmap.josm.plugins.mapillary.MapillarySequence;
+import org.openstreetmap.josm.plugins.mapillary.commands.CommandJoin;
+import org.openstreetmap.josm.plugins.mapillary.commands.CommandUnjoin;
+import org.openstreetmap.josm.plugins.mapillary.commands.MapillaryRecord;
 
 /**
@@ -44,15 +46,22 @@
     } else if (this.lastClick != null
         && this.data.getHighlightedImage() instanceof MapillaryImportedImage) {
-      if (((this.data.getHighlightedImage().previous() == null && this.lastClick.next() == null) || (this.data
-          .getHighlightedImage().next() == null && this.lastClick.previous() == null))
-          && (this.data.getHighlightedImage().getSequence() != this.lastClick.getSequence() || this.lastClick
-              .getSequence() == null)) {
-        join(this.lastClick, (MapillaryImportedImage) this.data.getHighlightedImage());
+      if (((this.data.getHighlightedImage().previous() == null && this.lastClick
+          .next() == null) || (this.data.getHighlightedImage().next() == null && this.lastClick
+          .previous() == null))
+          && (this.data.getHighlightedImage().getSequence() != this.lastClick
+              .getSequence() || this.lastClick.getSequence() == null)) {
+
+        MapillaryRecord.getInstance().addCommand(
+            new CommandJoin(Arrays.asList(new MapillaryAbstractImage[] {
+                this.lastClick, this.data.getHighlightedImage() })));
       } else if (this.lastClick.next() == this.data.getHighlightedImage()
           || this.lastClick.previous() == this.data.getHighlightedImage())
-        unjoin(this.lastClick, (MapillaryImportedImage) this.data.getHighlightedImage());
+        MapillaryRecord.getInstance().addCommand(
+            new CommandUnjoin(Arrays.asList(new MapillaryAbstractImage[] {
+                this.lastClick, this.data.getHighlightedImage() })));
       this.lastClick = null;
     }
-    MapillaryData.dataUpdated();
+    if (Main.main != null)
+      MapillaryData.dataUpdated();
   }
 
@@ -77,60 +86,4 @@
   }
 
-  private static void join(MapillaryImportedImage img1, MapillaryImportedImage img2) {
-    MapillaryImportedImage firstImage = img1;
-    MapillaryImportedImage secondImage = img2;
-
-    if (img1.next() != null) {
-      firstImage = img2;
-      secondImage = img1;
-    }
-    if (firstImage.getSequence() == null) {
-      MapillarySequence seq = new MapillarySequence();
-      seq.add(firstImage);
-      firstImage.setSequence(seq);
-    }
-    if (secondImage.getSequence() == null) {
-      MapillarySequence seq = new MapillarySequence();
-      seq.add(secondImage);
-      img2.setSequence(seq);
-    }
-
-    for (MapillaryAbstractImage img : secondImage.getSequence().getImages()) {
-      firstImage.getSequence().add(img);
-      img.setSequence(firstImage.getSequence());
-    }
-  }
-
-  private static void unjoin(MapillaryImportedImage img1, MapillaryImportedImage img2) {
-    MapillaryImportedImage firstImage = img1;
-    MapillaryImportedImage secondImage = img2;
-
-    if (img1.next() != img2) {
-      firstImage = img2;
-      secondImage = img1;
-    }
-
-    ArrayList<MapillaryAbstractImage> firstHalf = new ArrayList<>(firstImage
-        .getSequence().getImages()
-        .subList(0, firstImage.getSequence().getImages().indexOf(secondImage)));
-    ArrayList<MapillaryAbstractImage> secondHalf = new ArrayList<>(firstImage
-        .getSequence()
-        .getImages()
-        .subList(firstImage.getSequence().getImages().indexOf(secondImage),
-            firstImage.getSequence().getImages().size()));
-
-    MapillarySequence seq1 = new MapillarySequence();
-    MapillarySequence seq2 = new MapillarySequence();
-
-    for (MapillaryAbstractImage img : firstHalf) {
-      img.setSequence(seq1);
-      seq1.add(img);
-    }
-    for (MapillaryAbstractImage img : secondHalf) {
-      img.setSequence(seq2);
-      seq2.add(img);
-    }
-  }
-
   @Override
   public String toString() {
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java	(revision 31488)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java	(revision 31489)
@@ -7,9 +7,14 @@
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.util.ArrayList;
 
 import org.apache.commons.imaging.common.RationalNumber;
 import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
+import org.openstreetmap.josm.plugins.mapillary.MapillarySequence;
 
 /**
@@ -120,3 +125,77 @@
     }
   }
+
+  /**
+   * Joins two images into the same sequence.
+   *
+   * @param img1
+   * @param img2
+   */
+  public synchronized static void join(MapillaryImportedImage img1,
+      MapillaryImportedImage img2) {
+    MapillaryImportedImage firstImage = img1;
+    MapillaryImportedImage secondImage = img2;
+
+    if (img1.next() != null) {
+      firstImage = img2;
+      secondImage = img1;
+    }
+    if (firstImage.getSequence() == null) {
+      MapillarySequence seq = new MapillarySequence();
+      seq.add(firstImage);
+      firstImage.setSequence(seq);
+    }
+    if (secondImage.getSequence() == null) {
+      MapillarySequence seq = new MapillarySequence();
+      seq.add(secondImage);
+      img2.setSequence(seq);
+    }
+
+    for (MapillaryAbstractImage img : secondImage.getSequence().getImages()) {
+      firstImage.getSequence().add(img);
+      img.setSequence(firstImage.getSequence());
+    }
+    if (Main.main != null)
+      MapillaryData.dataUpdated();
+  }
+
+  /**
+   * Separates two images belonging to the same sequence.
+   *
+   * @param img1
+   * @param img2
+   */
+  public synchronized static void unjoin(MapillaryImportedImage img1,
+      MapillaryImportedImage img2) {
+    MapillaryImportedImage firstImage = img1;
+    MapillaryImportedImage secondImage = img2;
+
+    if (img1.next() != img2) {
+      firstImage = img2;
+      secondImage = img1;
+    }
+
+    ArrayList<MapillaryAbstractImage> firstHalf = new ArrayList<>(firstImage
+        .getSequence().getImages()
+        .subList(0, firstImage.getSequence().getImages().indexOf(secondImage)));
+    ArrayList<MapillaryAbstractImage> secondHalf = new ArrayList<>(firstImage
+        .getSequence()
+        .getImages()
+        .subList(firstImage.getSequence().getImages().indexOf(secondImage),
+            firstImage.getSequence().getImages().size()));
+
+    MapillarySequence seq1 = new MapillarySequence();
+    MapillarySequence seq2 = new MapillarySequence();
+
+    for (MapillaryAbstractImage img : firstHalf) {
+      img.setSequence(seq1);
+      seq1.add(img);
+    }
+    for (MapillaryAbstractImage img : secondHalf) {
+      img.setSequence(seq2);
+      seq2.add(img);
+    }
+    if (Main.main != null)
+      MapillaryData.dataUpdated();
+  }
 }
