@@ -142,6 +142,67 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
142142 return 0 ;
143143}
144144
145+ static int do_serialize = 0 ;
146+ static int do_implicit_deserialize = 0 ;
147+ static int do_explicit_deserialize = 0 ;
148+ static char * deserialize_path = NULL ;
149+
150+ /*
151+ * --serialize | --serialize=1 | --serialize=v1
152+ *
153+ * Request that we serialize our output rather than printing in
154+ * any of the established formats. Optionally specify serialization
155+ * version.
156+ */
157+ static int opt_parse_serialize (const struct option * opt , const char * arg , int unset )
158+ {
159+ enum wt_status_format * value = (enum wt_status_format * )opt -> value ;
160+ if (unset || !arg )
161+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
162+ else if (!strcmp (arg , "v1" ) || !strcmp (arg , "1" ))
163+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
164+ else
165+ die ("unsupported serialize version '%s'" , arg );
166+
167+ if (do_explicit_deserialize )
168+ die ("cannot mix --serialize and --deserialize" );
169+ do_implicit_deserialize = 0 ;
170+
171+ do_serialize = 1 ;
172+ return 0 ;
173+ }
174+
175+ /*
176+ * --deserialize | --deserialize=<path> |
177+ * --no-deserialize
178+ *
179+ * Request that we deserialize status data from some existing resource
180+ * rather than performing a status scan.
181+ *
182+ * The input source can come from stdin or a path given here -- or be
183+ * inherited from the config settings.
184+ */
185+ static int opt_parse_deserialize (const struct option * opt , const char * arg , int unset )
186+ {
187+ if (unset ) {
188+ do_implicit_deserialize = 0 ;
189+ do_explicit_deserialize = 0 ;
190+ } else {
191+ if (do_serialize )
192+ die ("cannot mix --serialize and --deserialize" );
193+ if (arg ) /* override config or stdin */
194+ deserialize_path = xstrdup (arg );
195+ if (deserialize_path && * deserialize_path
196+ && (access (deserialize_path , R_OK ) != 0 ))
197+ die ("cannot find serialization file '%s'" ,
198+ deserialize_path );
199+
200+ do_explicit_deserialize = 1 ;
201+ }
202+
203+ return 0 ;
204+ }
205+
145206static int opt_parse_m (const struct option * opt , const char * arg , int unset )
146207{
147208 struct strbuf * buf = opt -> value ;
@@ -1035,6 +1096,8 @@ static void handle_untracked_files_arg(struct wt_status *s)
10351096 s -> show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES ;
10361097 else if (!strcmp (untracked_files_arg , "all" ))
10371098 s -> show_untracked_files = SHOW_ALL_UNTRACKED_FILES ;
1099+ else if (!strcmp (untracked_files_arg ,"complete" ))
1100+ s -> show_untracked_files = SHOW_COMPLETE_UNTRACKED_FILES ;
10381101 else
10391102 die (_ ("Invalid untracked files mode '%s'" ), untracked_files_arg );
10401103}
@@ -1263,6 +1326,19 @@ static int git_status_config(const char *k, const char *v, void *cb)
12631326 s -> relative_paths = git_config_bool (k , v );
12641327 return 0 ;
12651328 }
1329+ if (!strcmp (k , "status.deserializepath" )) {
1330+ /*
1331+ * Automatically assume deserialization if this is
1332+ * set in the config and the file exists. Do not
1333+ * complain if the file does not exist, because we
1334+ * silently fall back to normal mode.
1335+ */
1336+ if (v && * v && access (v , R_OK ) == 0 ) {
1337+ do_implicit_deserialize = 1 ;
1338+ deserialize_path = xstrdup (v );
1339+ }
1340+ return 0 ;
1341+ }
12661342 if (!strcmp (k , "status.showuntrackedfiles" )) {
12671343 if (!v )
12681344 return config_error_nonbool (k );
@@ -1305,7 +1381,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13051381 static int show_ignored_directory = 0 ;
13061382 static struct wt_status s ;
13071383 unsigned int progress_flag = 0 ;
1308- int fd ;
1384+ int try_deserialize ;
1385+ int fd = -1 ;
13091386 struct object_id oid ;
13101387 static struct option builtin_status_options [] = {
13111388 OPT__VERBOSE (& verbose , N_ ("be verbose" )),
@@ -1320,6 +1397,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13201397 { OPTION_CALLBACK , 0 , "porcelain" , & status_format ,
13211398 N_ ("version" ), N_ ("machine-readable output" ),
13221399 PARSE_OPT_OPTARG , opt_parse_porcelain },
1400+ { OPTION_CALLBACK , 0 , "serialize" , & status_format ,
1401+ N_ ("version" ), N_ ("serialize raw status data to stdout" ),
1402+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG , opt_parse_serialize },
1403+ { OPTION_CALLBACK , 0 , "deserialize" , NULL ,
1404+ N_ ("path" ), N_ ("deserialize raw status data from file" ),
1405+ PARSE_OPT_OPTARG , opt_parse_deserialize },
13231406 OPT_SET_INT (0 , "long" , & status_format ,
13241407 N_ ("show status in long format (default)" ),
13251408 STATUS_FORMAT_LONG ),
@@ -1380,10 +1463,26 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13801463 s .show_untracked_files == SHOW_NO_UNTRACKED_FILES )
13811464 die (_ ("Unsupported combination of ignored and untracked-files arguments" ));
13821465
1466+ if (s .show_untracked_files == SHOW_COMPLETE_UNTRACKED_FILES &&
1467+ s .show_ignored_mode == SHOW_NO_IGNORED )
1468+ die (_ ("Complete Untracked only supported with ignored files" ));
1469+
13831470 parse_pathspec (& s .pathspec , 0 ,
13841471 PATHSPEC_PREFER_FULL ,
13851472 prefix , argv );
13861473
1474+ /*
1475+ * If we want to try to deserialize status data from a cache file,
1476+ * we need to re-order the initialization code. The problem is that
1477+ * this makes for a very nasty diff and causes merge conflicts as we
1478+ * carry it forward. And it easy to mess up the merge, so we
1479+ * duplicate some code here to hopefully reduce conflicts.
1480+ */
1481+ try_deserialize = (!do_serialize &&
1482+ (do_implicit_deserialize || do_explicit_deserialize ));
1483+ if (try_deserialize )
1484+ goto skip_init ;
1485+
13871486 enable_fscache (0 );
13881487 if (status_format != STATUS_FORMAT_PORCELAIN &&
13891488 status_format != STATUS_FORMAT_PORCELAIN_V2 )
@@ -1398,6 +1497,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13981497 else
13991498 fd = -1 ;
14001499
1500+ skip_init :
14011501 s .is_initial = get_oid (s .reference , & oid ) ? 1 : 0 ;
14021502 if (!s .is_initial )
14031503 hashcpy (s .sha1_commit , oid .hash );
@@ -1414,6 +1514,24 @@ int cmd_status(int argc, const char **argv, const char *prefix)
14141514 s .rename_score = parse_rename_score (& rename_score_arg );
14151515 }
14161516
1517+ if (try_deserialize ) {
1518+ if (s .relative_paths )
1519+ s .prefix = prefix ;
1520+
1521+ if (wt_status_deserialize (& s , deserialize_path ) == DESERIALIZE_OK )
1522+ return 0 ;
1523+
1524+ /* deserialize failed, so force the initialization we skipped above. */
1525+ enable_fscache (1 );
1526+ read_cache_preload (& s .pathspec );
1527+ refresh_index (& the_index , REFRESH_QUIET |REFRESH_UNMERGED , & s .pathspec , NULL , NULL );
1528+
1529+ if (use_optional_locks ())
1530+ fd = hold_locked_index (& index_lock , 0 );
1531+ else
1532+ fd = -1 ;
1533+ }
1534+
14171535 wt_status_collect (& s );
14181536
14191537 if (0 <= fd )
0 commit comments