# [PATCH V2/RFC][GSoC] diff-no-index: transform "$directory $file" args to "$directory/$file $file"

2 messages from 2015-03-26 to 2015-03-26. Participants: Yurii Shevtsov, Junio C Hamano.
Thread: https://gitlist.dev/t/38919

## Yurii Shevtsov, 2015-03-26 20:54

Subject: [PATCH V2/RFC][GSoC] diff-no-index: transform "$directory $file" args to "$directory/$file $file"
Message-ID: <CAHLaBN+nE9tmGMdJM65V-bONKe8CE9PZ1Ottc1R9D=Pm0X7k_g@mail.gmail.com>
URL: https://gitlist.dev/e/CAHLaBN%2BnE9tmGMdJM65V-bONKe8CE9PZ1Ottc1R9D%3DPm0X7k_g%40mail.gmail.com

```
git diff --no-index refuses to compare if args are directory and file,
instead of usual diff.

Now git diff --no-index modifies args, if they're directory and file,
and diffs files, as usual diff does.

Changes are done in diff_no_index().

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Yurii Shevtsov <ungetch@gmail.com>
---
 diff-no-index.c |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/diff-no-index.c b/diff-no-index.c
index 265709b..ecff15e 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -186,7 +186,7 @@ void diff_no_index(struct rev_info *revs,
            int argc, const char **argv,
            const char *prefix)
 {
-    int i, prefixlen;
+    int i, prefixlen, mode1 = 0, mode2 = 0;
     const char *paths[2];

     diff_setup(&revs->diffopt);
@@ -229,8 +229,35 @@ void diff_no_index(struct rev_info *revs,
     setup_diff_pager(&revs->diffopt);
     DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);

-    if (queue_diff(&revs->diffopt, paths[0], paths[1]))
+    if (get_mode(paths[0], &mode1) || get_mode(paths[1], &mode2))
+        exit(2);
+
+    if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) {
+        struct strbuf pathtofile;
+        const char *dir, *file;
+        char *filename;
+        int ret;
+
+        dir = S_ISDIR(mode1) ? paths[0] : paths[1];
+        file = (dir == paths[0]) ? paths[1] : paths[0];
+        strbuf_init(&pathtofile, strlen(paths[0]) + strlen(paths[1]) + 1);
+        strbuf_addstr(&pathtofile, dir);
+        if (pathtofile.len && pathtofile.buf[pathtofile.len - 1] != '/')
+               strbuf_addch(&pathtofile, '/');
+        filename = strrchr(file, '/');
+        strbuf_addstr(&pathtofile, filename ? (filename + 1) : file);
+
+        if (file == paths[0])
+            ret = queue_diff(&revs->diffopt, file, pathtofile.buf);
+        else
+            ret = queue_diff(&revs->diffopt, pathtofile.buf, file);
+        strbuf_release(&pathtofile);
+        if (ret)
+            exit(1);
+    }
+    else if (queue_diff(&revs->diffopt, paths[0], paths[1]))
         exit(1);
+
     diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
     diffcore_std(&revs->diffopt);
     diff_flush(&revs->diffopt);
-- 

Attached patch file because gmail always replaces tabs with spaces and
refuses to authorize 'git send-email'


From 0e160b47960dd436b32e55229184688c0a9da069 Mon Sep 17 00:00:00 2001
From: Yurii Shevtsov <ungetch@gmail.com>
Date: Thu, 25 Mar 2015 18:43:24 +0200
Subject: [PATCH]  diff-no-index: transform "$directory $file" args to "$directory/$file $file"
git diff --no-index refuses to compare if args are directory and file, instead of usual diff.

Now git diff --no-index modifies args, if they're directory and file, and
diffs files, as usual diff does.

Changes are done in diff_no_index().

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Yurii Shevtsov <ungetch@gmail.com>
---
 diff-no-index.c |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/diff-no-index.c b/diff-no-index.c
index 265709b..ecff15e 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -186,7 +186,7 @@ void diff_no_index(struct rev_info *revs,
 		   int argc, const char **argv,
 		   const char *prefix)
 {
-	int i, prefixlen;
+	int i, prefixlen, mode1 = 0, mode2 = 0;
 	const char *paths[2];
 
 	diff_setup(&revs->diffopt);
@@ -229,8 +229,35 @@ void diff_no_index(struct rev_info *revs,
 	setup_diff_pager(&revs->diffopt);
 	DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
 
-	if (queue_diff(&revs->diffopt, paths[0], paths[1]))
+	if (get_mode(paths[0], &mode1) || get_mode(paths[1], &mode2))
+		exit(2);
+
+	if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) {
+		struct strbuf pathtofile;
+		const char *dir, *file;
+		char *filename;
+		int ret;
+
+		dir = S_ISDIR(mode1) ? paths[0] : paths[1];
+		file = (dir == paths[0]) ? paths[1] : paths[0];
+		strbuf_init(&pathtofile, strlen(paths[0]) + strlen(paths[1]) + 1);
+		strbuf_addstr(&pathtofile, dir);
+		if (pathtofile.len && pathtofile.buf[pathtofile.len - 1] != '/')
+			   strbuf_addch(&pathtofile, '/');
+		filename = strrchr(file, '/');
+		strbuf_addstr(&pathtofile, filename ? (filename + 1) : file);
+
+		if (file == paths[0])
+			ret = queue_diff(&revs->diffopt, file, pathtofile.buf);
+		else
+			ret = queue_diff(&revs->diffopt, pathtofile.buf, file);
+		strbuf_release(&pathtofile);
+		if (ret)
+			exit(1);
+	}
+	else if (queue_diff(&revs->diffopt, paths[0], paths[1]))
 		exit(1);
+
 	diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
 	diffcore_std(&revs->diffopt);
 	diff_flush(&revs->diffopt);
-- 
1.7.1


```

## Junio C Hamano, 2015-03-26 22:58

Subject: Re: [PATCH V2/RFC][GSoC] diff-no-index: transform "$directory $file" args to "$directory/$file $file"
Message-ID: <xmqq4mp7xt5k.fsf@gitster.dls.corp.google.com>
URL: https://gitlist.dev/e/xmqq4mp7xt5k.fsf%40gitster.dls.corp.google.com
In-Reply-To: <CAHLaBN+nE9tmGMdJM65V-bONKe8CE9PZ1Ottc1R9D=Pm0X7k_g@mail.gmail.com>

```
Yurii Shevtsov <ungetch@gmail.com> writes:

> git diff --no-index refuses to compare if args are directory and file,
> instead of usual diff.
>
> Now git diff --no-index modifies args, if they're directory and file,
> and diffs files, as usual diff does.
>
> Changes are done in diff_no_index().
>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Yurii Shevtsov <ungetch@gmail.com>
> ---
>  diff-no-index.c |   31 +++++++++++++++++++++++++++++--
>  1 files changed, 29 insertions(+), 2 deletions(-)

This round looks sensible.  Good catch to notice that POSIX wants
you to append not just the "path to the file", but the basename of
the file, to the directory name.

I didn't try your patch, but I wouldn't be surprised if it passed
the tests in the patches I wrote last night in the $gmane/266315
thread ;-).

Good luck with your GSoC application.

```
