Git development
 help / color / mirror / Atom feed
From: Junio C Hamano <junkio@cox.net>
To: Jim Meyering <jim@meyering.net>
Cc: git@vger.kernel.org
Subject: Re: committing selected 'changed' or 'added' files works, but not 'removed'
Date: Mon, 14 May 2007 00:44:36 -0700	[thread overview]
Message-ID: <7viravonmj.fsf@assigned-by-dhcp.cox.net> (raw)
In-Reply-To: <87y7jsgcag.fsf@rho.meyering.net> (Jim Meyering's message of "Mon, 14 May 2007 08:16:39 +0200")

Jim Meyering <jim@meyering.net> writes:

> Why should "removed" files be handled so differently?  If I cannot commit
> a selected "file removal" (regardless of the state of the index), then
> isn't that an opportunity to add a feature?

The answer is because it is a bit cumbersome to arrange, and
people who felt the need were too lazy to add that.  And
everybody knows that I am not from the "partial commit" camp.

You could do something like this...

NOTE NOTE NOTE.

I am not quite happy with this one, as it exposes one of my
favorite pet peeves -- wildcard pathspecs behave differently
between diff-tree family and ls-files family.  After modifying a
random C source file, you can say:

	git commit -m 'C files changed' -- '*.c'

but you cannot say:

	git commit -m 'C files modified and/or removed' -- '*.c'

after removing a C source file, because diff-tree's pathspec
only works as top-down, subdirectory limiter.

-- >8 --
git-commit: Allow removal to be partially committed as well

We allow partial commit of modified and added files but never
handled removed files.  This hacks it around.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 git-commit.sh     |   36 ++++++++++++++++++++++++++++++-
 t/t7400-commit.sh |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 1 deletions(-)

diff --git a/git-commit.sh b/git-commit.sh
index f28fc24..f4ba0ef 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -59,6 +59,40 @@ run_status () {
 		${untracked_files:+--untracked}
 }
 
+compute_commit_only () {
+
+	# The first one cannot commit removal
+	if test -n "$initial_commit"
+	then
+		exec git-ls-files --error-unmatch -- "$@"
+	fi
+
+	# Usual case -- no unmatch
+	if files=$(git-ls-files --error-unmatch -- "$@" 2>/dev/null)
+	then
+		echo "$files"
+		exit 0
+	fi
+
+	has_unmatch_errs=
+	# Otherwise we need to do it the hard way
+	for p in "$@"
+	do
+		removed=$(git-diff-index --cached --name-only \
+			--diff-filter=D HEAD -- "$p")
+		if test -n "$removed"
+		then
+			echo "$removed"
+		elif git-ls-files --error-unmatch -- "$p"
+		then
+			: ok so far
+		else
+			has_unmatch_errs=t
+		fi
+	done
+	test -z "$has_unmatch_errs"
+}
+
 trap '
 	test -z "$TMP_INDEX" || {
 		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
@@ -364,7 +398,7 @@ t,)
 			refuse_partial "Cannot do a partial commit during a merge."
 		fi
 		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		commit_only=`git-ls-files --error-unmatch -- "$@"` || exit
+		commit_only=$( (compute_commit_only "$@") ) || exit
 
 		# Build a temporary index and update the real index
 		# the same way.
diff --git a/t/t7400-commit.sh b/t/t7400-commit.sh
new file mode 100755
index 0000000..81196b0
--- /dev/null
+++ b/t/t7400-commit.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='git commit porcelain-ish'
+
+. ./test-lib.sh
+
+test_expect_success 'the basics' '
+
+	echo doing partial >"commit is" &&
+	mkdir not &&
+	echo very much encouraged but we should >not/forbid &&
+	git add "commit is" not &&
+	echo update added "commit is" file >"commit is" &&
+	echo also update another >not/forbid &&
+	test_tick &&
+	git commit -a -m "initial with -a" &&
+
+	git cat-file blob HEAD:"commit is" >current.1 &&
+	git cat-file blob HEAD:not/forbid >current.2 &&
+
+	cmp current.1 "commit is" &&
+	cmp current.2 not/forbid
+
+'
+
+test_expect_success 'partial' '
+
+	echo another >"commit is" &&
+	echo another >not/forbid &&
+	test_tick &&
+	git commit -m "partial commit to handle a file" "commit is" &&
+
+	changed=$(git diff-tree --name-only HEAD^ HEAD) &&
+	test "$changed" = "commit is"
+
+'
+
+test_expect_success 'partial modification into subdirecotry' '
+
+	test_tick &&
+	git commit -m "partial commit to subdirectory" not &&
+
+	changed=$(git diff-tree -r --name-only HEAD^ HEAD) &&
+	test "$changed" = "not/forbid"
+
+'
+
+test_expect_success 'partial removal' '
+
+	git rm not/forbid &&
+	git commit -m "partial commit to remove not/forbid" not &&
+
+	changed=$(git diff-tree -r --name-only HEAD^ HEAD) &&
+	test "$changed" = "not/forbid" &&
+	remain=$(git ls-tree -r --name-only HEAD) &&
+	test "$remain" = "commit is"
+
+'
+
+test_done

  reply	other threads:[~2007-05-14  7:44 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-14  6:16 committing selected 'changed' or 'added' files works, but not 'removed' Jim Meyering
2007-05-14  7:44 ` Junio C Hamano [this message]
2007-05-14 12:48   ` Jim Meyering

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7viravonmj.fsf@assigned-by-dhcp.cox.net \
    --to=junkio@cox.net \
    --cc=git@vger.kernel.org \
    --cc=jim@meyering.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox