A patch to src/checkin.c to accomplish this:
<pre>
@@ -448,11 +448,10 @@

 /*
 ** Populate the Global.aCommitFile[] based on the command line arguments
 ** to a [commit] command. Global.aCommitFile is an array of integers
-** sized at (N+1), where N is the number of arguments passed to [commit].
-** The contents are the [id] values from the vfile table corresponding
-** to the filenames passed as arguments.
+** statically sized at 2000. The contents are the [id] values from the
+** vfile table corresponding to the filenames passed as arguments.
 **
 ** The last element of aCommitFile[] is always 0 - indicating the end
 ** of the array.
 **
@@ -461,24 +460,37 @@
 ** to mean "all files".
 */
 void select_commit_files(void){
   if( g.argc>2 ){
-    int ii;
+    int ii, iIn;
+    Stmt q;
     Blob b;
+    char *zPath;
     blob_zero(&b);
-    g.aCommitFile = malloc(sizeof(int)*(g.argc-1));
-
+    g.aCommitFile = malloc(sizeof(int)*2000);
+
+    iIn = 0;
     for(ii=2; ii<g.argc; ii++){
       int iId;
       file_tree_name(g.argv[ii], &b, 1);
-      iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
+
+      zPath = blob_str(&b);
+      db_prepare(&q, "SELECT id FROM vfile WHERE pathname=%Q OR (pathname LIKE '%q/%%' AND chnged = 1)", zPath, zPath);
+      iId = -1;
+      while( db_step(&q)==SQLITE_ROW ){
+        if( iIn>=2000 ){
+          fossil_fatal("too many files: max 2000");
+        }
+
+        iId = db_column_int(&q, 0);
+        g.aCommitFile[iIn++] = iId;
+      }
       if( iId<0 ){
         fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
       }
-      g.aCommitFile[ii-2] = iId;
       blob_reset(&b);
     }
-    g.aCommitFile[ii-2] = 0;
+    g.aCommitFile[iIn] = 0;
   }
 }

 /*
</pre>