From: Linus Torvalds Date: Thu, 26 May 2005 22:10:02 +0000 (-0700) Subject: git-apply: add "--check" option to check that the diff makes sense X-Git-Tag: v0.99~447 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=a577284aee793d71982e896b711c7b3d57e6bcf2;p=git.git git-apply: add "--check" option to check that the diff makes sense It currently only verifies the index against the working directory, it doesn't actually verify the diff fragments themselves yet. --- diff --git a/apply.c b/apply.c index 2fab34754..3160207b9 100644 --- a/apply.c +++ b/apply.c @@ -17,11 +17,19 @@ #include "cache.h" // We default to the merge behaviour, since that's what most people would -// expect +// expect. +// +// --check turns on checking that the working tree matches the +// files that are being modified, but doesn't apply the patch +// --stat does just a diffstat, and doesn't actually apply +// --show-files shows the directory changes +// static int merge_patch = 1; static int diffstat = 0; -static int check = 1; -static const char apply_usage[] = "git-apply "; +static int check = 0; +static int apply = 1; +static int show_files = 0; +static const char apply_usage[] = "git-apply [--stat] [--check] [--show-files] "; /* * For "diff-stat" like behaviour, we keep track of the biggest change @@ -723,44 +731,90 @@ static void show_stats(struct patch *patch) add, pluses, del, minuses); } -static void check_patch(struct patch *patch) +static int check_patch(struct patch *patch) { + struct stat st; const char *old_name = patch->old_name; const char *new_name = patch->new_name; if (old_name) { - if (cache_name_pos(old_name, strlen(old_name)) < 0) - die("file %s does not exist", old_name); + int pos = cache_name_pos(old_name, strlen(old_name)); + int changed; + + if (pos < 0) + return error("%s: does not exist in index", old_name); if (patch->is_new < 0) patch->is_new = 0; + if (lstat(old_name, &st) < 0) + return error("%s: %s\n", strerror(errno)); + changed = ce_match_stat(active_cache[pos], &st); + if (changed) + return error("%s: does not match index", old_name); + if (!patch->old_mode) + patch->old_mode = st.st_mode; } + if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) { if (cache_name_pos(new_name, strlen(new_name)) >= 0) - die("file %s already exists", new_name); + return error("%s: already exists in index", new_name); + if (!lstat(new_name, &st)) + return error("%s: already exists in working directory", new_name); + if (errno != ENOENT) + return error("%s: %s", new_name, strerror(errno)); } + return 0; } -static void apply_patch_list(struct patch *patch) +static int check_patch_list(struct patch *patch) { - int files, adds, dels; + int error = 0; + + for (;patch ; patch = patch->next) + error |= check_patch(patch); + return error; +} + +static void show_file(int c, unsigned int mode, const char *name) +{ + printf("%c %o %s\n", c, mode, name); +} - files = adds = dels = 0; - if (!patch) - die("no patch found"); - do { - if (check) - check_patch(patch); - - if (diffstat) { - files++; - adds += patch->lines_added; - dels += patch->lines_deleted; - show_stats(patch); +static void show_file_list(struct patch *patch) +{ + for (;patch ; patch = patch->next) { + if (patch->is_rename) { + show_file('-', patch->old_mode, patch->old_name); + show_file('+', patch->new_mode, patch->new_name); + continue; + } + if (patch->is_copy || patch->is_new) { + show_file('+', patch->new_mode, patch->new_name); + continue; + } + if (patch->is_delete) { + show_file('-', patch->old_mode, patch->old_name); + continue; + } + if (patch->old_mode && patch->new_mode && patch->old_mode != patch->new_mode) { + printf("M %o:%o %s\n", patch->old_mode, patch->new_mode, patch->old_name); + continue; } - } while ((patch = patch->next) != NULL); + printf("M %o %s\n", patch->old_mode, patch->old_name); + } +} - if (diffstat) - printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels); +static void stat_patch_list(struct patch *patch) +{ + int files, adds, dels; + + for (files = adds = dels = 0 ; patch ; patch = patch->next) { + files++; + adds += patch->lines_added; + dels += patch->lines_deleted; + show_stats(patch); + } + + printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels); } static void patch_stats(struct patch *patch) @@ -806,7 +860,14 @@ static int apply_patch(int fd) size -= nr; } - apply_patch_list(list); + if ((check || apply) && check_patch_list(list) < 0) + exit(1); + + if (show_files) + show_file_list(list); + + if (diffstat) + stat_patch_list(list); free(buffer); return 0; @@ -834,10 +895,19 @@ int main(int argc, char **argv) continue; } if (!strcmp(arg, "--stat")) { - check = 0; + apply = 0; diffstat = 1; continue; } + if (!strcmp(arg, "--check")) { + apply = 0; + check = 1; + continue; + } + if (!strcmp(arg, "--show-files")) { + show_files = 1; + continue; + } fd = open(arg, O_RDONLY); if (fd < 0) usage(apply_usage);