git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] difftool: add support for an extended revision syntax
@ 2009-03-23 10:15 David Aguilar
  2009-03-23 14:51 ` Michael J Gruber
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: David Aguilar @ 2009-03-23 10:15 UTC (permalink / raw)
  To: gitster; +Cc: git, David Aguilar

This adds an extended revision syntax to git-difftool.
Users often ask "how do I compare a file against its
previous version" and the answer is typically a combination
of 'git log <file>' and 'git difftool <sha1> <sha1> <file>'.

This makes answering that question considerably easier.
Users can now simply say:

	$ git difftool <file>~

to compare <file> in the worktree against its
previous version, and:

	$ git difftool <file>~2 <file>~

to compare <file> from 2 versions ago to <file>'s
previous version, etc.

The extended revision syntax also expands revisions
that are suffixed with '!' as a convenient way to
see commit diffs.  Specifying only '!' is equivalent
to specifying 'HEAD!'.

This makes the following statements equivalent:

	$ git difftool !
	$ git difftool HEAD!
	$ git difftool HEAD~ HEAD

Signed-off-by: David Aguilar <davvid@gmail.com>
---

This patch is based on top of the "add tests to difftool"
patch which itself is based upon the "move difftool out of contrib"
patch currently in the "pu" and "da/difftool" branches.

This feature is incredibly useful but it also adds a brand new
way of specifying revisions that is only understood by git-difftool.

This was specifically asked for by a git-difftool user
who was disapointed to learn that they had to dig through
git-log just to use git-difftool effectively.

I do not think git-diff should know anything about the
"extended revision syntax" which is why this behavior
is best suited for a porcelain such as difftool.
I can imagine that 'file~' would be a useful construct
in core git, but changing the plumbing just for something
like that seems both daunting and misguided.

Some of the conditional expressions were modified to match
the style used in git-add--interactive.perl.  I can split
this patch into two if needed, but I figured they were
trivial and didn't warrant a separate patch.

I had to escape some tilde characters in the documentation
because asciidoc kept generating invalid html when the
{tilde} notation was used within single quotes multiple times.

In case anyone asks, git-diff understands this new syntax too
(though we did have to twist its arm ;))

	$ git config alias.ddiff 'difftool --no-ext-diff'
	$ git ddiff Makefile~

Any thoughts on whether adding this syntax to git-diff/rev-parse
would be feasible/sane/worth it?

 Documentation/git-difftool.txt |   55 ++++++++++++++++++-
 git-difftool.perl              |  119 ++++++++++++++++++++++++++++++++++++++--
 t/t7800-difftool.sh            |   43 ++++++++++++++
 3 files changed, 210 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 5ae02f8..2911b84 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -7,7 +7,9 @@ git-difftool - Show changes using common diff tools
 
 SYNOPSIS
 --------
-'git difftool' [--tool=<tool>] [--no-prompt] [<'git diff' options>]
+'git difftool' [--tool=<tool>] [--no-prompt]
+               [<'git diff' options>]
+               [<extended revision syntax>]
 
 DESCRIPTION
 -----------
@@ -54,6 +56,57 @@ with custom merge tool commands and has the same value as `$LOCAL`.
 
 See linkgit:git-diff[1] for the full list of supported options.
 
+EXTENDED REVISION SYNTAX
+------------------------
+'git-difftool' understands an extended syntax for specifying revisions.
+
+* A suffix '{tilde}' to a file means the previous commit that touched file.
+
+* A suffix '{tilde}<n>' to a file means the <n>th previous commit that
+touched file.  E.g. 'file\~3' is equivalent to 'file\~\~\~'.
+
+* A revision suffixed with an exclamation mark '!' expands to
+'revision\~..revision', i.e. the commit diff for that revision.
+
+'git-difftool' recognizes this syntax and passes the corresponding
+commits to 'git-diff'.
+
+Examples
+~~~~~~~~
+
+---------------------------------------------------
+# File Revision Specifiers
+$ git difftool Makefile~2 <1>
+$ git difftool Makefile~4 Makefile~2 <2>
+$ git difftool Makefile~~~~ Makefile~~ <3>
+
+# Commit Diff Specifiers
+$ git difftool origin/next~! <4>
+$ git difftool HEAD! <5>
+$ git difftool ! <6>
+---------------------------------------------------
+
+<1> compare 'Makefile' in the worktree against 'Makefile'
+as it existed two `versions` ago.  `Versions` here means
+"changes to Makefile" such that only commits that touch
+'Makefile' are considered when finding commits.
+
+<2> compare 'Makefile' as it existed four versions ago to
+'Makefile' as it existed two versions ago.
+
+<3> equivalent to example 2 and illustrates what happens when
+multiple '{tilde}' characters are used.
+
+<4> show the commit diff for 'origin/next\~'.
+Specifying '!' expands 'origin/next\~' to
+'origin/next\~\~..origin/next\~'.
+
+<5> show the commit diff for the most recent commit.
+'HEAD!' is equivalent to 'HEAD\~..HEAD'.
+
+<6> '!' is a shorthand for 'HEAD!' and is equivalent to example 5.
+
+
 CONFIG VARIABLES
 ----------------
 'git-difftool' falls back to 'git-mergetool' config variables when the
diff --git a/git-difftool.perl b/git-difftool.perl
index 0deda3a..4845f9b 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -12,13 +12,17 @@ use warnings;
 use Cwd qw(abs_path);
 use File::Basename qw(dirname);
 
+binmode(STDOUT, ":raw");
+
 my $DIR = abs_path(dirname($0));
 
 
 sub usage
 {
 	print << 'USAGE';
-usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options]
+usage: git difftool [--tool=<tool>] [--no-prompt]
+                    [<'git diff' options>]
+                    [<extended revision specifier>]
 USAGE
 	exit 1;
 }
@@ -33,12 +37,18 @@ sub setup_environment
 sub exe
 {
 	my $exe = shift;
-	return defined $ENV{COMSPEC} ? "$exe.exe" : $exe;
+	if ($^O eq 'MSWin32' || $^O eq 'msys') {
+		return "$exe.exe";
+	}
+	return  $exe;
 }
 
 sub generate_command
 {
+	# Generate a git-diff command line and set environment
+	# variables recognized by git-difftool-helper
 	my @command = (exe('git'), 'diff');
+	my @args = ();
 	my $skip_next = 0;
 	my $idx = -1;
 	for my $arg (@ARGV) {
@@ -47,7 +57,7 @@ sub generate_command
 			$skip_next = 0;
 			next;
 		}
-		if ($arg eq '-t' or $arg eq '--tool') {
+		if ($arg eq '-t' || $arg eq '--tool') {
 			usage() if $#ARGV <= $idx;
 			$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
 			$skip_next = 1;
@@ -61,12 +71,109 @@ sub generate_command
 			$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
 			next;
 		}
-		if ($arg eq '-h' or $arg eq '--help') {
+		if ($arg eq '-h' || $arg eq '--help') {
 			usage();
 		}
-		push @command, $arg;
+		push @args, $arg;
+	}
+	return (@command, interpolate_args(@args));
+}
+
+
+sub interpolate_args
+{
+	# Interpolates arguments that should be expanded out to
+	# corresponding commits, e.g. 'file~3' or 'master!'.
+	my @args = @_;
+	my $file = undef;
+	my @command = ();
+	for my $arg (@args) {
+		if (defined $file && $arg eq $file) {
+			# This allows 'git difftool file~ file'
+			next;
+		}
+		if ($arg =~ /^(.+?)(~+\d*)$/) {
+			# This arg might be a file-revision specifier
+			my $cur_file = $1;
+			my $rev_spec = $2;
+			if (defined $file && $file ne $cur_file) {
+				# We don't currently support comparing
+				# file~ to other_file~
+				usage();
+			}
+			if (!-e $cur_file) {
+				# This arg is a revision parameter and should
+				# be passed along to git-diff as-is
+				push @command, $arg;
+				next;
+			}
+			# This arg is a file-revision specifier so find the
+			# corresponding commits
+			$file = $cur_file;
+			push @command,
+				find_commit_for_file($cur_file, $rev_spec);
+		}
+		elsif ($arg =~ /^(.*?)!$/) {
+			# Expand 'sha1!' to 'sha1~ sha1'
+			my $head = $1;
+			if (length($head) == 0) {
+				# Expand '!' to 'HEAD~ HEAD'
+				$head = 'HEAD';
+			}
+			push @command, $head.'~';
+			push @command, $head;
+		}
+		else {
+			# This is a regular arg so just pass it along
+			push @command, $arg;
+		}
+	}
+	if (defined $file) {
+		# We're using a 'file~' revision specifier so
+		# automatically limit git-diff to just a single file
+		$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
+		push @command, '--', $file;
+	}
+	return @command;
+}
+
+sub find_commit_for_file
+{
+	# Searches back in $file's history according to $rev_spec
+	# and finds the corresponding commits.
+	# $rev_spec usually looks like '~' or '~2'.
+	my ($file, $rev_spec) = @_;
+	my $num = 0;
+	if ($rev_spec =~ /^(~+)(\d+)$/) {
+		$num = length($1);
+		$num += $2;
+	}
+	else {
+		$num = 1;
+		$num += length($rev_spec);
+	}
+	my @cmd = (exe('git'), 'log');
+	my @opts = ('--reverse', '--pretty=format:%H', '--max-count='.$num);
+	my @args = ('--', $file);
+	return read_first_line(@cmd, @opts, @args);
+}
+
+sub read_first_line
+{
+	# Runs a command in a child process and returns the first line
+	my @command = @_;
+	my $pid = open(CHILD, '-|');
+	if ($pid) {
+		# Grab the first line and loop over stdout until we're done
+		my $line = <CHILD>;
+		while(<CHILD>) {};
+		close(CHILD);
+		chomp $line;
+		return $line;
+	} else {
+		# Execute the command and pipe output to our parent
+		exec(@command) or exit 1;
 	}
-	return @command
 }
 
 setup_environment();
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index c7cd2b1..88af30a 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -136,4 +136,47 @@ test_expect_success 'difftool + mergetool config variables' '
 	restore_test_defaults
 '
 
+test_expect_success 'extended file revision syntax' '
+	git checkout branch &&
+
+	diff=$(git difftool file~) &&
+	test "$diff" = "master" &&
+
+	diff=$(git difftool file~ file) &&
+	test "$diff" = "master" &&
+
+	echo branch 2 >file &&
+	git commit -a -m "branch changes again" &&
+
+	diff=$(git difftool file~~ file) &&
+	test "$diff" = "master" &&
+
+	diff=$(git difftool file~2 file) &&
+	test "$diff" = "master" &&
+
+	git reset --hard HEAD~ &&
+	git checkout master
+'
+
+test_expect_success 'extended commit-ish revision syntax' '
+	git checkout branch &&
+
+	diff=$(git difftool --no-prompt HEAD!) &&
+	test "$diff" = "master" &&
+
+	diff=$(git difftool --no-prompt !) &&
+	test "$diff" = "master" &&
+
+	echo branch again >file &&
+	git commit -a -m "branch again" &&
+	git checkout master &&
+
+	diff=$(git difftool --no-prompt branch!) &&
+	test "$diff" = "branch" &&
+
+	git checkout branch &&
+	git reset --hard HEAD~ &&
+	git checkout master
+'
+
 test_done
-- 
1.6.2.1.303.g63699

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 10:15 [PATCH] difftool: add support for an extended revision syntax David Aguilar
@ 2009-03-23 14:51 ` Michael J Gruber
  2009-03-23 16:33   ` David Aguilar
  2009-03-23 23:50 ` Junio C Hamano
  2009-03-27 15:59 ` Jakub Narebski
  2 siblings, 1 reply; 12+ messages in thread
From: Michael J Gruber @ 2009-03-23 14:51 UTC (permalink / raw)
  To: David Aguilar; +Cc: gitster, git

David Aguilar venit, vidit, dixit 23.03.2009 11:15:
> This adds an extended revision syntax to git-difftool.
> Users often ask "how do I compare a file against its
> previous version" and the answer is typically a combination
> of 'git log <file>' and 'git difftool <sha1> <sha1> <file>'.
> 
> This makes answering that question considerably easier.
> Users can now simply say:
> 
> 	$ git difftool <file>~
> 
> to compare <file> in the worktree against its
> previous version, and:
> 
> 	$ git difftool <file>~2 <file>~
> 
> to compare <file> from 2 versions ago to <file>'s
> previous version, etc.
> 
> The extended revision syntax also expands revisions
> that are suffixed with '!' as a convenient way to
> see commit diffs.  Specifying only '!' is equivalent
> to specifying 'HEAD!'.
> 
> This makes the following statements equivalent:
> 
> 	$ git difftool !
> 	$ git difftool HEAD!
> 	$ git difftool HEAD~ HEAD
> 
> Signed-off-by: David Aguilar <davvid@gmail.com>
> ---
> 
> This patch is based on top of the "add tests to difftool"
> patch which itself is based upon the "move difftool out of contrib"
> patch currently in the "pu" and "da/difftool" branches.
> 
> This feature is incredibly useful but it also adds a brand new
> way of specifying revisions that is only understood by git-difftool.
> 
> This was specifically asked for by a git-difftool user
> who was disapointed to learn that they had to dig through
> git-log just to use git-difftool effectively.
> 
> I do not think git-diff should know anything about the
> "extended revision syntax" which is why this behavior
> is best suited for a porcelain such as difftool.
> I can imagine that 'file~' would be a useful construct
> in core git, but changing the plumbing just for something
> like that seems both daunting and misguided.
> 
> Some of the conditional expressions were modified to match
> the style used in git-add--interactive.perl.  I can split
> this patch into two if needed, but I figured they were
> trivial and didn't warrant a separate patch.
> 
> I had to escape some tilde characters in the documentation
> because asciidoc kept generating invalid html when the
> {tilde} notation was used within single quotes multiple times.
> 
> In case anyone asks, git-diff understands this new syntax too
> (though we did have to twist its arm ;))
> 
> 	$ git config alias.ddiff 'difftool --no-ext-diff'
> 	$ git ddiff Makefile~
> 
> Any thoughts on whether adding this syntax to git-diff/rev-parse
> would be feasible/sane/worth it?

I like the idea of having a shortcut like that a lot, but I'm sorry I'm
not supportive of a tool-specific rev syntax extension; for principal
reasons, but also because diff, checkout and maybe others could make
good use of it.

Work is underway on clearing out the issue of forbidden characters in
revision specifiers. We already have commit:file. I think something like
~2:file would be short enough as well as in line with the usual
semantics. Similarly,

git diff ~3 ~2 file
git diff ~3 file

would be short and simple as soon as ~3 is implemented to be a shortcut
for HEAD~3. (I'm not sure we can actually use ~, even though it would
fit in with the usual "if it's not specified it's HEAD".) This would
only need a shortcut for HEAD, such as not even specifying it (as above)
or c~ with c being our new fancy character for that.

>  Documentation/git-difftool.txt |   55 ++++++++++++++++++-
>  git-difftool.perl              |  119 ++++++++++++++++++++++++++++++++++++++--
>  t/t7800-difftool.sh            |   43 ++++++++++++++
>  3 files changed, 210 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
> index 5ae02f8..2911b84 100644
> --- a/Documentation/git-difftool.txt
> +++ b/Documentation/git-difftool.txt
> @@ -7,7 +7,9 @@ git-difftool - Show changes using common diff tools
>  
>  SYNOPSIS
>  --------
> -'git difftool' [--tool=<tool>] [--no-prompt] [<'git diff' options>]
> +'git difftool' [--tool=<tool>] [--no-prompt]
> +               [<'git diff' options>]
> +               [<extended revision syntax>]
>  
>  DESCRIPTION
>  -----------
> @@ -54,6 +56,57 @@ with custom merge tool commands and has the same value as `$LOCAL`.
>  
>  See linkgit:git-diff[1] for the full list of supported options.
>  
> +EXTENDED REVISION SYNTAX
> +------------------------
> +'git-difftool' understands an extended syntax for specifying revisions.
> +
> +* A suffix '{tilde}' to a file means the previous commit that touched file.
> +
> +* A suffix '{tilde}<n>' to a file means the <n>th previous commit that
> +touched file.  E.g. 'file\~3' is equivalent to 'file\~\~\~'.
> +
> +* A revision suffixed with an exclamation mark '!' expands to
> +'revision\~..revision', i.e. the commit diff for that revision.
> +
> +'git-difftool' recognizes this syntax and passes the corresponding
> +commits to 'git-diff'.
> +
> +Examples
> +~~~~~~~~
> +
> +---------------------------------------------------
> +# File Revision Specifiers
> +$ git difftool Makefile~2 <1>
> +$ git difftool Makefile~4 Makefile~2 <2>
> +$ git difftool Makefile~~~~ Makefile~~ <3>
> +
> +# Commit Diff Specifiers
> +$ git difftool origin/next~! <4>
> +$ git difftool HEAD! <5>
> +$ git difftool ! <6>
> +---------------------------------------------------
> +
> +<1> compare 'Makefile' in the worktree against 'Makefile'
> +as it existed two `versions` ago.  `Versions` here means
> +"changes to Makefile" such that only commits that touch
> +'Makefile' are considered when finding commits.
> +
> +<2> compare 'Makefile' as it existed four versions ago to
> +'Makefile' as it existed two versions ago.
> +
> +<3> equivalent to example 2 and illustrates what happens when
> +multiple '{tilde}' characters are used.
> +
> +<4> show the commit diff for 'origin/next\~'.
> +Specifying '!' expands 'origin/next\~' to
> +'origin/next\~\~..origin/next\~'.
> +
> +<5> show the commit diff for the most recent commit.
> +'HEAD!' is equivalent to 'HEAD\~..HEAD'.
> +
> +<6> '!' is a shorthand for 'HEAD!' and is equivalent to example 5.
> +
> +
>  CONFIG VARIABLES
>  ----------------
>  'git-difftool' falls back to 'git-mergetool' config variables when the
> diff --git a/git-difftool.perl b/git-difftool.perl
> index 0deda3a..4845f9b 100755
> --- a/git-difftool.perl
> +++ b/git-difftool.perl
> @@ -12,13 +12,17 @@ use warnings;
>  use Cwd qw(abs_path);
>  use File::Basename qw(dirname);
>  
> +binmode(STDOUT, ":raw");
> +
>  my $DIR = abs_path(dirname($0));
>  
>  
>  sub usage
>  {
>  	print << 'USAGE';
> -usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options]
> +usage: git difftool [--tool=<tool>] [--no-prompt]
> +                    [<'git diff' options>]
> +                    [<extended revision specifier>]
>  USAGE
>  	exit 1;
>  }
> @@ -33,12 +37,18 @@ sub setup_environment
>  sub exe
>  {
>  	my $exe = shift;
> -	return defined $ENV{COMSPEC} ? "$exe.exe" : $exe;
> +	if ($^O eq 'MSWin32' || $^O eq 'msys') {
> +		return "$exe.exe";
> +	}
> +	return  $exe;
>  }
>  
>  sub generate_command
>  {
> +	# Generate a git-diff command line and set environment
> +	# variables recognized by git-difftool-helper
>  	my @command = (exe('git'), 'diff');
> +	my @args = ();
>  	my $skip_next = 0;
>  	my $idx = -1;
>  	for my $arg (@ARGV) {
> @@ -47,7 +57,7 @@ sub generate_command
>  			$skip_next = 0;
>  			next;
>  		}
> -		if ($arg eq '-t' or $arg eq '--tool') {
> +		if ($arg eq '-t' || $arg eq '--tool') {
>  			usage() if $#ARGV <= $idx;
>  			$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
>  			$skip_next = 1;
> @@ -61,12 +71,109 @@ sub generate_command
>  			$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
>  			next;
>  		}
> -		if ($arg eq '-h' or $arg eq '--help') {
> +		if ($arg eq '-h' || $arg eq '--help') {
>  			usage();
>  		}
> -		push @command, $arg;
> +		push @args, $arg;
> +	}
> +	return (@command, interpolate_args(@args));
> +}
> +
> +
> +sub interpolate_args
> +{
> +	# Interpolates arguments that should be expanded out to
> +	# corresponding commits, e.g. 'file~3' or 'master!'.
> +	my @args = @_;
> +	my $file = undef;
> +	my @command = ();
> +	for my $arg (@args) {
> +		if (defined $file && $arg eq $file) {
> +			# This allows 'git difftool file~ file'
> +			next;
> +		}
> +		if ($arg =~ /^(.+?)(~+\d*)$/) {
> +			# This arg might be a file-revision specifier
> +			my $cur_file = $1;
> +			my $rev_spec = $2;
> +			if (defined $file && $file ne $cur_file) {
> +				# We don't currently support comparing
> +				# file~ to other_file~
> +				usage();
> +			}
> +			if (!-e $cur_file) {
> +				# This arg is a revision parameter and should
> +				# be passed along to git-diff as-is
> +				push @command, $arg;
> +				next;
> +			}
> +			# This arg is a file-revision specifier so find the
> +			# corresponding commits
> +			$file = $cur_file;
> +			push @command,
> +				find_commit_for_file($cur_file, $rev_spec);
> +		}
> +		elsif ($arg =~ /^(.*?)!$/) {
> +			# Expand 'sha1!' to 'sha1~ sha1'
> +			my $head = $1;
> +			if (length($head) == 0) {
> +				# Expand '!' to 'HEAD~ HEAD'
> +				$head = 'HEAD';
> +			}
> +			push @command, $head.'~';
> +			push @command, $head;
> +		}
> +		else {
> +			# This is a regular arg so just pass it along
> +			push @command, $arg;
> +		}
> +	}
> +	if (defined $file) {
> +		# We're using a 'file~' revision specifier so
> +		# automatically limit git-diff to just a single file
> +		$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
> +		push @command, '--', $file;
> +	}
> +	return @command;
> +}
> +
> +sub find_commit_for_file
> +{
> +	# Searches back in $file's history according to $rev_spec
> +	# and finds the corresponding commits.
> +	# $rev_spec usually looks like '~' or '~2'.
> +	my ($file, $rev_spec) = @_;
> +	my $num = 0;
> +	if ($rev_spec =~ /^(~+)(\d+)$/) {
> +		$num = length($1);
> +		$num += $2;
> +	}
> +	else {
> +		$num = 1;
> +		$num += length($rev_spec);
> +	}
> +	my @cmd = (exe('git'), 'log');
> +	my @opts = ('--reverse', '--pretty=format:%H', '--max-count='.$num);
> +	my @args = ('--', $file);
> +	return read_first_line(@cmd, @opts, @args);
> +}
> +
> +sub read_first_line
> +{
> +	# Runs a command in a child process and returns the first line
> +	my @command = @_;
> +	my $pid = open(CHILD, '-|');
> +	if ($pid) {
> +		# Grab the first line and loop over stdout until we're done
> +		my $line = <CHILD>;
> +		while(<CHILD>) {};
> +		close(CHILD);
> +		chomp $line;
> +		return $line;
> +	} else {
> +		# Execute the command and pipe output to our parent
> +		exec(@command) or exit 1;
>  	}
> -	return @command
>  }
>  
>  setup_environment();
> diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
> index c7cd2b1..88af30a 100755
> --- a/t/t7800-difftool.sh
> +++ b/t/t7800-difftool.sh
> @@ -136,4 +136,47 @@ test_expect_success 'difftool + mergetool config variables' '
>  	restore_test_defaults
>  '
>  
> +test_expect_success 'extended file revision syntax' '
> +	git checkout branch &&
> +
> +	diff=$(git difftool file~) &&
> +	test "$diff" = "master" &&
> +
> +	diff=$(git difftool file~ file) &&
> +	test "$diff" = "master" &&
> +
> +	echo branch 2 >file &&
> +	git commit -a -m "branch changes again" &&
> +
> +	diff=$(git difftool file~~ file) &&
> +	test "$diff" = "master" &&
> +
> +	diff=$(git difftool file~2 file) &&
> +	test "$diff" = "master" &&
> +
> +	git reset --hard HEAD~ &&
> +	git checkout master
> +'
> +
> +test_expect_success 'extended commit-ish revision syntax' '
> +	git checkout branch &&
> +
> +	diff=$(git difftool --no-prompt HEAD!) &&
> +	test "$diff" = "master" &&
> +
> +	diff=$(git difftool --no-prompt !) &&
> +	test "$diff" = "master" &&
> +
> +	echo branch again >file &&
> +	git commit -a -m "branch again" &&
> +	git checkout master &&
> +
> +	diff=$(git difftool --no-prompt branch!) &&
> +	test "$diff" = "branch" &&
> +
> +	git checkout branch &&
> +	git reset --hard HEAD~ &&
> +	git checkout master
> +'
> +
>  test_done

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 14:51 ` Michael J Gruber
@ 2009-03-23 16:33   ` David Aguilar
  2009-03-23 16:46     ` Michael J Gruber
  2009-03-23 23:22     ` Junio C Hamano
  0 siblings, 2 replies; 12+ messages in thread
From: David Aguilar @ 2009-03-23 16:33 UTC (permalink / raw)
  To: Michael J Gruber; +Cc: gitster, git

On  0, Michael J Gruber <git@drmicha.warpmail.net> wrote:
> David Aguilar venit, vidit, dixit 23.03.2009 11:15:
> > 
> > This makes answering that question considerably easier.
> > Users can now simply say:
> > 
> > 	$ git difftool <file>~
> > 
> > to compare <file> in the worktree against its
> > previous version, and:
> > 
> > 	$ git difftool <file>~2 <file>~
> > 
> > to compare <file> from 2 versions ago to <file>'s
> > previous version, etc.
> > 
> 
> I like the idea of having a shortcut like that a lot, but I'm sorry I'm
> not supportive of a tool-specific rev syntax extension; for principal
> reasons, but also because diff, checkout and maybe others could make
> good use of it.

I completely agree.  I want a convenient shortcut to use everywhere.


> Work is underway on clearing out the issue of forbidden characters in
> revision specifiers. We already have commit:file. I think something like
> ~2:file would be short enough as well as in line with the usual
> semantics. Similarly,
> 
> git diff ~3 ~2 file
> git diff ~3 file
> 
> would be short and simple as soon as ~3 is implemented to be a shortcut
> for HEAD~3. (I'm not sure we can actually use ~, even though it would
> fit in with the usual "if it's not specified it's HEAD".) This would
> only need a shortcut for HEAD, such as not even specifying it (as above)
> or c~ with c being our new fancy character for that.


One of my ulterior motives for sending this patch was to
start a discussion on this topic.  I missed the discussion
about clearing out forbidden characters so I'll see if I can
find it in the archives.  Do you happen to have a link?

Keep in mind that the syntax that this patch added does
not have file~3 = HEAD~3.  file~3 means finding file as it
existed 3 changes-to-file ago, which is != to HEAD~3 if file
did not change in the last 3 commits.

It basically runs 'git log -- file' so that only the commits
that touch file are considered.

Are you suggesting that ~3:file could be the shortcut for
this, or would we need a different syntax since you just
said that ~3 would be a shortcut for HEAD~3?

If there's work on syntax-sugarfying diff/checkout/etc. with
these kind of shortcuts then I would like to help out with
patches, testing, etc.

This is a feature that lots of users would enjoy--I know that
for sure.

-- 

	David

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 16:33   ` David Aguilar
@ 2009-03-23 16:46     ` Michael J Gruber
  2009-03-23 23:22     ` Junio C Hamano
  1 sibling, 0 replies; 12+ messages in thread
From: Michael J Gruber @ 2009-03-23 16:46 UTC (permalink / raw)
  To: David Aguilar; +Cc: gitster, git

David Aguilar venit, vidit, dixit 23.03.2009 17:33:
> On  0, Michael J Gruber <git@drmicha.warpmail.net> wrote:
>> David Aguilar venit, vidit, dixit 23.03.2009 11:15:
>>>
>>> This makes answering that question considerably easier.
>>> Users can now simply say:
>>>
>>> 	$ git difftool <file>~
>>>
>>> to compare <file> in the worktree against its
>>> previous version, and:
>>>
>>> 	$ git difftool <file>~2 <file>~
>>>
>>> to compare <file> from 2 versions ago to <file>'s
>>> previous version, etc.
>>>
>>
>> I like the idea of having a shortcut like that a lot, but I'm sorry I'm
>> not supportive of a tool-specific rev syntax extension; for principal
>> reasons, but also because diff, checkout and maybe others could make
>> good use of it.
> 
> I completely agree.  I want a convenient shortcut to use everywhere.
> 
> 
>> Work is underway on clearing out the issue of forbidden characters in
>> revision specifiers. We already have commit:file. I think something like
>> ~2:file would be short enough as well as in line with the usual
>> semantics. Similarly,
>>
>> git diff ~3 ~2 file
>> git diff ~3 file
>>
>> would be short and simple as soon as ~3 is implemented to be a shortcut
>> for HEAD~3. (I'm not sure we can actually use ~, even though it would
>> fit in with the usual "if it's not specified it's HEAD".) This would
>> only need a shortcut for HEAD, such as not even specifying it (as above)
>> or c~ with c being our new fancy character for that.
> 
> 
> One of my ulterior motives for sending this patch was to
> start a discussion on this topic.  I missed the discussion
> about clearing out forbidden characters so I'll see if I can
> find it in the archives.  Do you happen to have a link?
> 
> Keep in mind that the syntax that this patch added does
> not have file~3 = HEAD~3.  file~3 means finding file as it
> existed 3 changes-to-file ago, which is != to HEAD~3 if file
> did not change in the last 3 commits.
> 
> It basically runs 'git log -- file' so that only the commits
> that touch file are considered.
> 
> Are you suggesting that ~3:file could be the shortcut for
> this, or would we need a different syntax since you just
> said that ~3 would be a shortcut for HEAD~3?

I think both would be useful. Depending on the way it's done, only
HEAD~3 maybe be realizable.

> If there's work on syntax-sugarfying diff/checkout/etc. with
> these kind of shortcuts then I would like to help out with
> patches, testing, etc.

http://article.gmane.org/gmane.comp.version-control.git/114257 is the
newest installment, although
http://article.gmane.org/gmane.comp.version-control.git/114076 and
especially
http://article.gmane.org/gmane.comp.version-control.git/113647 is very
worthwhile reading :)

[Isn't there a better way to link to posts? I think I used to take
message ids.]

> This is a feature that lots of users would enjoy--I know that
> for sure.
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 16:33   ` David Aguilar
  2009-03-23 16:46     ` Michael J Gruber
@ 2009-03-23 23:22     ` Junio C Hamano
  2009-03-23 23:33       ` David Aguilar
  1 sibling, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2009-03-23 23:22 UTC (permalink / raw)
  To: David Aguilar; +Cc: Michael J Gruber, git

David Aguilar <davvid@gmail.com> writes:

> Keep in mind that the syntax that this patch added does not have file~3
> = HEAD~3.  file~3 means finding file as it existed 3 changes-to-file
> ago, which is != to HEAD~3 if file did not change in the last 3 commits.

If your motive is to introduce inconsistency to the UI by adding this kind
of new notation _only to difftool_, I have to reconsider moving it out of
contrib/ area.

While I do not fundamentally oppose to add convenient notations for useful
concepts, you need to start at making sure if this "three changes ago" is
a well defined concept to begin with.

And it is not a well defined concept in a merge-heavy environment, unless
you define what you mean by "three changes ago".

If you consider this history:

 ---Y---o---X---M---o mainline = HEAD
               /
   ---A---B---C topic

where A, B, C and X, Y are the only commits that touched the file you are
interested in, how do you define 3-changes-ago?

Maybe X was just a totally uninteresting typofix to a comment, while A, B
and C were adding a very interesting new feature.  Don't forget that M
also changes the file from either of its parents (X or C).  Does M count
as the last change?  Or does it not count because it is just a mechanical
unconflicting merge?  Which one of X or C is the penultimate change?  The
one with an earlier committer timestamp?  Tiebreaking with timestamps is
known to be flawed in the presense of clock skew.

For the consistency of the UI, "starting at HEAD, following first-parent
ancestry, find N-th commit that touches the path, ignoring all the side
branches" MUST be the semantics of a notation that uses tilde followed by
number (so file~3 must mean Y in the above picture), because HEAD~3 is
defined as "three parents ago, only following the first parent ancestry".
Anything else will invite user confusion.

But I do not think it is necessarily useful to follow only the first
parent ancestry to find "three-changes ago" (if such a concept exists).
If you want a notation that means something else, such as X (because
chronologically the commits that touched the file are M, C and X in the
ideal world that everybody has well synchronized clock), you shouldn't use
tilde-number notation but use something else.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 23:22     ` Junio C Hamano
@ 2009-03-23 23:33       ` David Aguilar
  0 siblings, 0 replies; 12+ messages in thread
From: David Aguilar @ 2009-03-23 23:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Michael J Gruber, git

On Mon, Mar 23, 2009 at 4:22 PM, Junio C Hamano <gitster@pobox.com> wrote:
> David Aguilar <davvid@gmail.com> writes:
>
>> Keep in mind that the syntax that this patch added does not have file~3
>> = HEAD~3.  file~3 means finding file as it existed 3 changes-to-file
>> ago, which is != to HEAD~3 if file did not change in the last 3 commits.
>
> If your motive is to introduce inconsistency to the UI by adding this kind
> of new notation _only to difftool_, I have to reconsider moving it out of
> contrib/ area.


I totally agree that this patch was half-baked, not fully defined,
and should be dropped.  I hope that doesn't influence
your decision for the rest of the patches that came before it.

The notion of "3 commits ago" is ambiguous in a merge-heavy work flow
and using ~ would only confuse things, so I'll see if we can find a better
way to do it, but it shouldn't happen in difftool (if it happens at all).


>
> While I do not fundamentally oppose to add convenient notations for useful
> concepts, you need to start at making sure if this "three changes ago" is
> a well defined concept to begin with.
>
> And it is not a well defined concept in a merge-heavy environment, unless
> you define what you mean by "three changes ago".
>
> If you consider this history:
>
>  ---Y---o---X---M---o mainline = HEAD
>               /
>   ---A---B---C topic
>
> where A, B, C and X, Y are the only commits that touched the file you are
> interested in, how do you define 3-changes-ago?
>
> Maybe X was just a totally uninteresting typofix to a comment, while A, B
> and C were adding a very interesting new feature.  Don't forget that M
> also changes the file from either of its parents (X or C).  Does M count
> as the last change?  Or does it not count because it is just a mechanical
> unconflicting merge?  Which one of X or C is the penultimate change?  The
> one with an earlier committer timestamp?  Tiebreaking with timestamps is
> known to be flawed in the presense of clock skew.
>
> For the consistency of the UI, "starting at HEAD, following first-parent
> ancestry, find N-th commit that touches the path, ignoring all the side
> branches" MUST be the semantics of a notation that uses tilde followed by
> number (so file~3 must mean Y in the above picture), because HEAD~3 is
> defined as "three parents ago, only following the first parent ancestry".
> Anything else will invite user confusion.
>
> But I do not think it is necessarily useful to follow only the first
> parent ancestry to find "three-changes ago" (if such a concept exists).
> If you want a notation that means something else, such as X (because
> chronologically the commits that touched the file are M, C and X in the
> ideal world that everybody has well synchronized clock), you shouldn't use
> tilde-number notation but use something else.
>

Understood and thanks for the help,

-- 
    David

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 10:15 [PATCH] difftool: add support for an extended revision syntax David Aguilar
  2009-03-23 14:51 ` Michael J Gruber
@ 2009-03-23 23:50 ` Junio C Hamano
  2009-03-27 15:59 ` Jakub Narebski
  2 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2009-03-23 23:50 UTC (permalink / raw)
  To: David Aguilar; +Cc: git

David Aguilar <davvid@gmail.com> writes:

> This makes answering that question considerably easier.
> Users can now simply say:
>
> 	$ git difftool <file>~
>
> to compare <file> in the worktree against its
> previous version, and:
>
> 	$ git difftool <file>~2 <file>~
>
> to compare <file> from 2 versions ago to <file>'s
> previous version, etc.

These two examples are not that interesting.  Because you can say:

	$ git log -p -1 file
	$ git log -p -2 file

(admittedly you need to skip the first entry of the output in the latter
one to get to what you are interested in).

What existing syntax does not allow you to say easily is something like:

	$ git difftool <file>~4 <file>

That is, "I do not care about the intermediate states, but want to see the
4 changes consolidated in one".

As I told you in my previous message, I am not convinced a short-and-sweet
notation such as tilde-four is expressive enough for most user's needs (I
suspect most users use git as a fast CVS and have rather linear history,
in which case "Nth commit that changes the file, following only the first
parent chain down from the HEAD" _could_ be a perfectly fine and useful
semantics), but if it is, I think it would not be too involved to patch
revision.c::handle_revision_arg() to make it available to everybody.

> This makes the following statements equivalent:
>
> 	$ git difftool !
> 	$ git difftool HEAD!
> 	$ git difftool HEAD~ HEAD

Which would be:

	$ git log -p -1 file

right?

Perhaps we would want a convenient way for "log -p" or "show -p" to drive
difftool as a backend?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-23 10:15 [PATCH] difftool: add support for an extended revision syntax David Aguilar
  2009-03-23 14:51 ` Michael J Gruber
  2009-03-23 23:50 ` Junio C Hamano
@ 2009-03-27 15:59 ` Jakub Narebski
  2009-03-27 16:28   ` David Aguilar
  2 siblings, 1 reply; 12+ messages in thread
From: Jakub Narebski @ 2009-03-27 15:59 UTC (permalink / raw)
  To: David Aguilar; +Cc: gitster, git

David Aguilar <davvid@gmail.com> writes:

> This adds an extended revision syntax to git-difftool.
> Users often ask "how do I compare a file against its
> previous version" and the answer is typically a combination
> of 'git log <file>' and 'git difftool <sha1> <sha1> <file>'.
> 
> This makes answering that question considerably easier.
> Users can now simply say:
> 
> 	$ git difftool <file>~
> 
> to compare <file> in the worktree against its
> previous version, and:
> 
> 	$ git difftool <file>~2 <file>~
> 
> to compare <file> from 2 versions ago to <file>'s
> previous version, etc.

Because <rev>~<n> means (see git-rev-parse(1) for example) n-th parent
in _first parent_ line, then <file>~<n> should also use first-parent
line, otherwise you invite confusion.

Also I am not sure about the syntax, as there are no restrictions on
filenames, and filenames can contain '~'.  Perhaps (proposed in this
thread) ~<n>:<file> == 
  "$(git rev-list -n <n> --first-parent HEAD -- <file> | tail):<file>"

But this might be mistaken for HEAD~<n>:<file>, which can be something
else...
 
> The extended revision syntax also expands revisions
> that are suffixed with '!' as a convenient way to
> see commit diffs.  Specifying only '!' is equivalent
> to specifying 'HEAD!'.
> 
> This makes the following statements equivalent:
> 
> 	$ git difftool !
> 	$ git difftool HEAD!
> 	$ git difftool HEAD~ HEAD

Errr... there already exists such syntax, and it is called HEAD^!
(if git-difftool can accept a..b revision specification)... or not,
as git-rev-parse(1) states:

  r1^! includes commit r1 but excludes all of its parents.

So depending on how "r1 --not r1^" and "r1 --not r1^1 r1^2" is
interpreted by diff (which accpets points, not ranges) it might be, or
might be not what you wanted by introducying '!' / <rev>:!
specification...

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-27 15:59 ` Jakub Narebski
@ 2009-03-27 16:28   ` David Aguilar
  2009-03-27 17:21     ` Junio C Hamano
  2009-03-27 17:36     ` Junio C Hamano
  0 siblings, 2 replies; 12+ messages in thread
From: David Aguilar @ 2009-03-27 16:28 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: gitster, git, spearce

On  0, Jakub Narebski <jnareb@gmail.com> wrote:
> David Aguilar <davvid@gmail.com> writes:
> 
> > This adds an extended revision syntax to git-difftool.
> > Users often ask "how do I compare a file against its
> > previous version" and the answer is typically a combination
> > of 'git log <file>' and 'git difftool <sha1> <sha1> <file>'.
> > 
> > [snip]
> > 
> > The extended revision syntax also expands revisions
> > that are suffixed with '!' as a convenient way to
> > see commit diffs.  Specifying only '!' is equivalent
> > to specifying 'HEAD!'.
> > 
> > This makes the following statements equivalent:
> > 
> > 	$ git difftool !
> > 	$ git difftool HEAD!
> > 	$ git difftool HEAD~ HEAD
> 
> Errr... there already exists such syntax, and it is called HEAD^!


Yup, this patch was a mistake ;)

^! does exactly what I needed and difftool supports it since
git-diff does.

I'm still interested in the file~<n> idea [though maybe not
that exact syntax] and have been reading revision.c (as Junio
suggested) to see if it can be done in a good way.

I'm still not sure if it is a good idea since the types of
users who would want it are probably better off with tighter
integration between gitk and difftool as opposed to a
convenient command-line syntax (tho I do see how it would be
useful every now and then).  Ideally, we'd want to select two
commits in gitk and compare them.  I think qgit can do that,
but it doesn't yet know about difftool (since, of course,
difftool is not in master yet).

I noticed that my patches for "add tests to difftool" and "add
the -y shortcut for --no-prompt" were in git.git's pu branch
the other day but aren't there anymore.  Was that intentional?



> (if git-difftool can accept a..b revision specification)... or not,
> as git-rev-parse(1) states:
> 
>   r1^! includes commit r1 but excludes all of its parents.
> 
> So depending on how "r1 --not r1^" and "r1 --not r1^1 r1^2" is
> interpreted by diff (which accpets points, not ranges) it might be, or
> might be not what you wanted by introducying '!' / <rev>:!
> specification...
> 
> -- 
> Jakub Narebski
> Poland
> ShadeHawk on #git

-- 

	David

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-27 16:28   ` David Aguilar
@ 2009-03-27 17:21     ` Junio C Hamano
  2009-03-27 18:16       ` David Aguilar
  2009-03-27 17:36     ` Junio C Hamano
  1 sibling, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2009-03-27 17:21 UTC (permalink / raw)
  To: David Aguilar; +Cc: Jakub Narebski, gitster, git, spearce

David Aguilar <davvid@gmail.com> writes:

> I'm still interested in the file~<n> idea [though maybe not
> that exact syntax] and have been reading revision.c (as Junio
> suggested) to see if it can be done in a good way.

I'll send a comment in a separate message.

> I noticed that my patches for "add tests to difftool" and "add
> the -y shortcut for --no-prompt" were in git.git's pu branch
> the other day but aren't there anymore.  Was that intentional?

Yes, it makes 'pu' not pass the self test.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-27 16:28   ` David Aguilar
  2009-03-27 17:21     ` Junio C Hamano
@ 2009-03-27 17:36     ` Junio C Hamano
  1 sibling, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2009-03-27 17:36 UTC (permalink / raw)
  To: David Aguilar; +Cc: Jakub Narebski, git, spearce, Christian Couder

David Aguilar <davvid@gmail.com> writes:

> I'm still interested in the file~<n> idea [though maybe not
> that exact syntax] and have been reading revision.c (as Junio
> suggested) to see if it can be done in a good way.

Modern git programs use setup_revisions() to parse object names and range
notation given on the command line, and leave results in revs->pending
array.  This array holds pointers to "struct object" instances, and they
are often (always?) already parsed.  This gives the caller an easy access
to the parse results.

Recently there have been two topics that made me suspect that solving them
cleanly may require breaking this model.  I haven't thought things through
for the second one yet, so please do not take this as a criticism or
pointing-out-concrete-problems in the latter series.  At least for the
latter one, it is still an unsubstantiated fear.

(1) "The commit that touched this path the last time"

The objective of this extension is to accept a pathspec and come up with
the name of the commit object that touched the given pathspec recently.
There can be some variations to the parameter the feature could take, and
in the most generic form, the query would be:

 * set of commits: start digging from these;
 * pathspecs: find commits whose change touches some path that matches them;
 * N: do not stop at the latest change, but find the Nth one.

I am not good at coming up with a notation, so I'll leave the actual
syntax to other people, but you can say things like:

	git diff <<--all, Documentation t, 4>>
	git log <<master, Makefile, 10>>..next -- Makefile

The problem with this feature is this.  In order to come up with the
answer, you need to internally run:

	git rev-list --all -- Documentation t
	git rev-list master -- Makefile

and in order to compute this, the revision traversal machinery has to
not only open and parse commit objects but _rewrite_ the parent field of
these commits for history simplification purposes.  This is a destructive
operation, and after it comes back, we would need to clean them up by
unparsing these commits so that the original command that asked for its
command line arguments to be parsed can operate correctly.

At least, this can be fixed by unparsing all the objects parsed so far
when the revision command line parser finishes each such argument, and
force the caller parse them again when they read from rev->pending.


(2) "refs/replace/SHA-1 holds name of the object that replaces SHA-1"

The objective of this extension is to generalize the graft mechanism, so
that they can be shared across the usual object transfer mechanism, the
ordinary revision traversal mechanism can honor the replacement just like
they honor grafts file, while reachability machinery used by object
transfer, fsck and prune can ignore the replacement.  When refs/replace/A
has value B, a commit C that records A as its parent would behave as if B
is its parent (so "git log C" will show B as the second entry in its
output), while pushing C will notice C's true parent is A and sends A to
the other end.  By pushing refs/replace/A to the other end, you can share
the same "fake" history across repositories.

This feature has similar problem as (1).  If you say

	git rev-list master..next^^

how should next^^ be interpreted?  Because it is an input coming from the
user, we may want to honor the "graft/replace", and we need to read and
parse next, next^, and next^^ while possibly reading from refs/replace/
hiearchy.  But after getting the end result, the name of the commit object
the notation refers to, we would need to unparse the objects involved so
that the main parts of the command can start from the clean slate.

There are three issues with this:

 (1) When you ask for the data for a concrete SHA-1 (i.e. not "next^", but
     something like "9856dd811ee0f256d067b89cbccb58d944aa9c8c"), with and
     without grafts/replacements, the actual object data changes.

     This again needs at least unparsing of all the objects as in the
     <<commits, pathspecs, Nth>> case above to deal with.

 (2) Depending on the use of grafts/replacements, the interpretation of
     "next^^" changes; should we follow the true parenthood, or the
     replaced one?

     In order to give Porcelains the same freedom to honor or ignore the
     replacements, we would eventually need to expose --ignore-replace
     option to "git rev-list":

	git rev-list --ignore-replace master..next^^

     It gets tricky when --ignore-replace should take effect.  Before or
     after master..next^^ is interpreted?

 (3) Depending on the use of replacements, even the type of the object an
     extended SHA-1 expression refers to can change.  tag-foo may point at
     an object 9856dd811ee0f256d067b89cbccb58d944aa9c8c, and without
     replacements it may be a commit but the replacement mechanism is
     allowed to say it is another tag that points at a commit.

Not that the "replacement" feature is bad, it is just that the feature is
too flexible for the current codebase to handle sanely.

In order to solve these issues safely (not necessarily efficiently nor
cleanly), I think we might need to change the setup_revisions() to:

 (1) operate the way it currently does, leaving the parsed objects in
     revs->pending;

 (2) remember the objects' SHA-1 and flags in the revs->pending array;

 (3) discard all parsed objects, as revision traversals may have rewritten
     commits for history simplification purposes; and

 (4) rebuild revs->pending list by parsing the objects again, using the
     SHA-1 values we remembered in step (2)

or something like that.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] difftool: add support for an extended revision syntax
  2009-03-27 17:21     ` Junio C Hamano
@ 2009-03-27 18:16       ` David Aguilar
  0 siblings, 0 replies; 12+ messages in thread
From: David Aguilar @ 2009-03-27 18:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jakub Narebski, git, spearce

On  0, Junio C Hamano <gitster@pobox.com> wrote:
> David Aguilar <davvid@gmail.com> writes:
> 
> > I noticed that my patches for "add tests to difftool" and "add
> > the -y shortcut for --no-prompt" were in git.git's pu branch
> > the other day but aren't there anymore.  Was that intentional?
> 
> Yes, it makes 'pu' not pass the self test.


Oops, was this related to your suggestions about the patch
that added the tests?  I sent a v2 patch that included the
fixups.  I'll try running the tests when I get back home to my
Linux machine on Monday (I'm currently in Chicago on a trip)
though I'm not sure if I'd be able to reproduce the failure if
it's platform-specific.

Sorry 'bout that.

-- 

	David

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-03-27 18:17 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-23 10:15 [PATCH] difftool: add support for an extended revision syntax David Aguilar
2009-03-23 14:51 ` Michael J Gruber
2009-03-23 16:33   ` David Aguilar
2009-03-23 16:46     ` Michael J Gruber
2009-03-23 23:22     ` Junio C Hamano
2009-03-23 23:33       ` David Aguilar
2009-03-23 23:50 ` Junio C Hamano
2009-03-27 15:59 ` Jakub Narebski
2009-03-27 16:28   ` David Aguilar
2009-03-27 17:21     ` Junio C Hamano
2009-03-27 18:16       ` David Aguilar
2009-03-27 17:36     ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).