[PATCH] git-explain

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Junio C Hamano <junkio@xxxxxxx> writes:

> Linus Torvalds <torvalds@xxxxxxxx> writes:
>
>> So "git reset" is generally your friend whenever something goes wrong. If 
>> you also want to reset your checked-out files (which you did NOT want to 
>> do in this case, of course), you would have added the "--hard" flag to git 
>> reset.
>>
>> And that (finally) concludes this particularly boring "git usage 101" 
>> session.
>
> One observation about git, made in a relatively distant past,
> was "git is not a usable system yet; there is no 'git undo'".  I
> think it was on the kernel list (I think it was from Alan who
> seems to have lost his last name from his From: line lately, but
> I may be mistaken).
>
> It left a deep psychological trauma in me, not because it was
> stated in a brutal way (it wasn't) but because I fully agreed
> with that statement from the end user point of view, but I did
> not see a good solution to the problem (and I from the beginning
> kept saying "I do not do Porcelains" and kept calling what is
> shipped with core "Porcelain-ish").
> ...
> I think one cause of the "problem" (if not having a general
> "undo" is a problem, and I think it is to some extent) is that
> git Porcelain-ish commands try to stay stateless to allow mixing
> and matching of different commands to leave the door open to the
> end user to be flexible, but they go too far.

They go too far by doing too little.

And here is throwing an idea to remedy it; it is far from
complete but sending it out early before spending too much time
on pursuit of a wild goose.

-- >8 --
[PATCH] git-explain

This patch adds "git-explain" script that notices various clues
other commands can leave the working tree and repository in and
intended to guide the end user out of the confused mess.

This is only a demonstration-of-concept, as many commands do not
leave enough information for us to truly figure out what state
we are in nor how we got into the mess.  As a demonstration, it
makes "git merge" to leave a new "$GIT_DIR/FAILED_MERGE" file
when it gives up before touching the working tree.

Signed-off-by: Junio C Hamano <junkio@xxxxxxx>
---
 git-explain.sh |  172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 git-merge.sh   |    3 +-
 git-reset.sh   |    3 +-
 3 files changed, 176 insertions(+), 2 deletions(-)

diff --git a/git-explain.sh b/git-explain.sh
new file mode 100755
index 0000000..07115ae
--- /dev/null
+++ b/git-explain.sh
@@ -0,0 +1,172 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Junio C Hamano
+#
+
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+
+TOP=`git-rev-parse --show-cdup`
+test -z "$TOP" && TOP=./
+
+say_with_indent() {
+	echo "$@" | sed -e 's/^/	/'
+}
+
+explain_merge_conflict () {
+	test -f $GIT_DIR/HEAD &&
+	test -f "$GIT_DIR/MERGE_HEAD" &&
+	test -f "$GIT_DIR/MERGE_MSG" &&
+	test "z`git ls-files -u`" != z || return 1
+
+	title=$(sed -e q "$GIT_DIR/MERGE_MSG")
+
+	conflicts=$(git ls-files -u |
+		sed -e 's/^[0-7]* [0-9a-f]* [0-3]	//' |
+		uniq)
+
+	git diff-index -r --name-only HEAD >"$tmp-1"
+	git diff-tree -r --name-only HEAD MERGE_HEAD >"$tmp-2"
+	locals=`comm -23 "$tmp-1" "$tmp-2"`
+
+	cat <<EOF
+You tried a merge whose title will be
+
+	$title
+
+This may have successfully merged some paths and they are already
+staged for the next commit, but the following paths could not be
+automatically merged:
+
+EOF
+
+	say_with_indent "$conflicts"
+
+	if test "z$locals" != z
+	then
+		cat <<\EOF
+
+Also you seem to have local modifications unrelated to this
+merge in the following paths:
+
+EOF
+
+		say_with_indent "$locals"
+	fi
+
+	cat <<\EOF
+
+There are two ways to proceed from here:
+
+(1) You can decide to abort this for now and get back to the
+    state before you started the merge.
+
+	$ git reset --hard
+
+    will revert your working tree files to the latest commit
+    before this merge.  Note that you would lose the local
+    modifications with this action, so you might want to
+    preserve them with this command before doing so:
+
+	$ git diff HEAD -- <locally changed files> >preserved-local-changes
+
+    Then you can re-apply the changes after running "git reset
+    --hard".
+
+(2) To resolve the conflicts and record this merge, you first
+    need to examine the conflicted paths listed above, and edit
+    them in your working tree.  After you are done, stage the
+    final version of these paths and make a commit, like this:
+
+	$ git add <locally changed files>
+	$ git commit
+
+    Do not use "git commit -a" unless you want the local
+    modifications that are not related to this merge committed
+    along with the changes this merge brings in.
+EOF
+}
+
+explain_merge_stop () {
+	test -f $GIT_DIR/HEAD &&
+	test -f $GIT_DIR/FAILED_MERGE &&
+	test "z`git rev-parse HEAD`" = "z`git rev-parse ORIG_HEAD`" &&
+	test "z`git ls-files -u`" = z || return 1
+
+	git diff-index -r --name-only HEAD >"$tmp-1"
+	git diff-tree -r --name-only HEAD FAILED_MERGE >"$tmp-2"
+	conflicts=`comm -12 "$tmp-1" "$tmp-2"`
+	locals=`comm -23 "$tmp-1" "$tmp-2"`
+
+	cat <<\EOF
+You tried a merge but it stopped without touching your working tree,
+because you had local changes in the following paths that may also
+be involved in the merge:
+
+EOF
+	say_with_indent "$conflicts"
+
+	if test "z$locals" != z
+	then
+		cat <<\EOF
+
+Also you seem to have local modifications unrelated to this
+merge in the following paths:
+
+EOF
+
+		say_with_indent "$locals"
+
+	fi
+
+	cat <<\EOF
+
+There are two ways to proceed from here:
+
+(1) You can decide to abort this merge for now.  You do not have
+    to do anything in this case because the merge hasn't touched
+    your working tree files yet.
+
+(2) You can first make the merge and re-apply your local changes
+    on top of the merge result.  To do this, first stash away
+    your local changes in a temporary commit, like this:
+
+	$ git commit -a -m 'WIP'
+	$ git tag WIP
+	$ git reset --hard HEAD^
+
+    and run the same "git merge" (or "git pull") again.  After
+    you finished the merge, you can review the local change with:
+
+	$ git show WIP
+
+    and re-apply them to your working tree as you see fit.
+EOF
+}
+
+explain_am () {
+	test -d $TOP/.dotest || return 1
+
+	cat <<EOF
+You tried to apply a series of `cat .dotest/last` patch(es) and
+are currently handling patch #`cat .dotest/next`.
+
+EOF
+
+}
+
+explain_base () {
+	# This comes at the end.
+	cat <<EOF
+Don't worry, you are not in the middle of anything complicated.
+EOF
+
+}
+
+tmp="$GIT_DIR/tmp"
+trap 'rm -f $tmp-*' 0
+
+explain_merge_conflict ||
+explain_merge_stop ||
+explain_am ||
+explain_base
\ No newline at end of file
diff --git a/git-merge.sh b/git-merge.sh
index 272f004..674abad 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -20,7 +20,7 @@ index_merge=t
 
 dropsave() {
 	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
-		 "$GIT_DIR/MERGE_SAVE" || exit 1
+		 "$GIT_DIR/MERGE_SAVE" "$GIT_DIR/FAILED_MERGE" || exit 1
 }
 
 savestate() {
@@ -400,6 +400,7 @@ case "$best_strategy" in
 '')
 	restorestate
 	echo >&2 "No merge strategy handled the merge."
+	echo "$@" >"$GIT_DIR/FAILED_MERGE"
 	exit 2
 	;;
 "$wt_strategy")
diff --git a/git-reset.sh b/git-reset.sh
index 3133b5b..045ee79 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -63,6 +63,7 @@ case "$reset_type" in
 	;;
 esac
 
-rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" "$GIT_DIR/SQUASH_MSG"
+rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" \
+	"$GIT_DIR/SQUASH_MSG" "$GIT_DIR/FAILED_MERGE"
 
 exit $update_ref_status
-- 
1.4.4.1.g15e3


-
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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]