Index: trunk/src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 5496)
+++ trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 5497)
@@ -14,4 +14,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.upload.ApiPreconditionCheckerHook;
+import org.openstreetmap.josm.actions.upload.DiscardTagsHook;
 import org.openstreetmap.josm.actions.upload.RelationUploadOrderHook;
 import org.openstreetmap.josm.actions.upload.UploadHook;
@@ -50,4 +51,5 @@
      */
     private static final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
+    private static final LinkedList<UploadHook> lateUploadHooks = new LinkedList<UploadHook>();
     static {
         uploadHooks.add(new ValidateUploadHook());
@@ -61,4 +63,9 @@
          */
         uploadHooks.add(new RelationUploadOrderHook());
+
+        /**
+         * Removes discardable tags like created_by on modified objects
+         */
+        lateUploadHooks.add(new DiscardTagsHook());
     }
 
@@ -69,7 +76,25 @@
      */
     public static void registerUploadHook(UploadHook hook) {
+        registerUploadHook(hook, false);
+    }
+
+    /**
+     * Registers an upload hook. Adds the hook at the first position of the upload hooks.
+     *
+     * @param hook the upload hook. Ignored if null.
+     * @param late true, if the hook should be executed after the upload dialog
+     * has been confirmed. Late upload hooks should in general succeed and not
+     * abort the upload.
+     */
+    public static void registerUploadHook(UploadHook hook, boolean late) {
         if(hook == null) return;
-        if (!uploadHooks.contains(hook)) {
-            uploadHooks.add(0,hook);
+        if (late) {
+            if (!lateUploadHooks.contains(hook)) {
+                lateUploadHooks.add(0, hook);
+            }
+        } else {
+            if (!uploadHooks.contains(hook)) {
+                uploadHooks.add(0, hook);
+            }
         }
     }
@@ -84,4 +109,7 @@
         if (uploadHooks.contains(hook)) {
             uploadHooks.remove(hook);
+        }
+        if (lateUploadHooks.contains(hook)) {
+            lateUploadHooks.remove(hook);
         }
     }
@@ -122,5 +150,5 @@
      * want to continue
      */
-    public static final boolean warnUploadDiscouraged(OsmDataLayer layer) {
+    public static boolean warnUploadDiscouraged(OsmDataLayer layer) {
         return GuiHelper.warnUser(tr("Upload discouraged"),
                 "<html>" +
@@ -200,4 +228,9 @@
         dialog.rememberUserInput();
 
+        for (UploadHook hook : lateUploadHooks) {
+            if (!hook.checkUpload(apiData))
+                return;
+        }
+
         Main.worker.execute(
                 new UploadPrimitivesTask(
Index: trunk/src/org/openstreetmap/josm/actions/upload/DiscardTagsHook.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/upload/DiscardTagsHook.java	(revision 5497)
+++ trunk/src/org/openstreetmap/josm/actions/upload/DiscardTagsHook.java	(revision 5497)
@@ -0,0 +1,50 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.upload;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+/**
+ * Removes discardable tags such as created_by from all modified objects before upload
+ */
+public class DiscardTagsHook implements UploadHook {
+
+    public boolean checkUpload(APIDataSet apiDataSet) {
+        List<OsmPrimitive> objectsToUpload = apiDataSet.getPrimitives();
+        Collection<String> discardableKeys = new HashSet<String>(OsmPrimitive.getDiscardableKeys());
+
+        boolean needsChange = false;
+        OUTER: for (OsmPrimitive osm : objectsToUpload) {
+            for (String key : osm.keySet()) {
+                if (discardableKeys.contains(key)) {
+                    needsChange = true;
+                    break OUTER;
+                }
+            }
+        }
+
+        if (needsChange) {
+            AbstractMap<String, String> map = new HashMap<String, String>();
+            for (String key : discardableKeys) {
+                map.put(key, null);
+            }
+
+            SequenceCommand removeKeys = new SequenceCommand(tr("Removed obsolete tags"),
+                    new ChangePropertyCommand(objectsToUpload, map));
+            Main.main.undoRedo.add(removeKeys);
+        }
+        return true;
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 5496)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 5497)
@@ -609,6 +609,7 @@
      *----------------------------------*/
 
-
     private static volatile Collection<String> uninteresting = null;
+    private static volatile Collection<String> discardable = null;
+    
     /**
      * Contains a list of "uninteresting" keys that do not make an object
@@ -620,9 +621,24 @@
         if (uninteresting == null) {
             uninteresting = Main.pref.getCollection("tags.uninteresting",
-                    Arrays.asList(new String[]{"source", "source_ref", "source:", "note", "comment",
+                    Arrays.asList("source", "source_ref", "source:", "note", "comment",
                             "converted_by", "created_by", "watch", "watch:", "fixme", "FIXME",
-                            "description", "attribution"}));
+                            "description", "attribution"));
         }
         return uninteresting;
+    }
+
+    /**
+     * Returns a list of keys which have been deemed uninteresting to the point
+     * that they can be silently removed from data which is being edited.
+     */
+    public static Collection<String> getDiscardableKeys() {
+        if(discardable == null) {
+            discardable = Main.pref.getCollection("tags.discardable",
+                    Arrays.asList("created_by",
+                            "tiger:upload_uuid", "tiger:tlid", "tiger:source", "tiger:separated",
+                            "geobase:datasetName", "geobase:uuid", "sub_sea:type",
+                            "odbl", "odbl:note"));
+        }
+        return discardable;
     }
 
Index: trunk/src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 5496)
+++ trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 5497)
@@ -219,8 +219,6 @@
             Collections.sort(entries, byKeyComparator);
             for (Entry<String, String> e : entries) {
-                if ((osm instanceof Changeset) || !("created_by".equals(e.getKey()))) {
-                    out.println("    <tag k='"+ XmlWriter.encode(e.getKey()) +
-                            "' v='"+XmlWriter.encode(e.getValue())+ "' />");
-                }
+                out.println("    <tag k='"+ XmlWriter.encode(e.getKey()) +
+                        "' v='"+XmlWriter.encode(e.getValue())+ "' />");
             }
             out.println("  </" + tagname + ">");
