@@ -160,6 +160,70 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
160160 return 0 ;
161161}
162162
163+ static int do_serialize = 0 ;
164+ static int do_implicit_deserialize = 0 ;
165+ static int do_explicit_deserialize = 0 ;
166+ static char * deserialize_path = NULL ;
167+
168+ /*
169+ * --serialize | --serialize=1 | --serialize=v1
170+ *
171+ * Request that we serialize our output rather than printing in
172+ * any of the established formats. Optionally specify serialization
173+ * version.
174+ */
175+ static int opt_parse_serialize (const struct option * opt , const char * arg , int unset )
176+ {
177+ enum wt_status_format * value = (enum wt_status_format * )opt -> value ;
178+ if (unset || !arg )
179+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
180+ else if (!strcmp (arg , "v1" ) || !strcmp (arg , "1" ))
181+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
182+ else
183+ die ("unsupported serialize version '%s'" , arg );
184+
185+ if (do_explicit_deserialize )
186+ die ("cannot mix --serialize and --deserialize" );
187+ do_implicit_deserialize = 0 ;
188+
189+ do_serialize = 1 ;
190+ return 0 ;
191+ }
192+
193+ /*
194+ * --deserialize | --deserialize=<path> |
195+ * --no-deserialize
196+ *
197+ * Request that we deserialize status data from some existing resource
198+ * rather than performing a status scan.
199+ *
200+ * The input source can come from stdin or a path given here -- or be
201+ * inherited from the config settings.
202+ */
203+ static int opt_parse_deserialize (const struct option * opt , const char * arg , int unset )
204+ {
205+ if (unset ) {
206+ do_implicit_deserialize = 0 ;
207+ do_explicit_deserialize = 0 ;
208+ } else {
209+ if (do_serialize )
210+ die ("cannot mix --serialize and --deserialize" );
211+ if (arg ) {
212+ /* override config or stdin */
213+ free (deserialize_path );
214+ deserialize_path = xstrdup (arg );
215+ }
216+ if (deserialize_path && * deserialize_path
217+ && (access (deserialize_path , R_OK ) != 0 ))
218+ die ("cannot find serialization file '%s'" ,
219+ deserialize_path );
220+
221+ do_explicit_deserialize = 1 ;
222+ }
223+
224+ return 0 ;
225+ }
226+
163227static int opt_parse_m (const struct option * opt , const char * arg , int unset )
164228{
165229 struct strbuf * buf = opt -> value ;
@@ -1152,6 +1216,8 @@ static void handle_untracked_files_arg(struct wt_status *s)
11521216 s -> show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES ;
11531217 else if (!strcmp (untracked_files_arg , "all" ))
11541218 s -> show_untracked_files = SHOW_ALL_UNTRACKED_FILES ;
1219+ else if (!strcmp (untracked_files_arg ,"complete" ))
1220+ s -> show_untracked_files = SHOW_COMPLETE_UNTRACKED_FILES ;
11551221 /*
11561222 * Please update $__git_untracked_file_modes in
11571223 * git-completion.bash when you add new options
@@ -1437,6 +1503,19 @@ static int git_status_config(const char *k, const char *v, void *cb)
14371503 s -> relative_paths = git_config_bool (k , v );
14381504 return 0 ;
14391505 }
1506+ if (!strcmp (k , "status.deserializepath" )) {
1507+ /*
1508+ * Automatically assume deserialization if this is
1509+ * set in the config and the file exists. Do not
1510+ * complain if the file does not exist, because we
1511+ * silently fall back to normal mode.
1512+ */
1513+ if (v && * v && access (v , R_OK ) == 0 ) {
1514+ do_implicit_deserialize = 1 ;
1515+ deserialize_path = xstrdup (v );
1516+ }
1517+ return 0 ;
1518+ }
14401519 if (!strcmp (k , "status.showuntrackedfiles" )) {
14411520 if (!v )
14421521 return config_error_nonbool (k );
@@ -1477,7 +1556,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
14771556 static const char * rename_score_arg = (const char * )-1 ;
14781557 static struct wt_status s ;
14791558 unsigned int progress_flag = 0 ;
1480- int fd ;
1559+ int try_deserialize ;
1560+ int fd = -1 ;
14811561 struct object_id oid ;
14821562 static struct option builtin_status_options [] = {
14831563 OPT__VERBOSE (& verbose , N_ ("be verbose" )),
@@ -1492,6 +1572,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
14921572 OPT_CALLBACK_F (0 , "porcelain" , & status_format ,
14931573 N_ ("version" ), N_ ("machine-readable output" ),
14941574 PARSE_OPT_OPTARG , opt_parse_porcelain ),
1575+ { OPTION_CALLBACK , 0 , "serialize" , & status_format ,
1576+ N_ ("version" ), N_ ("serialize raw status data to stdout" ),
1577+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG , opt_parse_serialize },
1578+ { OPTION_CALLBACK , 0 , "deserialize" , NULL ,
1579+ N_ ("path" ), N_ ("deserialize raw status data from file" ),
1580+ PARSE_OPT_OPTARG , opt_parse_deserialize },
14951581 OPT_SET_INT (0 , "long" , & status_format ,
14961582 N_ ("show status in long format (default)" ),
14971583 STATUS_FORMAT_LONG ),
@@ -1536,10 +1622,26 @@ int cmd_status(int argc, const char **argv, const char *prefix)
15361622 s .show_untracked_files == SHOW_NO_UNTRACKED_FILES )
15371623 die (_ ("Unsupported combination of ignored and untracked-files arguments" ));
15381624
1625+ if (s .show_untracked_files == SHOW_COMPLETE_UNTRACKED_FILES &&
1626+ s .show_ignored_mode == SHOW_NO_IGNORED )
1627+ die (_ ("Complete Untracked only supported with ignored files" ));
1628+
15391629 parse_pathspec (& s .pathspec , 0 ,
15401630 PATHSPEC_PREFER_FULL ,
15411631 prefix , argv );
15421632
1633+ /*
1634+ * If we want to try to deserialize status data from a cache file,
1635+ * we need to re-order the initialization code. The problem is that
1636+ * this makes for a very nasty diff and causes merge conflicts as we
1637+ * carry it forward. And it easy to mess up the merge, so we
1638+ * duplicate some code here to hopefully reduce conflicts.
1639+ */
1640+ try_deserialize = (!do_serialize &&
1641+ (do_implicit_deserialize || do_explicit_deserialize ));
1642+ if (try_deserialize )
1643+ goto skip_init ;
1644+
15431645 enable_fscache (0 );
15441646 if (status_format != STATUS_FORMAT_PORCELAIN &&
15451647 status_format != STATUS_FORMAT_PORCELAIN_V2 )
@@ -1554,6 +1656,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
15541656 else
15551657 fd = -1 ;
15561658
1659+ skip_init :
15571660 s .is_initial = get_oid (s .reference , & oid ) ? 1 : 0 ;
15581661 if (!s .is_initial )
15591662 oidcpy (& s .oid_commit , & oid );
@@ -1570,6 +1673,24 @@ int cmd_status(int argc, const char **argv, const char *prefix)
15701673 s .rename_score = parse_rename_score (& rename_score_arg );
15711674 }
15721675
1676+ if (try_deserialize ) {
1677+ if (s .relative_paths )
1678+ s .prefix = prefix ;
1679+
1680+ if (wt_status_deserialize (& s , deserialize_path ) == DESERIALIZE_OK )
1681+ return 0 ;
1682+
1683+ /* deserialize failed, so force the initialization we skipped above. */
1684+ enable_fscache (1 );
1685+ read_cache_preload (& s .pathspec );
1686+ refresh_index (& the_index , REFRESH_QUIET |REFRESH_UNMERGED , & s .pathspec , NULL , NULL );
1687+
1688+ if (use_optional_locks ())
1689+ fd = hold_locked_index (& index_lock , 0 );
1690+ else
1691+ fd = -1 ;
1692+ }
1693+
15731694 wt_status_collect (& s );
15741695
15751696 if (0 <= fd )
0 commit comments