{"thread":{"id":"12102","subject":"[PATCH 2/2] add--interactive: handle initial commit better","startedAt":"2008-02-14T10:34:40Z","lastAt":"2008-02-14T10:34:40Z","messageCount":1,"participants":["Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"68728","messageId":"20080214103440.GB17951@coredump.intra.peff.net","threadId":"12102","inReplyTo":"f20febf5dbdc5d3af69bccff8be8e3e2bcec0a90.1202985100.git.peff@peff.net","subject":"[PATCH 2/2] add--interactive: handle initial commit better","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-02-14T10:34:40Z","receivedAt":"2008-02-14T10:34:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There were several points where we looked at the HEAD\ncommit; for initial commits, this is meaningless. So instead\nwe:\n\n  - show staged status data as a diff against the empty tree\n    instead of HEAD\n  - show file diffs as creation events\n  - use \"git rm --cached\" to revert instead of going back to\n    the HEAD commit\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis is close to what is in pu, but using '{}' instead of the raw sha1,\nand adding some tests.\n\n git-add--interactive.perl  |   51 ++++++++++++++++++++++----------\n t/t3701-add-interactive.sh |   69 ++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 104 insertions(+), 16 deletions(-)\n create mode 100755 t/t3701-add-interactive.sh\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 17ca5b8..130bc30 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -82,6 +82,15 @@ sub list_untracked {\n my $status_fmt = '%12s %12s %s';\n my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');\n \n+{\n+\tmy $initial;\n+\tsub is_initial_commit {\n+\t\t$initial = system('git rev-parse HEAD -- >/dev/null 2>&1') != 0\n+\t\t\tunless defined $initial;\n+\t\treturn $initial;\n+\t}\n+}\n+\n # Returns list of hashes, contents of each of which are:\n # VALUE:\tpathname\n # BINARY:\tis a binary path\n@@ -103,8 +112,10 @@ sub list_modified {\n \t\treturn if (!@tracked);\n \t}\n \n+\tmy $reference = is_initial_commit() ? '{}' : 'HEAD';\n \tfor (run_cmd_pipe(qw(git diff-index --cached\n-\t\t\t     --numstat --summary HEAD --), @tracked)) {\n+\t\t\t     --numstat --summary), $reference,\n+\t\t\t     '--', @tracked)) {\n \t\tif (($add, $del, $file) =\n \t\t    /^([-\\d]+)\t([-\\d]+)\t(.*)/) {\n \t\t\tmy ($change, $bin);\n@@ -476,21 +487,27 @@ sub revert_cmd {\n \t\t\t\t       HEADER => $status_head, },\n \t\t\t\t     list_modified());\n \tif (@update) {\n-\t\tmy @lines = run_cmd_pipe(qw(git ls-tree HEAD --),\n-\t\t\t\t\t map { $_->{VALUE} } @update);\n-\t\tmy $fh;\n-\t\topen $fh, '| git update-index --index-info'\n-\t\t    or die;\n-\t\tfor (@lines) {\n-\t\t\tprint $fh $_;\n+\t\tif (is_initial_commit()) {\n+\t\t\tsystem(qw(git rm --cached),\n+\t\t\t\tmap { $_->{VALUE} } @update);\n \t\t}\n-\t\tclose($fh);\n-\t\tfor (@update) {\n-\t\t\tif ($_->{INDEX_ADDDEL} &&\n-\t\t\t    $_->{INDEX_ADDDEL} eq 'create') {\n-\t\t\t\tsystem(qw(git update-index --force-remove --),\n-\t\t\t\t       $_->{VALUE});\n-\t\t\t\tprint \"note: $_->{VALUE} is untracked now.\\n\";\n+\t\telse {\n+\t\t\tmy @lines = run_cmd_pipe(qw(git ls-tree HEAD --),\n+\t\t\t\t\t\t map { $_->{VALUE} } @update);\n+\t\t\tmy $fh;\n+\t\t\topen $fh, '| git update-index --index-info'\n+\t\t\t    or die;\n+\t\t\tfor (@lines) {\n+\t\t\t\tprint $fh $_;\n+\t\t\t}\n+\t\t\tclose($fh);\n+\t\t\tfor (@update) {\n+\t\t\t\tif ($_->{INDEX_ADDDEL} &&\n+\t\t\t\t    $_->{INDEX_ADDDEL} eq 'create') {\n+\t\t\t\t\tsystem(qw(git update-index --force-remove --),\n+\t\t\t\t\t       $_->{VALUE});\n+\t\t\t\t\tprint \"note: $_->{VALUE} is untracked now.\\n\";\n+\t\t\t\t}\n \t\t\t}\n \t\t}\n \t\trefresh();\n@@ -956,7 +973,9 @@ sub diff_cmd {\n \t\t\t\t     HEADER => $status_head, },\n \t\t\t\t   @mods);\n \treturn if (!@them);\n-\tsystem(qw(git diff -p --cached HEAD --), map { $_->{VALUE} } @them);\n+\tmy $reference = is_initial_commit() ? '{}' : 'HEAD';\n+\tsystem(qw(git diff -p --cached), $reference, '--',\n+\t\tmap { $_->{VALUE} } @them);\n }\n \n sub quit_cmd {\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nnew file mode 100755\nindex 0000000..c8dc1ac\n--- /dev/null\n+++ b/t/t3701-add-interactive.sh\n@@ -0,0 +1,69 @@\n+#!/bin/sh\n+\n+test_description='add -i basic tests'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup (initial)' '\n+\techo content >file &&\n+\tgit add file &&\n+\techo more >>file &&\n+\techo lines >>file\n+'\n+test_expect_success 'status works (initial)' '\n+\tgit add -i </dev/null >output &&\n+\tgrep \"+1/-0 *+2/-0 file\" output\n+'\n+cat >expected <<EOF\n+new file mode 100644\n+index 0000000..d95f3ad\n+--- /dev/null\n++++ b/file\n+@@ -0,0 +1 @@\n++content\n+EOF\n+test_expect_success 'diff works (initial)' '\n+\t(echo d; echo 1) | git add -i >output &&\n+\tsed -ne \"/new file/,/content/p\" <output >diff &&\n+\tdiff -u expected diff\n+'\n+test_expect_success 'revert works (initial)' '\n+\tgit add file &&\n+\t(echo r; echo 1) | git add -i &&\n+\tgit ls-files >output &&\n+\t! grep . output\n+'\n+\n+test_expect_success 'setup (commit)' '\n+\techo baseline >file &&\n+\tgit add file &&\n+\tgit commit -m commit &&\n+\techo content >>file &&\n+\tgit add file &&\n+\techo more >>file &&\n+\techo lines >>file\n+'\n+test_expect_success 'status works (commit)' '\n+\tgit add -i </dev/null >output &&\n+\tgrep \"+1/-0 *+2/-0 file\" output\n+'\n+cat >expected <<EOF\n+index 180b47c..b6f2c08 100644\n+--- a/file\n++++ b/file\n+@@ -1 +1,2 @@\n+ baseline\n++content\n+EOF\n+test_expect_success 'diff works (commit)' '\n+\t(echo d; echo 1) | git add -i >output &&\n+\tsed -ne \"/^index/,/content/p\" <output >diff &&\n+\tdiff -u expected diff\n+'\n+test_expect_success 'revert works (commit)' '\n+\tgit add file &&\n+\t(echo r; echo 1) | git add -i &&\n+\tgit add -i </dev/null >output &&\n+\tgrep \"unchanged *+3/-0 file\" output\n+'\n+\n+test_done\n-- \n1.5.4.1.123.ge4e8d-dirty\n"}]}