{"thread":{"id":"19465","subject":"git-ls-files --added?","startedAt":"2009-05-24T07:54:05Z","lastAt":"2009-05-31T16:19:16Z","messageCount":13,"participants":["Jon Seymour","Jakub Narebski","Junio C Hamano","Constantine Plotnikov","Björn Steinbrink","David Aguilar","Nanako Shiraishi","Tony Finch"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"114550","messageId":"2cfc40320905240054j2c08da8bt4df95c6f1bc9e254@mail.gmail.com","threadId":"19465","inReplyTo":null,"subject":"git-ls-files --added?","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2009-05-24T07:54:05Z","receivedAt":"2009-05-24T07:54:05Z","isPatch":false,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Hi,\n\nIs there a reason why git-ls-files does not have an --added option?\n\nI'd like to get a list of new files, due to be committed. Currently, I\nhave to parse the output of git status to get that, but it seems like\na reasonable function for git-ls-files.\n\njon.\n"},{"id":"114551","messageId":"m3fxeudhho.fsf@localhost.localdomain","threadId":"19465","inReplyTo":"2cfc40320905240054j2c08da8bt4df95c6f1bc9e254@mail.gmail.com","subject":"Re: git-ls-files --added?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-05-24T08:37:11Z","receivedAt":"2009-05-24T08:37:11Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Jon Seymour <jon.seymour@gmail.com> writes:\n\n> Is there a reason why git-ls-files does not have an --added option?\n> \n> I'd like to get a list of new files, due to be committed. Currently, I\n> have to parse the output of git status to get that, but it seems like\n> a reasonable function for git-ls-files.\n\nYou can use git-diff-* with --name-only and --diff-filter=A for\nthat; you shouldn't parse result of porcelain git-status.\n\nAnd there is also contrib/examples/git-commit.sh as a guideline...\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"114552","messageId":"2cfc40320905240212jc111b1xfeb39b1851c606d3@mail.gmail.com","threadId":"19465","inReplyTo":"m3fxeudhho.fsf@localhost.localdomain","subject":"Re: git-ls-files --added?","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2009-05-24T09:12:00Z","receivedAt":"2009-05-24T09:12:00Z","isPatch":false,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Jakub,\n\nThanks - yes, I wasn't happy about parsing git status.\n\nI am still interested in the rationale for git-ls-files not supporting\nsuch an option directly, since git-diff still seems a little indirect.\n\nRegards,\n\njon.\n\nOn Sun, May 24, 2009 at 6:37 PM, Jakub Narebski <jnareb@gmail.com> wrote:\n> Jon Seymour <jon.seymour@gmail.com> writes:\n>\n>> Is there a reason why git-ls-files does not have an --added option?\n>>\n>> I'd like to get a list of new files, due to be committed. Currently, I\n>> have to parse the output of git status to get that, but it seems like\n>> a reasonable function for git-ls-files.\n>\n> You can use git-diff-* with --name-only and --diff-filter=A for\n> that; you shouldn't parse result of porcelain git-status.\n>\n> And there is also contrib/examples/git-commit.sh as a guideline...\n>\n> --\n> Jakub Narebski\n> Poland\n> ShadeHawk on #git\n>\n"},{"id":"114585","messageId":"7vmy921i3j.fsf@alter.siamese.dyndns.org","threadId":"19465","inReplyTo":"2cfc40320905240212jc111b1xfeb39b1851c606d3@mail.gmail.com","subject":"Re: git-ls-files --added?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-05-24T18:17:04Z","receivedAt":"2009-05-24T18:17:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jon Seymour <jon.seymour@gmail.com> writes:\n\n> Jakub,\n>\n> Thanks - yes, I wasn't happy about parsing git status.\n>\n> I am still interested in the rationale for git-ls-files not supporting\n> such an option directly, since git-diff still seems a little indirect.\n\nPartly historical, but more fundamental reason is because ls-files\nplumbing is about the index.\n\nThe index by definition knows about the work tree files.  Reporting the\nstatus of work tree files by comparing what was added to the index makes\nsense in that context.\n\ngit-ls-files documentation lists --cached/deleted...  and if you think\nabout them, you will realize that the all of them make sense; they are\nabout the index or comparison between the index and the work tree.\n\nAdded is _not_ about comparision between the index and the work tree.  It\nis between the HEAD commit and the index, and it does not belong to\nls-files plumbing.\n"},{"id":"114622","messageId":"7vws85y9n7.fsf@alter.siamese.dyndns.org","threadId":"19465","inReplyTo":"7vmy921i3j.fsf@alter.siamese.dyndns.org","subject":"Re: git-ls-files --added?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-05-25T06:33:16Z","receivedAt":"2009-05-25T06:33:16Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jon Seymour <jon.seymour@gmail.com> writes:\n> ...\n>> I am still interested in the rationale for git-ls-files not supporting\n>> such an option directly, since git-diff still seems a little indirect.\n> \n> Partly historical, but more fundamental reason is because ls-files\n> plumbing is about the index.\n> ...\n> Added is _not_ about comparision between the index and the work tree.  It\n> is between the HEAD commit and the index, and it does not belong to\n> ls-files plumbing.\n\nHaving said all that, I think you might be interested in pursuing\n\n  http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134\n\nAlso, the following thread may serve as a food for thought; it shows that\nthere is real need for some concise, easy to parse output for people who\nwant their own Porcelain.\n\n  http://thread.gmane.org/gmane.comp.version-control.git/106122/focus=108110\n\nIn short, ls-files and diff-index _can_ give you what you want, but often\npeople would want information from both, consolidated.\n"},{"id":"114628","messageId":"85647ef50905250031m375a14d9y252444a8bdc250b5@mail.gmail.com","threadId":"19465","inReplyTo":"7vws85y9n7.fsf@alter.siamese.dyndns.org","subject":"Re: git-ls-files --added?","fromName":"Constantine Plotnikov","fromEmail":"constantine.plotnikov@gmail.com","sentAt":"2009-05-25T07:31:42Z","receivedAt":"2009-05-25T07:31:42Z","isPatch":false,"sender":{"key":"constantine.plotnikov@gmail.com","avatar":null},"body":"On Mon, May 25, 2009 at 10:33 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Jon Seymour <jon.seymour@gmail.com> writes:\n>> ...\n>>> I am still interested in the rationale for git-ls-files not supporting\n>>> such an option directly, since git-diff still seems a little indirect.\n>>\n>> Partly historical, but more fundamental reason is because ls-files\n>> plumbing is about the index.\n>> ...\n>> Added is _not_ about comparision between the index and the work tree.  It\n>> is between the HEAD commit and the index, and it does not belong to\n>> ls-files plumbing.\n>\n> Having said all that, I think you might be interested in pursuing\n>\n>  http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134\n>\n> Also, the following thread may serve as a food for thought; it shows that\n> there is real need for some concise, easy to parse output for people who\n> want their own Porcelain.\n>\n>  http://thread.gmane.org/gmane.comp.version-control.git/106122/focus=108110\n>\n> In short, ls-files and diff-index _can_ give you what you want, but often\n> people would want information from both, consolidated.\n\nI'm one of those people :) Writing git support for IDEs is quite\ntricky at times, and status check was one of quite unpleasant\nexperiences.\n\nBTW git-diff won't work in situation when the directory was just\ninitialized and there were no commit. In that case added file = staged\nfile and it is possible to use git-ls-files.\n\nConstantine\n"},{"id":"114632","messageId":"20090525074606.GA30061@atjola.homenet","threadId":"19465","inReplyTo":"85647ef50905250031m375a14d9y252444a8bdc250b5@mail.gmail.com","subject":"Re: git-ls-files --added?","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-05-25T07:46:06Z","receivedAt":"2009-05-25T07:46:06Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.05.25 11:31:42 +0400, Constantine Plotnikov wrote:\n> BTW git-diff won't work in situation when the directory was just\n> initialized and there were no commit. In that case added file = staged\n> file and it is possible to use git-ls-files.\n\nYou can use the object name of the empty tree with diff-* in that case,\nthat's what the pre-commit.sample hook does.\n\nBjörn\n"},{"id":"114727","messageId":"2cfc40320905251756t32e092fdqda769e21669f5d86@mail.gmail.com","threadId":"19465","inReplyTo":"7vws85y9n7.fsf@alter.siamese.dyndns.org","subject":"Re: git-ls-files --added?","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2009-05-26T00:56:52Z","receivedAt":"2009-05-26T00:56:52Z","isPatch":false,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Thanks for your answer's Junio.\n\nI am indeed writing some porcelain. I currently have some bash tooling\nthat wraps bash which does useful things for primarily linear\ndevelopment in the subversion world [ trunk + well-controlled branches\n] and in order to ease the transition of the organization to\nfull-blown adoption of git, I'd like to provide some equivalents that\noperate in git land.\n\nscm unknown  [ equivalent to not added to index yet ]\nscm broken [ equivalent to deleted from working tree but not index ]\nscm uncommittable [ union of unknown and broken ]\nscm added\nscm modified\nscm deleted\nscm other  [ cases I didn't think of yet ]\n\nI am happy to munge these together with bash, but I thought I'd just\n+1 the general requirement.\n\njon.\n\nOn Mon, May 25, 2009 at 4:33 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Jon Seymour <jon.seymour@gmail.com> writes:\n>> ...\n>>> I am still interested in the rationale for git-ls-files not supporting\n>>> such an option directly, since git-diff still seems a little indirect.\n>>\n>> Partly historical, but more fundamental reason is because ls-files\n>> plumbing is about the index.\n>> ...\n>> Added is _not_ about comparision between the index and the work tree.  It\n>> is between the HEAD commit and the index, and it does not belong to\n>> ls-files plumbing.\n>\n> Having said all that, I think you might be interested in pursuing\n>\n>  http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134\n>\n> Also, the following thread may serve as a food for thought; it shows that\n> there is real need for some concise, easy to parse output for people who\n> want their own Porcelain.\n>\n>  http://thread.gmane.org/gmane.comp.version-control.git/106122/focus=108110\n>\n> In short, ls-files and diff-index _can_ give you what you want, but often\n> people would want information from both, consolidated.\n>\n"},{"id":"115050","messageId":"20090529212634.GA86167@gmail.com","threadId":"19465","inReplyTo":"2cfc40320905251756t32e092fdqda769e21669f5d86@mail.gmail.com","subject":"Re: git-ls-files --added?","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2009-05-29T21:26:42Z","receivedAt":"2009-05-29T21:26:42Z","isPatch":false,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"On Tue, May 26, 2009 at 10:56:52AM +1000, Jon Seymour wrote:\n> Thanks for your answer's Junio.\n> \n> I am indeed writing some porcelain. I currently have some bash tooling\n\n\nI know that for the purposes of writing scripts it would be\nreally great if we had a plumbing command that gave us exactly\nwhat git-status tells us, but in a machine-parseable\nand stable output format.\n\nParticularly tricky to get both correct and fast is\npartially-staged files, but git-status gets it right.\nBy partially staged I mean it has new uncommitted content\nin the index as well as even newer content in the worktree.\n\nFiles fall roughly into these categories:\n\n1. Staged:\n\t1.1 Existing file\n\t1.2 New file\n\t1.3 Deleted file\n\t1.4 File was renamed, this is the old path\n\t1.5 File was renamed, this is the new path\n\n\n2. Unmerged\n\n3. Modified\n\t3.1 File was modified\n\t3.2 File was deleted\n\n4. Untracked\n\t4.1 This is a file\n\t4.2 This is a directory\n\n\nHere's some semantics I would expect from such a command:\n\n- A file can be both staged and modified.\n\n- A file that is unmerged is only unmerged.\n  It is neither modified nor staged.\n\n- Untracked path behavior is nicer with git-status then with\n  git-ls-files, the reason being that status special-cases\n  directories.\n\n\nGetting all of this information quickly (without having to run\nmultiple commands) would be ideal.  This command is a\ncombination of diff-against-worktree, diff-against-index,\nshow-untracked-files, etc. so it's not a paradigm that's\neasily constructed with the existing plumbing.\n\n\n-- \n\t\tDavid\n"},{"id":"115054","messageId":"20090530070111.6117@nanako3.lavabit.com","threadId":"19465","inReplyTo":"20090529212634.GA86167@gmail.com","subject":"Re: git-ls-files --added?","fromName":"Nanako Shiraishi","fromEmail":"nanako3@lavabit.com","sentAt":"2009-05-29T22:01:11Z","receivedAt":"2009-05-29T22:01:11Z","isPatch":false,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Quoting David Aguilar <davvid@gmail.com> writes:\n\n> On Tue, May 26, 2009 at 10:56:52AM +1000, Jon Seymour wrote:\n>> Thanks for your answer's Junio.\n>> \n>> I am indeed writing some porcelain. I currently have some bash tooling\n>\n> I know that for the purposes of writing scripts it would be\n> really great if we had a plumbing command that gave us exactly\n> what git-status tells us, but in a machine-parseable\n> and stable output format.\n\nPerhaps you weren't following the thread closely, but I think the patch in the thread quoted by Junio (http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134) does exactly that.\n\n-- \nNanako Shiraishi\nhttp://ivory.ap.teacup.com/nanako3/\n"},{"id":"115057","messageId":"7v4ov38q5x.fsf@alter.siamese.dyndns.org","threadId":"19465","inReplyTo":"20090530070111.6117@nanako3.lavabit.com","subject":"Re: git-ls-files --added?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-05-29T23:06:50Z","receivedAt":"2009-05-29T23:06:50Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nanako Shiraishi <nanako3@lavabit.com> writes:\n\n> ..., but I think the patch in the thread quoted by Junio (http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134) does exactly that.\n\nI do not know if it matches what David wants, but I can tell you that that\npatch is certainly ancient.\n\nHere is a minimal update to make it apply cleanly on top of today's\n'master'.\n\n-- >8 --\nSubject: Add git-shortstatus plumbing\n\nBecause I was bored thinking about what to talk about in Gittogether and\nlacked enough concentration to do anything productive, I did this that:\n\n (1) introduces the \"find and summarize changes in a single string list\"\n     infrastructure;\n\n (2) rewrites wt_status_print_{updated,changed} to use it; and\n\n (3) adds \"git shortstatus\" that does not take any parameter (so it is not\n     about \"preview of commit with the same paths arguments\" anymore) to\n     give the status in:\n\n        XsssY PATH1 -> PATH2\n\n    format, where X is the diff status between HEAD and the index, sss is the\n    rename/copy score of the change (if X is rename or copy --- otherwise\n    it is blank), Y is the diff status between the index and the worktree.  \n    PATH1 is the path in the HEAD, and \" -> PATH2\" part is shown only when\n    PATH1 corresponds to a different path in the index/worktree.\n\nThis was done primarily for fun and killing-time, so I won't be committing\nit to my tree, but it seems to pass all the existing tests.\n\nIf you apply this patch with \"git apply\" (no --index) and then\n\n        $ git mv COPYING RENAMING\n\nthen you would see:\n\n        $ ./git-shortstatus\n        M     Makefile\n        R100  COPYING -> RENAMING\n            M builtin-commit.c\n            M builtin-revert.c\n            M builtin.h\n            M git.c\n            M wt-status.c\n            M wt-status.h        \n\nIt is very much welcomed if somebody wants to build on top of this.  A few\nobvious things, aside from bikeshedding to drop the score value (which I\njust did as a sanity check measure and for nothing else --- I won't feel\nhurt if we lost that field from the output) and such are:\n\n * We can also rewrite wt_status_print_untracked() using the collected\n   data by making the collector pay attention to untracked files quite\n   easily;\n\n * I did not bouther touching wt_status_print_initial() but I think it\n   should be straightforward to produce its output from the collected\n   data, as the collector already knows how to handle the initial commit.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n Makefile         |    1 +\n builtin-commit.c |   45 +++++++++++-\n builtin-revert.c |    1 +\n builtin.h        |    1 +\n git.c            |    1 +\n wt-status.c      |  214 ++++++++++++++++++++++++++++++++++++++++++-----------\n wt-status.h      |    9 ++\n 7 files changed, 226 insertions(+), 46 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex eaae45d..fd497d4 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -359,6 +359,7 @@ BUILT_INS += git-init$X\n BUILT_INS += git-merge-subtree$X\n BUILT_INS += git-peek-remote$X\n BUILT_INS += git-repo-config$X\n+BUILT_INS += git-shortstatus$X\n BUILT_INS += git-show$X\n BUILT_INS += git-stage$X\n BUILT_INS += git-status$X\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex baaa75c..463356b 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -14,6 +14,7 @@\n #include \"diffcore.h\"\n #include \"commit.h\"\n #include \"revision.h\"\n+#include \"string-list.h\"\n #include \"wt-status.h\"\n #include \"run-command.h\"\n #include \"refs.h\"\n@@ -21,7 +22,6 @@\n #include \"strbuf.h\"\n #include \"utf8.h\"\n #include \"parse-options.h\"\n-#include \"string-list.h\"\n #include \"rerere.h\"\n #include \"unpack-trees.h\"\n \n@@ -817,6 +817,49 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \treturn argc;\n }\n \n+int cmd_shortstatus(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct wt_status s;\n+\tint i;\n+\n+\tread_cache();\n+\trefresh_cache(REFRESH_QUIET);\n+\twt_status_prepare(&s);\n+\twt_status_collect_changes(&s);\n+\tfor (i = 0; i < s.change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\t\tchar pfx[1 + 3 + 1 + 1];\n+\n+\t\tit = &(s.change.items[i]);\n+\t\td = it->util;\n+\t\tswitch (d->index_status) {\n+\t\tcase DIFF_STATUS_COPIED:\n+\t\tcase DIFF_STATUS_RENAMED:\n+\t\t\tsprintf(pfx, \"%c%3d\",\n+\t\t\t\td->index_status,\n+\t\t\t\t(int)(d->index_score * 100 / MAX_SCORE));\n+\t\t\tbreak;\n+\t\tcase 0:\n+\t\t\tmemcpy(pfx, \"    \", 4);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tsprintf(pfx, \"%c   \", d->index_status);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!d->worktree_status)\n+\t\t\tpfx[4] = ' ';\n+\t\telse\n+\t\t\tpfx[4] = d->worktree_status;\n+\t\tpfx[5] = '\\0';\n+\t\tprintf(\"%s \", pfx);\n+\t\tif (d->head_path)\n+\t\t\tprintf(\"%s -> \", d->head_path);\n+\t\tprintf(\"%s\\n\", it->string);\n+\t}\n+\treturn 0;\n+}\n+\n int cmd_status(int argc, const char **argv, const char *prefix)\n {\n \tconst char *index_file;\ndiff --git a/builtin-revert.c b/builtin-revert.c\nindex 3f2614e..10f1655 100644\n--- a/builtin-revert.c\n+++ b/builtin-revert.c\n@@ -3,6 +3,7 @@\n #include \"object.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n+#include \"string-list.h\"\n #include \"wt-status.h\"\n #include \"run-command.h\"\n #include \"exec_cmd.h\"\ndiff --git a/builtin.h b/builtin.h\nindex 425ff8e..23e9eb6 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -95,6 +95,7 @@ extern int cmd_shortlog(int argc, const char **argv, const char *prefix);\n extern int cmd_show(int argc, const char **argv, const char *prefix);\n extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\n extern int cmd_status(int argc, const char **argv, const char *prefix);\n+extern int cmd_shortstatus(int argc, const char **argv, const char *prefix);\n extern int cmd_stripspace(int argc, const char **argv, const char *prefix);\n extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);\n extern int cmd_tag(int argc, const char **argv, const char *prefix);\ndiff --git a/git.c b/git.c\nindex 5a00726..68c223e 100644\n--- a/git.c\n+++ b/git.c\n@@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"rm\", cmd_rm, RUN_SETUP },\n \t\t{ \"send-pack\", cmd_send_pack, RUN_SETUP },\n \t\t{ \"shortlog\", cmd_shortlog, USE_PAGER },\n+\t\t{ \"shortstatus\", cmd_shortstatus, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n \t\t{ \"show\", cmd_show, RUN_SETUP | USE_PAGER },\n \t\t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\ndiff --git a/wt-status.c b/wt-status.c\nindex 1b6df45..89be28e 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"string-list.h\"\n #include \"wt-status.h\"\n #include \"color.h\"\n #include \"object.h\"\n@@ -56,6 +57,7 @@ void wt_status_prepare(struct wt_status *s)\n \ts->reference = \"HEAD\";\n \ts->fp = stdout;\n \ts->index_file = get_index_file();\n+\ts->change.strdup_strings = 1;\n }\n \n static void wt_status_print_cached_header(struct wt_status *s)\n@@ -98,18 +100,22 @@ static void wt_status_print_trailer(struct wt_status *s)\n \n #define quote_path quote_path_relative\n \n-static void wt_status_print_filepair(struct wt_status *s,\n-\t\t\t\t     int t, struct diff_filepair *p)\n+static void wt_status_print_change_data(struct wt_status *s,\n+\t\t\t\t\tint t,\n+\t\t\t\t\tint status,\n+\t\t\t\t\tchar *one_name,\n+\t\t\t\t\tchar *two_name,\n+\t\t\t\t\tint score)\n {\n \tconst char *c = color(t);\n \tconst char *one, *two;\n \tstruct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;\n \n-\tone = quote_path(p->one->path, -1, &onebuf, s->prefix);\n-\ttwo = quote_path(p->two->path, -1, &twobuf, s->prefix);\n+\tone = quote_path(one_name, -1, &onebuf, s->prefix);\n+\ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n-\tswitch (p->status) {\n+\tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n \t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n \t\tbreak;\n@@ -135,64 +141,88 @@ static void wt_status_print_filepair(struct wt_status *s,\n \t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", p->status);\n+\t\tdie(\"bug: unhandled diff status %c\", status);\n \t}\n \tfprintf(s->fp, \"\\n\");\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n \n-static void wt_status_print_updated_cb(struct diff_queue_struct *q,\n-\t\tstruct diff_options *options,\n-\t\tvoid *data)\n+static void wt_status_collect_changed_cb(struct diff_queue_struct *q,\n+\t\t\t\t\t struct diff_options *options,\n+\t\t\t\t\t void *data)\n {\n \tstruct wt_status *s = data;\n-\tint shown_header = 0;\n \tint i;\n+\n+\tif (!q->nr)\n+\t\treturn;\n+\ts->workdir_dirty = 1;\n \tfor (i = 0; i < q->nr; i++) {\n-\t\tif (q->queue[i]->status == 'U')\n-\t\t\tcontinue;\n-\t\tif (!shown_header) {\n-\t\t\twt_status_print_cached_header(s);\n-\t\t\ts->commitable = 1;\n-\t\t\tshown_header = 1;\n-\t\t}\n-\t\twt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);\n+\t\tstruct diff_filepair *p;\n+\t\tstruct string_list_item *it;\n+\t\tstruct wt_status_change_data *d;\n+\n+\t\tp = q->queue[i];\n+\n+\t\td = xcalloc(1, sizeof(*d));\n+\t\td->worktree_status = p->status;\n+\t\tit = string_list_insert(p->one->path, &s->change);\n+\t\tit->util = d;\n \t}\n-\tif (shown_header)\n-\t\twt_status_print_trailer(s);\n }\n \n-static void wt_status_print_changed_cb(struct diff_queue_struct *q,\n-                        struct diff_options *options,\n-                        void *data)\n+static void wt_status_collect_updated_cb(struct diff_queue_struct *q,\n+\t\t\t\t\t struct diff_options *options,\n+\t\t\t\t\t void *data)\n {\n \tstruct wt_status *s = data;\n \tint i;\n-\tif (q->nr) {\n-\t\tint has_deleted = 0;\n-\t\ts->workdir_dirty = 1;\n-\t\tfor (i = 0; i < q->nr; i++)\n-\t\t\tif (q->queue[i]->status == DIFF_STATUS_DELETED) {\n-\t\t\t\thas_deleted = 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\twt_status_print_dirty_header(s, has_deleted);\n+\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p;\n+\t\tstruct string_list_item *it;\n+\t\tstruct wt_status_change_data *d;\n+\n+\t\tp = q->queue[i];\n+\t\tit = string_list_insert(p->two->path, &s->change);\n+\t\td = it->util;\n+\t\tif (!d) {\n+\t\t\td = xcalloc(1, sizeof(*d));\n+\t\t\tit->util = d;\n+\t\t}\n+\t\td->index_status = p->status;\n+\t\tswitch (p->status) {\n+\t\tcase DIFF_STATUS_COPIED:\n+\t\tcase DIFF_STATUS_RENAMED:\n+\t\t\td->head_path = xstrdup(p->one->path);\n+\t\t\td->index_score = p->score;\n+\t\t\tbreak;\n+\t\t}\n \t}\n-\tfor (i = 0; i < q->nr; i++)\n-\t\twt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);\n-\tif (q->nr)\n-\t\twt_status_print_trailer(s);\n }\n \n-static void wt_status_print_updated(struct wt_status *s)\n+static void wt_status_collect_changes_worktree(struct wt_status *s)\n+{\n+\tstruct rev_info rev;\n+\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(0, NULL, &rev, NULL);\n+\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = wt_status_collect_changed_cb;\n+\trev.diffopt.format_callback_data = s;\n+\trun_diff_files(&rev, 0);\n+}\n+\n+static void wt_status_collect_changes_index(struct wt_status *s)\n {\n \tstruct rev_info rev;\n+\n \tinit_revisions(&rev, NULL);\n \tsetup_revisions(0, NULL, &rev,\n \t\ts->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);\n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n-\trev.diffopt.format_callback = wt_status_print_updated_cb;\n+\trev.diffopt.format_callback = wt_status_collect_updated_cb;\n \trev.diffopt.format_callback_data = s;\n \trev.diffopt.detect_rename = 1;\n \trev.diffopt.rename_limit = 200;\n@@ -200,15 +230,107 @@ static void wt_status_print_updated(struct wt_status *s)\n \trun_diff_index(&rev, 1);\n }\n \n+static void wt_status_collect_changes_initial(struct wt_status *s)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct string_list_item *it;\n+\t\tstruct wt_status_change_data *d;\n+\n+\t\tit = string_list_insert(active_cache[i]->name, &s->change);\n+\t\td = it->util;\n+\t\tif (!d) {\n+\t\t\td = xcalloc(1, sizeof(*d));\n+\t\t\tit->util = d;\n+\t\t}\n+\t\td->index_status = DIFF_STATUS_ADDED;\n+\t}\n+}\n+\n+void wt_status_collect_changes(struct wt_status *s)\n+{\n+\twt_status_collect_changes_worktree(s);\n+\n+\tif (s->is_initial)\n+\t\twt_status_collect_changes_initial(s);\n+\telse\n+\t\twt_status_collect_changes_index(s);\n+}\n+\n+static void wt_status_print_updated(struct wt_status *s)\n+{\n+\tint shown_header = 0;\n+\tint i;\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\t\tit = &(s->change.items[i]);\n+\t\td = it->util;\n+\t\tif (!d->index_status)\n+\t\t\tcontinue;\n+\t\tif (!shown_header) {\n+\t\t\twt_status_print_cached_header(s);\n+\t\t\ts->commitable = 1;\n+\t\t\tshown_header = 1;\n+\t\t}\n+\t\twt_status_print_change_data(s, WT_STATUS_UPDATED,\n+\t\t\t\t\t    d->index_status,\n+\t\t\t\t\t    d->head_path ? d->head_path : it->string,\n+\t\t\t\t\t    it->string,\n+\t\t\t\t\t    d->index_score);\n+\t}\n+\tif (shown_header)\n+\t\twt_status_print_trailer(s);\n+}\n+\n+/*\n+ * -1 : has delete\n+ *  0 : no change\n+ *  1 : some change but no delete\n+ */\n+static int wt_status_check_worktree_changes(struct wt_status *s)\n+{\n+\tint i;\n+\tint changes = 0;\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\td = s->change.items[i].util;\n+\t\tif (!d->worktree_status)\n+\t\t\tcontinue;\n+\t\tchanges = 1;\n+\t\tif (d->worktree_status == DIFF_STATUS_DELETED)\n+\t\t\treturn -1;\n+\t}\n+\treturn changes;\n+}\n+\n static void wt_status_print_changed(struct wt_status *s)\n {\n-\tstruct rev_info rev;\n-\tinit_revisions(&rev, \"\");\n-\tsetup_revisions(0, NULL, &rev, NULL);\n-\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n-\trev.diffopt.format_callback = wt_status_print_changed_cb;\n-\trev.diffopt.format_callback_data = s;\n-\trun_diff_files(&rev, 0);\n+\tint i;\n+\tint worktree_changes = wt_status_check_worktree_changes(s);\n+\n+\tif (!worktree_changes)\n+\t\treturn;\n+\n+\twt_status_print_dirty_header(s, worktree_changes < 0);\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\t\tit = &(s->change.items[i]);\n+\t\td = it->util;\n+\t\tif (!d->worktree_status)\n+\t\t\tcontinue;\n+\t\twt_status_print_change_data(s, WT_STATUS_CHANGED,\n+\t\t\t\t\t    d->worktree_status,\n+\t\t\t\t\t    it->string,\n+\t\t\t\t\t    it->string,\n+\t\t\t\t\t    0);\n+\t}\n+\twt_status_print_trailer(s);\n }\n \n static void wt_status_print_submodule_summary(struct wt_status *s)\n@@ -337,6 +459,8 @@ void wt_status_print(struct wt_status *s)\n \t\t\twt_status_print_tracking(s);\n \t}\n \n+\twt_status_collect_changes(s);\n+\n \tif (s->is_initial) {\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"# Initial commit\");\ndiff --git a/wt-status.h b/wt-status.h\nindex 78add09..00508c3 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -18,6 +18,13 @@ enum untracked_status_type {\n };\n extern enum untracked_status_type show_untracked_files;\n \n+struct wt_status_change_data {\n+\tint worktree_status;\n+\tint index_status;\n+\tint index_score;\n+\tchar *head_path;\n+};\n+\n struct wt_status {\n \tint is_initial;\n \tchar *branch;\n@@ -33,6 +40,7 @@ struct wt_status {\n \tconst char *index_file;\n \tFILE *fp;\n \tconst char *prefix;\n+\tstruct string_list change;\n };\n \n int git_status_config(const char *var, const char *value, void *cb);\n@@ -40,5 +48,6 @@ extern int wt_status_use_color;\n extern int wt_status_relative_paths;\n void wt_status_prepare(struct wt_status *s);\n void wt_status_print(struct wt_status *s);\n+void wt_status_collect_changes(struct wt_status *s);\n \n #endif /* STATUS_H */\n"},{"id":"115070","messageId":"20090530060233.GA10033@gmail.com","threadId":"19465","inReplyTo":"7v4ov38q5x.fsf@alter.siamese.dyndns.org","subject":"Re: git-ls-files --added?","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2009-05-30T06:02:34Z","receivedAt":"2009-05-30T06:02:34Z","isPatch":false,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"On Fri, May 29, 2009 at 04:06:50PM -0700, Junio C Hamano wrote:\n> Nanako Shiraishi <nanako3@lavabit.com> writes:\n> \n> > ..., but I think the patch in the thread quoted by Junio (http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134) does exactly that.\n> \n> I do not know if it matches what David wants, but I can tell you that that\n> patch is certainly ancient.\n> \n> Here is a minimal update to make it apply cleanly on top of today's\n> 'master'.\n\nThanks Nanako + Junio!\n\nThere's good stuff to build upon here so I'll take a deeper look\ninto it.  Getting this as plumbing will help a lot of future git\nscripters.\n\n>         XsssY PATH1 -> PATH2\n> \n>     format, where X is the diff status between HEAD and the index, sss is the\n>     rename/copy score of the change (if X is rename or copy --- otherwise\n>     it is blank), Y is the diff status between the index and the worktree.  \n>     PATH1 is the path in the HEAD, and \" -> PATH2\" part is shown only when\n>     PATH1 corresponds to a different path in the index/worktree.\n\nCan/should shortstatus handle comparing against arbitrary revs,\nso we can parse the same info against HEAD~ to see a fake\nstatus as if we're amending a commit?  That'd be pretty useful.\n\n\n> If you apply this patch with \"git apply\" (no --index) and then\n> \n>         $ git mv COPYING RENAMING\n> \n> then you would see:\n> \n>         $ ./git-shortstatus\n>         M     Makefile\n>         R100  COPYING -> RENAMING\n>             M builtin-commit.c\n>             M builtin-revert.c\n>             M builtin.h\n>             M git.c\n>             M wt-status.c\n>             M wt-status.h        \n\nVery nice.\n\nI'll look into your suggestions below when I have some more\ntime and welcome others to help out as well.\n\n\n> It is very much welcomed if somebody wants to build on top of this.  A few\n> obvious things, aside from bikeshedding to drop the score value (which I\n> just did as a sanity check measure and for nothing else --- I won't feel\n> hurt if we lost that field from the output) and such are:\n> \n>  * We can also rewrite wt_status_print_untracked() using the collected\n>    data by making the collector pay attention to untracked files quite\n>    easily;\n> \n>  * I did not bouther touching wt_status_print_initial() but I think it\n>    should be straightforward to produce its output from the collected\n>    data, as the collector already knows how to handle the initial commit.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> \n>  Makefile         |    1 +\n>  builtin-commit.c |   45 +++++++++++-\n>  builtin-revert.c |    1 +\n>  builtin.h        |    1 +\n>  git.c            |    1 +\n>  wt-status.c      |  214 ++++++++++++++++++++++++++++++++++++++++++-----------\n>  wt-status.h      |    9 ++\n>  7 files changed, 226 insertions(+), 46 deletions(-)\n> \n> diff --git a/Makefile b/Makefile\n> index eaae45d..fd497d4 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -359,6 +359,7 @@ BUILT_INS += git-init$X\n>  BUILT_INS += git-merge-subtree$X\n>  BUILT_INS += git-peek-remote$X\n>  BUILT_INS += git-repo-config$X\n> +BUILT_INS += git-shortstatus$X\n>  BUILT_INS += git-show$X\n>  BUILT_INS += git-stage$X\n>  BUILT_INS += git-status$X\n> diff --git a/builtin-commit.c b/builtin-commit.c\n> index baaa75c..463356b 100644\n> --- a/builtin-commit.c\n> +++ b/builtin-commit.c\n> @@ -14,6 +14,7 @@\n>  #include \"diffcore.h\"\n>  #include \"commit.h\"\n>  #include \"revision.h\"\n> +#include \"string-list.h\"\n>  #include \"wt-status.h\"\n>  #include \"run-command.h\"\n>  #include \"refs.h\"\n> @@ -21,7 +22,6 @@\n>  #include \"strbuf.h\"\n>  #include \"utf8.h\"\n>  #include \"parse-options.h\"\n> -#include \"string-list.h\"\n>  #include \"rerere.h\"\n>  #include \"unpack-trees.h\"\n>  \n> @@ -817,6 +817,49 @@ static int parse_and_validate_options(int argc, const char *argv[],\n>  \treturn argc;\n>  }\n>  \n> +int cmd_shortstatus(int argc, const char **argv, const char *prefix)\n> +{\n> +\tstruct wt_status s;\n> +\tint i;\n> +\n> +\tread_cache();\n> +\trefresh_cache(REFRESH_QUIET);\n> +\twt_status_prepare(&s);\n> +\twt_status_collect_changes(&s);\n> +\tfor (i = 0; i < s.change.nr; i++) {\n> +\t\tstruct wt_status_change_data *d;\n> +\t\tstruct string_list_item *it;\n> +\t\tchar pfx[1 + 3 + 1 + 1];\n> +\n> +\t\tit = &(s.change.items[i]);\n> +\t\td = it->util;\n> +\t\tswitch (d->index_status) {\n> +\t\tcase DIFF_STATUS_COPIED:\n> +\t\tcase DIFF_STATUS_RENAMED:\n> +\t\t\tsprintf(pfx, \"%c%3d\",\n> +\t\t\t\td->index_status,\n> +\t\t\t\t(int)(d->index_score * 100 / MAX_SCORE));\n> +\t\t\tbreak;\n> +\t\tcase 0:\n> +\t\t\tmemcpy(pfx, \"    \", 4);\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tsprintf(pfx, \"%c   \", d->index_status);\n> +\t\t\tbreak;\n> +\t\t}\n> +\t\tif (!d->worktree_status)\n> +\t\t\tpfx[4] = ' ';\n> +\t\telse\n> +\t\t\tpfx[4] = d->worktree_status;\n> +\t\tpfx[5] = '\\0';\n> +\t\tprintf(\"%s \", pfx);\n> +\t\tif (d->head_path)\n> +\t\t\tprintf(\"%s -> \", d->head_path);\n> +\t\tprintf(\"%s\\n\", it->string);\n> +\t}\n> +\treturn 0;\n> +}\n> +\n>  int cmd_status(int argc, const char **argv, const char *prefix)\n>  {\n>  \tconst char *index_file;\n> diff --git a/builtin-revert.c b/builtin-revert.c\n> index 3f2614e..10f1655 100644\n> --- a/builtin-revert.c\n> +++ b/builtin-revert.c\n> @@ -3,6 +3,7 @@\n>  #include \"object.h\"\n>  #include \"commit.h\"\n>  #include \"tag.h\"\n> +#include \"string-list.h\"\n>  #include \"wt-status.h\"\n>  #include \"run-command.h\"\n>  #include \"exec_cmd.h\"\n> diff --git a/builtin.h b/builtin.h\n> index 425ff8e..23e9eb6 100644\n> --- a/builtin.h\n> +++ b/builtin.h\n> @@ -95,6 +95,7 @@ extern int cmd_shortlog(int argc, const char **argv, const char *prefix);\n>  extern int cmd_show(int argc, const char **argv, const char *prefix);\n>  extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\n>  extern int cmd_status(int argc, const char **argv, const char *prefix);\n> +extern int cmd_shortstatus(int argc, const char **argv, const char *prefix);\n>  extern int cmd_stripspace(int argc, const char **argv, const char *prefix);\n>  extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);\n>  extern int cmd_tag(int argc, const char **argv, const char *prefix);\n> diff --git a/git.c b/git.c\n> index 5a00726..68c223e 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)\n>  \t\t{ \"rm\", cmd_rm, RUN_SETUP },\n>  \t\t{ \"send-pack\", cmd_send_pack, RUN_SETUP },\n>  \t\t{ \"shortlog\", cmd_shortlog, USE_PAGER },\n> +\t\t{ \"shortstatus\", cmd_shortstatus, RUN_SETUP | NEED_WORK_TREE },\n>  \t\t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n>  \t\t{ \"show\", cmd_show, RUN_SETUP | USE_PAGER },\n>  \t\t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n> diff --git a/wt-status.c b/wt-status.c\n> index 1b6df45..89be28e 100644\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -1,4 +1,5 @@\n>  #include \"cache.h\"\n> +#include \"string-list.h\"\n>  #include \"wt-status.h\"\n>  #include \"color.h\"\n>  #include \"object.h\"\n> @@ -56,6 +57,7 @@ void wt_status_prepare(struct wt_status *s)\n>  \ts->reference = \"HEAD\";\n>  \ts->fp = stdout;\n>  \ts->index_file = get_index_file();\n> +\ts->change.strdup_strings = 1;\n>  }\n>  \n>  static void wt_status_print_cached_header(struct wt_status *s)\n> @@ -98,18 +100,22 @@ static void wt_status_print_trailer(struct wt_status *s)\n>  \n>  #define quote_path quote_path_relative\n>  \n> -static void wt_status_print_filepair(struct wt_status *s,\n> -\t\t\t\t     int t, struct diff_filepair *p)\n> +static void wt_status_print_change_data(struct wt_status *s,\n> +\t\t\t\t\tint t,\n> +\t\t\t\t\tint status,\n> +\t\t\t\t\tchar *one_name,\n> +\t\t\t\t\tchar *two_name,\n> +\t\t\t\t\tint score)\n>  {\n>  \tconst char *c = color(t);\n>  \tconst char *one, *two;\n>  \tstruct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;\n>  \n> -\tone = quote_path(p->one->path, -1, &onebuf, s->prefix);\n> -\ttwo = quote_path(p->two->path, -1, &twobuf, s->prefix);\n> +\tone = quote_path(one_name, -1, &onebuf, s->prefix);\n> +\ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n>  \n>  \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n> -\tswitch (p->status) {\n> +\tswitch (status) {\n>  \tcase DIFF_STATUS_ADDED:\n>  \t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n>  \t\tbreak;\n> @@ -135,64 +141,88 @@ static void wt_status_print_filepair(struct wt_status *s,\n>  \t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n>  \t\tbreak;\n>  \tdefault:\n> -\t\tdie(\"bug: unhandled diff status %c\", p->status);\n> +\t\tdie(\"bug: unhandled diff status %c\", status);\n>  \t}\n>  \tfprintf(s->fp, \"\\n\");\n>  \tstrbuf_release(&onebuf);\n>  \tstrbuf_release(&twobuf);\n>  }\n>  \n> -static void wt_status_print_updated_cb(struct diff_queue_struct *q,\n> -\t\tstruct diff_options *options,\n> -\t\tvoid *data)\n> +static void wt_status_collect_changed_cb(struct diff_queue_struct *q,\n> +\t\t\t\t\t struct diff_options *options,\n> +\t\t\t\t\t void *data)\n>  {\n>  \tstruct wt_status *s = data;\n> -\tint shown_header = 0;\n>  \tint i;\n> +\n> +\tif (!q->nr)\n> +\t\treturn;\n> +\ts->workdir_dirty = 1;\n>  \tfor (i = 0; i < q->nr; i++) {\n> -\t\tif (q->queue[i]->status == 'U')\n> -\t\t\tcontinue;\n> -\t\tif (!shown_header) {\n> -\t\t\twt_status_print_cached_header(s);\n> -\t\t\ts->commitable = 1;\n> -\t\t\tshown_header = 1;\n> -\t\t}\n> -\t\twt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);\n> +\t\tstruct diff_filepair *p;\n> +\t\tstruct string_list_item *it;\n> +\t\tstruct wt_status_change_data *d;\n> +\n> +\t\tp = q->queue[i];\n> +\n> +\t\td = xcalloc(1, sizeof(*d));\n> +\t\td->worktree_status = p->status;\n> +\t\tit = string_list_insert(p->one->path, &s->change);\n> +\t\tit->util = d;\n>  \t}\n> -\tif (shown_header)\n> -\t\twt_status_print_trailer(s);\n>  }\n>  \n> -static void wt_status_print_changed_cb(struct diff_queue_struct *q,\n> -                        struct diff_options *options,\n> -                        void *data)\n> +static void wt_status_collect_updated_cb(struct diff_queue_struct *q,\n> +\t\t\t\t\t struct diff_options *options,\n> +\t\t\t\t\t void *data)\n>  {\n>  \tstruct wt_status *s = data;\n>  \tint i;\n> -\tif (q->nr) {\n> -\t\tint has_deleted = 0;\n> -\t\ts->workdir_dirty = 1;\n> -\t\tfor (i = 0; i < q->nr; i++)\n> -\t\t\tif (q->queue[i]->status == DIFF_STATUS_DELETED) {\n> -\t\t\t\thas_deleted = 1;\n> -\t\t\t\tbreak;\n> -\t\t\t}\n> -\t\twt_status_print_dirty_header(s, has_deleted);\n> +\n> +\tfor (i = 0; i < q->nr; i++) {\n> +\t\tstruct diff_filepair *p;\n> +\t\tstruct string_list_item *it;\n> +\t\tstruct wt_status_change_data *d;\n> +\n> +\t\tp = q->queue[i];\n> +\t\tit = string_list_insert(p->two->path, &s->change);\n> +\t\td = it->util;\n> +\t\tif (!d) {\n> +\t\t\td = xcalloc(1, sizeof(*d));\n> +\t\t\tit->util = d;\n> +\t\t}\n> +\t\td->index_status = p->status;\n> +\t\tswitch (p->status) {\n> +\t\tcase DIFF_STATUS_COPIED:\n> +\t\tcase DIFF_STATUS_RENAMED:\n> +\t\t\td->head_path = xstrdup(p->one->path);\n> +\t\t\td->index_score = p->score;\n> +\t\t\tbreak;\n> +\t\t}\n>  \t}\n> -\tfor (i = 0; i < q->nr; i++)\n> -\t\twt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);\n> -\tif (q->nr)\n> -\t\twt_status_print_trailer(s);\n>  }\n>  \n> -static void wt_status_print_updated(struct wt_status *s)\n> +static void wt_status_collect_changes_worktree(struct wt_status *s)\n> +{\n> +\tstruct rev_info rev;\n> +\n> +\tinit_revisions(&rev, NULL);\n> +\tsetup_revisions(0, NULL, &rev, NULL);\n> +\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n> +\trev.diffopt.format_callback = wt_status_collect_changed_cb;\n> +\trev.diffopt.format_callback_data = s;\n> +\trun_diff_files(&rev, 0);\n> +}\n> +\n> +static void wt_status_collect_changes_index(struct wt_status *s)\n>  {\n>  \tstruct rev_info rev;\n> +\n>  \tinit_revisions(&rev, NULL);\n>  \tsetup_revisions(0, NULL, &rev,\n>  \t\ts->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);\n>  \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n> -\trev.diffopt.format_callback = wt_status_print_updated_cb;\n> +\trev.diffopt.format_callback = wt_status_collect_updated_cb;\n>  \trev.diffopt.format_callback_data = s;\n>  \trev.diffopt.detect_rename = 1;\n>  \trev.diffopt.rename_limit = 200;\n> @@ -200,15 +230,107 @@ static void wt_status_print_updated(struct wt_status *s)\n>  \trun_diff_index(&rev, 1);\n>  }\n>  \n> +static void wt_status_collect_changes_initial(struct wt_status *s)\n> +{\n> +\tint i;\n> +\n> +\tfor (i = 0; i < active_nr; i++) {\n> +\t\tstruct string_list_item *it;\n> +\t\tstruct wt_status_change_data *d;\n> +\n> +\t\tit = string_list_insert(active_cache[i]->name, &s->change);\n> +\t\td = it->util;\n> +\t\tif (!d) {\n> +\t\t\td = xcalloc(1, sizeof(*d));\n> +\t\t\tit->util = d;\n> +\t\t}\n> +\t\td->index_status = DIFF_STATUS_ADDED;\n> +\t}\n> +}\n> +\n> +void wt_status_collect_changes(struct wt_status *s)\n> +{\n> +\twt_status_collect_changes_worktree(s);\n> +\n> +\tif (s->is_initial)\n> +\t\twt_status_collect_changes_initial(s);\n> +\telse\n> +\t\twt_status_collect_changes_index(s);\n> +}\n> +\n> +static void wt_status_print_updated(struct wt_status *s)\n> +{\n> +\tint shown_header = 0;\n> +\tint i;\n> +\n> +\tfor (i = 0; i < s->change.nr; i++) {\n> +\t\tstruct wt_status_change_data *d;\n> +\t\tstruct string_list_item *it;\n> +\t\tit = &(s->change.items[i]);\n> +\t\td = it->util;\n> +\t\tif (!d->index_status)\n> +\t\t\tcontinue;\n> +\t\tif (!shown_header) {\n> +\t\t\twt_status_print_cached_header(s);\n> +\t\t\ts->commitable = 1;\n> +\t\t\tshown_header = 1;\n> +\t\t}\n> +\t\twt_status_print_change_data(s, WT_STATUS_UPDATED,\n> +\t\t\t\t\t    d->index_status,\n> +\t\t\t\t\t    d->head_path ? d->head_path : it->string,\n> +\t\t\t\t\t    it->string,\n> +\t\t\t\t\t    d->index_score);\n> +\t}\n> +\tif (shown_header)\n> +\t\twt_status_print_trailer(s);\n> +}\n> +\n> +/*\n> + * -1 : has delete\n> + *  0 : no change\n> + *  1 : some change but no delete\n> + */\n> +static int wt_status_check_worktree_changes(struct wt_status *s)\n> +{\n> +\tint i;\n> +\tint changes = 0;\n> +\n> +\tfor (i = 0; i < s->change.nr; i++) {\n> +\t\tstruct wt_status_change_data *d;\n> +\t\td = s->change.items[i].util;\n> +\t\tif (!d->worktree_status)\n> +\t\t\tcontinue;\n> +\t\tchanges = 1;\n> +\t\tif (d->worktree_status == DIFF_STATUS_DELETED)\n> +\t\t\treturn -1;\n> +\t}\n> +\treturn changes;\n> +}\n> +\n>  static void wt_status_print_changed(struct wt_status *s)\n>  {\n> -\tstruct rev_info rev;\n> -\tinit_revisions(&rev, \"\");\n> -\tsetup_revisions(0, NULL, &rev, NULL);\n> -\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n> -\trev.diffopt.format_callback = wt_status_print_changed_cb;\n> -\trev.diffopt.format_callback_data = s;\n> -\trun_diff_files(&rev, 0);\n> +\tint i;\n> +\tint worktree_changes = wt_status_check_worktree_changes(s);\n> +\n> +\tif (!worktree_changes)\n> +\t\treturn;\n> +\n> +\twt_status_print_dirty_header(s, worktree_changes < 0);\n> +\n> +\tfor (i = 0; i < s->change.nr; i++) {\n> +\t\tstruct wt_status_change_data *d;\n> +\t\tstruct string_list_item *it;\n> +\t\tit = &(s->change.items[i]);\n> +\t\td = it->util;\n> +\t\tif (!d->worktree_status)\n> +\t\t\tcontinue;\n> +\t\twt_status_print_change_data(s, WT_STATUS_CHANGED,\n> +\t\t\t\t\t    d->worktree_status,\n> +\t\t\t\t\t    it->string,\n> +\t\t\t\t\t    it->string,\n> +\t\t\t\t\t    0);\n> +\t}\n> +\twt_status_print_trailer(s);\n>  }\n>  \n>  static void wt_status_print_submodule_summary(struct wt_status *s)\n> @@ -337,6 +459,8 @@ void wt_status_print(struct wt_status *s)\n>  \t\t\twt_status_print_tracking(s);\n>  \t}\n>  \n> +\twt_status_collect_changes(s);\n> +\n>  \tif (s->is_initial) {\n>  \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n>  \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"# Initial commit\");\n> diff --git a/wt-status.h b/wt-status.h\n> index 78add09..00508c3 100644\n> --- a/wt-status.h\n> +++ b/wt-status.h\n> @@ -18,6 +18,13 @@ enum untracked_status_type {\n>  };\n>  extern enum untracked_status_type show_untracked_files;\n>  \n> +struct wt_status_change_data {\n> +\tint worktree_status;\n> +\tint index_status;\n> +\tint index_score;\n> +\tchar *head_path;\n> +};\n> +\n>  struct wt_status {\n>  \tint is_initial;\n>  \tchar *branch;\n> @@ -33,6 +40,7 @@ struct wt_status {\n>  \tconst char *index_file;\n>  \tFILE *fp;\n>  \tconst char *prefix;\n> +\tstruct string_list change;\n>  };\n>  \n>  int git_status_config(const char *var, const char *value, void *cb);\n> @@ -40,5 +48,6 @@ extern int wt_status_use_color;\n>  extern int wt_status_relative_paths;\n>  void wt_status_prepare(struct wt_status *s);\n>  void wt_status_print(struct wt_status *s);\n> +void wt_status_collect_changes(struct wt_status *s);\n>  \n>  #endif /* STATUS_H */\n\n-- \n\t\tDavid\n"},{"id":"115150","messageId":"alpine.LSU.2.00.0905311718480.8963@hermes-2.csi.cam.ac.uk","threadId":"19465","inReplyTo":"20090530060233.GA10033@gmail.com","subject":"Re: git-ls-files --added?","fromName":"Tony Finch","fromEmail":"dot@dotat.at","sentAt":"2009-05-31T16:19:16Z","receivedAt":"2009-05-31T16:19:16Z","isPatch":false,"sender":{"key":"dot@dotat.at","avatar":"https://avatars.githubusercontent.com/u/68429?v=4"},"body":"On Fri, 29 May 2009, David Aguilar wrote:\n>\n> There's good stuff to build upon here so I'll take a deeper look\n> into it.  Getting this as plumbing will help a lot of future git\n> scripters.\n\nI would certainly find this useful.\n\nTony.\n-- \nf.anthony.n.finch  <dot@dotat.at>  http://dotat.at/\nGERMAN BIGHT HUMBER: SOUTHWEST 5 TO 7. MODERATE OR ROUGH. SQUALLY SHOWERS.\nMODERATE OR GOOD.\n"}]}