@@ -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
@@ -1090,7 +1100,7 @@ static int stash_working_tree(struct stash_info *info, struct pathspec ps)
10901100
10911101static int do_create_stash (struct pathspec ps , struct strbuf * stash_msg_buf ,
10921102 int include_untracked , int patch_mode ,
1093- struct stash_info * info )
1103+ struct stash_info * info , struct strbuf * patch )
10941104{
10951105 int ret = 0 ;
10961106 int flags = 0 ;
@@ -1103,7 +1113,6 @@ static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
11031113 struct strbuf msg = STRBUF_INIT ;
11041114 struct strbuf commit_tree_label = STRBUF_INIT ;
11051115 struct strbuf untracked_files = STRBUF_INIT ;
1106- struct strbuf patch = STRBUF_INIT ;
11071116
11081117 prepare_fallback_ident ("git stash" , "git@stash" );
11091118
@@ -1152,7 +1161,7 @@ static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf,
11521161 untracked_commit_option = 1 ;
11531162 }
11541163 if (patch_mode ) {
1155- ret = stash_patch (info , ps , & patch );
1164+ ret = stash_patch (info , ps , patch );
11561165 if (ret < 0 ) {
11571166 fprintf_ln (stderr , _ ("Cannot save the current "
11581167 "worktree state" ));
@@ -1223,7 +1232,8 @@ static int create_stash(int argc, const char **argv, const char *prefix)
12231232
12241233 memset (& ps , 0 , sizeof (ps ));
12251234 strbuf_addstr (& stash_msg_buf , stash_msg );
1226- ret = do_create_stash (ps , & stash_msg_buf , include_untracked , 0 , & info );
1235+ ret = do_create_stash (ps , & stash_msg_buf , include_untracked , 0 , & info ,
1236+ NULL );
12271237 if (!ret )
12281238 printf_ln ("%s" , oid_to_hex (& info .w_commit ));
12291239
@@ -1236,6 +1246,232 @@ static int create_stash(int argc, const char **argv, const char *prefix)
12361246 return ret < 0 ;
12371247}
12381248
1249+ static int do_push_stash (struct pathspec ps , const char * stash_msg , int quiet ,
1250+ int keep_index , int patch_mode , int include_untracked )
1251+ {
1252+ int ret = 0 ;
1253+ struct stash_info info ;
1254+ struct strbuf patch = STRBUF_INIT ;
1255+ struct strbuf stash_msg_buf = STRBUF_INIT ;
1256+
1257+ if (patch_mode && keep_index == -1 )
1258+ keep_index = 1 ;
1259+
1260+ if (patch_mode && include_untracked ) {
1261+ fprintf_ln (stderr , _ ("Can't use --patch and --include-untracked"
1262+ " or --all at the same time" ));
1263+ ret = -1 ;
1264+ goto done ;
1265+ }
1266+
1267+ read_cache_preload (NULL );
1268+ if (!include_untracked && ps .nr ) {
1269+ int i ;
1270+ char * ps_matched = xcalloc (ps .nr , 1 );
1271+
1272+ for (i = 0 ; i < active_nr ; i ++ )
1273+ ce_path_match (& the_index , active_cache [i ], & ps ,
1274+ ps_matched );
1275+
1276+ if (report_path_error (ps_matched , & ps , NULL )) {
1277+ fprintf_ln (stderr , _ ("Did you forget to 'git add'?" ));
1278+ ret = -1 ;
1279+ free (ps_matched );
1280+ goto done ;
1281+ }
1282+ free (ps_matched );
1283+ }
1284+
1285+ if (refresh_cache (REFRESH_QUIET )) {
1286+ ret = -1 ;
1287+ goto done ;
1288+ }
1289+
1290+ if (!check_changes (ps , include_untracked )) {
1291+ if (!quiet )
1292+ printf_ln (_ ("No local changes to save" ));
1293+ goto done ;
1294+ }
1295+
1296+ if (!reflog_exists (ref_stash ) && do_clear_stash ()) {
1297+ ret = -1 ;
1298+ fprintf_ln (stderr , _ ("Cannot initialize stash" ));
1299+ goto done ;
1300+ }
1301+
1302+ if (stash_msg )
1303+ strbuf_addstr (& stash_msg_buf , stash_msg );
1304+ if (do_create_stash (ps , & stash_msg_buf , include_untracked , patch_mode ,
1305+ & info , & patch )) {
1306+ ret = -1 ;
1307+ goto done ;
1308+ }
1309+
1310+ if (do_store_stash (& info .w_commit , stash_msg_buf .buf , 1 )) {
1311+ ret = -1 ;
1312+ fprintf_ln (stderr , _ ("Cannot save the current status" ));
1313+ goto done ;
1314+ }
1315+
1316+ printf_ln (_ ("Saved working directory and index state %s" ),
1317+ stash_msg_buf .buf );
1318+
1319+ if (!patch_mode ) {
1320+ if (include_untracked && !ps .nr ) {
1321+ struct child_process cp = CHILD_PROCESS_INIT ;
1322+
1323+ cp .git_cmd = 1 ;
1324+ argv_array_pushl (& cp .args , "clean" , "--force" ,
1325+ "--quiet" , "-d" , NULL );
1326+ if (include_untracked == INCLUDE_ALL_FILES )
1327+ argv_array_push (& cp .args , "-x" );
1328+ if (run_command (& cp )) {
1329+ ret = -1 ;
1330+ goto done ;
1331+ }
1332+ }
1333+ discard_cache ();
1334+ if (ps .nr ) {
1335+ struct child_process cp_add = CHILD_PROCESS_INIT ;
1336+ struct child_process cp_diff = CHILD_PROCESS_INIT ;
1337+ struct child_process cp_apply = CHILD_PROCESS_INIT ;
1338+ struct strbuf out = STRBUF_INIT ;
1339+
1340+ cp_add .git_cmd = 1 ;
1341+ argv_array_push (& cp_add .args , "add" );
1342+ if (!include_untracked )
1343+ argv_array_push (& cp_add .args , "-u" );
1344+ if (include_untracked == INCLUDE_ALL_FILES )
1345+ argv_array_push (& cp_add .args , "--force" );
1346+ argv_array_push (& cp_add .args , "--" );
1347+ add_pathspecs (& cp_add .args , ps );
1348+ if (run_command (& cp_add )) {
1349+ ret = -1 ;
1350+ goto done ;
1351+ }
1352+
1353+ cp_diff .git_cmd = 1 ;
1354+ argv_array_pushl (& cp_diff .args , "diff-index" , "-p" ,
1355+ "--cached" , "--binary" , "HEAD" , "--" ,
1356+ NULL );
1357+ add_pathspecs (& cp_diff .args , ps );
1358+ if (pipe_command (& cp_diff , NULL , 0 , & out , 0 , NULL , 0 )) {
1359+ ret = -1 ;
1360+ goto done ;
1361+ }
1362+
1363+ cp_apply .git_cmd = 1 ;
1364+ argv_array_pushl (& cp_apply .args , "apply" , "--index" ,
1365+ "-R" , NULL );
1366+ if (pipe_command (& cp_apply , out .buf , out .len , NULL , 0 ,
1367+ NULL , 0 )) {
1368+ ret = -1 ;
1369+ goto done ;
1370+ }
1371+ } else {
1372+ struct child_process cp = CHILD_PROCESS_INIT ;
1373+ cp .git_cmd = 1 ;
1374+ argv_array_pushl (& cp .args , "reset" , "--hard" , "-q" ,
1375+ NULL );
1376+ if (run_command (& cp )) {
1377+ ret = -1 ;
1378+ goto done ;
1379+ }
1380+ }
1381+
1382+ if (keep_index == 1 && !is_null_oid (& info .i_tree )) {
1383+ struct child_process cp_ls = CHILD_PROCESS_INIT ;
1384+ struct child_process cp_checkout = CHILD_PROCESS_INIT ;
1385+ struct strbuf out = STRBUF_INIT ;
1386+
1387+ if (reset_tree (& info .i_tree , 0 , 1 )) {
1388+ ret = -1 ;
1389+ goto done ;
1390+ }
1391+
1392+ cp_ls .git_cmd = 1 ;
1393+ argv_array_pushl (& cp_ls .args , "ls-files" , "-z" ,
1394+ "--modified" , "--" , NULL );
1395+
1396+ add_pathspecs (& cp_ls .args , ps );
1397+ if (pipe_command (& cp_ls , NULL , 0 , & out , 0 , NULL , 0 )) {
1398+ ret = -1 ;
1399+ goto done ;
1400+ }
1401+
1402+ cp_checkout .git_cmd = 1 ;
1403+ argv_array_pushl (& cp_checkout .args , "checkout-index" ,
1404+ "-z" , "--force" , "--stdin" , NULL );
1405+ if (pipe_command (& cp_checkout , out .buf , out .len , NULL ,
1406+ 0 , NULL , 0 )) {
1407+ ret = -1 ;
1408+ goto done ;
1409+ }
1410+ }
1411+ goto done ;
1412+ } else {
1413+ struct child_process cp = CHILD_PROCESS_INIT ;
1414+
1415+ cp .git_cmd = 1 ;
1416+ argv_array_pushl (& cp .args , "apply" , "-R" , NULL );
1417+
1418+ if (pipe_command (& cp , patch .buf , patch .len , NULL , 0 , NULL , 0 )) {
1419+ fprintf_ln (stderr , _ ("Cannot remove worktree changes" ));
1420+ ret = -1 ;
1421+ goto done ;
1422+ }
1423+
1424+ if (keep_index < 1 ) {
1425+ struct child_process cp = CHILD_PROCESS_INIT ;
1426+
1427+ cp .git_cmd = 1 ;
1428+ argv_array_pushl (& cp .args , "reset" , "-q" , "--" , NULL );
1429+ add_pathspecs (& cp .args , ps );
1430+ if (run_command (& cp )) {
1431+ ret = -1 ;
1432+ goto done ;
1433+ }
1434+ }
1435+ goto done ;
1436+ }
1437+
1438+ done :
1439+ strbuf_release (& stash_msg_buf );
1440+ return ret ;
1441+ }
1442+
1443+ static int push_stash (int argc , const char * * argv , const char * prefix )
1444+ {
1445+ int keep_index = -1 ;
1446+ int patch_mode = 0 ;
1447+ int include_untracked = 0 ;
1448+ int quiet = 0 ;
1449+ const char * stash_msg = NULL ;
1450+ struct pathspec ps ;
1451+ struct option options [] = {
1452+ OPT_BOOL ('k' , "keep-index" , & keep_index ,
1453+ N_ ("keep index" )),
1454+ OPT_BOOL ('p' , "patch" , & patch_mode ,
1455+ N_ ("stash in patch mode" )),
1456+ OPT__QUIET (& quiet , N_ ("quiet mode" )),
1457+ OPT_BOOL ('u' , "include-untracked" , & include_untracked ,
1458+ N_ ("include untracked files in stash" )),
1459+ OPT_SET_INT ('a' , "all" , & include_untracked ,
1460+ N_ ("include ignore files" ), 2 ),
1461+ OPT_STRING ('m' , "message" , & stash_msg , N_ ("message" ),
1462+ N_ ("stash message" )),
1463+ OPT_END ()
1464+ };
1465+
1466+ argc = parse_options (argc , argv , prefix , options ,
1467+ git_stash_helper_push_usage ,
1468+ 0 );
1469+
1470+ parse_pathspec (& ps , 0 , PATHSPEC_PREFER_FULL , prefix , argv );
1471+ return do_push_stash (ps , stash_msg , quiet , keep_index , patch_mode ,
1472+ include_untracked );
1473+ }
1474+
12391475int cmd_stash__helper (int argc , const char * * argv , const char * prefix )
12401476{
12411477 pid_t pid = getpid ();
@@ -1274,6 +1510,8 @@ int cmd_stash__helper(int argc, const char **argv, const char *prefix)
12741510 return !!store_stash (argc , argv , prefix );
12751511 else if (!strcmp (argv [0 ], "create" ))
12761512 return !!create_stash (argc , argv , prefix );
1513+ else if (!strcmp (argv [0 ], "push" ))
1514+ return !!push_stash (argc , argv , prefix );
12771515
12781516 usage_msg_opt (xstrfmt (_ ("unknown subcommand: %s" ), argv [0 ]),
12791517 git_stash_helper_usage , options );
0 commit comments