Code

add --path option to git hash-object
authorDmitry Potapov <dpotapov@gmail.com>
Sun, 3 Aug 2008 14:36:21 +0000 (18:36 +0400)
committerJunio C Hamano <gitster@pobox.com>
Sun, 3 Aug 2008 20:33:06 +0000 (13:33 -0700)
The --path option allows us to pretend as if the contents being hashed
came from the specified path, and affects which input filter is used via
the attributes mechanism.  This is useful for hashing a temporary file
whose name is different from the path that is meant to have the hashed
contents.

Signed-off-by: Dmitry Potapov <dpotapov@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-hash-object.txt
hash-object.c
t/t1007-hash-object.sh

index a4703ec0defe4686780184354120e666b79f26f6..fececbf7537bf1bf53ca6bc5db2439062c778b8c 100644 (file)
@@ -9,7 +9,7 @@ git-hash-object - Compute object ID and optionally creates a blob from a file
 SYNOPSIS
 --------
 [verse]
-'git hash-object' [-t <type>] [-w] [--stdin] [--] <file>...
+'git hash-object' [-t <type>] [-w] [--path=<file>] [--stdin] [--] <file>...
 'git hash-object' [-t <type>] [-w] --stdin-paths < <list-of-paths>
 
 DESCRIPTION
@@ -37,6 +37,16 @@ OPTIONS
 --stdin-paths::
        Read file names from stdin instead of from the command-line.
 
+--path::
+       Hash object as it were located at the given path. The location of
+       file does not directly influence on the hash value, but path is
+       used to determine what git filters should be applied to the object
+       before it can be placed to the object database, and, as result of
+       applying filters, the actual blob put into the object database may
+       differ from the given file. This option is mainly useful for hashing
+       temporary files located outside of the working directory or files
+       read from stdin.
+
 Author
 ------
 Written by Junio C Hamano <gitster@pobox.com>
index 489e8369d8b8baca4bbe8a1b95f757401f18fde3..ce04d150a444e6c9b68097721180c998039f632e 100644 (file)
@@ -22,13 +22,14 @@ static void hash_fd(int fd, const char *type, int write_object, const char *path
        maybe_flush_or_die(stdout, "hash to stdout");
 }
 
-static void hash_object(const char *path, const char *type, int write_object)
+static void hash_object(const char *path, const char *type, int write_object,
+                       const char *vpath)
 {
        int fd;
        fd = open(path, O_RDONLY);
        if (fd < 0)
                die("Cannot open %s", path);
-       hash_fd(fd, type, write_object, path);
+       hash_fd(fd, type, write_object, vpath);
 }
 
 static void hash_stdin_paths(const char *type, int write_objects)
@@ -44,14 +45,14 @@ static void hash_stdin_paths(const char *type, int write_objects)
                                die("line is badly quoted");
                        strbuf_swap(&buf, &nbuf);
                }
-               hash_object(buf.buf, type, write_objects);
+               hash_object(buf.buf, type, write_objects, buf.buf);
        }
        strbuf_release(&buf);
        strbuf_release(&nbuf);
 }
 
 static const char * const hash_object_usage[] = {
-       "git hash-object [-t <type>] [-w] [--stdin] [--] <file>...",
+       "git hash-object [-t <type>] [-w] [--path=<file>] [--stdin] [--] <file>...",
        "git hash-object  --stdin-paths < <list-of-paths>",
        NULL
 };
@@ -60,12 +61,14 @@ static const char *type;
 static int write_object;
 static int hashstdin;
 static int stdin_paths;
+static const char *vpath;
 
 static const struct option hash_object_options[] = {
        OPT_STRING('t', NULL, &type, "type", "object type"),
        OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"),
        OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"),
        OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"),
+       OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"),
        OPT_END()
 };
 
@@ -85,6 +88,8 @@ int main(int argc, const char **argv)
        if (write_object) {
                prefix = setup_git_directory();
                prefix_length = prefix ? strlen(prefix) : 0;
+               if (vpath && prefix)
+                       vpath = prefix_filename(prefix, prefix_length, vpath);
        }
 
        if (stdin_paths) {
@@ -92,6 +97,8 @@ int main(int argc, const char **argv)
                        errstr = "Can't use --stdin-paths with --stdin";
                else if (argc)
                        errstr = "Can't specify files with --stdin-paths";
+               else if (vpath)
+                       errstr = "Can't use --stdin-paths with --path";
        }
        else if (hashstdin > 1)
                errstr = "Multiple --stdin arguments are not supported";
@@ -102,14 +109,14 @@ int main(int argc, const char **argv)
        }
 
        if (hashstdin)
-               hash_fd(0, type, write_object, NULL);
+               hash_fd(0, type, write_object, vpath);
 
        for (i = 0 ; i < argc; i++) {
                const char *arg = argv[i];
 
                if (0 <= prefix_length)
                        arg = prefix_filename(prefix, prefix_length, arg);
-               hash_object(arg, type, write_object);
+               hash_object(arg, type, write_object, vpath ? vpath : arg);
        }
 
        if (stdin_paths)
index 6d505fafeb1c41bec93db82a5f2a66f3f65b623c..f3972a79afe515fb02b3d984c5185e0a723aab1b 100755 (executable)
@@ -61,6 +61,10 @@ test_expect_success "Can't pass filenames as arguments with --stdin-paths" '
        echo example | test_must_fail git hash-object --stdin-paths hello
 '
 
+test_expect_success "Can't use --path with --stdin-paths" '
+       echo example | test_must_fail git hash-object --stdin-paths --path=foo
+'
+
 # Behavior
 
 push_repo
@@ -93,6 +97,26 @@ test_expect_success 'git hash-object --stdin file1 <file0 first operates on file
        test "$obname1" = "$obname1new"
 '
 
+test_expect_success 'check that appropriate filter is invoke when --path is used' '
+       echo fooQ | tr Q "\\015" >file0 &&
+       cp file0 file1 &&
+       echo "file0 -crlf" >.gitattributes &&
+       echo "file1 crlf" >>.gitattributes &&
+       git config core.autocrlf true &&
+       file0_sha=$(git hash-object file0) &&
+       file1_sha=$(git hash-object file1) &&
+       test "$file0_sha" != "$file1_sha" &&
+       path1_sha=$(git hash-object --path=file1 file0) &&
+       path0_sha=$(git hash-object --path=file0 file1) &&
+       test "$file0_sha" = "$path0_sha" &&
+       test "$file1_sha" = "$path1_sha" &&
+       path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) &&
+       path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) &&
+       test "$file0_sha" = "$path0_sha" &&
+       test "$file1_sha" = "$path1_sha" &&
+       git config --unset core.autocrlf
+'
+
 pop_repo
 
 for args in "-w --stdin" "--stdin -w"; do