@@ -143,6 +143,67 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
143143 return 0 ;
144144}
145145
146+ static int do_serialize = 0 ;
147+ static int do_implicit_deserialize = 0 ;
148+ static int do_explicit_deserialize = 0 ;
149+ static char * deserialize_path = NULL ;
150+
151+ /*
152+ * --serialize | --serialize=1 | --serialize=v1
153+ *
154+ * Request that we serialize our output rather than printing in
155+ * any of the established formats. Optionally specify serialization
156+ * version.
157+ */
158+ static int opt_parse_serialize (const struct option * opt , const char * arg , int unset )
159+ {
160+ enum wt_status_format * value = (enum wt_status_format * )opt -> value ;
161+ if (unset || !arg )
162+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
163+ else if (!strcmp (arg , "v1" ) || !strcmp (arg , "1" ))
164+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
165+ else
166+ die ("unsupported serialize version '%s'" , arg );
167+
168+ if (do_explicit_deserialize )
169+ die ("cannot mix --serialize and --deserialize" );
170+ do_implicit_deserialize = 0 ;
171+
172+ do_serialize = 1 ;
173+ return 0 ;
174+ }
175+
176+ /*
177+ * --deserialize | --deserialize=<path> |
178+ * --no-deserialize
179+ *
180+ * Request that we deserialize status data from some existing resource
181+ * rather than performing a status scan.
182+ *
183+ * The input source can come from stdin or a path given here -- or be
184+ * inherited from the config settings.
185+ */
186+ static int opt_parse_deserialize (const struct option * opt , const char * arg , int unset )
187+ {
188+ if (unset ) {
189+ do_implicit_deserialize = 0 ;
190+ do_explicit_deserialize = 0 ;
191+ } else {
192+ if (do_serialize )
193+ die ("cannot mix --serialize and --deserialize" );
194+ /* override config or stdin */
195+ deserialize_path = xstrdup_or_null (arg );
196+ if (deserialize_path && * deserialize_path
197+ && (access (deserialize_path , R_OK ) != 0 ))
198+ die ("cannot find serialization file '%s'" ,
199+ deserialize_path );
200+
201+ do_explicit_deserialize = 1 ;
202+ }
203+
204+ return 0 ;
205+ }
206+
146207static int opt_parse_m (const struct option * opt , const char * arg , int unset )
147208{
148209 struct strbuf * buf = opt -> value ;
@@ -1038,6 +1099,8 @@ static void handle_untracked_files_arg(struct wt_status *s)
10381099 s -> show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES ;
10391100 else if (!strcmp (untracked_files_arg , "all" ))
10401101 s -> show_untracked_files = SHOW_ALL_UNTRACKED_FILES ;
1102+ else if (!strcmp (untracked_files_arg ,"complete" ))
1103+ s -> show_untracked_files = SHOW_COMPLETE_UNTRACKED_FILES ;
10411104 else
10421105 die (_ ("Invalid untracked files mode '%s'" ), untracked_files_arg );
10431106}
@@ -1266,6 +1329,19 @@ static int git_status_config(const char *k, const char *v, void *cb)
12661329 s -> relative_paths = git_config_bool (k , v );
12671330 return 0 ;
12681331 }
1332+ if (!strcmp (k , "status.deserializepath" )) {
1333+ /*
1334+ * Automatically assume deserialization if this is
1335+ * set in the config and the file exists. Do not
1336+ * complain if the file does not exist, because we
1337+ * silently fall back to normal mode.
1338+ */
1339+ if (v && * v && access (v , R_OK ) == 0 ) {
1340+ do_implicit_deserialize = 1 ;
1341+ deserialize_path = xstrdup (v );
1342+ }
1343+ return 0 ;
1344+ }
12691345 if (!strcmp (k , "status.showuntrackedfiles" )) {
12701346 if (!v )
12711347 return config_error_nonbool (k );
@@ -1308,7 +1384,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13081384 static int show_ignored_directory = 0 ;
13091385 static struct wt_status s ;
13101386 unsigned int progress_flag = 0 ;
1311- int fd ;
1387+ int try_deserialize ;
1388+ int fd = -1 ;
13121389 struct object_id oid ;
13131390 static struct option builtin_status_options [] = {
13141391 OPT__VERBOSE (& verbose , N_ ("be verbose" )),
@@ -1323,6 +1400,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13231400 { OPTION_CALLBACK , 0 , "porcelain" , & status_format ,
13241401 N_ ("version" ), N_ ("machine-readable output" ),
13251402 PARSE_OPT_OPTARG , opt_parse_porcelain },
1403+ { OPTION_CALLBACK , 0 , "serialize" , & status_format ,
1404+ N_ ("version" ), N_ ("serialize raw status data to stdout" ),
1405+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG , opt_parse_serialize },
1406+ { OPTION_CALLBACK , 0 , "deserialize" , NULL ,
1407+ N_ ("path" ), N_ ("deserialize raw status data from file" ),
1408+ PARSE_OPT_OPTARG , opt_parse_deserialize },
13261409 OPT_SET_INT (0 , "long" , & status_format ,
13271410 N_ ("show status in long format (default)" ),
13281411 STATUS_FORMAT_LONG ),
@@ -1383,10 +1466,26 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13831466 s .show_untracked_files == SHOW_NO_UNTRACKED_FILES )
13841467 die (_ ("Unsupported combination of ignored and untracked-files arguments" ));
13851468
1469+ if (s .show_untracked_files == SHOW_COMPLETE_UNTRACKED_FILES &&
1470+ s .show_ignored_mode == SHOW_NO_IGNORED )
1471+ die (_ ("Complete Untracked only supported with ignored files" ));
1472+
13861473 parse_pathspec (& s .pathspec , 0 ,
13871474 PATHSPEC_PREFER_FULL ,
13881475 prefix , argv );
13891476
1477+ /*
1478+ * If we want to try to deserialize status data from a cache file,
1479+ * we need to re-order the initialization code. The problem is that
1480+ * this makes for a very nasty diff and causes merge conflicts as we
1481+ * carry it forward. And it easy to mess up the merge, so we
1482+ * duplicate some code here to hopefully reduce conflicts.
1483+ */
1484+ try_deserialize = (!do_serialize &&
1485+ (do_implicit_deserialize || do_explicit_deserialize ));
1486+ if (try_deserialize )
1487+ goto skip_init ;
1488+
13901489 enable_fscache (0 );
13911490 if (status_format != STATUS_FORMAT_PORCELAIN &&
13921491 status_format != STATUS_FORMAT_PORCELAIN_V2 )
@@ -1401,6 +1500,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
14011500 else
14021501 fd = -1 ;
14031502
1503+ skip_init :
14041504 s .is_initial = get_oid (s .reference , & oid ) ? 1 : 0 ;
14051505 if (!s .is_initial )
14061506 hashcpy (s .sha1_commit , oid .hash );
@@ -1417,6 +1517,24 @@ int cmd_status(int argc, const char **argv, const char *prefix)
14171517 s .rename_score = parse_rename_score (& rename_score_arg );
14181518 }
14191519
1520+ if (try_deserialize ) {
1521+ if (s .relative_paths )
1522+ s .prefix = prefix ;
1523+
1524+ if (wt_status_deserialize (& s , deserialize_path ) == DESERIALIZE_OK )
1525+ return 0 ;
1526+
1527+ /* deserialize failed, so force the initialization we skipped above. */
1528+ enable_fscache (1 );
1529+ read_cache_preload (& s .pathspec );
1530+ refresh_index (& the_index , REFRESH_QUIET |REFRESH_UNMERGED , & s .pathspec , NULL , NULL );
1531+
1532+ if (use_optional_locks ())
1533+ fd = hold_locked_index (& index_lock , 0 );
1534+ else
1535+ fd = -1 ;
1536+ }
1537+
14201538 wt_status_collect (& s );
14211539
14221540 if (0 <= fd )
0 commit comments