@@ -164,6 +164,70 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
164
164
return 0 ;
165
165
}
166
166
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
+
167
231
static int opt_parse_m (const struct option * opt , const char * arg , int unset )
168
232
{
169
233
struct strbuf * buf = opt -> value ;
@@ -1188,6 +1252,8 @@ static enum untracked_status_type parse_untracked_setting_name(const char *u)
1188
1252
return SHOW_NORMAL_UNTRACKED_FILES ;
1189
1253
else if (!strcmp (u , "all" ))
1190
1254
return SHOW_ALL_UNTRACKED_FILES ;
1255
+ else if (!strcmp (u ,"complete" ))
1256
+ return SHOW_COMPLETE_UNTRACKED_FILES ;
1191
1257
else
1192
1258
return SHOW_UNTRACKED_FILES_ERROR ;
1193
1259
}
@@ -1483,6 +1549,19 @@ static int git_status_config(const char *k, const char *v,
1483
1549
s -> relative_paths = git_config_bool (k , v );
1484
1550
return 0 ;
1485
1551
}
1552
+ if (!strcmp (k , "status.deserializepath" )) {
1553
+ /*
1554
+ * Automatically assume deserialization if this is
1555
+ * set in the config and the file exists. Do not
1556
+ * complain if the file does not exist, because we
1557
+ * silently fall back to normal mode.
1558
+ */
1559
+ if (v && * v && access (v , R_OK ) == 0 ) {
1560
+ do_implicit_deserialize = 1 ;
1561
+ deserialize_path = xstrdup (v );
1562
+ }
1563
+ return 0 ;
1564
+ }
1486
1565
if (!strcmp (k , "status.showuntrackedfiles" )) {
1487
1566
enum untracked_status_type u ;
1488
1567
@@ -1522,7 +1601,8 @@ struct repository *repo UNUSED)
1522
1601
static const char * rename_score_arg = (const char * )-1 ;
1523
1602
static struct wt_status s ;
1524
1603
unsigned int progress_flag = 0 ;
1525
- int fd ;
1604
+ int try_deserialize ;
1605
+ int fd = -1 ;
1526
1606
struct object_id oid ;
1527
1607
static struct option builtin_status_options [] = {
1528
1608
OPT__VERBOSE (& verbose , N_ ("be verbose" )),
@@ -1537,6 +1617,12 @@ struct repository *repo UNUSED)
1537
1617
OPT_CALLBACK_F (0 , "porcelain" , & status_format ,
1538
1618
N_ ("version" ), N_ ("machine-readable output" ),
1539
1619
PARSE_OPT_OPTARG , opt_parse_porcelain ),
1620
+ { OPTION_CALLBACK , 0 , "serialize" , & status_format ,
1621
+ N_ ("version" ), N_ ("serialize raw status data to stdout" ),
1622
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG , opt_parse_serialize },
1623
+ { OPTION_CALLBACK , 0 , "deserialize" , NULL ,
1624
+ N_ ("path" ), N_ ("deserialize raw status data from file" ),
1625
+ PARSE_OPT_OPTARG , opt_parse_deserialize },
1540
1626
OPT_SET_INT (0 , "long" , & status_format ,
1541
1627
N_ ("show status in long format (default)" ),
1542
1628
STATUS_FORMAT_LONG ),
@@ -1581,10 +1667,26 @@ struct repository *repo UNUSED)
1581
1667
s .show_untracked_files == SHOW_NO_UNTRACKED_FILES )
1582
1668
die (_ ("Unsupported combination of ignored and untracked-files arguments" ));
1583
1669
1670
+ if (s .show_untracked_files == SHOW_COMPLETE_UNTRACKED_FILES &&
1671
+ s .show_ignored_mode == SHOW_NO_IGNORED )
1672
+ die (_ ("Complete Untracked only supported with ignored files" ));
1673
+
1584
1674
parse_pathspec (& s .pathspec , 0 ,
1585
1675
PATHSPEC_PREFER_FULL ,
1586
1676
prefix , argv );
1587
1677
1678
+ /*
1679
+ * If we want to try to deserialize status data from a cache file,
1680
+ * we need to re-order the initialization code. The problem is that
1681
+ * this makes for a very nasty diff and causes merge conflicts as we
1682
+ * carry it forward. And it easy to mess up the merge, so we
1683
+ * duplicate some code here to hopefully reduce conflicts.
1684
+ */
1685
+ try_deserialize = (!do_serialize &&
1686
+ (do_implicit_deserialize || do_explicit_deserialize ));
1687
+ if (try_deserialize )
1688
+ goto skip_init ;
1689
+
1588
1690
enable_fscache (0 );
1589
1691
if (status_format != STATUS_FORMAT_PORCELAIN &&
1590
1692
status_format != STATUS_FORMAT_PORCELAIN_V2 )
@@ -1599,6 +1701,7 @@ struct repository *repo UNUSED)
1599
1701
else
1600
1702
fd = -1 ;
1601
1703
1704
+ skip_init :
1602
1705
s .is_initial = repo_get_oid (the_repository , s .reference , & oid ) ? 1 : 0 ;
1603
1706
if (!s .is_initial )
1604
1707
oidcpy (& s .oid_commit , & oid );
@@ -1615,6 +1718,24 @@ struct repository *repo UNUSED)
1615
1718
s .rename_score = parse_rename_score (& rename_score_arg );
1616
1719
}
1617
1720
1721
+ if (try_deserialize ) {
1722
+ if (s .relative_paths )
1723
+ s .prefix = prefix ;
1724
+
1725
+ if (wt_status_deserialize (& s , deserialize_path ) == DESERIALIZE_OK )
1726
+ return 0 ;
1727
+
1728
+ /* deserialize failed, so force the initialization we skipped above. */
1729
+ enable_fscache (1 );
1730
+ repo_read_index_preload (the_repository , & s .pathspec , 0 );
1731
+ refresh_index (the_repository -> index , REFRESH_QUIET |REFRESH_UNMERGED , & s .pathspec , NULL , NULL );
1732
+
1733
+ if (use_optional_locks ())
1734
+ fd = repo_hold_locked_index (the_repository , & index_lock , 0 );
1735
+ else
1736
+ fd = -1 ;
1737
+ }
1738
+
1618
1739
wt_status_collect (& s );
1619
1740
1620
1741
if (0 <= fd )
0 commit comments