@@ -24,6 +24,9 @@ static const char * const git_stash_helper_usage[] = {
2424 N_ ("git stash--helper ( pop | apply ) [--index] [-q|--quiet] [<stash>]" ),
2525 N_ ("git stash--helper branch <branchname> [<stash>]" ),
2626 N_ ("git stash--helper clear" ),
27+ N_ ("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
28+ " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
29+ " [--] [<pathspec>...]]" ),
2730 NULL
2831};
2932
@@ -72,6 +75,13 @@ static const char * const git_stash_helper_create_usage[] = {
7275 NULL
7376};
7477
78+ static const char * const git_stash_helper_push_usage [] = {
79+ N_ ("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
80+ " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
81+ " [--] [<pathspec>...]]" ),
82+ NULL
83+ };
84+
7585static const char * ref_stash = "refs/stash" ;
7686static struct strbuf stash_index_path = STRBUF_INIT ;
7787
@@ -1094,7 +1104,7 @@ static int stash_working_tree(struct stash_info *info, struct pathspec ps)
10941104
10951105static int do_create_stash (struct pathspec ps , struct strbuf * stash_msg_buf ,
10961106 int include_untracked , int patch_mode ,
1097- struct stash_info * info )
1107+ struct stash_info * info , struct strbuf * patch )
10981108{
10991109 int ret = 0 ;
11001110 int flags = 0 ;
@@ -1107,7 +1117,6 @@ static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
11071117 struct strbuf msg = STRBUF_INIT ;
11081118 struct strbuf commit_tree_label = STRBUF_INIT ;
11091119 struct strbuf untracked_files = STRBUF_INIT ;
1110- struct strbuf patch = STRBUF_INIT ;
11111120
11121121 prepare_fallback_ident ("git stash" , "git@stash" );
11131122
@@ -1156,7 +1165,7 @@ static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
11561165 untracked_commit_option = 1 ;
11571166 }
11581167 if (patch_mode ) {
1159- ret = stash_patch (info , ps , & patch );
1168+ ret = stash_patch (info , ps , patch );
11601169 if (ret < 0 ) {
11611170 fprintf_ln (stderr , _ ("Cannot save the current "
11621171 "worktree state" ));
@@ -1227,7 +1236,8 @@ static int create_stash(int argc, const char **argv, const char *prefix)
12271236
12281237 memset (& ps , 0 , sizeof (ps ));
12291238 strbuf_addstr (& stash_msg_buf , stash_msg );
1230- ret = do_create_stash (ps , & stash_msg_buf , include_untracked , 0 , & info );
1239+ ret = do_create_stash (ps , & stash_msg_buf , include_untracked , 0 , & info ,
1240+ NULL );
12311241
12321242 if (!ret )
12331243 printf_ln ("%s" , oid_to_hex (& info .w_commit ));
@@ -1241,6 +1251,231 @@ static int create_stash(int argc, const char **argv, const char *prefix)
12411251 return ret < 0 ;
12421252}
12431253
1254+ static int do_push_stash (struct pathspec ps , const char * stash_msg , int quiet ,
1255+ int keep_index , int patch_mode , int include_untracked )
1256+ {
1257+ int ret = 0 ;
1258+ struct stash_info info ;
1259+ struct strbuf patch = STRBUF_INIT ;
1260+ struct strbuf stash_msg_buf = STRBUF_INIT ;
1261+
1262+ if (patch_mode && keep_index == -1 )
1263+ keep_index = 1 ;
1264+
1265+ if (patch_mode && include_untracked ) {
1266+ fprintf_ln (stderr , _ ("Can't use --patch and --include-untracked"
1267+ " or --all at the same time" ));
1268+ ret = -1 ;
1269+ goto done ;
1270+ }
1271+
1272+ read_cache_preload (NULL );
1273+ if (!include_untracked && ps .nr ) {
1274+ int i ;
1275+ char * ps_matched = xcalloc (ps .nr , 1 );
1276+
1277+ for (i = 0 ; i < active_nr ; i ++ )
1278+ ce_path_match (& the_index , active_cache [i ], & ps ,
1279+ ps_matched );
1280+
1281+ if (report_path_error (ps_matched , & ps , NULL )) {
1282+ fprintf_ln (stderr , _ ("Did you forget to 'git add'?" ));
1283+ ret = -1 ;
1284+ free (ps_matched );
1285+ goto done ;
1286+ }
1287+ free (ps_matched );
1288+ }
1289+
1290+ if (refresh_cache (REFRESH_QUIET )) {
1291+ ret = -1 ;
1292+ goto done ;
1293+ }
1294+
1295+ if (!check_changes (ps , include_untracked )) {
1296+ if (!quiet )
1297+ printf_ln (_ ("No local changes to save" ));
1298+ goto done ;
1299+ }
1300+
1301+ if (!reflog_exists (ref_stash ) && do_clear_stash ()) {
1302+ ret = -1 ;
1303+ fprintf_ln (stderr , _ ("Cannot initialize stash" ));
1304+ goto done ;
1305+ }
1306+
1307+ if (stash_msg )
1308+ strbuf_addstr (& stash_msg_buf , stash_msg );
1309+ if (do_create_stash (ps , & stash_msg_buf , include_untracked , patch_mode ,
1310+ & info , & patch )) {
1311+ ret = -1 ;
1312+ goto done ;
1313+ }
1314+
1315+ if (do_store_stash (& info .w_commit , stash_msg_buf .buf , 1 )) {
1316+ ret = -1 ;
1317+ fprintf_ln (stderr , _ ("Cannot save the current status" ));
1318+ goto done ;
1319+ }
1320+
1321+ printf_ln (_ ("Saved working directory and index state %s" ),
1322+ stash_msg_buf .buf );
1323+
1324+ if (!patch_mode ) {
1325+ if (include_untracked && !ps .nr ) {
1326+ struct child_process cp = CHILD_PROCESS_INIT ;
1327+
1328+ cp .git_cmd = 1 ;
1329+ argv_array_pushl (& cp .args , "clean" , "--force" ,
1330+ "--quiet" , "-d" , NULL );
1331+ if (include_untracked == INCLUDE_ALL_FILES )
1332+ argv_array_push (& cp .args , "-x" );
1333+ if (run_command (& cp )) {
1334+ ret = -1 ;
1335+ goto done ;
1336+ }
1337+ }
1338+ if (ps .nr ) {
1339+ struct child_process cp_add = CHILD_PROCESS_INIT ;
1340+ struct child_process cp_diff = CHILD_PROCESS_INIT ;
1341+ struct child_process cp_apply = CHILD_PROCESS_INIT ;
1342+ struct strbuf out = STRBUF_INIT ;
1343+
1344+ cp_add .git_cmd = 1 ;
1345+ argv_array_push (& cp_add .args , "add" );
1346+ if (!include_untracked )
1347+ argv_array_push (& cp_add .args , "-u" );
1348+ if (include_untracked == INCLUDE_ALL_FILES )
1349+ argv_array_push (& cp_add .args , "--force" );
1350+ argv_array_push (& cp_add .args , "--" );
1351+ add_pathspecs (& cp_add .args , ps );
1352+ if (run_command (& cp_add )) {
1353+ ret = -1 ;
1354+ goto done ;
1355+ }
1356+
1357+ cp_diff .git_cmd = 1 ;
1358+ argv_array_pushl (& cp_diff .args , "diff-index" , "-p" ,
1359+ "--cached" , "--binary" , "HEAD" , "--" ,
1360+ NULL );
1361+ add_pathspecs (& cp_diff .args , ps );
1362+ if (pipe_command (& cp_diff , NULL , 0 , & out , 0 , NULL , 0 )) {
1363+ ret = -1 ;
1364+ goto done ;
1365+ }
1366+
1367+ cp_apply .git_cmd = 1 ;
1368+ argv_array_pushl (& cp_apply .args , "apply" , "--index" ,
1369+ "-R" , NULL );
1370+ if (pipe_command (& cp_apply , out .buf , out .len , NULL , 0 ,
1371+ NULL , 0 )) {
1372+ ret = -1 ;
1373+ goto done ;
1374+ }
1375+ } else {
1376+ struct child_process cp = CHILD_PROCESS_INIT ;
1377+ cp .git_cmd = 1 ;
1378+ argv_array_pushl (& cp .args , "reset" , "--hard" , "-q" ,
1379+ NULL );
1380+ if (run_command (& cp )) {
1381+ ret = -1 ;
1382+ goto done ;
1383+ }
1384+ }
1385+
1386+ if (keep_index == 1 && !is_null_oid (& info .i_tree )) {
1387+ struct child_process cp_ls = CHILD_PROCESS_INIT ;
1388+ struct child_process cp_checkout = CHILD_PROCESS_INIT ;
1389+ struct strbuf out = STRBUF_INIT ;
1390+
1391+ if (reset_tree (& info .i_tree , 0 , 1 )) {
1392+ ret = -1 ;
1393+ goto done ;
1394+ }
1395+
1396+ cp_ls .git_cmd = 1 ;
1397+ argv_array_pushl (& cp_ls .args , "ls-files" , "-z" ,
1398+ "--modified" , "--" , NULL );
1399+
1400+ add_pathspecs (& cp_ls .args , ps );
1401+ if (pipe_command (& cp_ls , NULL , 0 , & out , 0 , NULL , 0 )) {
1402+ ret = -1 ;
1403+ goto done ;
1404+ }
1405+
1406+ cp_checkout .git_cmd = 1 ;
1407+ argv_array_pushl (& cp_checkout .args , "checkout-index" ,
1408+ "-z" , "--force" , "--stdin" , NULL );
1409+ if (pipe_command (& cp_checkout , out .buf , out .len , NULL ,
1410+ 0 , NULL , 0 )) {
1411+ ret = -1 ;
1412+ goto done ;
1413+ }
1414+ }
1415+ goto done ;
1416+ } else {
1417+ struct child_process cp = CHILD_PROCESS_INIT ;
1418+
1419+ cp .git_cmd = 1 ;
1420+ argv_array_pushl (& cp .args , "apply" , "-R" , NULL );
1421+
1422+ if (pipe_command (& cp , patch .buf , patch .len , NULL , 0 , NULL , 0 )) {
1423+ fprintf_ln (stderr , _ ("Cannot remove worktree changes" ));
1424+ ret = -1 ;
1425+ goto done ;
1426+ }
1427+
1428+ if (keep_index < 1 ) {
1429+ struct child_process cp = CHILD_PROCESS_INIT ;
1430+
1431+ cp .git_cmd = 1 ;
1432+ argv_array_pushl (& cp .args , "reset" , "-q" , "--" , NULL );
1433+ add_pathspecs (& cp .args , ps );
1434+ if (run_command (& cp )) {
1435+ ret = -1 ;
1436+ goto done ;
1437+ }
1438+ }
1439+ goto done ;
1440+ }
1441+
1442+ done :
1443+ strbuf_release (& stash_msg_buf );
1444+ return ret ;
1445+ }
1446+
1447+ static int push_stash (int argc , const char * * argv , const char * prefix )
1448+ {
1449+ int keep_index = -1 ;
1450+ int patch_mode = 0 ;
1451+ int include_untracked = 0 ;
1452+ int quiet = 0 ;
1453+ const char * stash_msg = NULL ;
1454+ struct pathspec ps ;
1455+ struct option options [] = {
1456+ OPT_BOOL ('k' , "keep-index" , & keep_index ,
1457+ N_ ("keep index" )),
1458+ OPT_BOOL ('p' , "patch" , & patch_mode ,
1459+ N_ ("stash in patch mode" )),
1460+ OPT__QUIET (& quiet , N_ ("quiet mode" )),
1461+ OPT_BOOL ('u' , "include-untracked" , & include_untracked ,
1462+ N_ ("include untracked files in stash" )),
1463+ OPT_SET_INT ('a' , "all" , & include_untracked ,
1464+ N_ ("include ignore files" ), 2 ),
1465+ OPT_STRING ('m' , "message" , & stash_msg , N_ ("message" ),
1466+ N_ ("stash message" )),
1467+ OPT_END ()
1468+ };
1469+
1470+ argc = parse_options (argc , argv , prefix , options ,
1471+ git_stash_helper_push_usage ,
1472+ 0 );
1473+
1474+ parse_pathspec (& ps , 0 , PATHSPEC_PREFER_FULL , prefix , argv );
1475+ return do_push_stash (ps , stash_msg , quiet , keep_index , patch_mode ,
1476+ include_untracked );
1477+ }
1478+
12441479int cmd_stash__helper (int argc , const char * * argv , const char * prefix )
12451480{
12461481 pid_t pid = getpid ();
@@ -1279,6 +1514,8 @@ int cmd_stash__helper(int argc, const char **argv, const char *prefix)
12791514 return !!store_stash (argc , argv , prefix );
12801515 else if (!strcmp (argv [0 ], "create" ))
12811516 return !!create_stash (argc , argv , prefix );
1517+ else if (!strcmp (argv [0 ], "push" ))
1518+ return !!push_stash (argc , argv , prefix );
12821519
12831520 usage_msg_opt (xstrfmt (_ ("unknown subcommand: %s" ), argv [0 ]),
12841521 git_stash_helper_usage , options );
0 commit comments