From 4ac2a10aec0464411f5d4c2154ae010430cfe131 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 18 Dec 2014 19:14:10 -0700 Subject: [PATCH 01/12] log: teach --invert-grep option "git log --grep=" shows only commits with messages that match the given string, but sometimes it is useful to be able to show only commits that do *not* have certain messages (e.g. "show me ones that are not FIXUP commits"). Introduce a new --invert-grep option, and add a corresponding bit in the rev_info struct that tells us "we'd run the usual grep thing on the log message, and instead of filtering to show only the commits with matching message, show the ones with messages that do not match". Signed-off-by: Christoph Junghans Signed-off-by: Junio C Hamano --- Documentation/rev-list-options.txt | 4 ++++ contrib/completion/git-completion.bash | 2 +- revision.c | 4 +++- revision.h | 2 ++ t/t4202-log.sh | 12 ++++++++++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index deb8cca9173ccb..05aa997fd1037d 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -66,6 +66,10 @@ if it is part of the log message. Limit the commits output to ones that match all given `--grep`, instead of ones that match at least one. +--invert-grep:: + Limit the commits output to ones with log message that do not + match the pattern specified with `--grep=`. + -i:: --regexp-ignore-case:: Match the regular expression limiting patterns without regard to letter diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 06bf262087768d..53857f0bbf608c 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1428,7 +1428,7 @@ __git_log_gitk_options=" # Options that go well for log and shortlog (not gitk) __git_log_shortlog_options=" --author= --committer= --grep= - --all-match + --all-match --invert-grep " __git_log_pretty_formats="oneline short medium full fuller email raw format:" diff --git a/revision.c b/revision.c index 615535c9845333..84b33a33ca1100 100644 --- a/revision.c +++ b/revision.c @@ -1952,6 +1952,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter); } else if (!strcmp(arg, "--all-match")) { revs->grep_filter.all_match = 1; + } else if (!strcmp(arg, "--invert-grep")) { + revs->invert_grep = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { if (strcmp(optarg, "none")) git_log_output_encoding = xstrdup(optarg); @@ -2848,7 +2850,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt) (char *)message, strlen(message)); strbuf_release(&buf); unuse_commit_buffer(commit, message); - return retval; + return opt->invert_grep ? !retval : retval; } static inline int want_ancestry(const struct rev_info *revs) diff --git a/revision.h b/revision.h index a6205307cf3bb2..b0b82e766eba38 100644 --- a/revision.h +++ b/revision.h @@ -168,6 +168,8 @@ struct rev_info { /* Filter by commit log message */ struct grep_opt grep_filter; + /* Negate the match of grep_filter */ + int invert_grep; /* Display history graph */ struct git_graph *graph; diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 99ab7ca21f2673..1c9934ebf61cd8 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -212,6 +212,18 @@ test_expect_success 'log --grep' ' test_cmp expect actual ' +test_expect_success 'log --invert-grep --grep' ' + echo second >expect && + git log -1 --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual && + test_cmp expect actual +' + +test_expect_success 'log --invert-grep --grep -i' ' + echo initial >expect && + git log -1 --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual && + test_cmp expect actual +' + test_expect_success 'log --grep option parsing' ' echo second >expect && git log -1 --pretty="tformat:%s" --grep sec >actual && From 1f5798959c883fb8108e5a26938f761894ef915d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Jan 2015 10:26:06 -0800 Subject: [PATCH 02/12] Revert "Merge branch 'cj/log-invert-grep' into next" This reverts commit 4589ca234b1c10017901f857a354954090ef6e1c, reversing changes made to 0cbbf4a2f0b3231bb27655c8371b3813201d7727. --- Documentation/rev-list-options.txt | 4 ---- contrib/completion/git-completion.bash | 2 +- revision.c | 4 +--- revision.h | 2 -- t/t4202-log.sh | 12 ------------ 5 files changed, 2 insertions(+), 22 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 0f3d460d34a628..2984f407a9f308 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -66,10 +66,6 @@ if it is part of the log message. Limit the commits output to ones that match all given `--grep`, instead of ones that match at least one. ---invert-grep:: - Limit the commits output to ones with log message that do not - match the pattern specified with `--grep=`. - -i:: --regexp-ignore-case:: Match the regular expression limiting patterns without regard to letter diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index c21190d7510c17..8cfee95f880062 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1425,7 +1425,7 @@ __git_log_gitk_options=" # Options that go well for log and shortlog (not gitk) __git_log_shortlog_options=" --author= --committer= --grep= - --all-match --invert-grep + --all-match " __git_log_pretty_formats="oneline short medium full fuller email raw format:" diff --git a/revision.c b/revision.c index 4bc851c070e40f..86406a26a2d459 100644 --- a/revision.c +++ b/revision.c @@ -2017,8 +2017,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter); } else if (!strcmp(arg, "--all-match")) { revs->grep_filter.all_match = 1; - } else if (!strcmp(arg, "--invert-grep")) { - revs->invert_grep = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { if (strcmp(optarg, "none")) git_log_output_encoding = xstrdup(optarg); @@ -2917,7 +2915,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt) (char *)message, strlen(message)); strbuf_release(&buf); unuse_commit_buffer(commit, message); - return opt->invert_grep ? !retval : retval; + return retval; } static inline int want_ancestry(const struct rev_info *revs) diff --git a/revision.h b/revision.h index 17ebafc4c76de4..033a24460e71b7 100644 --- a/revision.h +++ b/revision.h @@ -169,8 +169,6 @@ struct rev_info { /* Filter by commit log message */ struct grep_opt grep_filter; - /* Negate the match of grep_filter */ - int invert_grep; /* Display history graph */ struct git_graph *graph; diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 1c9934ebf61cd8..99ab7ca21f2673 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -212,18 +212,6 @@ test_expect_success 'log --grep' ' test_cmp expect actual ' -test_expect_success 'log --invert-grep --grep' ' - echo second >expect && - git log -1 --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual && - test_cmp expect actual -' - -test_expect_success 'log --invert-grep --grep -i' ' - echo initial >expect && - git log -1 --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual && - test_cmp expect actual -' - test_expect_success 'log --grep option parsing' ' echo second >expect && git log -1 --pretty="tformat:%s" --grep sec >actual && From 2db92d6ca0b93187cb6bee75fe7080163aa405e6 Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Sat, 17 Jan 2015 20:56:38 +0000 Subject: [PATCH 03/12] git-p4: support excluding paths on sync The clone subcommand has long had support for excluding subdirectories, but sync has not. This is a nuisance, since as soon as you do a sync, any changed files that were initially excluded start showing up. Move the "exclude" command-line option into the parent class; the actual behavior was already present there so it simply had to be exposed. Signed-off-by: Luke Diamand Reviewed-by: Pete Wyckoff Signed-off-by: Junio C Hamano --- Documentation/git-p4.txt | 6 ++-- git-p4.py | 18 +++++----- t/t9817-git-p4-exclude.sh | 71 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 12 deletions(-) create mode 100755 t/t9817-git-p4-exclude.sh diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt index 6ab5f9497ab353..a1664b9f684bae 100644 --- a/Documentation/git-p4.txt +++ b/Documentation/git-p4.txt @@ -241,6 +241,9 @@ Git repository: Use a client spec to find the list of interesting files in p4. See the "CLIENT SPEC" section below. +-/ :: + Exclude selected depot paths when cloning or syncing. + Clone options ~~~~~~~~~~~~~ These options can be used in an initial 'clone', along with the 'sync' @@ -254,9 +257,6 @@ options described above. --bare:: Perform a bare clone. See linkgit:git-clone[1]. --/ :: - Exclude selected depot paths when cloning. - Submit options ~~~~~~~~~~~~~~ These options can be used to modify 'git p4 submit' behavior. diff --git a/git-p4.py b/git-p4.py index ff132b2117c5ed..38029a4a5cc2cd 100755 --- a/git-p4.py +++ b/git-p4.py @@ -1916,6 +1916,9 @@ def __init__(self): help="Keep entire BRANCH/DIR/SUBDIR prefix during import"), optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true', help="Only sync files that are included in the Perforce Client Spec") + optparse.make_option("-/", dest="cloneExclude", + action="append", type="string", + help="exclude depot path"), ] self.description = """Imports from Perforce into a git repository.\n example: @@ -1950,6 +1953,12 @@ def __init__(self): if gitConfig("git-p4.syncFromOrigin") == "false": self.syncWithOrigin = False + # This is required for the "append" cloneExclude action + def ensure_value(self, attr, value): + if not hasattr(self, attr) or getattr(self, attr) is None: + setattr(self, attr, value) + return getattr(self, attr) + # Force a checkpoint in fast-import and wait for it to finish def checkpoint(self): self.gitStream.write("checkpoint\n\n") @@ -3101,9 +3110,6 @@ def __init__(self): optparse.make_option("--destination", dest="cloneDestination", action='store', default=None, help="where to leave result of the clone"), - optparse.make_option("-/", dest="cloneExclude", - action="append", type="string", - help="exclude depot path"), optparse.make_option("--bare", dest="cloneBare", action="store_true", default=False), ] @@ -3111,12 +3117,6 @@ def __init__(self): self.needsGit = False self.cloneBare = False - # This is required for the "append" cloneExclude action - def ensure_value(self, attr, value): - if not hasattr(self, attr) or getattr(self, attr) is None: - setattr(self, attr, value) - return getattr(self, attr) - def defaultDestination(self, args): ## TODO: use common prefix of args? depotPath = args[0] diff --git a/t/t9817-git-p4-exclude.sh b/t/t9817-git-p4-exclude.sh new file mode 100755 index 00000000000000..aac568eadfcab6 --- /dev/null +++ b/t/t9817-git-p4-exclude.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='git p4 tests for excluded paths during clone and sync' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# Create a repo with the structure: +# +# //depot/wanted/foo +# //depot/discard/foo +# +# Check that we can exclude a subdirectory with both +# clone and sync operations. + +test_expect_success 'create exclude repo' ' + ( + cd "$cli" && + mkdir -p wanted discard && + echo wanted >wanted/foo && + echo discard >discard/foo && + p4 add wanted/foo discard/foo && + p4 submit -d "initial revision" + ) +' + +test_expect_success 'check the repo was created correctly' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot/...@all && + ( + cd "$git" && + test_path_is_file wanted/foo && + test_path_is_file discard/foo + ) +' + +test_expect_success 'clone, excluding part of repo' ' + test_when_finished cleanup_git && + git p4 clone -//depot/discard/... --dest="$git" //depot/...@all && + ( + cd "$git" && + test_path_is_file wanted/foo && + test_path_is_missing discard/foo + ) +' + +test_expect_success 'clone, then sync with exclude' ' + test_when_finished cleanup_git && + git p4 clone -//depot/discard/... --dest="$git" //depot/...@all && + ( + cd "$cli" && + p4 edit wanted/foo discard/foo && + date >>wanted/foo && + date >>discard/foo && + p4 submit -d "updating" && + + cd "$git" && + git p4 sync -//depot/discard/... && + test_path_is_file wanted/foo && + test_path_is_missing discard/foo + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done From 157212afa3f0263bd1c27a65073c3bc2ecb6920e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 9 Dec 2014 13:36:48 +0100 Subject: [PATCH 04/12] TO-UNDO: debug Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e8ce649ca1e2fb..4b8427981e963a 100644 --- a/Makefile +++ b/Makefile @@ -364,7 +364,7 @@ GIT-VERSION-FILE: FORCE # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -Wall LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From b097cc91e1b93d0e6579be38a7c4e2db107967b8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Feb 2015 08:57:22 +0100 Subject: [PATCH 05/12] fsck_commit: look at parents only if the commit was parsed already We want to use the fsck machinery also for objects that are just about to be written, i.e. well before they actually *can* be parsed. So let's teach the fsck machinery to avoid accessing possibly uninitialized data. Signed-off-by: Johannes Schindelin --- fsck.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fsck.c b/fsck.c index 10bcb651516e2c..3e8343fd451aac 100644 --- a/fsck.c +++ b/fsck.c @@ -305,7 +305,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, { unsigned char tree_sha1[20], sha1[20]; struct commit_graft *graft; - unsigned parent_count, parent_line_count = 0; + unsigned parent_line_count = 0; int err; if (require_end_of_header(buffer, size, &commit->object, error_func)) @@ -323,15 +323,17 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, parent_line_count++; } graft = lookup_commit_graft(commit->object.sha1); - parent_count = commit_list_count(commit->parents); - if (graft) { - if (graft->nr_parent == -1 && !parent_count) - ; /* shallow commit */ - else if (graft->nr_parent != parent_count) - return error_func(&commit->object, FSCK_ERROR, "graft objects missing"); - } else { - if (parent_count != parent_line_count) - return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); + if (commit->object.parsed) { + unsigned parent_count = commit_list_count(commit->parents); + if (graft) { + if (graft->nr_parent == -1 && !parent_count) + ; /* shallow commit */ + else if (graft->nr_parent != parent_count) + return error_func(&commit->object, FSCK_ERROR, "graft objects missing"); + } else { + if (parent_count != parent_line_count) + return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); + } } if (!skip_prefix(buffer, "author ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); From 2819adce27fb54b3c974c013a374c13299d6ccfa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 9 Dec 2014 11:48:59 +0100 Subject: [PATCH 06/12] git-mktree: introduce the --strict option So far, `git mktree` performs rudimentary checks on the input, but we should really perform deeper checks lest we introduce invalid tree objects into the repository. With `--strict`, we now call the fsck machinery to validate the tree object before writing. Signed-off-by: Johannes Schindelin --- Documentation/git-mktree.txt | 6 +++++- builtin/mktree.c | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/git-mktree.txt b/Documentation/git-mktree.txt index 5c6ebdfad93ea8..774e34caf06f32 100644 --- a/Documentation/git-mktree.txt +++ b/Documentation/git-mktree.txt @@ -9,7 +9,7 @@ git-mktree - Build a tree-object from ls-tree formatted text SYNOPSIS -------- [verse] -'git mktree' [-z] [--missing] [--batch] +'git mktree' [-z] [--strict] [--missing] [--batch] DESCRIPTION ----------- @@ -23,6 +23,10 @@ OPTIONS -z:: Read the NUL-terminated `ls-tree -z` output instead. +--strict:: + Validate the tree object before writing (the validation is equivalent + to the one performed by linkgit:git-fsck[1]). + --missing:: Allow missing objects. The default behaviour (without this option) is to verify that each tree entry's sha1 identifies an existing diff --git a/builtin/mktree.c b/builtin/mktree.c index a964d6be521c09..baf47fba06c436 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -7,7 +7,10 @@ #include "quote.h" #include "tree.h" #include "parse-options.h" +#include "tree.h" +#include "fsck.h" +static int strict; static struct treeent { unsigned mode; unsigned char sha1[20]; @@ -56,6 +59,16 @@ static void write_tree(unsigned char *sha1) strbuf_add(&buf, ent->sha1, 20); } + if (strict) { + struct tree tree; + memset(&tree, 0, sizeof(tree)); + tree.object.type = OBJ_TREE; + parse_tree_buffer(&tree, buf.buf, buf.len); + if (fsck_object(&tree.object, buf.buf, buf.len, 1, + fsck_error_function)) + exit(1); + } + write_sha1_file(buf.buf, buf.len, tree_type, sha1); strbuf_release(&buf); } @@ -150,6 +163,7 @@ int cmd_mktree(int ac, const char **av, const char *prefix) OPT_SET_INT('z', NULL, &line_termination, N_("input is NUL terminated"), '\0'), OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1), OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1), + OPT_BOOL( 0 , "strict", &strict, N_("validate the tree object")), OPT_END() }; From b7f357635762e8871d87c6ea8f2ea08828b863a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 9 Dec 2014 12:00:15 +0100 Subject: [PATCH 07/12] Add tests for git-mktree validation This test verifies that git-mktree refuses to write a tree object that references invalid file names. Signed-off-by: Johannes Schindelin --- t/t1010-mktree.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh index b946f8768649dd..96ed460a23866b 100755 --- a/t/t1010-mktree.sh +++ b/t/t1010-mktree.sh @@ -66,4 +66,10 @@ test_expect_success 'mktree refuses to read ls-tree -r output (2)' ' test_must_fail git mktree actual ' +test_expect_success '`mktree --strict` validates before writing' ' + printf "40000 tree %s\t.\n" $(git rev-parse HEAD:) > bogus-tree && + test_must_fail git mktree --strict Date: Tue, 9 Dec 2014 19:05:55 +0100 Subject: [PATCH 08/12] git hash-object: introduce the --strict option With the new option, the fsck machinery is used to validate the hashed object. Signed-off-by: Johannes Schindelin --- Documentation/git-hash-object.txt | 7 +++++-- builtin/hash-object.c | 9 +++++++-- cache.h | 1 + sha1_file.c | 17 ++++++++++++++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt index 02c1f126855b24..2a2afdb4602635 100644 --- a/Documentation/git-hash-object.txt +++ b/Documentation/git-hash-object.txt @@ -9,8 +9,8 @@ git-hash-object - Compute object ID and optionally creates a blob from a file SYNOPSIS -------- [verse] -'git hash-object' [-t ] [-w] [--path=|--no-filters] [--stdin] [--] ... -'git hash-object' [-t ] [-w] --stdin-paths [--no-filters] < +'git hash-object' [--strict] [-t ] [-w] [--path=|--no-filters] [--stdin] [--] ... +'git hash-object' [--strict] [-t ] [-w] --stdin-paths [--no-filters] < DESCRIPTION ----------- @@ -25,6 +25,9 @@ specified, it defaults to "blob". OPTIONS ------- +--strict:: + Validate the object (equivalent to linkgit:git-fsck[1]). + -t :: Specify the type (default: "blob"). diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 207b90c7b13e10..58d97ecd0a8755 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -79,8 +79,8 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags, int cmd_hash_object(int argc, const char **argv, const char *prefix) { static const char * const hash_object_usage[] = { - N_("git hash-object [-t ] [-w] [--path= | --no-filters] [--stdin] [--] ..."), - N_("git hash-object --stdin-paths < "), + N_("git hash-object [--strict] [-t ] [-w] [--path= | --no-filters] [--stdin] [--] ..."), + N_("git hash-object [--strict] --stdin-paths < "), NULL }; const char *type = blob_type; @@ -88,6 +88,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) int stdin_paths = 0; int no_filters = 0; int literally = 0; + int strict = 0; unsigned flags = HASH_FORMAT_CHECK; const char *vpath = NULL; const struct option hash_object_options[] = { @@ -97,6 +98,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")), OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")), OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")), + OPT_BOOL( 0, "strict", &strict, N_("validate thoroughly before writing")), OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")), OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")), OPT_END() @@ -137,6 +139,9 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) usage_with_options(hash_object_usage, hash_object_options); } + if (strict) + flags |= HASH_FORMAT_STRICT; + if (hashstdin) hash_fd(0, type, vpath, flags, literally); diff --git a/cache.h b/cache.h index f704af5df0984e..513e6ee1925575 100644 --- a/cache.h +++ b/cache.h @@ -536,6 +536,7 @@ extern int ie_modified(const struct index_state *, const struct cache_entry *, s #define HASH_WRITE_OBJECT 1 #define HASH_FORMAT_CHECK 2 +#define HASH_FORMAT_STRICT 4 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags); diff --git a/sha1_file.c b/sha1_file.c index 30995e61b38fbf..fa2ae7466899ba 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -23,6 +23,7 @@ #include "bulk-checkin.h" #include "streaming.h" #include "dir.h" +#include "fsck.h" #ifndef O_NOATIME #if defined(__linux__) && (defined(__i386__) || defined(__PPC__)) @@ -3117,11 +3118,21 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, } } if (flags & HASH_FORMAT_CHECK) { - if (type == OBJ_TREE) + if (flags & HASH_FORMAT_STRICT) { + struct object object; + + memset(&object, 0, sizeof(object)); + object.type = type; + memcpy(object.sha1, sha1, 20); + if (fsck_object(&object, buf, size, 1, + fsck_error_function)) + exit(1); + } + else if (type == OBJ_TREE) check_tree(buf, size); - if (type == OBJ_COMMIT) + else if (type == OBJ_COMMIT) check_commit(buf, size); - if (type == OBJ_TAG) + else if (type == OBJ_TAG) check_tag(buf, size); } From a8c1ace82953d54f521366f4d08bd4c6b418feb7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 9 Dec 2014 23:57:47 +0100 Subject: [PATCH 09/12] Add a test for hash-object --strict Signed-off-by: Johannes Schindelin --- t/t1007-hash-object.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index f83df8eb8b1430..39317ab6e59788 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -201,4 +201,18 @@ test_expect_success 'corrupt tag' ' test_must_fail git hash-object -t tag --stdin bogus-commit < 123459876 +0100 + +This commit message intentionally left blank +EOF + +test_expect_success 'hash-object --strict' ' + test_must_fail git hash-object \ + --strict -t commit --stdin -w Date: Wed, 10 Dec 2014 00:15:35 +0100 Subject: [PATCH 10/12] Enforce validation with `git replace --edit` Signed-off-by: Johannes Schindelin --- builtin/replace.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin/replace.c b/builtin/replace.c index 85d39b58d8aa35..b2ea28f9a93846 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -236,7 +236,7 @@ static void import_object(unsigned char *sha1, enum object_type type, die_errno("unable to open %s for reading", filename); if (!raw && type == OBJ_TREE) { - const char *argv[] = { "mktree", NULL }; + const char *argv[] = { "mktree", "--strict", NULL }; struct child_process cmd = CHILD_PROCESS_INIT; struct strbuf result = STRBUF_INIT; @@ -260,7 +260,8 @@ static void import_object(unsigned char *sha1, enum object_type type, strbuf_release(&result); } else { struct stat st; - int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT; + int flags = HASH_FORMAT_CHECK | HASH_FORMAT_STRICT | + HASH_WRITE_OBJECT; if (fstat(fd, &st) < 0) die_errno("unable to fstat %s", filename); From abb002863e292d0d06d4f5a05c6b589d135db8dc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 10 Dec 2014 00:31:53 +0100 Subject: [PATCH 11/12] Verify that `git replace --edit` validates before replacing It makes little sense to allow the user to replace objects with bogus objects... Signed-off-by: Johannes Schindelin --- t/t6050-replace.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 4d5a25eedfef50..6e2f3b215ad657 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -378,6 +378,17 @@ test_expect_success '--edit and change nothing or command failed' ' git cat-file commit "$PARA3" | grep "A fake Thor" ' +test_expect_success 'setup an intentionally broken fake editor' ' + write_script fakeeditor <<-\EOF + tr -d "<>" <"$1" >"$1.new" + mv "$1.new" "$1" + EOF +' + +test_expect_success '--edit validates before replacing the object' ' + test_must_fail env GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" +' + test_expect_success 'replace ref cleanup' ' test -n "$(git replace)" && git replace -d $(git replace) && From 09826f5fed326401e9b75b202f7783ab0b207ba6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Feb 2015 08:55:18 +0100 Subject: [PATCH 12/12] DEBUG Signed-off-by: Johannes Schindelin --- builtin/hash-object.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 58d97ecd0a8755..f3eb7857800a59 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -143,7 +143,14 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) flags |= HASH_FORMAT_STRICT; if (hashstdin) +{ +if (getenv("DEBUG_BOGUS_COMMIT")) { +int fd = open("bogus-commit", O_RDONLY); +hash_fd(fd, type, vpath, flags, literally); +close(fd); +} else hash_fd(0, type, vpath, flags, literally); +} for (i = 0 ; i < argc; i++) { const char *arg = argv[i];