The index is based on blah, however, the HEAD points at different commit.

5 messages, 1 author, 2016-06-15 · open the first message on its own page

The index is based on blah, however, the HEAD points at different commit.

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:03

Junio C Hamano [off-list ref] writes:
* jc/checkout (Thu Mar 29 01:23:12 2007 -0700) 4 commits
 + Use BASE index extension in git-commit and git-merge.
 + update-index --{set,get}-base
 + Add BASE index extension.
 + checkout: allow detaching to HEAD even when switching to the tip
   of a branch

I've rewritten the bottom commit not to require an explicit -d
option when detaching.  You can say "git checkout master^0"
instead to get a detached head that is at the tip of master.  I
may make that one commit graduate to 'master' earlier than
others.

This series is primarily to make it safer when somebody else
updates the tip of the branch you have currently checked out.
As I said in previous messages, I think the series covers basic
operations fine but there probably are gaps in the coverage.
Motivated volunteers are needed to fill them.
Regarding this series, if you find a command sequence that does
this:

 (1) A command that is BASE aware (e.g. "git commit") is used to
     point HEAD at a commit and records it in the index; and then,

 (2) A command that is not yet BASE aware moves the HEAD
     (perhaps creating a commit) but does not cause the
     previously recorded BASE in the index to be updated to
     point at the new HEAD (e.g. "git am");

your next invocation of a command that is BASE aware would barf,
saying something like:

  * The index is based on 'c053f05... My earlier commit made in (1).', however, the HEAD
    points at different commit '4fc2da4... The last of commits made with (2).'

When this happens, please first run "git-runstatus" [*1*] and
"git-diff HEAD" to see if this is a false positive.  If the
output shows the differences from the HEAD you expect to see and
you are sure your index is derived from the current HEAD, and
not the error message indicates (in the above example, c053f05
is such a wrong commit), that means you ran some command that
needs to be taught about the BASE.

A work-around until that command is fixed is to run this:

	$ git update-index --set-base `git-rev-parse HEAD`

This corrects the base commit recorded in the index to match
your current HEAD commit to allows you to keep going.

Motivated volunteers can help us further by doing two more
things.  One is obviously to report such a case and identify
such a BASE unaware command, and even better, make it BASE
aware and send in patches.

Another thing is to make a habit of running 'git update-index
--get-base' after doing any git operation to see if the index
correctly records the base commit.  

Currently, when git-read-tree is used to update the index, the
base information is discarded, and 'git update-index --get-base'
will return empty.  Commands that are already BASE aware will
not trigger when the index does not record any base.  This is to
prevent too many false positives while this safety feature is
still in development, but that means more false negatives.  We
should minimize this base clobbering so that we can use multiple
work trees tied to the same repository more safely.

I'll follow-up this message with four patch series to make "git am"
and "git reset" BASE aware.


[Footnote]

*1* We need to fix "git status" to be usable for this as well,
but currently it shares much of its code with "git commit" and
triggers the same false positive)

[PATCH 1/4] Move check_base() shell function to git-sh-setup

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:03

The scripts that attempt to make a commit on top of the current
HEAD need to use the same logic in check_base() to make sure the
current index is based on the HEAD commit we are going to build
on top of.  Move this function from git-commit to git-sh-setup,
so that it is available to everybody else.

Signed-off-by: Junio C Hamano <redacted>
---
 git-commit.sh   |   16 ----------------
 git-sh-setup.sh |   16 ++++++++++++++++
 2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/git-commit.sh b/git-commit.sh
index 42f1c93..6b4c784 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -25,22 +25,6 @@ refuse_partial () {
 	exit 1
 }
 
-check_base () {
-	quiet="$1"
-	if HEAD=`git rev-parse --verify HEAD 2>/dev/null` &&
-	   BASE=`git update-index --get-base` &&
-	   test -n "$BASE" &&
-	   test "$BASE" != "$HEAD"
-	then
-		test -z "$quiet" || exit 1
-		ours=`git show -s --pretty=oneline --abbrev-commit $BASE`
-		theirs=`git show -s --pretty=oneline --abbrev-commit $HEAD`
-		echo >&2 "* The index is based on '$ours', however, the HEAD"
-		echo >&2 "  points at different commit '$theirs'"
-		exit 1
-	fi
-}
-
 THIS_INDEX="$GIT_DIR/index"
 NEXT_INDEX="$GIT_DIR/next-index$$"
 rm -f "$NEXT_INDEX"
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index f24c7f2..0797acd 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -28,6 +28,22 @@ set_reflog_action() {
 	fi
 }
 
+check_base () {
+	quiet="$1"
+	if HEAD=`git rev-parse --verify HEAD 2>/dev/null` &&
+	   BASE=`git update-index --get-base` &&
+	   test -n "$BASE" &&
+	   test "$BASE" != "$HEAD"
+	then
+		test -z "$quiet" || exit 1
+		ours=`git show -s --pretty=oneline --abbrev-commit $BASE`
+		theirs=`git show -s --pretty=oneline --abbrev-commit $HEAD`
+		echo >&2 "* The index is based on '$ours', however, the HEAD"
+		echo >&2 "  points at different commit '$theirs'"
+		exit 1
+	fi
+}
+
 is_bare_repository () {
 	git-config --bool --get core.bare ||
 	case "$GIT_DIR" in
-- 
1.5.1.730.g0d43be

[PATCH 3/4] git-read-tree --set-base=<commit>

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:03

This allows the caller of read-tree to record the base commit
object in the index, so that later operations that build a new
commit based on the contents of the index can verify that the
HEAD is still at the expected place, and notice cases where
somebody else updated the tip of the current branch while we are
looking the other way.

Signed-off-by: Junio C Hamano <redacted>
---
 Documentation/git-read-tree.txt |    6 +++++-
 builtin-read-tree.c             |   19 +++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletions(-)
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 0ff2890..ef731e2 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index
 
 SYNOPSIS
 --------
-'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
+'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--set-base=<commit>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
 
 
 DESCRIPTION
@@ -86,6 +86,10 @@ OPTIONS
 	file (usually '.gitignore') and allows such an untracked
 	but explicitly ignored file to be overwritten.
 
+--set-base=<commit>::
+	This option records the commit object name in the index,
+	later to be retrieved with the `git-update-index --get-base`.
+
 <tree-ish#>::
 	The id of the tree object(s) to be read/merged.
 
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 06c2912..d1c4489 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -93,6 +93,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 {
 	int i, newfd, stage = 0;
 	unsigned char sha1[20];
+	unsigned char newbase[20];
+	int newbase_set = 0;
 	struct unpack_trees_options opts;
 
 	memset(&opts, 0, sizeof(opts));
@@ -158,6 +160,15 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 			continue;
 		}
 
+		if (!prefixcmp(arg, "--set-base=")) {
+			if (get_sha1(arg+11, newbase) ||
+			    sha1_object_info(newbase, NULL) != OBJ_COMMIT)
+				die("Specified base is not a valid commit object name '%s'",
+				    arg);
+			newbase_set = 1;
+			continue;
+		}
+
 		if (!strcmp(arg, "--trivial")) {
 			opts.trivial_merges_only = 1;
 			continue;
@@ -261,12 +272,20 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 	 * "-m ent" or "--reset ent" form), we can obtain a fully
 	 * valid cache-tree because the index must match exactly
 	 * what came from the tree.
+	 *
+	 * Also when we read from a single commit with --reset, the
+	 * index will be used to build a commit on top of it.
 	 */
 	if (trees && trees->item && !opts.prefix && (!opts.merge || (stage == 2))) {
 		cache_tree_free(&active_cache_tree);
 		prime_cache_tree();
 	}
 
+	if (newbase_set) {
+		active_cache_base_valid = 1;
+		hashcpy(active_cache_base, newbase);
+	}
+
 	if (write_cache(newfd, active_cache, active_nr) ||
 	    close(newfd) || commit_lock_file(&lock_file))
 		die("unable to write new index file");
-- 
1.5.1.730.g0d43be

[PATCH 2/4] Use BASE index extension in git-am.

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:03

This makes git-am to record the expected HEAD location after
finishing its operation in the index, so that subsequent BASE
check would notice when somebody else updated your branch head
while you are looking the other way.

Signed-off-by: Junio C Hamano <redacted>
---
 git-am.sh |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/git-am.sh b/git-am.sh
index e69ecbf..27912ce 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -13,6 +13,7 @@ git var GIT_COMMITTER_IDENT >/dev/null || exit
 
 stop_here () {
     echo "$1" >"$dotest/next"
+    git update-index --set-base $(git rev-parse --verify HEAD)
     exit 1
 }
 
@@ -157,6 +158,8 @@ do
 	esac
 done
 
+check_base || exit
+
 # If the dotest directory exists, but we have finished applying all the
 # patches in them, clear it out.
 if test -d "$dotest" &&
@@ -468,5 +471,6 @@ do
 
 	go_next
 done
+git update-index --set-base $(git rev-parse --verify HEAD)
 
 rm -fr "$dotest"
-- 
1.5.1.730.g0d43be

[PATCH 4/4] Teach git-reset to use index BASE extension.

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:03

After resetting the HEAD to point at a different commit, the
user obviously intends to make the next commit a child of the
updated HEAD commit.  Record it in the index so that we can
detect the case where somebody else updates the tip of the
current branch while we are looking the other way.

Signed-off-by: Junio C Hamano <redacted>
---
 git-reset.sh |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/git-reset.sh b/git-reset.sh
index fee6d98..982c726 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -71,7 +71,7 @@ then
 		die "Cannot do a soft reset in the middle of a merge."
 	fi
 else
-	git-read-tree --reset $update "$rev" || exit
+	git-read-tree --reset $update --set-base="$rev" "$rev" || exit
 fi
 
 # Any resets update HEAD to the head being switched to.
@@ -93,10 +93,11 @@ case "$reset_type" in
 	}
 	;;
 --soft )
-	;; # Nothing else to do
+	git-update-index --set-base "$rev"
+	;;
 --mixed )
 	# Report what has not been updated.
-	git-update-index --refresh
+	git-update-index --set-base "$rev" --refresh
 	;;
 esac
 
-- 
1.5.1.730.g0d43be
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help