@@ -164,6 +164,70 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
164164 return 0 ;
165165}
166166
167+ static int do_serialize = 0 ;
168+ static int do_implicit_deserialize = 0 ;
169+ static int do_explicit_deserialize = 0 ;
170+ static char * deserialize_path = NULL ;
171+
172+ /*
173+ * --serialize | --serialize=1 | --serialize=v1
174+ *
175+ * Request that we serialize our output rather than printing in
176+ * any of the established formats. Optionally specify serialization
177+ * version.
178+ */
179+ static int opt_parse_serialize (const struct option * opt , const char * arg , int unset )
180+ {
181+ enum wt_status_format * value = (enum wt_status_format * )opt -> value ;
182+ if (unset || !arg )
183+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
184+ else if (!strcmp (arg , "v1" ) || !strcmp (arg , "1" ))
185+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
186+ else
187+ die ("unsupported serialize version '%s'" , arg );
188+
189+ if (do_explicit_deserialize )
190+ die ("cannot mix --serialize and --deserialize" );
191+ do_implicit_deserialize = 0 ;
192+
193+ do_serialize = 1 ;
194+ return 0 ;
195+ }
196+
197+ /*
198+ * --deserialize | --deserialize=<path> |
199+ * --no-deserialize
200+ *
201+ * Request that we deserialize status data from some existing resource
202+ * rather than performing a status scan.
203+ *
204+ * The input source can come from stdin or a path given here -- or be
205+ * inherited from the config settings.
206+ */
207+ static int opt_parse_deserialize (const struct option * opt UNUSED , const char * arg , int unset )
208+ {
209+ if (unset ) {
210+ do_implicit_deserialize = 0 ;
211+ do_explicit_deserialize = 0 ;
212+ } else {
213+ if (do_serialize )
214+ die ("cannot mix --serialize and --deserialize" );
215+ if (arg ) {
216+ /* override config or stdin */
217+ free (deserialize_path );
218+ deserialize_path = xstrdup (arg );
219+ }
220+ if (deserialize_path && * deserialize_path
221+ && (access (deserialize_path , R_OK ) != 0 ))
222+ die ("cannot find serialization file '%s'" ,
223+ deserialize_path );
224+
225+ do_explicit_deserialize = 1 ;
226+ }
227+
228+ return 0 ;
229+ }
230+
167231static int opt_parse_m (const struct option * opt , const char * arg , int unset )
168232{
169233 struct strbuf * buf = opt -> value ;
@@ -1186,6 +1250,8 @@ static enum untracked_status_type parse_untracked_setting_name(const char *u)
11861250 return SHOW_NORMAL_UNTRACKED_FILES ;
11871251 else if (!strcmp (u , "all" ))
11881252 return SHOW_ALL_UNTRACKED_FILES ;
1253+ else if (!strcmp (u ,"complete" ))
1254+ return SHOW_COMPLETE_UNTRACKED_FILES ;
11891255 else
11901256 return SHOW_UNTRACKED_FILES_ERROR ;
11911257}
@@ -1481,6 +1547,19 @@ static int git_status_config(const char *k, const char *v,
14811547 s -> relative_paths = git_config_bool (k , v );
14821548 return 0 ;
14831549 }
1550+ if (!strcmp (k , "status.deserializepath" )) {
1551+ /*
1552+ * Automatically assume deserialization if this is
1553+ * set in the config and the file exists. Do not
1554+ * complain if the file does not exist, because we
1555+ * silently fall back to normal mode.
1556+ */
1557+ if (v && * v && access (v , R_OK ) == 0 ) {
1558+ do_implicit_deserialize = 1 ;
1559+ deserialize_path = xstrdup (v );
1560+ }
1561+ return 0 ;
1562+ }
14841563 if (!strcmp (k , "status.showuntrackedfiles" )) {
14851564 enum untracked_status_type u ;
14861565
@@ -1520,7 +1599,8 @@ struct repository *repo UNUSED)
15201599 static const char * rename_score_arg = (const char * )-1 ;
15211600 static struct wt_status s ;
15221601 unsigned int progress_flag = 0 ;
1523- int fd ;
1602+ int try_deserialize ;
1603+ int fd = -1 ;
15241604 struct object_id oid ;
15251605 static struct option builtin_status_options [] = {
15261606 OPT__VERBOSE (& verbose , N_ ("be verbose" )),
@@ -1535,6 +1615,12 @@ struct repository *repo UNUSED)
15351615 OPT_CALLBACK_F (0 , "porcelain" , & status_format ,
15361616 N_ ("version" ), N_ ("machine-readable output" ),
15371617 PARSE_OPT_OPTARG , opt_parse_porcelain ),
1618+ { OPTION_CALLBACK , 0 , "serialize" , & status_format ,
1619+ N_ ("version" ), N_ ("serialize raw status data to stdout" ),
1620+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG , opt_parse_serialize },
1621+ { OPTION_CALLBACK , 0 , "deserialize" , NULL ,
1622+ N_ ("path" ), N_ ("deserialize raw status data from file" ),
1623+ PARSE_OPT_OPTARG , opt_parse_deserialize },
15381624 OPT_SET_INT (0 , "long" , & status_format ,
15391625 N_ ("show status in long format (default)" ),
15401626 STATUS_FORMAT_LONG ),
@@ -1579,10 +1665,26 @@ struct repository *repo UNUSED)
15791665 s .show_untracked_files == SHOW_NO_UNTRACKED_FILES )
15801666 die (_ ("Unsupported combination of ignored and untracked-files arguments" ));
15811667
1668+ if (s .show_untracked_files == SHOW_COMPLETE_UNTRACKED_FILES &&
1669+ s .show_ignored_mode == SHOW_NO_IGNORED )
1670+ die (_ ("Complete Untracked only supported with ignored files" ));
1671+
15821672 parse_pathspec (& s .pathspec , 0 ,
15831673 PATHSPEC_PREFER_FULL ,
15841674 prefix , argv );
15851675
1676+ /*
1677+ * If we want to try to deserialize status data from a cache file,
1678+ * we need to re-order the initialization code. The problem is that
1679+ * this makes for a very nasty diff and causes merge conflicts as we
1680+ * carry it forward. And it easy to mess up the merge, so we
1681+ * duplicate some code here to hopefully reduce conflicts.
1682+ */
1683+ try_deserialize = (!do_serialize &&
1684+ (do_implicit_deserialize || do_explicit_deserialize ));
1685+ if (try_deserialize )
1686+ goto skip_init ;
1687+
15861688 enable_fscache (0 );
15871689 if (status_format != STATUS_FORMAT_PORCELAIN &&
15881690 status_format != STATUS_FORMAT_PORCELAIN_V2 )
@@ -1597,6 +1699,7 @@ struct repository *repo UNUSED)
15971699 else
15981700 fd = -1 ;
15991701
1702+ skip_init :
16001703 s .is_initial = repo_get_oid (the_repository , s .reference , & oid ) ? 1 : 0 ;
16011704 if (!s .is_initial )
16021705 oidcpy (& s .oid_commit , & oid );
@@ -1613,6 +1716,24 @@ struct repository *repo UNUSED)
16131716 s .rename_score = parse_rename_score (& rename_score_arg );
16141717 }
16151718
1719+ if (try_deserialize ) {
1720+ if (s .relative_paths )
1721+ s .prefix = prefix ;
1722+
1723+ if (wt_status_deserialize (& s , deserialize_path ) == DESERIALIZE_OK )
1724+ return 0 ;
1725+
1726+ /* deserialize failed, so force the initialization we skipped above. */
1727+ enable_fscache (1 );
1728+ repo_read_index_preload (the_repository , & s .pathspec , 0 );
1729+ refresh_index (the_repository -> index , REFRESH_QUIET |REFRESH_UNMERGED , & s .pathspec , NULL , NULL );
1730+
1731+ if (use_optional_locks ())
1732+ fd = repo_hold_locked_index (the_repository , & index_lock , 0 );
1733+ else
1734+ fd = -1 ;
1735+ }
1736+
16161737 wt_status_collect (& s );
16171738
16181739 if (0 <= fd )
0 commit comments