Index: /src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/SaveAction.java	(revision 51)
+++ /src/org/openstreetmap/josm/actions/SaveAction.java	(revision 52)
@@ -73,5 +73,5 @@
 			}
 			fileWriter.close();
-			Main.main.getMapFrame().mapView.editLayer().cleanData(false, false);
+			Main.main.getMapFrame().mapView.editLayer().cleanData(null, false);
 		} catch (IOException e) {
 			e.printStackTrace();
Index: /src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/UploadAction.java	(revision 51)
+++ /src/org/openstreetmap/josm/actions/UploadAction.java	(revision 52)
@@ -84,5 +84,5 @@
 					JOptionPane.showMessageDialog(Main.main, x.getMessage());
 				}
-				Main.main.getMapFrame().mapView.editLayer().cleanData(true, !add.isEmpty());
+				Main.main.getMapFrame().mapView.editLayer().cleanData(server.processed, !add.isEmpty());
 			}
 		}).start();
Index: /src/org/openstreetmap/josm/data/GeoPoint.java
===================================================================
--- /src/org/openstreetmap/josm/data/GeoPoint.java	(revision 51)
+++ /src/org/openstreetmap/josm/data/GeoPoint.java	(revision 52)
@@ -80,4 +80,14 @@
 
 	/**
+	 * @return <code>true</code>, if the other GeoPoint has almost the same lat/lon
+	 * values, only differ by no more than 1/Projection.MAX_SERVER_PRECISION.
+	 */
+	public boolean equalsLatLonEpsilon(GeoPoint other) {
+		final double p = 1/Projection.MAX_SERVER_PRECISION;
+		return Math.abs(lat-other.lat) <= p && Math.abs(lon-other.lon) <= p && 
+				!Double.isNaN(lat) && !Double.isNaN(lon);
+	}
+
+	/**
 	 * @return <code>true</code>, if the coordinate is outside the world, compared
 	 * by using lat/lon.
Index: /src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 51)
+++ /src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 52)
@@ -42,5 +42,5 @@
 			if (myNode.modified && !otherNode.modified)
 				return;
-			if (!myNode.coor.equalsLatLon(otherNode.coor)) {
+			if (!myNode.coor.equalsLatLonEpsilon(otherNode.coor)) {
 				myNode.coor = otherNode.coor;
 				myNode.modified = otherNode.modified;
@@ -51,5 +51,5 @@
 	/**
 	 * Merge the line segment if id matches or if both nodes are the same (and the
-	 * id is zero of either segment). Nodes are equal when they @see match
+	 * id is zero of either segment). Nodes are the "same" when they @see match
 	 */
 	public void visit(LineSegment otherLs) {
@@ -120,5 +120,5 @@
 	private boolean match(Node n1, Node n2) {
 		if (n1.id == 0 || n2.id == 0)
-			return n1.coor.equalsLatLon(n2.coor);
+			return n1.coor.equalsLatLonEpsilon(n2.coor);
 		return n1.id == n2.id;
 	}
@@ -153,21 +153,23 @@
 	 */
 	private void mergeCommon(OsmPrimitive myOsm, OsmPrimitive otherOsm) {
-		if (otherOsm.modified)
-			myOsm.modified = true;
 		if (otherOsm.isDeleted())
 			myOsm.setDeleted(true);
 		if (!myOsm.modified || otherOsm.modified) {
-			if (otherOsm.id != 0 && myOsm.id == 0)
+			if (myOsm.id == 0 && otherOsm.id != 0)
 				myOsm.id = otherOsm.id; // means not ncessary the object is now modified
+			else if (myOsm.id != 0 && otherOsm.id != 0 && otherOsm.modified)
+				myOsm.modified = true;
 		}
 		if (myOsm.modifiedProperties && !otherOsm.modifiedProperties)
 			return;
-		if (myOsm.keys != null && !myOsm.keys.equals(otherOsm.keys)) {
-			if (myOsm.keys == null)
-				myOsm.keys = otherOsm.keys;
-			else if (otherOsm.keys != null)
-				myOsm.keys.putAll(otherOsm.keys);
-			myOsm.modifiedProperties = true;
-		}
+		if (otherOsm.keys == null)
+			return;
+		if (myOsm.keys != null && myOsm.keys.entrySet().containsAll(otherOsm.keys.entrySet()))
+			return;
+		if (myOsm.keys == null)
+			myOsm.keys = otherOsm.keys;
+		else
+			myOsm.keys.putAll(otherOsm.keys);
+		myOsm.modifiedProperties = true;
 	}
 }
Index: /src/org/openstreetmap/josm/data/projection/Epsg4263.java
===================================================================
--- /src/org/openstreetmap/josm/data/projection/Epsg4263.java	(revision 51)
+++ /src/org/openstreetmap/josm/data/projection/Epsg4263.java	(revision 52)
@@ -16,6 +16,6 @@
 
 	public void xy2latlon(GeoPoint p) {
-		p.lat = Math.round(p.y*MAX_SERVER_PRECISION)/MAX_SERVER_PRECISION;
-		p.lon = Math.round(p.x*MAX_SERVER_PRECISION)/MAX_SERVER_PRECISION;
+		p.lat = p.y;
+		p.lon = p.x;
 	}
 
Index: /src/org/openstreetmap/josm/data/projection/Mercator.java
===================================================================
--- /src/org/openstreetmap/josm/data/projection/Mercator.java	(revision 51)
+++ /src/org/openstreetmap/josm/data/projection/Mercator.java	(revision 52)
@@ -22,7 +22,4 @@
 		p.lon = p.x*180/Math.PI;
 		p.lat = Math.atan(Math.sinh(p.y))*180/Math.PI;
-		// round values to maximum server precision
-		p.lon = Math.round(p.lon*MAX_SERVER_PRECISION)/MAX_SERVER_PRECISION;
-		p.lat = Math.round(p.lat*MAX_SERVER_PRECISION)/MAX_SERVER_PRECISION;
 	}
 
Index: /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 51)
+++ /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 52)
@@ -5,6 +5,8 @@
 import java.beans.PropertyChangeListener;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.Set;
 import java.util.Stack;
 
@@ -218,28 +220,32 @@
 	 * really deleting all deleted objects and reset the modified flags. This is done
 	 * after a successfull upload.
+	 * 
 	 * @param uploaded <code>true</code>, if the data was uploaded, false if saved to disk
-	 * @param dataAdded <code>true</code>, if data was added during the upload process.
-	 */
-	public void cleanData(boolean uploaded, boolean dataAdded) {
+	 * @param processed A list of all objects, that were actually uploaded. 
+	 * 		May be <code>null</code>, which means nothing has been uploaded but 
+	 * 		saved to disk instead.
+	 */
+	public void cleanData(Collection<OsmPrimitive> processed, boolean dataAdded) {
 		redoCommands.clear();
 		commands.clear();
-		
+
 		// if uploaded, clean the modified flags as well
-		if (uploaded) {
+		if (processed != null) {
+			Set<OsmPrimitive> processedSet = new HashSet<OsmPrimitive>(processed);
 			for (Iterator<Node> it = data.nodes.iterator(); it.hasNext();)
-				cleanModifiedFlag(it);
+				cleanIterator(it, processedSet);
 			for (Iterator<LineSegment> it = data.lineSegments.iterator(); it.hasNext();)
-				cleanModifiedFlag(it);
+				cleanIterator(it, processedSet);
 			for (Iterator<Track> it = data.tracks.iterator(); it.hasNext();)
-				cleanModifiedFlag(it);
+				cleanIterator(it, processedSet);
 		}
-		
+
 		// update the modified flag
 		
-		if (fromDisk && uploaded && !dataAdded)
+		if (fromDisk && processed != null && !dataAdded)
 			return; // do nothing when uploading non-harmful changes.
 		
 		// modified if server changed the data (esp. the id).
-		uploadedModified = fromDisk && uploaded && dataAdded;
+		uploadedModified = fromDisk && processed != null && dataAdded;
 		setModified(uploadedModified);
 		//TODO: Replace with listener scheme
@@ -248,6 +254,16 @@
 	}
 
-	private void cleanModifiedFlag(Iterator<? extends OsmPrimitive> it) {
+	/**
+	 * Clean the modified flag for the given iterator over a collection if it is in the
+	 * list of processed entries.
+	 * 
+	 * @param it The iterator to change the modified and remove the items if deleted.
+	 * @param processed A list of all objects that have been successfully progressed.
+	 * 		If the object in the iterator is not in the list, nothing will be changed on it.
+	 */
+	private void cleanIterator(Iterator<? extends OsmPrimitive> it, Collection<OsmPrimitive> processed) {
 		OsmPrimitive osm = it.next();
+		if (!processed.remove(osm))
+			return;
 		osm.modified = false;
 		osm.modifiedProperties = false;
Index: /src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 51)
+++ /src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 52)
@@ -11,4 +11,5 @@
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.LinkedList;
 
 import org.jdom.Document;
@@ -41,8 +42,18 @@
 
 	/**
+	 * This list contain all sucessfull processed objects. The caller of
+	 * upload* has to check this after the call and update its dataset.
+	 * 
+	 * If a server connection error occours, this may contain fewer entries
+	 * than where passed in the list to upload*.
+	 */
+	public Collection<OsmPrimitive> processed;
+	
+	/**
 	 * Send the dataset to the server. Ask the user first and does nothing if he
 	 * does not want to send the data.
 	 */
 	public void uploadOsm(Collection<OsmPrimitive> list) throws JDOMException {
+		processed = new LinkedList<OsmPrimitive>();
 		initAuthentication();
 
@@ -67,4 +78,5 @@
 			sendRequest("PUT", "node/" + n.id, n, true);
 		}
+		processed.add(n);
 	}
 
@@ -81,4 +93,5 @@
 			sendRequest("PUT", "segment/" + ls.id, ls, true);
 		}
+		processed.add(ls);
 	}
 
@@ -103,5 +116,5 @@
 
 	/**
-	 * Read an long from the input stream and return it.
+	 * Read a long from the input stream and return it.
 	 */
 	private long readId(InputStream inputStream) throws IOException {
@@ -118,4 +131,14 @@
 	}
 
+	/**
+	 * Send the request. The objects id will be replaced if it was 0 before
+	 * (on add requests).
+	 * 
+	 * @param requestMethod The http method used when talking with the server.
+	 * @param urlSuffix The suffix to add at the server url.
+	 * @param osm The primitive to encode to the server.
+	 * @param addBody <code>true</code>, if the whole primitive body should be added. 
+	 * 		<code>false</code>, if only the id is encoded.
+	 */
 	@SuppressWarnings("unchecked")
 	private void sendRequest(String requestMethod, String urlSuffix,
Index: /test/org/openstreetmap/josm/test/MergeVisitorTest.java
===================================================================
--- /test/org/openstreetmap/josm/test/MergeVisitorTest.java	(revision 52)
+++ /test/org/openstreetmap/josm/test/MergeVisitorTest.java	(revision 52)
@@ -0,0 +1,36 @@
+package org.openstreetmap.josm.test;
+
+import junit.framework.TestCase;
+
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;
+import org.openstreetmap.josm.test.framework.DataSetTestCaseHelper;
+
+public class MergeVisitorTest extends TestCase {
+
+	
+	/**
+	 * Merge of an old line segment with a new one. This should
+	 * be mergable (if the nodes matches).
+	 */
+	public void testMergeOldLineSegmentsWithNew() {
+		DataSet ds = new DataSet();
+		Node n1 = DataSetTestCaseHelper.createNode(ds);
+		n1.id = 1;
+		Node n2 = DataSetTestCaseHelper.createNode(ds);
+		n2.id = 2;
+		LineSegment ls1 = DataSetTestCaseHelper.createLineSegment(ds, n1, n2);
+		ls1.id = 3;
+
+		Node newnode = new Node();
+		newnode.coor = new GeoPoint(n2.coor.lat, n2.coor.lon);
+		LineSegment newls = new LineSegment(n1, newnode);
+
+		MergeVisitor v = new MergeVisitor(ds);
+		v.visit(newls);
+		assertEquals("line segment should have been merged.", 1, ds.lineSegments.size());
+	}
+}
Index: /test/org/openstreetmap/josm/test/framework/DataSetTestCaseHelper.java
===================================================================
--- /test/org/openstreetmap/josm/test/framework/DataSetTestCaseHelper.java	(revision 51)
+++ /test/org/openstreetmap/josm/test/framework/DataSetTestCaseHelper.java	(revision 52)
@@ -43,5 +43,5 @@
 	 * Create a line segment with out of the given nodes.
 	 */
-	private static LineSegment createLineSegment(DataSet ds, Node n1, Node n2) {
+	public static LineSegment createLineSegment(DataSet ds, Node n1, Node n2) {
 		LineSegment ls = new LineSegment(n1, n2);
 		ds.lineSegments.add(ls);
@@ -52,5 +52,5 @@
 	 * Add a random node.
 	 */
-	private static Node createNode(DataSet ds) {
+	public static Node createNode(DataSet ds) {
 		Node node = new Node();
 		node.coor = new GeoPoint(Math.random(), Math.random());
