{"thread":{"id":"8143","subject":"committing selected 'changed' or 'added' files works, but not 'removed'","startedAt":"2007-05-14T06:16:39Z","lastAt":"2007-05-14T12:48:53Z","messageCount":3,"participants":["Jim Meyering","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"42096","messageId":"87y7jsgcag.fsf@rho.meyering.net","threadId":"8143","inReplyTo":null,"subject":"committing selected 'changed' or 'added' files works, but not 'removed'","fromName":"Jim Meyering","fromEmail":"jim@meyering.net","sentAt":"2007-05-14T06:16:39Z","receivedAt":"2007-05-14T06:16:39Z","isPatch":false,"sender":{"key":"jim@meyering.net","avatar":"https://avatars.githubusercontent.com/u/710630?v=4"},"body":"Hello,\n\nIf I've just run \"git-rm -f c\" in a directory with a few modified\nor git-added files, is there some way to commit (non-interactively)\nonly the removal of that selected file?  I.e., not any other changes\nin the working directory?  git-commit -m. -- c fails with this:\n\n  error: pathspec 'c' did not match any file(s) known to git\n\nIf I use \"cg-commit\" instead of \"git-commit\", it works fine.\n\nWhen I asked on IRC, \"cehteh\" suggested to create a temporary branch,\ndo the removal there, and then to rebase that change back onto the\noriginal branch -- and to remove the disposable branch.  Yes, that works,\nbut I want do the job with a single commit command, the same way I can\nfor \"added\" and \"modified\" files.  And I've been trying (until now,\nsuccessfully) to wean myself away from cogito.\n\nWhy should \"removed\" files be handled so differently?  If I cannot commit\na selected \"file removal\" (regardless of the state of the index), then\nisn't that an opportunity to add a feature?\n\nIn case you're wondering, I want this functionality in order to make\na version control agnostic commit/diff/ChangeLog tool work the same way\nwith raw git as it did using cogito.\n\n-------------------------------------------\nIn case an actual scenario helps, I'd like to be able to commit the\nremoval of \"c\", below without also committing the change to \"b\":\n\nmkdir .j && cd .j && git-init > /dev/null && touch b c && git-add b c \\\n  && git-commit -q -m. && echo > b && git-rm --quiet -f c \\\n  && git-commit -m. -- c\n\nThe final commit above fails like this:\n\n  error: pathspec 'c' did not match any file(s) known to git.\n  Did you forget to 'git add'?\n"},{"id":"42101","messageId":"7viravonmj.fsf@assigned-by-dhcp.cox.net","threadId":"8143","inReplyTo":"87y7jsgcag.fsf@rho.meyering.net","subject":"Re: committing selected 'changed' or 'added' files works, but not 'removed'","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-14T07:44:36Z","receivedAt":"2007-05-14T07:44:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jim Meyering <jim@meyering.net> writes:\n\n> Why should \"removed\" files be handled so differently?  If I cannot commit\n> a selected \"file removal\" (regardless of the state of the index), then\n> isn't that an opportunity to add a feature?\n\nThe answer is because it is a bit cumbersome to arrange, and\npeople who felt the need were too lazy to add that.  And\neverybody knows that I am not from the \"partial commit\" camp.\n\nYou could do something like this...\n\nNOTE NOTE NOTE.\n\nI am not quite happy with this one, as it exposes one of my\nfavorite pet peeves -- wildcard pathspecs behave differently\nbetween diff-tree family and ls-files family.  After modifying a\nrandom C source file, you can say:\n\n\tgit commit -m 'C files changed' -- '*.c'\n\nbut you cannot say:\n\n\tgit commit -m 'C files modified and/or removed' -- '*.c'\n\nafter removing a C source file, because diff-tree's pathspec\nonly works as top-down, subdirectory limiter.\n\n-- >8 --\ngit-commit: Allow removal to be partially committed as well\n\nWe allow partial commit of modified and added files but never\nhandled removed files.  This hacks it around.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-commit.sh     |   36 ++++++++++++++++++++++++++++++-\n t/t7400-commit.sh |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 95 insertions(+), 1 deletions(-)\n\ndiff --git a/git-commit.sh b/git-commit.sh\nindex f28fc24..f4ba0ef 100755\n--- a/git-commit.sh\n+++ b/git-commit.sh\n@@ -59,6 +59,40 @@ run_status () {\n \t\t${untracked_files:+--untracked}\n }\n \n+compute_commit_only () {\n+\n+\t# The first one cannot commit removal\n+\tif test -n \"$initial_commit\"\n+\tthen\n+\t\texec git-ls-files --error-unmatch -- \"$@\"\n+\tfi\n+\n+\t# Usual case -- no unmatch\n+\tif files=$(git-ls-files --error-unmatch -- \"$@\" 2>/dev/null)\n+\tthen\n+\t\techo \"$files\"\n+\t\texit 0\n+\tfi\n+\n+\thas_unmatch_errs=\n+\t# Otherwise we need to do it the hard way\n+\tfor p in \"$@\"\n+\tdo\n+\t\tremoved=$(git-diff-index --cached --name-only \\\n+\t\t\t--diff-filter=D HEAD -- \"$p\")\n+\t\tif test -n \"$removed\"\n+\t\tthen\n+\t\t\techo \"$removed\"\n+\t\telif git-ls-files --error-unmatch -- \"$p\"\n+\t\tthen\n+\t\t\t: ok so far\n+\t\telse\n+\t\t\thas_unmatch_errs=t\n+\t\tfi\n+\tdone\n+\ttest -z \"$has_unmatch_errs\"\n+}\n+\n trap '\n \ttest -z \"$TMP_INDEX\" || {\n \t\ttest -f \"$TMP_INDEX\" && rm -f \"$TMP_INDEX\"\n@@ -364,7 +398,7 @@ t,)\n \t\t\trefuse_partial \"Cannot do a partial commit during a merge.\"\n \t\tfi\n \t\tTMP_INDEX=\"$GIT_DIR/tmp-index$$\"\n-\t\tcommit_only=`git-ls-files --error-unmatch -- \"$@\"` || exit\n+\t\tcommit_only=$( (compute_commit_only \"$@\") ) || exit\n \n \t\t# Build a temporary index and update the real index\n \t\t# the same way.\ndiff --git a/t/t7400-commit.sh b/t/t7400-commit.sh\nnew file mode 100755\nindex 0000000..81196b0\n--- /dev/null\n+++ b/t/t7400-commit.sh\n@@ -0,0 +1,60 @@\n+#!/bin/sh\n+\n+test_description='git commit porcelain-ish'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'the basics' '\n+\n+\techo doing partial >\"commit is\" &&\n+\tmkdir not &&\n+\techo very much encouraged but we should >not/forbid &&\n+\tgit add \"commit is\" not &&\n+\techo update added \"commit is\" file >\"commit is\" &&\n+\techo also update another >not/forbid &&\n+\ttest_tick &&\n+\tgit commit -a -m \"initial with -a\" &&\n+\n+\tgit cat-file blob HEAD:\"commit is\" >current.1 &&\n+\tgit cat-file blob HEAD:not/forbid >current.2 &&\n+\n+\tcmp current.1 \"commit is\" &&\n+\tcmp current.2 not/forbid\n+\n+'\n+\n+test_expect_success 'partial' '\n+\n+\techo another >\"commit is\" &&\n+\techo another >not/forbid &&\n+\ttest_tick &&\n+\tgit commit -m \"partial commit to handle a file\" \"commit is\" &&\n+\n+\tchanged=$(git diff-tree --name-only HEAD^ HEAD) &&\n+\ttest \"$changed\" = \"commit is\"\n+\n+'\n+\n+test_expect_success 'partial modification into subdirecotry' '\n+\n+\ttest_tick &&\n+\tgit commit -m \"partial commit to subdirectory\" not &&\n+\n+\tchanged=$(git diff-tree -r --name-only HEAD^ HEAD) &&\n+\ttest \"$changed\" = \"not/forbid\"\n+\n+'\n+\n+test_expect_success 'partial removal' '\n+\n+\tgit rm not/forbid &&\n+\tgit commit -m \"partial commit to remove not/forbid\" not &&\n+\n+\tchanged=$(git diff-tree -r --name-only HEAD^ HEAD) &&\n+\ttest \"$changed\" = \"not/forbid\" &&\n+\tremain=$(git ls-tree -r --name-only HEAD) &&\n+\ttest \"$remain\" = \"commit is\"\n+\n+'\n+\n+test_done\n"},{"id":"42110","messageId":"87646vh8p6.fsf@rho.meyering.net","threadId":"8143","inReplyTo":"7viravonmj.fsf@assigned-by-dhcp.cox.net","subject":"Re: committing selected 'changed' or 'added' files works, but not 'removed'","fromName":"Jim Meyering","fromEmail":"jim@meyering.net","sentAt":"2007-05-14T12:48:53Z","receivedAt":"2007-05-14T12:48:53Z","isPatch":false,"sender":{"key":"jim@meyering.net","avatar":"https://avatars.githubusercontent.com/u/710630?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> You could do something like this...\n...\n> -- >8 --\n> git-commit: Allow removal to be partially committed as well\n>\n> We allow partial commit of modified and added files but never\n> handled removed files.  This hacks it around.\n\nNice!  Thanks for the quick patch.\nI liked the test cases :-)\n"}]}