1313#include "git-compat-util.h"
1414#include "abspath.h"
1515#include "base85.h"
16+ #include "clean-status.h"
17+ #include "clean-status-index.h"
1618#include "config.h"
1719#include "odb.h"
1820#include "delta.h"
1921#include "diff.h"
2022#include "dir.h"
2123#include "environment.h"
24+ #include "fsmonitor-settings.h"
2225#include "gettext.h"
2326#include "hex.h"
2427#include "xdiff-interface.h"
3134#include "path.h"
3235#include "quote.h"
3336#include "read-cache.h"
37+ #include "replace-object.h"
3438#include "repository.h"
3539#include "rerere.h"
3640#include "apply.h"
@@ -4440,9 +4444,79 @@ static void patch_stats(struct apply_state *state, struct patch *patch)
44404444 }
44414445}
44424446
4447+ static int patch_preserves_clean_history (struct apply_state * state ,
4448+ struct patch * patch )
4449+ {
4450+ struct index_state * istate = state -> repo -> index ;
4451+ const struct cache_entry * old ;
4452+ int suspended = clean_status_fsmonitor_backoff_suspended (istate );
4453+ int pos ;
4454+
4455+ if (!state -> update_index || state -> ita_only || state -> threeway ||
4456+ state -> apply_with_reject || state -> fake_ancestor ||
4457+ state -> index_file || !fstat_is_reliable () ||
4458+ (getenv (INDEX_ENVIRONMENT ) &&
4459+ !clean_status_index_path_is_main (istate -> repo ,
4460+ istate -> repo -> index_file )) ||
4461+ getenv (GIT_WORK_TREE_ENVIRONMENT ) ||
4462+ getenv (GIT_COMMON_DIR_ENVIRONMENT ) ||
4463+ getenv (DB_ENVIRONMENT ) || getenv (ALTERNATE_DB_ENVIRONMENT ) ||
4464+ istate != istate -> repo -> index || istate -> split_index ||
4465+ istate -> sparse_index != INDEX_EXPANDED ||
4466+ repo_config_values (istate -> repo )-> apply_sparse_checkout ||
4467+ !istate -> repo -> config_values_private_ .trust_ctime ||
4468+ !istate -> repo -> config_values_private_ .check_stat ||
4469+ (fsm_settings__get_mode (istate -> repo ) != FSMONITOR_MODE_IPC &&
4470+ !suspended ) ||
4471+ repo_has_replace_refs_uncached (istate -> repo ) ||
4472+ patch -> is_new > 0 || patch -> is_delete > 0 || patch -> is_copy ||
4473+ patch -> is_rename || patch -> conflicted_threeway ||
4474+ !patch -> old_name || !patch -> new_name ||
4475+ strcmp (patch -> old_name , patch -> new_name ) ||
4476+ !S_ISREG (patch -> old_mode ) || !S_ISREG (patch -> new_mode ) ||
4477+ create_ce_mode (patch -> old_mode ) !=
4478+ create_ce_mode (patch -> new_mode ) ||
4479+ !clean_status_external_history_enabled (istate ) ||
4480+ !istate -> untracked ||
4481+ !istate -> untracked -> root )
4482+ return 0 ;
4483+ if (suspended ) {
4484+ /* Keep only the authenticated historical boundary during backoff. */
4485+ if (!clean_status_fsmonitor_semantic_baseline_pending (istate ) ||
4486+ !istate -> untracked -> root -> valid ||
4487+ !istate -> untracked -> fsmonitor_revalidation )
4488+ return 0 ;
4489+ } else if (!clean_status_has_persistent_fsmonitor_semantic_history (istate ) ||
4490+ !clean_status_revalidated_token_matches (istate ) ||
4491+ !istate -> fsmonitor_token_valid ||
4492+ !istate -> fsmonitor_untracked_valid ||
4493+ !istate -> fsmonitor_untracked_extension_seen ||
4494+ istate -> fsmonitor_untracked_extension_invalid ||
4495+ !istate -> fsmonitor_last_update ||
4496+ !istate -> fsmonitor_untracked_token ||
4497+ strcmp (istate -> fsmonitor_last_update ,
4498+ istate -> fsmonitor_untracked_token ) ||
4499+ !istate -> untracked -> use_fsmonitor ) {
4500+ return 0 ;
4501+ }
4502+
4503+ pos = index_name_pos (istate , patch -> old_name ,
4504+ strlen (patch -> old_name ));
4505+ if (pos < 0 )
4506+ return 0 ;
4507+ old = istate -> cache [pos ];
4508+ return S_ISREG (old -> ce_mode ) &&
4509+ old -> ce_mode == create_ce_mode (patch -> new_mode ) &&
4510+ clean_status_index_entry_is_semantically_safe (
4511+ istate , old , old );
4512+ }
4513+
44434514static int remove_file (struct apply_state * state , struct patch * patch , int rmdir_empty )
44444515{
4445- if (state -> update_index && !state -> ita_only ) {
4516+ if (state -> update_index && !state -> ita_only &&
4517+ !patch_preserves_clean_history (state , patch )) {
4518+ if (clean_status_external_history_enabled (state -> repo -> index ))
4519+ clean_status_invalidate_current_proof (state -> repo -> index );
44464520 if (remove_file_from_index (state -> repo -> index , patch -> old_name ) < 0 )
44474521 return error (_ ("unable to remove %s from index" ), patch -> old_name );
44484522 }
@@ -4455,6 +4529,7 @@ static int remove_file(struct apply_state *state, struct patch *patch, int rmdir
44554529}
44564530
44574531static int add_index_file (struct apply_state * state ,
4532+ struct patch * patch ,
44584533 const char * path ,
44594534 unsigned mode ,
44604535 void * buf ,
@@ -4463,6 +4538,7 @@ static int add_index_file(struct apply_state *state,
44634538 struct stat st ;
44644539 struct cache_entry * ce ;
44654540 int namelen = strlen (path );
4541+ int options = ADD_CACHE_OK_TO_ADD ;
44664542
44674543 ce = make_empty_cache_entry (state -> repo -> index , namelen );
44684544 memcpy (ce -> name , path , namelen );
@@ -4497,7 +4573,13 @@ static int add_index_file(struct apply_state *state,
44974573 "for newly created file %s" ), path );
44984574 }
44994575 }
4500- if (add_index_entry (state -> repo -> index , ce , ADD_CACHE_OK_TO_ADD ) < 0 ) {
4576+ if (patch_preserves_clean_history (state , patch )) {
4577+ options |= ADD_CACHE_OK_TO_REPLACE |
4578+ ADD_CACHE_PRESERVE_CLEAN_HISTORY ;
4579+ } else if (clean_status_external_history_enabled (state -> repo -> index )) {
4580+ clean_status_invalidate_current_proof (state -> repo -> index );
4581+ }
4582+ if (add_index_entry (state -> repo -> index , ce , options ) < 0 ) {
45014583 discard_cache_entry (ce );
45024584 return error (_ ("unable to add cache entry for %s" ), path );
45034585 }
@@ -4697,7 +4779,7 @@ static int create_file(struct apply_state *state, struct patch *patch)
46974779 if (patch -> conflicted_threeway )
46984780 return add_conflicted_stages_file (state , patch );
46994781 else if (state -> check_index || (state -> ita_only && patch -> is_new > 0 ))
4700- return add_index_file (state , path , mode , buf , size );
4782+ return add_index_file (state , patch , path , mode , buf , size );
47014783 return 0 ;
47024784}
47034785
@@ -4828,6 +4910,18 @@ static int write_out_results(struct apply_state *state, struct patch *list)
48284910 struct patch * l ;
48294911 struct string_list cpath = STRING_LIST_INIT_DUP ;
48304912
4913+ if (state -> update_index &&
4914+ clean_status_external_history_enabled (state -> repo -> index )) {
4915+ for (l = list ; l ; l = l -> next ) {
4916+ if (l -> rejected ||
4917+ !patch_preserves_clean_history (state , l )) {
4918+ clean_status_invalidate_current_proof (
4919+ state -> repo -> index );
4920+ break ;
4921+ }
4922+ }
4923+ }
4924+
48314925 for (phase = 0 ; phase < 2 ; phase ++ ) {
48324926 l = list ;
48334927 while (l ) {
0 commit comments