Index: /trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 8446)
+++ /trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 8447)
@@ -140,5 +140,9 @@
                                                                             w.getNode(segmentIndex+1).getEastNorth(),
                                                                             node.getEastNorth());
-                        cmds.add(new MoveCommand(node, Projections.inverseProject(newPosition)));
+                        MoveCommand c = new MoveCommand(node, Projections.inverseProject(newPosition));
+                        // Avoid moving a given node several times at the same position in case of overlapping ways
+                        if (!cmds.contains(c)) {
+                            cmds.add(c);
+                        }
                     }
                 }
Index: /trunk/src/org/openstreetmap/josm/command/Command.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/command/Command.java	(revision 8446)
+++ /trunk/src/org/openstreetmap/josm/command/Command.java	(revision 8447)
@@ -100,4 +100,38 @@
             return modified;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((eastNorth == null) ? 0 : eastNorth.hashCode());
+            result = prime * result + ((latlon == null) ? 0 : latlon.hashCode());
+            result = prime * result + (modified ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            OldNodeState other = (OldNodeState) obj;
+            if (eastNorth == null) {
+                if (other.eastNorth != null)
+                    return false;
+            } else if (!eastNorth.equals(other.eastNorth))
+                return false;
+            if (latlon == null) {
+                if (other.latlon != null)
+                    return false;
+            } else if (!latlon.equals(other.latlon))
+                return false;
+            if (modified != other.modified)
+                return false;
+            return true;
+        }
     }
 
@@ -266,3 +300,33 @@
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((cloneMap == null) ? 0 : cloneMap.hashCode());
+        result = prime * result + ((layer == null) ? 0 : layer.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Command other = (Command) obj;
+        if (cloneMap == null) {
+            if (other.cloneMap != null)
+                return false;
+        } else if (!cloneMap.equals(other.cloneMap))
+            return false;
+        if (layer == null) {
+            if (other.layer != null)
+                return false;
+        } else if (!layer.equals(other.layer))
+            return false;
+        return true;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 8446)
+++ /trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 8447)
@@ -66,4 +66,5 @@
      * Constructs a new {@code MoveCommand} to move a node.
      * @param node The node to move
+     * @param position The new location (lat/lon)
      */
     public MoveCommand(Node node, LatLon position) {
@@ -97,4 +98,10 @@
     }
 
+    /**
+     * Constructs a new {@code MoveCommand} to move a collection of primitives.
+     * @param objects The primitives to move
+     * @param start The starting position (northern/eastern)
+     * @param end The ending position (northern/eastern)
+     */
     public MoveCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
         this(objects, end.getX()-start.getX(), end.getY()-start.getY());
@@ -102,4 +109,10 @@
     }
 
+    /**
+     * Constructs a new {@code MoveCommand} to move a primitive.
+     * @param p The primitive to move
+     * @param start The starting position (northern/eastern)
+     * @param end The ending position (northern/eastern)
+     */
     public MoveCommand(OsmPrimitive p, EastNorth start, EastNorth end) {
         this(Collections.singleton(p), end.getX()-start.getX(), end.getY()-start.getY());
@@ -223,3 +236,57 @@
         return nodes;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        long temp;
+        temp = Double.doubleToLongBits(backupX);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        temp = Double.doubleToLongBits(backupY);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        result = prime * result + ((nodes == null) ? 0 : nodes.hashCode());
+        result = prime * result + ((oldState == null) ? 0 : oldState.hashCode());
+        result = prime * result + ((startEN == null) ? 0 : startEN.hashCode());
+        temp = Double.doubleToLongBits(x);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        temp = Double.doubleToLongBits(y);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        MoveCommand other = (MoveCommand) obj;
+        if (Double.doubleToLongBits(backupX) != Double.doubleToLongBits(other.backupX))
+            return false;
+        if (Double.doubleToLongBits(backupY) != Double.doubleToLongBits(other.backupY))
+            return false;
+        if (nodes == null) {
+            if (other.nodes != null)
+                return false;
+        } else if (!nodes.equals(other.nodes))
+            return false;
+        if (oldState == null) {
+            if (other.oldState != null)
+                return false;
+        } else if (!oldState.equals(other.oldState))
+            return false;
+        if (startEN == null) {
+            if (other.startEN != null)
+                return false;
+        } else if (!startEN.equals(other.startEN))
+            return false;
+        if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
+            return false;
+        if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
+            return false;
+        return true;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/command/PseudoCommand.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/command/PseudoCommand.java	(revision 8446)
+++ /trunk/src/org/openstreetmap/josm/command/PseudoCommand.java	(revision 8447)
@@ -17,4 +17,5 @@
     /**
      * Provides a description text representing this command.
+     * @return description text representing this command
      */
     public abstract String getDescriptionText();
@@ -22,4 +23,5 @@
     /**
      * Provides a descriptive icon of this command.
+     * @return descriptive icon of this command
      */
     public Icon getDescriptionIcon() {
@@ -29,4 +31,5 @@
     /**
      * Return the primitives that take part in this command.
+     * @return primitives that take part in this command
      */
     public abstract Collection<? extends OsmPrimitive> getParticipatingPrimitives();
