44#include "git-compat-util.h"
55#include "add-patch.h"
66#include "advice.h"
7+ #include "commit.h"
78#include "config.h"
89#include "diff.h"
910#include "editor.h"
1011#include "environment.h"
1112#include "gettext.h"
13+ #include "hex.h"
1214#include "object-name.h"
1315#include "pager.h"
1416#include "read-cache-ll.h"
@@ -263,6 +265,8 @@ struct hunk {
263265
264266struct add_p_state {
265267 struct repository * r ;
268+ struct index_state * index ;
269+ const char * index_file ;
266270 struct interactive_config cfg ;
267271 struct strbuf answer , buf ;
268272
@@ -438,7 +442,7 @@ static void setup_child_process(struct add_p_state *s,
438442
439443 cp -> git_cmd = 1 ;
440444 strvec_pushf (& cp -> env ,
441- INDEX_ENVIRONMENT "=%s" , s -> r -> index_file );
445+ INDEX_ENVIRONMENT "=%s" , s -> index_file );
442446}
443447
444448static int parse_range (const char * * p ,
@@ -1559,7 +1563,7 @@ static void apply_patch(struct add_p_state *s, struct file_diff *file_diff)
15591563 strbuf_reset (& s -> buf );
15601564 reassemble_patch (s , file_diff , 0 , & s -> buf );
15611565
1562- discard_index (s -> r -> index );
1566+ discard_index (s -> index );
15631567 if (s -> mode -> apply_for_checkout )
15641568 apply_for_checkout (s , & s -> buf ,
15651569 s -> mode -> is_reverse );
@@ -1570,9 +1574,11 @@ static void apply_patch(struct add_p_state *s, struct file_diff *file_diff)
15701574 NULL , 0 , NULL , 0 ))
15711575 error (_ ("'git apply' failed" ));
15721576 }
1573- if (repo_read_index (s -> r ) >= 0 )
1577+ if (read_index_from (s -> index , s -> index_file , s -> r -> gitdir ) >= 0 &&
1578+ s -> index == s -> r -> index ) {
15741579 repo_refresh_and_write_index (s -> r , REFRESH_QUIET , 0 ,
15751580 1 , NULL , NULL , NULL );
1581+ }
15761582 }
15771583
15781584}
@@ -1996,18 +2002,51 @@ static size_t patch_update_file(struct add_p_state *s, size_t idx)
19962002 return patch_update_resp ;
19972003}
19982004
2005+ static int run_add_p_common (struct add_p_state * state ,
2006+ const struct pathspec * ps )
2007+ {
2008+ size_t binary_count = 0 ;
2009+ size_t i ;
2010+
2011+ if (parse_diff (state , ps ) < 0 )
2012+ return -1 ;
2013+
2014+ for (i = 0 ; i < state -> file_diff_nr ;) {
2015+ if (state -> file_diff [i ].binary && !state -> file_diff [i ].hunk_nr ) {
2016+ binary_count ++ ;
2017+ i ++ ;
2018+ continue ;
2019+ }
2020+ if ((i = patch_update_file (state , i )) == state -> file_diff_nr )
2021+ break ;
2022+ }
2023+
2024+ if (!state -> cfg .auto_advance )
2025+ for (i = 0 ; i < state -> file_diff_nr ; i ++ )
2026+ apply_patch (state , state -> file_diff + i );
2027+
2028+ if (state -> file_diff_nr == 0 )
2029+ err (state , _ ("No changes." ));
2030+ else if (binary_count == state -> file_diff_nr )
2031+ err (state , _ ("Only binary files changed." ));
2032+
2033+ return 0 ;
2034+ }
2035+
19992036int run_add_p (struct repository * r , enum add_p_mode mode ,
20002037 struct interactive_options * opts , const char * revision ,
20012038 const struct pathspec * ps )
20022039{
20032040 struct add_p_state s = {
20042041 .r = r ,
2042+ .index = r -> index ,
2043+ .index_file = r -> index_file ,
20052044 .answer = STRBUF_INIT ,
20062045 .buf = STRBUF_INIT ,
20072046 .plain = STRBUF_INIT ,
20082047 .colored = STRBUF_INIT ,
20092048 };
2010- size_t i , binary_count = 0 ;
2049+ int ret ;
20112050
20122051 interactive_config_init (& s .cfg , r , opts );
20132052
@@ -2040,30 +2079,90 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
20402079 if (repo_read_index (r ) < 0 ||
20412080 (!s .mode -> index_only &&
20422081 repo_refresh_and_write_index (r , REFRESH_QUIET , 0 , 1 ,
2043- NULL , NULL , NULL ) < 0 ) ||
2044- parse_diff (& s , ps ) < 0 ) {
2045- add_p_state_clear (& s );
2046- return -1 ;
2082+ NULL , NULL , NULL ) < 0 )) {
2083+ ret = -1 ;
2084+ goto out ;
20472085 }
20482086
2049- for (i = 0 ; i < s .file_diff_nr ;) {
2050- if (s .file_diff [i ].binary && !s .file_diff [i ].hunk_nr ) {
2051- binary_count ++ ;
2052- i ++ ;
2053- continue ;
2054- }
2055- if ((i = patch_update_file (& s , i )) == s .file_diff_nr )
2056- break ;
2057- }
2058- if (!s .cfg .auto_advance )
2059- for (i = 0 ; i < s .file_diff_nr ; i ++ )
2060- apply_patch (& s , s .file_diff + i );
2087+ ret = run_add_p_common (& s , ps );
2088+ if (ret < 0 )
2089+ goto out ;
20612090
2062- if (s .file_diff_nr == 0 )
2063- err (& s , _ ("No changes." ));
2064- else if (binary_count == s .file_diff_nr )
2065- err (& s , _ ("Only binary files changed." ));
2091+ ret = 0 ;
20662092
2093+ out :
20672094 add_p_state_clear (& s );
2068- return 0 ;
2095+ return ret ;
2096+ }
2097+
2098+ int run_add_p_index (struct repository * r ,
2099+ struct index_state * index ,
2100+ const char * index_file ,
2101+ struct interactive_options * opts ,
2102+ const char * revision ,
2103+ const struct pathspec * ps )
2104+ {
2105+ struct patch_mode mode = {
2106+ .apply_args = { "--cached" , NULL },
2107+ .apply_check_args = { "--cached" , NULL },
2108+ .prompt_mode = {
2109+ N_ ("Stage mode change [y,n,q,a,d%s,?]? " ),
2110+ N_ ("Stage deletion [y,n,q,a,d%s,?]? " ),
2111+ N_ ("Stage addition [y,n,q,a,d%s,?]? " ),
2112+ N_ ("Stage this hunk [y,n,q,a,d%s,?]? " )
2113+ },
2114+ .edit_hunk_hint = N_ ("If the patch applies cleanly, the edited hunk "
2115+ "will immediately be marked for staging." ),
2116+ .help_patch_text =
2117+ N_ ("y - stage this hunk\n"
2118+ "n - do not stage this hunk\n"
2119+ "q - quit; do not stage this hunk or any of the remaining "
2120+ "ones\n"
2121+ "a - stage this hunk and all later hunks in the file\n"
2122+ "d - do not stage this hunk or any of the later hunks in "
2123+ "the file\n" ),
2124+ .index_only = 1 ,
2125+ };
2126+ struct add_p_state s = {
2127+ .r = r ,
2128+ .index = index ,
2129+ .index_file = index_file ,
2130+ .answer = STRBUF_INIT ,
2131+ .buf = STRBUF_INIT ,
2132+ .plain = STRBUF_INIT ,
2133+ .colored = STRBUF_INIT ,
2134+ .mode = & mode ,
2135+ .revision = revision ,
2136+ };
2137+ char parent_tree_oid [GIT_MAX_HEXSZ + 1 ];
2138+ struct commit * commit ;
2139+ int ret ;
2140+
2141+ interactive_config_init (& s .cfg , r , opts );
2142+
2143+ commit = lookup_commit_reference_by_name (revision );
2144+ if (!commit ) {
2145+ err (& s , _ ("Revision does not refer to a commit" ));
2146+ ret = -1 ;
2147+ goto out ;
2148+ }
2149+
2150+ if (commit -> parents )
2151+ oid_to_hex_r (parent_tree_oid , get_commit_tree_oid (commit -> parents -> item ));
2152+ else
2153+ oid_to_hex_r (parent_tree_oid , r -> hash_algo -> empty_tree );
2154+
2155+ mode .diff_cmd [0 ] = "diff-tree" ;
2156+ mode .diff_cmd [1 ] = "-r" ;
2157+ mode .diff_cmd [2 ] = parent_tree_oid ;
2158+
2159+ ret = run_add_p_common (& s , ps );
2160+ if (ret < 0 )
2161+ goto out ;
2162+
2163+ ret = 0 ;
2164+
2165+ out :
2166+ add_p_state_clear (& s );
2167+ return ret ;
20692168}
0 commit comments