Index: tests/keyfile-test.c
===================================================================
--- tests/keyfile-test.c	(revision 5430)
+++ tests/keyfile-test.c	(working copy)
@@ -445,6 +445,9 @@ test_comments (void)
   const gchar *data = 
     "# top comment\n"
     "# top comment, continued\n"
+    "\n"
+    "# group1 comment\n"
+    "# group1 comment, continued\n"
     "[group1]\n"
     "key1 = value1\n"
     "# key comment\n"
@@ -453,12 +456,13 @@ test_comments (void)
     "# line end check\r\n"
     "key3 = value3\n"
     "key4 = value4\n"
-    "# group comment\n"
-    "# group comment, continued\n"
+    "# group2 comment\n"
+    "# group2 comment, continued\n"
     "[group2]\n";
 
   const gchar *top_comment= " top comment\n top comment, continued\n";
-  const gchar *group_comment= " group comment\n group comment, continued\n";
+  const gchar *group1_comment= " group1 comment\n group1 comment, continued\n";
+  const gchar *group2_comment= " group2 comment\n group2 comment, continued\n";
   const gchar *key_comment= " key comment\n key comment, continued\n";
   
   keyfile = load_data (data, 0);
@@ -504,9 +508,13 @@ test_comments (void)
   check_name ("key comment", comment, key_comment, 0);
   g_free (comment);
 
+  comment = g_key_file_get_comment (keyfile, "group1", NULL, &error);
+  check_no_error (&error);
+  check_name ("group1 comment", comment, group1_comment, 0);
+  g_free (comment);
   comment = g_key_file_get_comment (keyfile, "group2", NULL, &error);
   check_no_error (&error);
-  check_name ("group comment", comment, group_comment, 0);
+  check_name ("group2 comment", comment, group2_comment, 0);
   g_free (comment);
 
   comment = g_key_file_get_comment (keyfile, "group3", NULL, &error);
@@ -1250,6 +1258,87 @@ test_duplicate_groups2 (void)
   g_key_file_free (keyfile);  
 }
 
+
+static void
+test_reload_idempotency (void)
+{
+  static const gchar *original_data=""
+    "# Top comment\n"
+    "\n"
+    "# First comment\n"
+    "[first]\n"
+    "key=value\n"
+    "# A random comment in the first group\n"
+    "anotherkey=anothervalue\n"
+    "# Second comment - one line\n"
+    "[second]\n"
+    "# Third comment - two lines\n"
+    "# Third comment - two lines\n"
+    "[third]\n"
+    "blank_line=1\n"
+    "\n"
+    "blank_lines=2\n"
+    "\n\n"
+    "[fourth]\n"
+    "[fifth]\n";
+  GKeyFile *keyfile;
+  GError *error = NULL;
+  gchar *data1, *data2;
+  gsize len1, len2;
+
+  /* check that we only insert a single new line between groups */
+  keyfile = g_key_file_new ();
+  if (!g_key_file_load_from_data (keyfile,
+	                          original_data, strlen(original_data),
+	                          G_KEY_FILE_KEEP_COMMENTS,
+	                          &error)) {
+    g_print ("Failed to parse keyfile[1]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+
+  data1 = g_key_file_to_data (keyfile, &len1, &error);
+  if (data1 == NULL) {
+    g_print ("Failed to extract keyfile[1]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+  g_key_file_free (keyfile);
+
+  keyfile = g_key_file_new ();
+  if (!g_key_file_load_from_data (keyfile,
+	                          data1, len1,
+				  G_KEY_FILE_KEEP_COMMENTS,
+				  &error)) {
+    g_print ("Failed to parse keyfile[2]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+
+  data2 = g_key_file_to_data (keyfile, &len2, &error);
+  if (data2 == NULL) {
+    g_print ("Failed to extract keyfile[2]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+  g_key_file_free (keyfile);
+
+
+  if (strcmp(data1, data2) != 0) {
+    g_print ("Reloading GKeyFile is not idempotent.");
+    g_print ("original:\n%s\n---\n", original_data);
+    g_print ("pass1:\n%s\n---\n", data1);
+    g_print ("pass2:\n%s\n---\n", data2);
+    exit (1);
+  }
+
+  g_free (data2);
+  g_free (data1);
+}
+
+
+
+
 static void 
 log_func (const gchar   *log_domain,
           GLogLevelFlags log_level,
@@ -1280,6 +1369,7 @@ main (int argc, char *argv[])
   test_duplicate_groups2 ();
   test_group_names ();
   test_key_names ();
+  test_reload_idempotency ();
   
   return 0;
 }
Index: glib/gkeyfile.c
===================================================================
--- glib/gkeyfile.c	(revision 5430)
+++ glib/gkeyfile.c	(working copy)
@@ -72,6 +72,7 @@ struct _GKeyFile
   GKeyFileGroup *current_group;
 
   GString *parse_buffer; /* Holds up to one line of not-yet-parsed data */
+  GList *comment_block;
 
   /* Used for sizing the output buffer during serialization
    */
@@ -88,7 +89,8 @@ struct _GKeyFileGroup
 {
   const gchar *name;  /* NULL for above first group (which will be comments) */
 
-  GKeyFileKeyValuePair *comment; /* Special comment that is stuck to the top of a group */
+  gchar *comment; /* Special comment that is stuck to the top of a group */
+  gboolean has_trailing_blank_line;
 
   GList *key_value_pairs; 
 
@@ -711,6 +713,46 @@ g_key_file_parse_line (GKeyFile     *key
 }
 
 static void
+g_key_file_add_comment_block_as_key_value_pairs (GKeyFile *key_file)
+{
+  GList *l;
+
+  if (key_file->comment_block == NULL)
+    return;
+
+  for (l = g_list_last (key_file->comment_block); l; l = g_list_previous (l))
+    {
+      key_file->current_group->key_value_pairs = g_list_prepend (
+	  key_file->current_group->key_value_pairs, l->data);
+    }
+  g_list_free (key_file->comment_block);
+  key_file->comment_block = NULL;
+  key_file->current_group->has_trailing_blank_line = TRUE;
+}
+
+static void
+g_key_file_add_comment_block_as_comment (GKeyFile *key_file)
+{
+  GString *comment;
+  GList *l;
+
+  if (key_file->comment_block == NULL)
+    return;
+
+  comment = g_string_sized_new (512);
+  for (l = g_list_last (key_file->comment_block); l; l = g_list_previous (l))
+    {
+      GKeyFileKeyValuePair *pair = l->data;
+       g_string_append (comment, pair->value);
+       if (g_list_previous (l))
+	 g_string_append_c (comment, '\n');
+    }
+  key_file->current_group->comment = g_string_free (comment, FALSE);
+  g_list_free (key_file->comment_block);
+  key_file->comment_block = NULL;
+}
+
+static void
 g_key_file_parse_comment (GKeyFile     *key_file,
 			  const gchar  *line,
 			  gsize         length,
@@ -721,14 +763,15 @@ g_key_file_parse_comment (GKeyFile     *
   if (!(key_file->flags & G_KEY_FILE_KEEP_COMMENTS))
     return;
   
-  g_assert (key_file->current_group != NULL);
-
   pair = g_slice_new (GKeyFileKeyValuePair);
   pair->key = NULL;
   pair->value = g_strndup (line, length);
-  
-  key_file->current_group->key_value_pairs =
-    g_list_prepend (key_file->current_group->key_value_pairs, pair);
+
+  key_file->comment_block =
+    g_list_prepend (key_file->comment_block, pair);
+
+  if (length == 0 || line[0] != '#')
+    g_key_file_add_comment_block_as_key_value_pairs (key_file);
 }
 
 static void
@@ -762,6 +805,8 @@ g_key_file_parse_group (GKeyFile     *ke
 
   g_key_file_add_group (key_file, group_name);
   g_free (group_name);
+
+  g_key_file_add_comment_block_as_comment (key_file);
 }
 
 static void
@@ -773,6 +818,9 @@ g_key_file_parse_key_value_pair (GKeyFil
   gchar *key, *value, *key_end, *value_start, *locale;
   gsize key_len, value_len;
 
+  /* always? even if we don't add the key due to an error? */
+  g_key_file_add_comment_block_as_key_value_pairs (key_file);
+
   if (key_file->current_group == NULL || key_file->current_group->name == NULL)
     {
       g_set_error (error, G_KEY_FILE_ERROR,
@@ -959,6 +1007,7 @@ g_key_file_to_data (GKeyFile  *key_file,
 {
   GString *data_string;
   GList *group_node, *key_file_node;
+  gboolean has_blank_line = TRUE;
 
   g_return_val_if_fail (key_file != NULL, NULL);
 
@@ -972,10 +1021,13 @@ g_key_file_to_data (GKeyFile  *key_file,
 
       group = (GKeyFileGroup *) group_node->data;
 
+      /* separate groups by at least an empty line */
+      if (!has_blank_line)
+	g_string_append_c (data_string, '\n');
+      has_blank_line = group->has_trailing_blank_line;
+
       if (group->comment != NULL)
-        g_string_append_printf (data_string, "%s\n", group->comment->value);
-      else if (group_node->next) /* separate groups by at least an empty line */
-        g_string_append_c (data_string, '\n');
+        g_string_append_printf (data_string, "%s\n", group->comment);
 
       if (group->name != NULL)
         g_string_append_printf (data_string, "[%s]\n", group->name);
@@ -990,7 +1042,7 @@ g_key_file_to_data (GKeyFile  *key_file,
 
           if (pair->key != NULL)
             g_string_append_printf (data_string, "%s=%s\n", pair->key, pair->value);
-          else
+	  else
             g_string_append_printf (data_string, "%s\n", pair->value);
         }
     }
@@ -2475,7 +2527,7 @@ g_key_file_set_group_comment (GKeyFile  
    */
   if (group->comment)
     {
-      g_key_file_key_value_pair_free (group->comment);
+      g_free (group->comment);
       group->comment = NULL;
     }
 
@@ -2484,9 +2536,7 @@ g_key_file_set_group_comment (GKeyFile  
 
   /* Now we can add our new comment
    */
-  group->comment = g_slice_new (GKeyFileKeyValuePair);
-  group->comment->key = NULL;
-  group->comment->value = g_key_file_parse_comment_as_value (key_file, comment);
+  group->comment = g_key_file_parse_comment_as_value (key_file, comment);
 }
 
 static void
@@ -2727,7 +2777,7 @@ g_key_file_get_group_comment (GKeyFile  
 
   group = (GKeyFileGroup *)group_node->data;
   if (group->comment)
-    return g_strdup (group->comment->value);
+    return g_key_file_parse_value_as_comment (key_file, group->comment);
   
   group_node = group_node->next;
   group = (GKeyFileGroup *)group_node->data;  
@@ -3074,6 +3124,7 @@ g_key_file_add_key (GKeyFile      *key_f
 
   g_hash_table_replace (group->lookup_map, pair->key, pair);
   group->key_value_pairs = g_list_prepend (group->key_value_pairs, pair);
+  group->has_trailing_blank_line = FALSE;
   key_file->approximate_size += strlen (key) + strlen (value) + 2;
 }
 
