Index: src/add.c
==================================================================
--- src/add.c
+++ src/add.c
@@ -92,66 +92,77 @@
 **
 ** Omit any file whose name is pOmit.
 */
 static int add_one_file(
   const char *zPath,   /* Tree-name of file to add. */
-  int vid              /* Add to this VFILE */
+  int vid,             /* Add to this VFILE */
+  int caseSensitive    /* True if filenames are case sensitive */
 ){
+  const char *zCollate = caseSensitive ? "binary" : "nocase";
   if( !file_is_simple_pathname(zPath) ){
     fossil_fatal("filename contains illegal characters: %s", zPath);
   }
-#if defined(_WIN32)
   if( db_exists("SELECT 1 FROM vfile"
-                " WHERE pathname=%Q COLLATE nocase", zPath) ){
+                " WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){
     db_multi_exec("UPDATE vfile SET deleted=0"
-                  " WHERE pathname=%Q COLLATE nocase", zPath);
-  }
-#else
-  if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){
-    db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath);
-  }
-#endif
-  else{
+                  " WHERE pathname=%Q COLLATE %s", zPath, zCollate);
+  }else{
     char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
     db_multi_exec(
       "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)"
       "VALUES(%d,0,0,0,%Q,%d)",
       vid, zPath, file_isexe(zFullname));
     fossil_free(zFullname);
   }
-  fossil_print("ADDED  %s\n", zPath);
-  return 1;
+  if( db_changes() ){
+    fossil_print("ADDED  %s\n", zPath);
+    return 1;
+  }else{
+    fossil_print("SKIP   %s\n", zPath);
+    return 0;
+  }
 }
 
 /*
 ** Add all files in the sfile temp table.
 **
 ** Automatically exclude the repository file.
 */
-static int add_files_in_sfile(int vid){
+static int add_files_in_sfile(int vid, int caseSensitive){
   const char *zRepo;        /* Name of the repository database file */
   int nAdd = 0;             /* Number of files added */
   int i;                    /* Loop counter */
   const char *zReserved;    /* Name of a reserved file */
   Blob repoName;            /* Treename of the repository */
   Stmt loop;                /* SQL to loop over all files to add */
+  int (*xCmp)(const char*,const char*);
  
   if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){
     blob_zero(&repoName);
     zRepo = "";
   }else{
     zRepo = blob_str(&repoName);
   }
+  if( caseSensitive ){
+    xCmp = fossil_strcmp;
+  }else{
+    xCmp = fossil_stricmp;
+    db_multi_exec(
+      "CREATE INDEX IF NOT EXISTS vfile_nocase"
+      "    ON vfile(pathname COLLATE nocase)"
+    );
+  }
+  xCmp = caseSensitive ? fossil_strcmp : fossil_stricmp;
   db_prepare(&loop, "SELECT x FROM sfile ORDER BY x");
   while( db_step(&loop)==SQLITE_ROW ){
     const char *zToAdd = db_column_text(&loop, 0);
     if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
     for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){
-      if( fossil_strcmp(zToAdd, zReserved)==0 ) break;
+      if( xCmp(zToAdd, zReserved)==0 ) break;
     }
     if( zReserved ) continue;
-    nAdd += add_one_file(zToAdd, vid);
+    nAdd += add_one_file(zToAdd, vid, caseSensitive);
   }
   db_finalize(&loop);
   blob_reset(&repoName);
   return nAdd;
 }
@@ -180,14 +191,17 @@
   int i;                     /* Loop counter */
   int vid;                   /* Currently checked out version */
   int nRoot;                 /* Full path characters in g.zLocalRoot */
   const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */
   Glob *pIgnore;             /* Ignore everything matching this glob pattern */
+  int caseSensitive;         /* True if filenames are case sensitive */
 
   zIgnoreFlag = find_option("ignore",0,1);
   includeDotFiles = find_option("dotfiles",0,0)!=0;
+  capture_case_sensitive_option();
   db_must_be_within_tree();
+  caseSensitive = filenames_are_case_sensitive();
   if( zIgnoreFlag==0 ){
     zIgnoreFlag = db_get("ignore-glob", 0);
   }
   vid = db_lget_int("checkout",0);
   if( vid==0 ){
@@ -229,11 +243,11 @@
     }
     blob_reset(&fullName);
   }
   glob_free(pIgnore);
 
-  add_files_in_sfile(vid);  
+  add_files_in_sfile(vid, caseSensitive);
   db_end_transaction(0);
 }
 
 /*
 ** COMMAND: rm
@@ -289,10 +303,48 @@
     "UPDATE vfile SET deleted=1 WHERE pathname IN sfile;"
     "DELETE FROM vfile WHERE rid=0 AND deleted;"
   );
   db_end_transaction(0);
 }
+
+/*
+** Capture the command-line --case-sensitive option.
+*/
+static const char *zCaseSensitive = 0;
+void capture_case_sensitive_option(void){
+  if( zCaseSensitive==0 ){
+    zCaseSensitive = find_option("case-sensitive",0,1);
+  }
+}
+
+/*
+** This routine determines if files should be case-sensitive or not.
+** In other words, this routine determines if two filenames that
+** differ only in case should be considered the same name or not.
+**
+** The case-sensitive setting determines the default value.  If
+** the case-sensitive setting is undefined, then case sensitivity
+** defaults on for Mac and Windows and off for all other unix.
+**
+** The --case-sensitive BOOLEAN command-line option overrides any
+** setting.
+*/
+int filenames_are_case_sensitive(void){
+  int caseSensitive;
+
+  if( zCaseSensitive ){
+    caseSensitive = is_truth(zCaseSensitive);
+  }else{
+#if !defined(_WIN32) && !defined(__DARWIN__) && !defined(__APPLE__)
+    caseSensitive = 1;
+#else
+    caseSensitive = 0;
+#endif
+    caseSensitive = db_get_boolean("case-sensitive",caseSensitive);
+  }
+  return caseSensitive;
+}
 
 /*
 ** COMMAND: addremove
 **
 ** Usage: %fossil addremove ?--dotfiles? ?--ignore GLOBPATTERN? ?--test?
@@ -319,27 +371,29 @@
 **
 ** The --test option shows what would happen without actually doing anything.
 **
 ** This command can be used to track third party software.
 **
-**
 ** SUMMARY: fossil addremove
-** Options: ?--dotfiles? ?--ignore GLOBPATTERN? ?--test?
+** Options: ?--dotfiles? ?--ignore GLOB? ?--test? ?--case-sensitive BOOL?
 */
-void import_cmd(void){
+void addremove_cmd(void){
   Blob path;
   const char *zIgnoreFlag = find_option("ignore",0,1);
   int allFlag = find_option("dotfiles",0,0)!=0;
   int isTest = find_option("test",0,0)!=0;
+  int caseSensitive;
   int n;
   Stmt q;
   int vid;
   int nAdd = 0;
   int nDelete = 0;
   Glob *pIgnore;
 
+  capture_case_sensitive_option();
   db_must_be_within_tree();
+  caseSensitive = filenames_are_case_sensitive();
   if( zIgnoreFlag==0 ){
     zIgnoreFlag = db_get("ignore-glob", 0);
   }
   vid = db_lget_int("checkout",0);
   if( vid==0 ){
@@ -358,11 +412,11 @@
   blob_init(&path, g.zLocalRoot, n-1);
   /* now we read the complete file structure into a temp table */
   pIgnore = glob_create(zIgnoreFlag);
   vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
   glob_free(pIgnore);
-  nAdd = add_files_in_sfile(vid);
+  nAdd = add_files_in_sfile(vid, caseSensitive);
 
   /* step 2: search for missing files */
   db_prepare(&q,
       "SELECT pathname, %Q || pathname, deleted FROM vfile"
       " WHERE NOT deleted"

Index: src/db.c
==================================================================
--- src/db.c
+++ src/db.c
@@ -1366,19 +1366,19 @@
 */
 int is_truth(const char *zVal){
   static const char *azOn[] = { "on", "yes", "true", "1" };
   int i;
   for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
-    if( fossil_strcmp(zVal,azOn[i])==0 ) return 1;
+    if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
   }
   return 0;
 }
 int is_false(const char *zVal){
   static const char *azOff[] = { "off", "no", "false", "0" };
   int i;
   for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
-    if( fossil_strcmp(zVal,azOff[i])==0 ) return 1;
+    if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
   }
   return 0;
 }
 
 /*
@@ -1647,10 +1647,11 @@
   { "access-log",    0,                0, "off"                 },
   { "auto-captcha",  "autocaptcha",    0, "on"                  },
   { "auto-shun",     0,                0, "on"                  },
   { "autosync",      0,                0, "on"                  },
   { "binary-glob",   0,               32, ""                    },
+  { "case-sensitive",0,                0, "on"                  },
   { "clearsign",     0,                0, "off"                 },
   { "crnl-glob",     0,               16, ""                    },
   { "default-perms", 0,               16, "u"                   },
   { "diff-command",  0,               16, ""                    },
   { "dont-push",     0,                0, "off"                 },
@@ -1703,10 +1704,15 @@
 **                     Default: on
 **
 **    binary-glob      The VALUE is a comma-separated list of GLOB patterns
 **                     that should be treated as binary files for merging
 **                     purposes.  Example:   *.xml
+**
+**    case-sensitive   If TRUE, the files whose names differ only in case
+**                     care considered distinct.  If FALSE files whose names
+**                     differ only in case are the same file.  Defaults to
+**                     TRUE for unix and FALSE for windows and mac.
 **
 **    clearsign        When enabled, fossil will attempt to sign all commits
 **                     with gpg.  When disabled (the default), commits will
 **                     be unsigned.  Default: off
 **

Index: src/merge.c
==================================================================
--- src/merge.c
+++ src/merge.c
@@ -53,10 +53,14 @@
 **                           and do not try to merge parallel changes.  This
 **                           option overrides the "binary-glob" setting.
 **
 **   --nochange | -n         Dryrun:  do not actually make any changes; just
 **                           show what would have happened.
+**
+**   --case-sensitive BOOL   Overwrite the case-sensitive setting.  If false,
+**                           files whose names differ only in case are taken
+**                           to be the same file.
 */
 void merge_cmd(void){
   int vid;              /* Current version "V" */
   int mid;              /* Version we are merging from "M" */
   int pid;              /* The pivot version - most recent common ancestor P */
@@ -69,10 +73,11 @@
   int debugFlag;        /* True if --debug is present */
   int nChng;            /* Number of file name changes */
   int *aChng;           /* An array of file name changes */
   int i;                /* Loop counter */
   int nConflict = 0;    /* Number of conflicts seen */
+  int caseSensitive;    /* True for case-sensitive filenames */
   Stmt q;
 
 
   /* Notation:
   **
@@ -87,14 +92,16 @@
   backoutFlag = find_option("backout",0,0)!=0;
   debugFlag = find_option("debug",0,0)!=0;
   zBinGlob = find_option("binary",0,1);
   nochangeFlag = find_option("nochange","n",0)!=0;
   zPivot = find_option("baseline",0,1);
+  capture_case_sensitive_option();
   if( g.argc!=3 ){
     usage("VERSION");
   }
   db_must_be_within_tree();
+  caseSensitive = filenames_are_case_sensitive();
   if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
   vid = db_lget_int("checkout", 0);
   if( vid==0 ){
     fossil_fatal("nothing is checked out");
   }
@@ -150,11 +157,11 @@
   ** in the current checkout, the pivot, and the version being merged.
   */
   db_multi_exec(
     "DROP TABLE IF EXISTS fv;"
     "CREATE TEMP TABLE fv("
-    "  fn TEXT PRIMARY KEY,"      /* The filename */
+    "  fn TEXT PRIMARY KEY COLLATE %s,"  /* The filename */
     "  idv INTEGER,"              /* VFILE entry for current version */
     "  idp INTEGER,"              /* VFILE entry for the pivot */
     "  idm INTEGER,"              /* VFILE entry for version merging in */
     "  chnged BOOLEAN,"           /* True if current version has been edited */
     "  ridv INTEGER,"             /* Record ID for current version */
@@ -161,11 +168,12 @@
     "  ridp INTEGER,"             /* Record ID for pivot */
     "  ridm INTEGER,"             /* Record ID for merge */
     "  isexe BOOLEAN,"            /* Execute permission enabled */
     "  fnp TEXT,"                 /* The filename in the pivot */
     "  fnm TEXT"                  /* the filename in the merged version */
-    ");"
+    ");",
+    caseSensitive ? "binary" : "nocase"
   );
 
   /* Add files found in V
   */
   db_multi_exec(