@@ -23,6 +23,9 @@ static const char * const git_stash_helper_usage[] = {
2323 N_ ("git stash--helper ( pop | apply ) [--index] [-q|--quiet] [<stash>]" ),
2424 N_ ("git stash--helper branch <branchname> [<stash>]" ),
2525 N_ ("git stash--helper clear" ),
26+ N_ ("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
27+ " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
28+ " [--] [<pathspec>...]]" ),
2629 NULL
2730};
2831
@@ -71,6 +74,13 @@ static const char * const git_stash_helper_create_usage[] = {
7174 NULL
7275};
7376
77+ static const char * const git_stash_helper_push_usage [] = {
78+ N_ ("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
79+ " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
80+ " [--] [<pathspec>...]]" ),
81+ NULL
82+ };
83+
7484static const char * ref_stash = "refs/stash" ;
7585static struct strbuf stash_index_path = STRBUF_INIT ;
7686
@@ -1088,7 +1098,7 @@ static int stash_working_tree(struct stash_info *info, struct pathspec ps)
10881098
10891099static int do_create_stash (struct pathspec ps , struct strbuf * stash_msg_buf ,
10901100 int include_untracked , int patch_mode ,
1091- struct stash_info * info )
1101+ struct stash_info * info , struct strbuf * patch )
10921102{
10931103 int ret = 0 ;
10941104 int flags = 0 ;
@@ -1101,7 +1111,6 @@ static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
11011111 struct strbuf msg = STRBUF_INIT ;
11021112 struct strbuf commit_tree_label = STRBUF_INIT ;
11031113 struct strbuf untracked_files = STRBUF_INIT ;
1104- struct strbuf patch = STRBUF_INIT ;
11051114
11061115 prepare_fallback_ident ("git stash" , "git@stash" );
11071116
@@ -1150,7 +1159,7 @@ static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
11501159 untracked_commit_option = 1 ;
11511160 }
11521161 if (patch_mode ) {
1153- ret = stash_patch (info , ps , & patch );
1162+ ret = stash_patch (info , ps , patch );
11541163 if (ret < 0 ) {
11551164 fprintf_ln (stderr , _ ("Cannot save the current "
11561165 "worktree state" ));
@@ -1221,7 +1230,8 @@ static int create_stash(int argc, const char **argv, const char *prefix)
12211230
12221231 memset (& ps , 0 , sizeof (ps ));
12231232 strbuf_addstr (& stash_msg_buf , stash_msg );
1224- ret = do_create_stash (ps , & stash_msg_buf , include_untracked , 0 , & info );
1233+ ret = do_create_stash (ps , & stash_msg_buf , include_untracked , 0 , & info ,
1234+ NULL );
12251235 if (!ret )
12261236 printf_ln ("%s" , oid_to_hex (& info .w_commit ));
12271237
@@ -1234,6 +1244,232 @@ static int create_stash(int argc, const char **argv, const char *prefix)
12341244 return ret < 0 ;
12351245}
12361246
1247+ static int do_push_stash (struct pathspec ps , const char * stash_msg , int quiet ,
1248+ int keep_index , int patch_mode , int include_untracked )
1249+ {
1250+ int ret = 0 ;
1251+ struct stash_info info ;
1252+ struct strbuf patch = STRBUF_INIT ;
1253+ struct strbuf stash_msg_buf = STRBUF_INIT ;
1254+
1255+ if (patch_mode && keep_index == -1 )
1256+ keep_index = 1 ;
1257+
1258+ if (patch_mode && include_untracked ) {
1259+ fprintf_ln (stderr , _ ("Can't use --patch and --include-untracked"
1260+ " or --all at the same time" ));
1261+ ret = -1 ;
1262+ goto done ;
1263+ }
1264+
1265+ read_cache_preload (NULL );
1266+ if (!include_untracked && ps .nr ) {
1267+ int i ;
1268+ char * ps_matched = xcalloc (ps .nr , 1 );
1269+
1270+ for (i = 0 ; i < active_nr ; i ++ )
1271+ ce_path_match (& the_index , active_cache [i ], & ps ,
1272+ ps_matched );
1273+
1274+ if (report_path_error (ps_matched , & ps , NULL )) {
1275+ fprintf_ln (stderr , _ ("Did you forget to 'git add'?" ));
1276+ ret = -1 ;
1277+ free (ps_matched );
1278+ goto done ;
1279+ }
1280+ free (ps_matched );
1281+ }
1282+
1283+ if (refresh_cache (REFRESH_QUIET )) {
1284+ ret = -1 ;
1285+ goto done ;
1286+ }
1287+
1288+ if (!check_changes (ps , include_untracked )) {
1289+ if (!quiet )
1290+ printf_ln (_ ("No local changes to save" ));
1291+ goto done ;
1292+ }
1293+
1294+ if (!reflog_exists (ref_stash ) && do_clear_stash ()) {
1295+ ret = -1 ;
1296+ fprintf_ln (stderr , _ ("Cannot initialize stash" ));
1297+ goto done ;
1298+ }
1299+
1300+ if (stash_msg )
1301+ strbuf_addstr (& stash_msg_buf , stash_msg );
1302+ if (do_create_stash (ps , & stash_msg_buf , include_untracked , patch_mode ,
1303+ & info , & patch )) {
1304+ ret = -1 ;
1305+ goto done ;
1306+ }
1307+
1308+ if (do_store_stash (& info .w_commit , stash_msg_buf .buf , 1 )) {
1309+ ret = -1 ;
1310+ fprintf_ln (stderr , _ ("Cannot save the current status" ));
1311+ goto done ;
1312+ }
1313+
1314+ printf_ln (_ ("Saved working directory and index state %s" ),
1315+ stash_msg_buf .buf );
1316+
1317+ if (!patch_mode ) {
1318+ if (include_untracked && !ps .nr ) {
1319+ struct child_process cp = CHILD_PROCESS_INIT ;
1320+
1321+ cp .git_cmd = 1 ;
1322+ argv_array_pushl (& cp .args , "clean" , "--force" ,
1323+ "--quiet" , "-d" , NULL );
1324+ if (include_untracked == INCLUDE_ALL_FILES )
1325+ argv_array_push (& cp .args , "-x" );
1326+ if (run_command (& cp )) {
1327+ ret = -1 ;
1328+ goto done ;
1329+ }
1330+ }
1331+ discard_cache ();
1332+ if (ps .nr ) {
1333+ struct child_process cp_add = CHILD_PROCESS_INIT ;
1334+ struct child_process cp_diff = CHILD_PROCESS_INIT ;
1335+ struct child_process cp_apply = CHILD_PROCESS_INIT ;
1336+ struct strbuf out = STRBUF_INIT ;
1337+
1338+ cp_add .git_cmd = 1 ;
1339+ argv_array_push (& cp_add .args , "add" );
1340+ if (!include_untracked )
1341+ argv_array_push (& cp_add .args , "-u" );
1342+ if (include_untracked == INCLUDE_ALL_FILES )
1343+ argv_array_push (& cp_add .args , "--force" );
1344+ argv_array_push (& cp_add .args , "--" );
1345+ add_pathspecs (& cp_add .args , ps );
1346+ if (run_command (& cp_add )) {
1347+ ret = -1 ;
1348+ goto done ;
1349+ }
1350+
1351+ cp_diff .git_cmd = 1 ;
1352+ argv_array_pushl (& cp_diff .args , "diff-index" , "-p" ,
1353+ "--cached" , "--binary" , "HEAD" , "--" ,
1354+ NULL );
1355+ add_pathspecs (& cp_diff .args , ps );
1356+ if (pipe_command (& cp_diff , NULL , 0 , & out , 0 , NULL , 0 )) {
1357+ ret = -1 ;
1358+ goto done ;
1359+ }
1360+
1361+ cp_apply .git_cmd = 1 ;
1362+ argv_array_pushl (& cp_apply .args , "apply" , "--index" ,
1363+ "-R" , NULL );
1364+ if (pipe_command (& cp_apply , out .buf , out .len , NULL , 0 ,
1365+ NULL , 0 )) {
1366+ ret = -1 ;
1367+ goto done ;
1368+ }
1369+ } else {
1370+ struct child_process cp = CHILD_PROCESS_INIT ;
1371+ cp .git_cmd = 1 ;
1372+ argv_array_pushl (& cp .args , "reset" , "--hard" , "-q" ,
1373+ NULL );
1374+ if (run_command (& cp )) {
1375+ ret = -1 ;
1376+ goto done ;
1377+ }
1378+ }
1379+
1380+ if (keep_index == 1 && !is_null_oid (& info .i_tree )) {
1381+ struct child_process cp_ls = CHILD_PROCESS_INIT ;
1382+ struct child_process cp_checkout = CHILD_PROCESS_INIT ;
1383+ struct strbuf out = STRBUF_INIT ;
1384+
1385+ if (reset_tree (& info .i_tree , 0 , 1 )) {
1386+ ret = -1 ;
1387+ goto done ;
1388+ }
1389+
1390+ cp_ls .git_cmd = 1 ;
1391+ argv_array_pushl (& cp_ls .args , "ls-files" , "-z" ,
1392+ "--modified" , "--" , NULL );
1393+
1394+ add_pathspecs (& cp_ls .args , ps );
1395+ if (pipe_command (& cp_ls , NULL , 0 , & out , 0 , NULL , 0 )) {
1396+ ret = -1 ;
1397+ goto done ;
1398+ }
1399+
1400+ cp_checkout .git_cmd = 1 ;
1401+ argv_array_pushl (& cp_checkout .args , "checkout-index" ,
1402+ "-z" , "--force" , "--stdin" , NULL );
1403+ if (pipe_command (& cp_checkout , out .buf , out .len , NULL ,
1404+ 0 , NULL , 0 )) {
1405+ ret = -1 ;
1406+ goto done ;
1407+ }
1408+ }
1409+ goto done ;
1410+ } else {
1411+ struct child_process cp = CHILD_PROCESS_INIT ;
1412+
1413+ cp .git_cmd = 1 ;
1414+ argv_array_pushl (& cp .args , "apply" , "-R" , NULL );
1415+
1416+ if (pipe_command (& cp , patch .buf , patch .len , NULL , 0 , NULL , 0 )) {
1417+ fprintf_ln (stderr , _ ("Cannot remove worktree changes" ));
1418+ ret = -1 ;
1419+ goto done ;
1420+ }
1421+
1422+ if (keep_index < 1 ) {
1423+ struct child_process cp = CHILD_PROCESS_INIT ;
1424+
1425+ cp .git_cmd = 1 ;
1426+ argv_array_pushl (& cp .args , "reset" , "-q" , "--" , NULL );
1427+ add_pathspecs (& cp .args , ps );
1428+ if (run_command (& cp )) {
1429+ ret = -1 ;
1430+ goto done ;
1431+ }
1432+ }
1433+ goto done ;
1434+ }
1435+
1436+ done :
1437+ strbuf_release (& stash_msg_buf );
1438+ return ret ;
1439+ }
1440+
1441+ static int push_stash (int argc , const char * * argv , const char * prefix )
1442+ {
1443+ int keep_index = -1 ;
1444+ int patch_mode = 0 ;
1445+ int include_untracked = 0 ;
1446+ int quiet = 0 ;
1447+ const char * stash_msg = NULL ;
1448+ struct pathspec ps ;
1449+ struct option options [] = {
1450+ OPT_BOOL ('k' , "keep-index" , & keep_index ,
1451+ N_ ("keep index" )),
1452+ OPT_BOOL ('p' , "patch" , & patch_mode ,
1453+ N_ ("stash in patch mode" )),
1454+ OPT__QUIET (& quiet , N_ ("quiet mode" )),
1455+ OPT_BOOL ('u' , "include-untracked" , & include_untracked ,
1456+ N_ ("include untracked files in stash" )),
1457+ OPT_SET_INT ('a' , "all" , & include_untracked ,
1458+ N_ ("include ignore files" ), 2 ),
1459+ OPT_STRING ('m' , "message" , & stash_msg , N_ ("message" ),
1460+ N_ ("stash message" )),
1461+ OPT_END ()
1462+ };
1463+
1464+ argc = parse_options (argc , argv , prefix , options ,
1465+ git_stash_helper_push_usage ,
1466+ 0 );
1467+
1468+ parse_pathspec (& ps , 0 , PATHSPEC_PREFER_FULL , prefix , argv );
1469+ return do_push_stash (ps , stash_msg , quiet , keep_index , patch_mode ,
1470+ include_untracked );
1471+ }
1472+
12371473int cmd_stash__helper (int argc , const char * * argv , const char * prefix )
12381474{
12391475 pid_t pid = getpid ();
@@ -1272,6 +1508,8 @@ int cmd_stash__helper(int argc, const char **argv, const char *prefix)
12721508 return !!store_stash (argc , argv , prefix );
12731509 else if (!strcmp (argv [0 ], "create" ))
12741510 return !!create_stash (argc , argv , prefix );
1511+ else if (!strcmp (argv [0 ], "push" ))
1512+ return !!push_stash (argc , argv , prefix );
12751513
12761514 usage_msg_opt (xstrfmt (_ ("unknown subcommand: %s" ), argv [0 ]),
12771515 git_stash_helper_usage , options );
0 commit comments