Last active
February 17, 2022 19:20
-
-
Save yosifkit/e56c211fe77367905960 to your computer and use it in GitHub Desktop.
dev-vcs/git-2.4.10 patch for git diff to work for process substitution: `$ git diff --color-words <(echo a b c) <(echo a d c)`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt | |
index bbab35f..f4ca476 100644 | |
--- a/Documentation/git-diff.txt | |
+++ b/Documentation/git-diff.txt | |
@@ -99,10 +99,17 @@ include::diff-options.txt[] | |
<path>...:: | |
The <paths> parameters, when given, are used to limit | |
the diff to the named paths (you can give directory | |
names and get diff for all files under them). | |
+ + | |
+ With --no-index, or with paths outside the worktree, | |
+ some paths are handled specially: - and /dev/stdin | |
+ refer to standard input, and /dev/fd/* can be used | |
+ to refer to existing file descriptors, as in: | |
+ | |
+ $ git diff --color-words <(echo a b c) <(echo a d c) | |
include::diff-format.txt[] | |
EXAMPLES | |
diff --git a/diff-no-index.c b/diff-no-index.c | |
index 265709b..586036b 100644 | |
--- a/diff-no-index.c | |
+++ b/diff-no-index.c | |
@@ -70,11 +70,11 @@ static int populate_from_stdin(struct diff_filespec *s) | |
s->should_munmap = 0; | |
s->data = strbuf_detach(&buf, &size); | |
s->size = size; | |
s->should_free = 1; | |
- s->is_stdin = 1; | |
+ s->skip_hashing = 1; | |
return 0; | |
} | |
static struct diff_filespec *noindex_filespec(const char *name, int mode) | |
{ | |
@@ -84,10 +84,16 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode) | |
name = "/dev/null"; | |
s = alloc_filespec(name); | |
fill_filespec(s, null_sha1, 0, mode); | |
if (name == file_from_standard_input) | |
populate_from_stdin(s); | |
+ else if (!strcmp(name, "/dev/stdin") || | |
+ !strncmp(name, "/dev/fd/", 8) || | |
+ !strncmp(name, "/proc/self/fd/", 14)) { | |
+ s->skip_hashing = 1; | |
+ s->follow_symlinks = 1; | |
+ } | |
return s; | |
} | |
static int queue_diff(struct diff_options *o, | |
const char *name1, const char *name2) | |
diff --git a/diff.c b/diff.c | |
index d7a5c81..c1150d7 100644 | |
--- a/diff.c | |
+++ b/diff.c | |
@@ -2713,22 +2713,26 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) | |
reuse_worktree_file(s->path, s->sha1, 0)) { | |
struct strbuf buf = STRBUF_INIT; | |
struct stat st; | |
int fd; | |
- if (lstat(s->path, &st) < 0) { | |
+ if (s->follow_symlinks) | |
+ err = stat(s->path, &st); | |
+ else | |
+ err = lstat(s->path, &st); | |
+ if (err < 0) { | |
if (errno == ENOENT) { | |
err_empty: | |
err = -1; | |
empty: | |
s->data = (char *)""; | |
s->size = 0; | |
return err; | |
} | |
} | |
s->size = xsize_t(st.st_size); | |
- if (!s->size) | |
+ if (S_ISREG(st.st_mode) && !s->size) | |
goto empty; | |
if (S_ISLNK(st.st_mode)) { | |
struct strbuf sb = STRBUF_INIT; | |
if (strbuf_readlink(&sb, s->path, s->size)) | |
@@ -2746,13 +2750,25 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) | |
return 0; | |
} | |
fd = open(s->path, O_RDONLY); | |
if (fd < 0) | |
goto err_empty; | |
- s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); | |
+ if (S_ISREG(st.st_mode)) { | |
+ s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); | |
+ s->should_munmap = 1; | |
+ } else { | |
+ struct strbuf sb = STRBUF_INIT; | |
+ if (strbuf_read(&sb, fd, s->size) < 0) { | |
+ err = error("error while reading from %s: %s", | |
+ s->path, strerror(errno)); | |
+ goto err_empty; | |
+ } | |
+ s->data = strbuf_detach(&sb, &s->size); | |
+ s->should_munmap = 0; | |
+ s->should_free = 1; | |
+ } | |
close(fd); | |
- s->should_munmap = 1; | |
/* | |
* Convert from working tree format to canonical git format | |
*/ | |
if (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) { | |
@@ -3084,11 +3100,11 @@ static void run_diff_cmd(const char *pgm, | |
static void diff_fill_sha1_info(struct diff_filespec *one) | |
{ | |
if (DIFF_FILE_VALID(one)) { | |
if (!one->sha1_valid) { | |
struct stat st; | |
- if (one->is_stdin) { | |
+ if (one->skip_hashing) { | |
hashcpy(one->sha1, null_sha1); | |
return; | |
} | |
if (lstat(one->path, &st) < 0) | |
die_errno("stat '%s'", one->path); | |
diff --git a/diffcore.h b/diffcore.h | |
index 33ea2de..e19b379 100644 | |
--- a/diffcore.h | |
+++ b/diffcore.h | |
@@ -32,20 +32,22 @@ struct diff_filespec { | |
unsigned long size; | |
int count; /* Reference count */ | |
int rename_used; /* Count of rename users */ | |
unsigned short mode; /* file mode */ | |
unsigned sha1_valid : 1; /* if true, use sha1 and trust mode; | |
- * if false, use the name and read from | |
- * the filesystem. | |
+ * if false, and skip_hashing is false, fill sha1 | |
+ * by using path and reading from the filesystem. | |
+ * If skip_hashing is true, use null_sha1. | |
*/ | |
#define DIFF_FILE_VALID(spec) (((spec)->mode) != 0) | |
unsigned should_free : 1; /* data should be free()'ed */ | |
unsigned should_munmap : 1; /* data should be munmap()'ed */ | |
unsigned dirty_submodule : 2; /* For submodules: its work tree is dirty */ | |
#define DIRTY_SUBMODULE_UNTRACKED 1 | |
#define DIRTY_SUBMODULE_MODIFIED 2 | |
- unsigned is_stdin : 1; | |
+ unsigned skip_hashing : 1; | |
+ unsigned follow_symlinks : 1; | |
unsigned has_more_entries : 1; /* only appear in combined diff */ | |
/* data should be considered "binary"; -1 means "don't know yet" */ | |
signed int is_binary : 2; | |
struct userdiff_driver *driver; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment