@@ -166,6 +166,70 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
166166 return 0 ;
167167}
168168
169+ static int do_serialize = 0 ;
170+ static int do_implicit_deserialize = 0 ;
171+ static int do_explicit_deserialize = 0 ;
172+ static char * deserialize_path = NULL ;
173+
174+ /*
175+ * --serialize | --serialize=1 | --serialize=v1
176+ *
177+ * Request that we serialize our output rather than printing in
178+ * any of the established formats. Optionally specify serialization
179+ * version.
180+ */
181+ static int opt_parse_serialize (const struct option * opt , const char * arg , int unset )
182+ {
183+ enum wt_status_format * value = (enum wt_status_format * )opt -> value ;
184+ if (unset || !arg )
185+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
186+ else if (!strcmp (arg , "v1" ) || !strcmp (arg , "1" ))
187+ * value = STATUS_FORMAT_SERIALIZE_V1 ;
188+ else
189+ die ("unsupported serialize version '%s'" , arg );
190+
191+ if (do_explicit_deserialize )
192+ die ("cannot mix --serialize and --deserialize" );
193+ do_implicit_deserialize = 0 ;
194+
195+ do_serialize = 1 ;
196+ return 0 ;
197+ }
198+
199+ /*
200+ * --deserialize | --deserialize=<path> |
201+ * --no-deserialize
202+ *
203+ * Request that we deserialize status data from some existing resource
204+ * rather than performing a status scan.
205+ *
206+ * The input source can come from stdin or a path given here -- or be
207+ * inherited from the config settings.
208+ */
209+ static int opt_parse_deserialize (const struct option * opt UNUSED , const char * arg , int unset )
210+ {
211+ if (unset ) {
212+ do_implicit_deserialize = 0 ;
213+ do_explicit_deserialize = 0 ;
214+ } else {
215+ if (do_serialize )
216+ die ("cannot mix --serialize and --deserialize" );
217+ if (arg ) {
218+ /* override config or stdin */
219+ free (deserialize_path );
220+ deserialize_path = xstrdup (arg );
221+ }
222+ if (deserialize_path && * deserialize_path
223+ && (access (deserialize_path , R_OK ) != 0 ))
224+ die ("cannot find serialization file '%s'" ,
225+ deserialize_path );
226+
227+ do_explicit_deserialize = 1 ;
228+ }
229+
230+ return 0 ;
231+ }
232+
169233static int opt_parse_m (const struct option * opt , const char * arg , int unset )
170234{
171235 struct strbuf * buf = opt -> value ;
@@ -1208,6 +1272,8 @@ static enum untracked_status_type parse_untracked_setting_name(const char *u)
12081272 return SHOW_NORMAL_UNTRACKED_FILES ;
12091273 else if (!strcmp (u , "all" ))
12101274 return SHOW_ALL_UNTRACKED_FILES ;
1275+ else if (!strcmp (u ,"complete" ))
1276+ return SHOW_COMPLETE_UNTRACKED_FILES ;
12111277 else
12121278 return SHOW_UNTRACKED_FILES_ERROR ;
12131279}
@@ -1503,6 +1569,19 @@ static int git_status_config(const char *k, const char *v,
15031569 s -> relative_paths = git_config_bool (k , v );
15041570 return 0 ;
15051571 }
1572+ if (!strcmp (k , "status.deserializepath" )) {
1573+ /*
1574+ * Automatically assume deserialization if this is
1575+ * set in the config and the file exists. Do not
1576+ * complain if the file does not exist, because we
1577+ * silently fall back to normal mode.
1578+ */
1579+ if (v && * v && access (v , R_OK ) == 0 ) {
1580+ do_implicit_deserialize = 1 ;
1581+ deserialize_path = xstrdup (v );
1582+ }
1583+ return 0 ;
1584+ }
15061585 if (!strcmp (k , "status.showuntrackedfiles" )) {
15071586 enum untracked_status_type u ;
15081587
@@ -1542,7 +1621,8 @@ struct repository *repo UNUSED)
15421621 static const char * rename_score_arg = (const char * )-1 ;
15431622 static struct wt_status s ;
15441623 unsigned int progress_flag = 0 ;
1545- int fd ;
1624+ int try_deserialize ;
1625+ int fd = -1 ;
15461626 struct object_id oid ;
15471627 static struct option builtin_status_options [] = {
15481628 OPT__VERBOSE (& verbose , N_ ("be verbose" )),
@@ -1557,6 +1637,12 @@ struct repository *repo UNUSED)
15571637 OPT_CALLBACK_F (0 , "porcelain" , & status_format ,
15581638 N_ ("version" ), N_ ("machine-readable output" ),
15591639 PARSE_OPT_OPTARG , opt_parse_porcelain ),
1640+ OPT_CALLBACK_F (0 , "serialize" , & status_format ,
1641+ N_ ("version" ), N_ ("serialize raw status data to stdout" ),
1642+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG , opt_parse_serialize ),
1643+ OPT_CALLBACK_F (0 , "deserialize" , NULL ,
1644+ N_ ("path" ), N_ ("deserialize raw status data from file" ),
1645+ PARSE_OPT_OPTARG , opt_parse_deserialize ),
15601646 OPT_SET_INT (0 , "long" , & status_format ,
15611647 N_ ("show status in long format (default)" ),
15621648 STATUS_FORMAT_LONG ),
@@ -1618,10 +1704,26 @@ struct repository *repo UNUSED)
16181704 s .show_untracked_files == SHOW_NO_UNTRACKED_FILES )
16191705 die (_ ("Unsupported combination of ignored and untracked-files arguments" ));
16201706
1707+ if (s .show_untracked_files == SHOW_COMPLETE_UNTRACKED_FILES &&
1708+ s .show_ignored_mode == SHOW_NO_IGNORED )
1709+ die (_ ("Complete Untracked only supported with ignored files" ));
1710+
16211711 parse_pathspec (& s .pathspec , 0 ,
16221712 PATHSPEC_PREFER_FULL ,
16231713 prefix , argv );
16241714
1715+ /*
1716+ * If we want to try to deserialize status data from a cache file,
1717+ * we need to re-order the initialization code. The problem is that
1718+ * this makes for a very nasty diff and causes merge conflicts as we
1719+ * carry it forward. And it easy to mess up the merge, so we
1720+ * duplicate some code here to hopefully reduce conflicts.
1721+ */
1722+ try_deserialize = (!do_serialize &&
1723+ (do_implicit_deserialize || do_explicit_deserialize ));
1724+ if (try_deserialize )
1725+ goto skip_init ;
1726+
16251727 enable_fscache (0 );
16261728 if (status_format != STATUS_FORMAT_PORCELAIN &&
16271729 status_format != STATUS_FORMAT_PORCELAIN_V2 )
@@ -1636,6 +1738,7 @@ struct repository *repo UNUSED)
16361738 else
16371739 fd = -1 ;
16381740
1741+ skip_init :
16391742 s .is_initial = repo_get_oid (the_repository , s .reference , & oid ) ? 1 : 0 ;
16401743 if (!s .is_initial )
16411744 oidcpy (& s .oid_commit , & oid );
@@ -1652,6 +1755,24 @@ struct repository *repo UNUSED)
16521755 s .rename_score = parse_rename_score (& rename_score_arg );
16531756 }
16541757
1758+ if (try_deserialize ) {
1759+ if (s .relative_paths )
1760+ s .prefix = prefix ;
1761+
1762+ if (wt_status_deserialize (& s , deserialize_path ) == DESERIALIZE_OK )
1763+ return 0 ;
1764+
1765+ /* deserialize failed, so force the initialization we skipped above. */
1766+ enable_fscache (1 );
1767+ repo_read_index_preload (the_repository , & s .pathspec , 0 );
1768+ refresh_index (the_repository -> index , REFRESH_QUIET |REFRESH_UNMERGED , & s .pathspec , NULL , NULL );
1769+
1770+ if (use_optional_locks ())
1771+ fd = repo_hold_locked_index (the_repository , & index_lock , 0 );
1772+ else
1773+ fd = -1 ;
1774+ }
1775+
16551776 wt_status_collect (& s );
16561777
16571778 if (0 <= fd )
0 commit comments