Skip to content

Commit a577284

Browse files
author
Linus Torvalds
committed
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.
1 parent 0e87e04 commit a577284

File tree

1 file changed

+96
-26
lines changed

1 file changed

+96
-26
lines changed

apply.c

Lines changed: 96 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@
1717
#include "cache.h"
1818

1919
// We default to the merge behaviour, since that's what most people would
20-
// expect
20+
// expect.
21+
//
22+
// --check turns on checking that the working tree matches the
23+
// files that are being modified, but doesn't apply the patch
24+
// --stat does just a diffstat, and doesn't actually apply
25+
// --show-files shows the directory changes
26+
//
2127
static int merge_patch = 1;
2228
static int diffstat = 0;
23-
static int check = 1;
24-
static const char apply_usage[] = "git-apply <patch>";
29+
static int check = 0;
30+
static int apply = 1;
31+
static int show_files = 0;
32+
static const char apply_usage[] = "git-apply [--stat] [--check] [--show-files] <patch>";
2533

2634
/*
2735
* For "diff-stat" like behaviour, we keep track of the biggest change
@@ -723,44 +731,90 @@ static void show_stats(struct patch *patch)
723731
add, pluses, del, minuses);
724732
}
725733

726-
static void check_patch(struct patch *patch)
734+
static int check_patch(struct patch *patch)
727735
{
736+
struct stat st;
728737
const char *old_name = patch->old_name;
729738
const char *new_name = patch->new_name;
730739

731740
if (old_name) {
732-
if (cache_name_pos(old_name, strlen(old_name)) < 0)
733-
die("file %s does not exist", old_name);
741+
int pos = cache_name_pos(old_name, strlen(old_name));
742+
int changed;
743+
744+
if (pos < 0)
745+
return error("%s: does not exist in index", old_name);
734746
if (patch->is_new < 0)
735747
patch->is_new = 0;
748+
if (lstat(old_name, &st) < 0)
749+
return error("%s: %s\n", strerror(errno));
750+
changed = ce_match_stat(active_cache[pos], &st);
751+
if (changed)
752+
return error("%s: does not match index", old_name);
753+
if (!patch->old_mode)
754+
patch->old_mode = st.st_mode;
736755
}
756+
737757
if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {
738758
if (cache_name_pos(new_name, strlen(new_name)) >= 0)
739-
die("file %s already exists", new_name);
759+
return error("%s: already exists in index", new_name);
760+
if (!lstat(new_name, &st))
761+
return error("%s: already exists in working directory", new_name);
762+
if (errno != ENOENT)
763+
return error("%s: %s", new_name, strerror(errno));
740764
}
765+
return 0;
741766
}
742767

743-
static void apply_patch_list(struct patch *patch)
768+
static int check_patch_list(struct patch *patch)
744769
{
745-
int files, adds, dels;
770+
int error = 0;
771+
772+
for (;patch ; patch = patch->next)
773+
error |= check_patch(patch);
774+
return error;
775+
}
776+
777+
static void show_file(int c, unsigned int mode, const char *name)
778+
{
779+
printf("%c %o %s\n", c, mode, name);
780+
}
746781

747-
files = adds = dels = 0;
748-
if (!patch)
749-
die("no patch found");
750-
do {
751-
if (check)
752-
check_patch(patch);
753-
754-
if (diffstat) {
755-
files++;
756-
adds += patch->lines_added;
757-
dels += patch->lines_deleted;
758-
show_stats(patch);
782+
static void show_file_list(struct patch *patch)
783+
{
784+
for (;patch ; patch = patch->next) {
785+
if (patch->is_rename) {
786+
show_file('-', patch->old_mode, patch->old_name);
787+
show_file('+', patch->new_mode, patch->new_name);
788+
continue;
789+
}
790+
if (patch->is_copy || patch->is_new) {
791+
show_file('+', patch->new_mode, patch->new_name);
792+
continue;
793+
}
794+
if (patch->is_delete) {
795+
show_file('-', patch->old_mode, patch->old_name);
796+
continue;
797+
}
798+
if (patch->old_mode && patch->new_mode && patch->old_mode != patch->new_mode) {
799+
printf("M %o:%o %s\n", patch->old_mode, patch->new_mode, patch->old_name);
800+
continue;
759801
}
760-
} while ((patch = patch->next) != NULL);
802+
printf("M %o %s\n", patch->old_mode, patch->old_name);
803+
}
804+
}
761805

762-
if (diffstat)
763-
printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels);
806+
static void stat_patch_list(struct patch *patch)
807+
{
808+
int files, adds, dels;
809+
810+
for (files = adds = dels = 0 ; patch ; patch = patch->next) {
811+
files++;
812+
adds += patch->lines_added;
813+
dels += patch->lines_deleted;
814+
show_stats(patch);
815+
}
816+
817+
printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels);
764818
}
765819

766820
static void patch_stats(struct patch *patch)
@@ -806,7 +860,14 @@ static int apply_patch(int fd)
806860
size -= nr;
807861
}
808862

809-
apply_patch_list(list);
863+
if ((check || apply) && check_patch_list(list) < 0)
864+
exit(1);
865+
866+
if (show_files)
867+
show_file_list(list);
868+
869+
if (diffstat)
870+
stat_patch_list(list);
810871

811872
free(buffer);
812873
return 0;
@@ -834,10 +895,19 @@ int main(int argc, char **argv)
834895
continue;
835896
}
836897
if (!strcmp(arg, "--stat")) {
837-
check = 0;
898+
apply = 0;
838899
diffstat = 1;
839900
continue;
840901
}
902+
if (!strcmp(arg, "--check")) {
903+
apply = 0;
904+
check = 1;
905+
continue;
906+
}
907+
if (!strcmp(arg, "--show-files")) {
908+
show_files = 1;
909+
continue;
910+
}
841911
fd = open(arg, O_RDONLY);
842912
if (fd < 0)
843913
usage(apply_usage);

0 commit comments

Comments
 (0)