On Wed, Feb 13, 2008 at 05:16:49AM -0500, Jeff King wrote: > However, I wonder if this is the best approach. It would be nice if > there were a shorthand for "the empty tree" for diffing, so you could > just diff against that rather than HEAD, and have the regular plumbing > generate. > > I suppose we could just create that tree object, though it adds a slight > amount of cruft to the object database. And here it is. I think this is a more sane approach in general than the last patch. The only ugly thing is the empty tree hack, but that can be addressed with a patch to allow referencing the empty tree without it existing in the object db. -- >8 -- There were several points where we looked at the HEAD commit; for initial commits, this is meaningless. So instead we: - show staged status data as a diff against the empty tree instead of HEAD - show file diffs as creation events - use "git rm --cached" to revert instead of going back to the HEAD commit The empty tree diff is a little hack-ish. We actually write the empty tree object from a fake index using "git write-tree". This would be a bit cleaner if we could magically reference the empty tree. Signed-off-by: Jeff King <peff@xxxxxxxx> --- git-add--interactive.perl | 64 +++++++++++++++++++++++++++++++++----------- 1 files changed, 48 insertions(+), 16 deletions(-) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 17ca5b8..bae631e 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -82,6 +82,28 @@ sub list_untracked { my $status_fmt = '%12s %12s %s'; my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path'); +{ + my $initial; + sub is_initial_commit { + $initial = system('git rev-parse HEAD -- >/dev/null 2>&1') != 0 + unless defined $initial; + return $initial; + } +} + +{ + my $sha1; + sub get_empty_tree { + if (!$sha1) { + local $ENV{GIT_INDEX_FILE} = "$GIT_DIR/empty_index"; + $sha1 = run_cmd_pipe(qw(git write-tree)); + chomp $sha1; + unlink($ENV{GIT_INDEX_FILE}); + } + return $sha1; + } +} + # Returns list of hashes, contents of each of which are: # VALUE: pathname # BINARY: is a binary path @@ -103,8 +125,10 @@ sub list_modified { return if (!@tracked); } + my $reference = is_initial_commit() ? get_empty_tree() : 'HEAD'; for (run_cmd_pipe(qw(git diff-index --cached - --numstat --summary HEAD --), @tracked)) { + --numstat --summary), $reference, + '--', @tracked)) { if (($add, $del, $file) = /^([-\d]+) ([-\d]+) (.*)/) { my ($change, $bin); @@ -476,21 +500,27 @@ sub revert_cmd { HEADER => $status_head, }, list_modified()); if (@update) { - my @lines = run_cmd_pipe(qw(git ls-tree HEAD --), - map { $_->{VALUE} } @update); - my $fh; - open $fh, '| git update-index --index-info' - or die; - for (@lines) { - print $fh $_; + if (is_initial_commit()) { + system(qw(git rm --cached), + map { $_->{VALUE} } @update); } - close($fh); - for (@update) { - if ($_->{INDEX_ADDDEL} && - $_->{INDEX_ADDDEL} eq 'create') { - system(qw(git update-index --force-remove --), - $_->{VALUE}); - print "note: $_->{VALUE} is untracked now.\n"; + else { + my @lines = run_cmd_pipe(qw(git ls-tree HEAD --), + map { $_->{VALUE} } @update); + my $fh; + open $fh, '| git update-index --index-info' + or die; + for (@lines) { + print $fh $_; + } + close($fh); + for (@update) { + if ($_->{INDEX_ADDDEL} && + $_->{INDEX_ADDDEL} eq 'create') { + system(qw(git update-index --force-remove --), + $_->{VALUE}); + print "note: $_->{VALUE} is untracked now.\n"; + } } } refresh(); @@ -956,7 +986,9 @@ sub diff_cmd { HEADER => $status_head, }, @mods); return if (!@them); - system(qw(git diff -p --cached HEAD --), map { $_->{VALUE} } @them); + my $reference = is_initial_commit() ? get_empty_tree() : 'HEAD'; + system(qw(git diff -p --cached), $reference, '--', + map { $_->{VALUE} } @them); } sub quit_cmd { -- 1.5.4.1.1296.g34f89-dirty - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html