threads / patch / 1015

patch, 2 partsD/F conflicts fixes.

Subject: [PATCH 0/2] D/F conflicts fixes.

## tl;dr

19 messages between Jun 23, 2005 and Jun 26, 2005. Diffs are folded; open one to read it.

replies: 18people: 3as markdown or json

Junio C Hamano· Jun 23, 2005, 23:25 UTC · re: Junio C Hamano · lore

[PATCH 1/2] Add more tests for read-tree --emu23.

This adds more tests for --emu23. One is to show how it can carry forward more local changes than the straightforward two-way fast forward, and another is to show the recent overeager optimization of directory/file conflict check broke things, which will be fixed in the next commit.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 t/t1001-read-tree-m-2way.sh       |   70 +++++++++++++++++++++++++---
 t/t1005-read-tree-m-2way-emu23.sh |   94 ++++++++++++++++++++++++++++++++++---
 2 files changed, 150 insertions(+), 14 deletions(-)
Show changes to 2 files +150 −14

t/t1001-read-tree-m-2way.sh, t/t1005-read-tree-m-2way-emu23.sh

diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -29,7 +29,6 @@ read_tree_twoway () {
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 compare_change () {
-    	cat current
 	sed -n >current \
 	    -e '/^--- /d; /^+++ /d; /^@@ /d;' \
 	    -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \
@@ -51,11 +50,22 @@ check_cache_at () {
 	esac
 }
 
+cat >bozbar-old <<\EOF
+This is a sample file used in two-way fast forward merge
+tests.  Its second line ends with a magic word bozbar
+which will be modified by the merged head to gnusto.
+It has some extra lines so that external tools can
+successfully merge independent changes made to later
+lines (such as this one), avoiding line conflicts.
+EOF
+
+sed -e 's/bozbar/gnusto (earlier bozbar)/' bozbar-old >bozbar-new
+
 test_expect_success \
     setup \
     'echo frotz >frotz &&
      echo nitfol >nitfol &&
-     echo bozbar >bozbar &&
+     cat bozbar-old >bozbar &&
      echo rezrov >rezrov &&
      echo yomin >yomin &&
      git-update-cache --add nitfol bozbar rezrov &&
@@ -63,7 +73,7 @@ test_expect_success \
      echo treeH $treeH &&
      git-ls-tree $treeH &&
 
-     echo gnusto >bozbar &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add frotz bozbar --force-remove rezrov &&
      git-ls-files --stage >M.out &&
      treeM=`git-write-tree` &&
@@ -86,6 +96,8 @@ echo '+100644 X 0	yomin' >expected
 test_expect_success \
     '4 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add yomin &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >4.out || exit
@@ -96,6 +108,8 @@ test_expect_success \
 test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo yomin >yomin &&
      git-update-cache --add yomin &&
      echo yomin yomin >yomin &&
@@ -108,6 +122,8 @@ test_expect_success \
 test_expect_success \
     '6 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add frotz &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >6.out &&
@@ -117,6 +133,8 @@ test_expect_success \
 test_expect_success \
     '7 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz frotz >frotz &&
@@ -128,6 +146,8 @@ test_expect_success \
 test_expect_success \
     '8 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -135,6 +155,8 @@ test_expect_success \
 test_expect_success \
     '9 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz >frotz &&
@@ -143,6 +165,8 @@ test_expect_success \
 test_expect_success \
     '10 - path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      read_tree_twoway $treeH $treeM &&
@@ -152,6 +176,8 @@ test_expect_success \
 test_expect_success \
     '11 - dirty path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov rezrov >rezrov &&
@@ -160,6 +186,8 @@ test_expect_success \
 test_expect_success \
     '12 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -167,6 +195,8 @@ test_expect_success \
 test_expect_success \
     '13 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov >rezrov &&
@@ -180,6 +210,8 @@ EOF
 test_expect_success \
     '14 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      read_tree_twoway $treeH $treeM &&
@@ -191,6 +223,8 @@ test_expect_success \
 test_expect_success \
     '15 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      echo nitfol nitfol nitfol >nitfol &&
@@ -203,6 +237,8 @@ test_expect_success \
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -210,6 +246,8 @@ test_expect_success \
 test_expect_success \
     '17 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      echo bozbar bozbar bozbar >bozbar &&
@@ -218,7 +256,9 @@ test_expect_success \
 test_expect_success \
     '18 - local change already having a good result.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >18.out &&
@@ -228,7 +268,9 @@ test_expect_success \
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      read_tree_twoway $treeH $treeM &&
@@ -239,7 +281,9 @@ test_expect_success \
 test_expect_success \
     '20 - no local change, use new tree.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >20.out &&
@@ -249,11 +293,23 @@ test_expect_success \
 test_expect_success \
     '21 - no local change, dirty cache.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
+# This fails with straight two-way fast forward.
+test_expect_success \
+    '22 - local change cache updated.' \
+    'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
+     git-update-cache --add bozbar &&
+     if read_tree_twoway $treeH $treeM; then false; else :; fi'
+
 # Also make sure we did not break DF vs DF/DF case.
 test_expect_success \
     'DF vs DF/DF case setup.' \
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -32,7 +32,6 @@ read_tree_twoway () {
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 compare_change () {
-    	cat current
 	sed -n >current \
 	    -e '/^--- /d; /^+++ /d; /^@@ /d;' \
 	    -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \
@@ -60,11 +59,22 @@ check_stages () {
     diff -u expected_stages current_stages
 }
 
+cat >bozbar-old <<\EOF
+This is a sample file used in two-way fast forward merge
+tests.  Its second line ends with a magic word bozbar
+which will be modified by the merged head to gnusto.
+It has some extra lines so that external tools can
+successfully merge independent changes made to later
+lines (such as this one), avoiding line conflicts.
+EOF
+
+sed -e 's/bozbar/gnusto (earlier bozbar)/' bozbar-old >bozbar-new
+
 test_expect_success \
     setup \
     'echo frotz >frotz &&
      echo nitfol >nitfol &&
-     echo bozbar >bozbar &&
+     cat bozbar-old >bozbar &&
      echo rezrov >rezrov &&
      echo yomin >yomin &&
      git-update-cache --add nitfol bozbar rezrov &&
@@ -72,7 +82,7 @@ test_expect_success \
      echo treeH $treeH &&
      git-ls-tree $treeH &&
 
-     echo gnusto >bozbar &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add frotz bozbar --force-remove rezrov &&
      git-ls-files --stage >M.out &&
      treeM=`git-write-tree` &&
@@ -106,6 +116,8 @@ echo '+100644 X 0	yomin' >expected
 test_expect_success \
     '4 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add yomin &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >4.out || exit
@@ -118,6 +130,8 @@ test_expect_success \
 test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo yomin >yomin &&
      git-update-cache --add yomin &&
      echo yomin yomin >yomin &&
@@ -132,6 +146,8 @@ test_expect_success \
 test_expect_success \
     '6 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add frotz &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >6.out &&
@@ -143,6 +159,8 @@ test_expect_success \
 test_expect_success \
     '7 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz frotz >frotz &&
@@ -154,6 +172,8 @@ test_expect_success \
 test_expect_success \
     '8 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -161,6 +181,8 @@ test_expect_success \
 test_expect_success \
     '9 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz >frotz &&
@@ -169,6 +191,8 @@ test_expect_success \
 test_expect_success \
     '10 - path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      read_tree_twoway $treeH $treeM &&
@@ -178,6 +202,8 @@ test_expect_success \
 test_expect_success \
     '11 - dirty path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov rezrov >rezrov &&
@@ -186,6 +212,8 @@ test_expect_success \
 test_expect_success \
     '12 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -193,6 +221,8 @@ test_expect_success \
 test_expect_success \
     '13 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov >rezrov &&
@@ -206,6 +236,8 @@ EOF
 test_expect_success \
     '14 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      read_tree_twoway $treeH $treeM &&
@@ -217,6 +249,8 @@ test_expect_success \
 test_expect_success \
     '15 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      echo nitfol nitfol nitfol >nitfol &&
@@ -233,6 +267,8 @@ test_expect_success \
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      git-read-tree --emu23 $treeH $treeM &&
@@ -249,6 +285,8 @@ EOF
 test_expect_success \
     '17 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      echo bozbar bozbar bozbar >bozbar &&
@@ -257,7 +295,9 @@ test_expect_success \
 test_expect_success \
     '18 - local change already having a good result.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >18.out &&
@@ -267,7 +307,9 @@ test_expect_success \
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      read_tree_twoway $treeH $treeM &&
@@ -278,7 +320,9 @@ test_expect_success \
 test_expect_success \
     '20 - no local change, use new tree.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >20.out &&
@@ -288,11 +332,31 @@ test_expect_success \
 test_expect_success \
     '21 - no local change, dirty cache.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
+echo '-100644 X 0	bozbar
++100644 X 0	bozbar' >expected
+
+# This fails with straight two-way fast forward, but emu23
+# can merge them.
+test_expect_success \
+    '22 - local change cache updated.' \
+    'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
+     git-update-cache --add bozbar &&
+     read_tree_twoway $treeH $treeM &&
+     git-ls-files --stage >22.out || exit
+     diff -u M.out 22.out >22diff.out
+     compare_change 22diff.out &&
+     check_cache_at bozbar clean'
+
 # Also make sure we did not break DF vs DF/DF case.
 test_expect_success \
     'DF vs DF/DF case setup.' \
@@ -324,4 +388,20 @@ test_expect_success \
      check_cache_at DF/DF clean && # different from pure 2-way
      :'
 
+# Emu23 can grok I having more than H.  Make sure we did not
+# botch the conflict tests (Linus code botches this test).
+test_expect_success \
+    'DF vs DF/DF case test (#2).' \
+    'rm -f .git/index &&
+     rm -fr DF &&
+     mkdir DF &&
+     echo DF/DF >DF/DF &&
+     git-update-cache --add DF/DF &&
+     # This should fail because I and H have a conflict
+     # at DF.
+     if git-read-tree --emu23 $treeDF $treeDFDF
+     then true  ;# should be false
+     else false ;# should be true
+     fi'
+
 test_done
------------
Junio C Hamano· Jun 24, 2005, 23:40 UTC · re: Junio C Hamano · lore

[PATCH 2/2] Fix oversimplified optimization for add_cache_entry().

An earlier change to optimize directory-file conflict check broke what "read-tree --emu23" expects. Introduce an explicit flag to tell add_cache_entry() not to check for conflicts and use it when reading an existing tree into an empty stage --- by definition this case can never introduce such conflicts.

Resurrect the unoptimized directory-file conflict check code for now as well. The new one did not handle higher stages properly.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 cache.h                           |    1 
 read-cache.c                      |  177 +++++++++++++++++++------------------
 t/t1005-read-tree-m-2way-emu23.sh |    6 +
 tree.c                            |    2 
 4 files changed, 95 insertions(+), 91 deletions(-)
cb13405368b0132ec3b3edcda22d32d89e9c1f85
Show changes to 4 files +95 −91

cache.h, read-cache.c, t/t1005-read-tree-m-2way-emu23.sh, tree.c

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -130,6 +130,7 @@ extern int write_cache(int newfd, struct
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
+#define ADD_CACHE_SKIP_DF_CHECK 4	/* Ok to skip directory/file conflict checks */
 extern int add_cache_entry(struct cache_entry *ce, int option);
 extern int remove_cache_entry_at(int pos);
 extern int remove_file_from_cache(char *path);
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -171,83 +171,6 @@ int ce_same_name(struct cache_entry *a, 
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
-/*
- * Do we have another file that has the beginning components being a
- * proper superset of the name we're trying to add?
- */
-static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replace)
-{
-	int retval = 0;
-	int len = ce_namelen(ce);
-	const char *name = ce->name;
-
-	while (pos < active_nr) {
-		struct cache_entry *p = active_cache[pos++];
-
-		if (len >= ce_namelen(p))
-			break;
-		if (memcmp(name, p->name, len))
-			break;
-		if (p->name[len] != '/')
-			continue;
-		retval = -1;
-		if (!ok_to_replace)
-			break;
-		remove_cache_entry_at(--pos);
-	}
-	return retval;
-}
-
-/*
- * Do we have another file with a pathname that is a proper
- * subset of the name we're trying to add?
- */
-static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
-{
-	int retval = 0;
-	const char *name = ce->name;
-	const char *slash = name + ce_namelen(ce);
-
-	for (;;) {
-		int len;
-
-		for (;;) {
-			if (*--slash == '/')
-				break;
-			if (slash <= ce->name)
-				return retval;
-		}
-		len = slash - name;
-
-		pos = cache_name_pos(name, len);
-		if (pos >= 0) {
-			retval = -1;
-			if (ok_to_replace)
-				break;
-			remove_cache_entry_at(pos);
-			continue;
-		}
-
-		/*
-		 * Trivial optimization: if we find an entry that
-		 * already matches the sub-directory, then we know
-		 * we're ok, and we can exit
-		 */
-		pos = -pos-1;
-		if (pos < active_nr) {
-			struct cache_entry *p = active_cache[pos];
-			if (ce_namelen(p) <= len)
-				continue;
-			if (p->name[len] != '/')
-				continue;
-			if (memcmp(p->name, name, len))
-				continue;
-			break;
-		}
-	}
-	return retval;
-}
-
 /* We may be in a situation where we already have path/file and path
  * is being added, or we already have path and path/file is being
  * added.  Either one would result in a nonsense tree that has path
@@ -257,19 +180,98 @@ static int has_dir_name(const struct cac
  * from the cache so the caller should recompute the insert position.
  * When this happens, we return non-zero.
  */
-static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
+static int check_file_directory_conflict(const struct cache_entry *ce,
+					 int ok_to_replace)
 {
+	int pos, replaced = 0;
+	const char *path = ce->name;
+	int namelen = strlen(path);
+	int stage = ce_stage(ce);
+	char *pathbuf = xmalloc(namelen + 1);
+	char *cp;
+
+	memcpy(pathbuf, path, namelen + 1);
+
 	/*
-	 * We check if the path is a sub-path of a subsequent pathname
-	 * first, since removing those will not change the position
-	 * in the array
+	 * We are inserting path/file.  Do they have path registered at
+	 * the same stage?  We need to do this for all the levels of our
+	 * subpath.
 	 */
-	int retval = has_file_name(ce, pos, ok_to_replace);
-	/*
-	 * Then check if the path might have a clashing sub-directory
-	 * before it.
+	cp = pathbuf;
+	while (1) {
+		char *ep = strchr(cp, '/');
+		int len;
+		if (!ep)
+			break;
+		*ep = 0;    /* first cut it at slash */
+		len = ep - pathbuf;
+		pos = cache_name_pos(pathbuf,
+				     ntohs(create_ce_flags(len, stage)));
+		if (0 <= pos) {
+			/* Our leading path component is registered as a file,
+			 * and we are trying to make it a directory.  This is
+			 * bad.
+			 */
+			if (!ok_to_replace) {
+				free(pathbuf);
+				return -1;
+			}
+			fprintf(stderr, "removing file '%s' to replace it with a directory to create '%s'.\n", pathbuf, path);
+			remove_cache_entry_at(pos);
+			replaced = 1;
+		}
+		*ep = '/';  /* then restore it and go downwards */
+		cp = ep + 1;
+	}
+	free(pathbuf);
+
+	/* Do we have an entry in the cache that makes our path a prefix
+	 * of it?  That is, are we creating a file where they already expect
+	 * a directory there?
+	 */
+	pos = cache_name_pos(path,
+			     ntohs(create_ce_flags(namelen, stage)));
+
+	/* (0 <= pos) cannot happen because add_cache_entry()
+	 * should have taken care of that case.
+	 */
+	pos = -pos-1;
+
+	/* pos would point at an existing entry that would come immediately
+	 * after our path.  It could be the same as our path in higher stage,
+	 * or different path but in a lower stage.
+	 *
+	 * E.g. when we are inserting path at stage 2,
+	 *
+	 *        1 path
+	 * pos->  3 path
+	 *        2 path/file1
+	 *        3 path/file1
+	 *        2 path/file2
+	 *        2 patho
+	 *
+	 * We need to examine pos, ignore it because it is at different
+	 * stage, examine next to find the path/file at stage 2, and
+	 * complain.  We need to do this until we are not the leading
+	 * path of an existing entry anymore.
 	 */
-	return retval + has_dir_name(ce, pos, ok_to_replace);
+
+	while (pos < active_nr) {
+		struct cache_entry *other = active_cache[pos];
+		if (strncmp(other->name, path, namelen))
+			break; /* it is not our "subdirectory" anymore */
+		if ((ce_stage(other) == stage) &&
+		    other->name[namelen] == '/') {
+			if (!ok_to_replace)
+				return -1;
+			fprintf(stderr, "removing file '%s' under '%s' to be replaced with a file\n", other->name, path);
+			remove_cache_entry_at(pos);
+			replaced = 1;
+			continue; /* cycle without updating pos */
+		}
+		pos++;
+	}
+	return replaced;
 }
 
 int add_cache_entry(struct cache_entry *ce, int option)
@@ -277,6 +279,7 @@ int add_cache_entry(struct cache_entry *
 	int pos;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
+	int skip_df_check = option & ADD_CACHE_SKIP_DF_CHECK;
 	pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
 
 	/* existing match? Just replace it */
@@ -302,7 +305,7 @@ int add_cache_entry(struct cache_entry *
 	if (!ok_to_add)
 		return -1;
 
-	if (!ce_stage(ce) && check_file_directory_conflict(ce, pos, ok_to_replace)) {
+	if (!skip_df_check && check_file_directory_conflict(ce, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
 		pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -389,7 +389,7 @@ test_expect_success \
      :'
 
 # Emu23 can grok I having more than H.  Make sure we did not
-# botch the conflict tests (Linus code botches this test).
+# botch the conflict tests (fixed).
 test_expect_success \
     'DF vs DF/DF case test (#2).' \
     'rm -f .git/index &&
@@ -400,8 +400,8 @@ test_expect_success \
      # This should fail because I and H have a conflict
      # at DF.
      if git-read-tree --emu23 $treeDF $treeDFDF
-     then true  ;# should be false
-     else false ;# should be true
+     then false
+     else true
      fi'
 
 test_done
diff --git a/tree.c b/tree.c
--- a/tree.c
+++ b/tree.c
@@ -18,7 +18,7 @@ static int read_one_entry(unsigned char 
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DF_CHECK);
 }
 
 static int read_tree_recursive(void *buffer, unsigned long size,
------------
Linus Torvalds· Jun 25, 2005, 00:57 UTC · re: Junio C Hamano · lore

Re: [PATCH 2/2] Fix oversimplified optimization for add_cache_entry().

On Fri, 24 Jun 2005, Junio C Hamano wrote:
> 
> Resurrect the unoptimized directory-file conflict check code for
> now as well.  The new one did not handle higher stages properly.
I really don't want to do this. 

Can you fix the "optimized" one instead? Currently the only "optimization" is really to just not call it for any non-stage0 thing, the real advantage is that the old code was totally unreadable and did everything in one big thing.

I'm ok with dropping the optimization, but I don't want to lose the cleanup of splitting that horrible old function into two.

		Linus
Junio C Hamano· Jun 25, 2005, 02:40 UTC · re: Linus Torvalds · lore

Re: [PATCH 2/2] Fix oversimplified optimization for add_cache_entry().

>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

LT> I really don't want to do this. LT> Can you fix the "optimized" one instead?

Will do.
Junio C Hamano· Jun 25, 2005, 09:16 UTC · re: Junio C Hamano · lore

[PATCH 0/9] Fix oversimplified optimization for add_cache_entry().

>>>>> "JCH" == Junio C Hamano <junkio@cox.net> writes:
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

LT> I really don't want to do this. LT> Can you fix the "optimized" one instead?

JCH> Will do.

I have this list which logically consists of three sets. I am using the new "git rebase" to maintain it and your not taking my patch stream gave me a good opportunity to test it ;-).

  [PATCH 1/9] [RFC] fix date parsing for GIT raw commit timestamp format.
  [PATCH 2/9] git-commit-script: get commit message from an existing one.
  [PATCH 3/9] git-cherry: find commits not merged upstream.
  [PATCH 4/9] git-rebase-script: rebase local commits to new upstream head.

These four are updated "git rebase" I've written while on-road without knowing about your git-patch-id; the updated one uses git-patch-id to identify which are merged and which are not.

To carry earlier commit datetime forward, date.c needs to be fixed (PATCH 1/9, which I sent you separately Friday), and enhancing git-commit-script to be able to specify an existing commit to slurp the commit message (and author & date information) was necessary (well, not strictly necessary, but that is the way I am used to, which is stolen from JIT), which is PATCH 2/9. PATCH 3/9 and PATCH 4/9 use git-patch-id to implement the cherrypick/rebase.

  [PATCH 5/9] Add more tests for read-tree --emu23.
  [PATCH 6/9] git-merge-one-file-script: do not misinterpret rm failure
  [PATCH 7/9] Fix oversimplified optimization for add_cache_entry().

These three are reworked D/F conflict fix. PATCH 5/9 is the same demonstration of what is broken in the current code. The problem fixed by PATCH 6/9 was discovered while I was trying out the fixes. PATCH 7/9 teaches your "optimized" has_file/has_dir implementation to honor stages while they operate.

  [PATCH 8/9] http-pull: documentation updates.
  [PATCH 9/9] Add a bit of developer documentation to pull.h
These are resend.
Junio C Hamano· Jun 25, 2005, 09:21 UTC · re: Junio C Hamano · lore

[PATCH 1/9] fix date parsing for GIT raw commit timestamp format.

Usually all of the match_xxx routines in date.c fill tm structure assuming that the parsed string talks about local time, and parse_date routine compensates for it by adjusting the value with tz offset parsed out separately. However, this logic does not work well when we feed GIT raw commit timestamp to it, because what match_digits gets is already in GMT.

A good testcase is:
    $ make test-date
    $ ./test-date 'Fri Jun 24 16:55:27 2005 -0700' '1119657327 -0700'

These two timestamps represent the same time, but the second one without the fix this commit introduces gives you 7 hours off.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 date.c |   14 +++++++++-----
 1 files changed, 9 insertions(+), 5 deletions(-)
dff2db477c3d450350a0dfdce4fa3f9543206b86
Show changes to date.c +9 −5
diff --git a/date.c b/date.c
--- a/date.c
+++ b/date.c
@@ -270,7 +270,7 @@ static int match_multi_number(unsigned l
 /*
  * We've seen a digit. Time? Year? Date? 
  */
-static int match_digit(char *date, struct tm *tm, int *offset)
+static int match_digit(char *date, struct tm *tm, int *offset, int *tm_gmt)
 {
 	int n;
 	char *end;
@@ -283,8 +283,10 @@ static int match_digit(char *date, struc
 	 */
 	if (num > 946684800) {
 		time_t time = num;
-		if (gmtime_r(&time, tm))
+		if (gmtime_r(&time, tm)) {
+			*tm_gmt = 1;
 			return end - date;
+		}
 	}
 
 	/*
@@ -389,7 +391,7 @@ static int match_tz(char *date, int *off
 void parse_date(char *date, char *result, int maxlen)
 {
 	struct tm tm;
-	int offset, sign;
+	int offset, sign, tm_gmt;
 	time_t then;
 
 	memset(&tm, 0, sizeof(tm));
@@ -398,6 +400,7 @@ void parse_date(char *date, char *result
 	tm.tm_mday = -1;
 	tm.tm_isdst = -1;
 	offset = -1;
+	tm_gmt = 0;
 
 	for (;;) {
 		int match = 0;
@@ -410,7 +413,7 @@ void parse_date(char *date, char *result
 		if (isalpha(c))
 			match = match_alpha(date, &tm, &offset);
 		else if (isdigit(c))
-			match = match_digit(date, &tm, &offset);
+			match = match_digit(date, &tm, &offset, &tm_gmt);
 		else if ((c == '-' || c == '+') && isdigit(date[1]))
 			match = match_tz(date, &offset);
 
@@ -430,7 +433,8 @@ void parse_date(char *date, char *result
 	if (then == -1)
 		return;
 
-	then -= offset * 60;
+	if (!tm_gmt)
+		then -= offset * 60;
 
 	sign = '+';
 	if (offset < 0) {
------------
Junio C Hamano· Jun 25, 2005, 09:22 UTC · re: Junio C Hamano · lore

[PATCH 2/9] git-commit-script: get commit message from an existing one.

With -m flag specified, git-commit-script takes the commit message along with author information from an existing commit.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 git-commit-script |   75 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 67 insertions(+), 8 deletions(-)
da2ff8148a94b982c7ee369d5a37c4d20e8dd2a4
Show changes to git-commit-script +67 −8
diff --git a/git-commit-script b/git-commit-script
--- a/git-commit-script
+++ b/git-commit-script
@@ -1,12 +1,37 @@
 #!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+#
+
+usage () {
+    echo 'git commit [-m existing-commit] [<path>...]'
+    exit 1
+}
+
 : ${GIT_DIR=.git}
-if [ ! -d $GIT_DIR ]; then
+if [ ! -d "$GIT_DIR" ]; then
 	echo Not a git directory 1>&2
 	exit 1
 fi
+while case "$#" in 0) break ;; esac
+do
+    case "$1" in
+    -m) shift
+        case "$#" in
+	0) usage ;;
+	*) use_commit=`git-rev-parse "$1"` ||
+	   exit ;;
+	esac
+	;;
+    *)  break
+        ;;
+    esac
+    shift
+done
+
 git-update-cache -q --refresh -- "$@" || exit 1
 PARENTS="-p HEAD"
-if [ ! -r $GIT_DIR/HEAD ]; then
+if [ ! -r "$GIT_DIR/HEAD" ]; then
 	if [ -z "$(git-ls-files)" ]; then
 		echo Nothing to commit 1>&2
 		exit 1
@@ -20,7 +45,7 @@ if [ ! -r $GIT_DIR/HEAD ]; then
 	) > .editmsg
 	PARENTS=""
 else
-	if [ -f $GIT_DIR/MERGE_HEAD ]; then
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 		echo "#"
 		echo "# It looks like your may be committing a MERGE."
 		echo "# If this is not correct, please remove the file"
@@ -28,8 +53,38 @@ else
 		echo "# and try again"
 		echo "#"
 		PARENTS="-p HEAD -p MERGE_HEAD"
-	fi > .editmsg
-	git-status-script >> .editmsg
+	elif test "$use_commit" != ""
+	then
+		pick_author_script='
+		/^author /{
+			h
+			s/^author \([^<]*\) <[^>]*> .*$/\1/
+			s/'\''/'\''\'\'\''/g
+			s/.*/GIT_AUTHOR_NAME='\''&'\''/p
+
+			g
+			s/^author [^<]* <\([^>]*\)> .*$/\1/
+			s/'\''/'\''\'\'\''/g
+			s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
+
+			g
+			s/^author [^<]* <[^>]*> \(.*\)$/\1/
+			s/'\''/'\''\'\'\''/g
+			s/.*/GIT_AUTHOR_DATE='\''&'\''/p
+
+			q
+		}
+		'
+		set_author_env=`git-cat-file commit "$use_commit" |
+		sed -ne "$pick_author_script"`
+		eval "$set_author_env"
+		export GIT_AUTHOR_NAME
+		export GIT_AUTHOR_EMAIL
+		export GIT_AUTHOR_DATE
+		git-cat-file commit "$use_commit" |
+		sed -e '1,/^$/d'
+	fi >.editmsg
+	git-status-script >>.editmsg
 fi
 if [ "$?" != "0" ]
 then
@@ -37,13 +92,17 @@ then
 	rm .editmsg
 	exit 1
 fi
-${VISUAL:-${EDITOR:-vi}} .editmsg
+case "$use_commit" in
+'')
+	${VISUAL:-${EDITOR:-vi}} .editmsg
+	;;
+esac
 grep -v '^#' < .editmsg | git-stripspace > .cmitmsg
 [ -s .cmitmsg ] && 
 	tree=$(git-write-tree) &&
 	commit=$(cat .cmitmsg | git-commit-tree $tree $PARENTS) &&
-	echo $commit > $GIT_DIR/HEAD &&
-	rm -f -- $GIT_DIR/MERGE_HEAD
+	echo $commit > "$GIT_DIR/HEAD" &&
+	rm -f -- "$GIT_DIR/MERGE_HEAD"
 ret="$?"
 rm -f .cmitmsg .editmsg
 exit "$ret"
------------
Junio C Hamano· Jun 25, 2005, 09:22 UTC · re: Junio C Hamano · lore

[PATCH 3/9] git-cherry: find commits not merged upstream.

The git-cherry command helps the git-rebase script by finding commits that have not been merged upstream. Commits already included in upstream are prefixed with '-' (meaning "drop from my local pull"), while commits missing from upstream are prefixed with '+' (meaning "add to the updated upstream").

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 Makefile   |    2 +
 git-cherry |   86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 1 deletions(-)
 create mode 100755 git-cherry
350e3957925c9b4404977bbd6f65bf68ba28d26f
Show changes to 2 files +87 −1

Makefile, git-cherry

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-deltafy-script git-fetch-script git-status-script git-commit-script \
 	git-log-script git-shortlog git-cvsimport-script git-diff-script \
 	git-reset-script git-add-script git-checkout-script git-clone-script \
-	gitk
+	gitk git-cherry
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
diff --git a/git-cherry b/git-cherry
new file mode 100755
--- /dev/null
+++ b/git-cherry
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano.
+#
+
+usage="usage: $0 "'<upstream> [<head>]
+
+             __*__*__*__*__> <upstream>
+            /
+  fork-point
+            \__+__+__+__+__+__+__+__> <head>
+
+Each commit between the fork-point and <head> is examined, and
+compared against the change each commit between the fork-point and
+<upstream> introduces.  If the change does not seem to be in the
+upstream, it is shown on the standard output.
+
+The output is intended to be used as:
+
+    OLD_HEAD=$(git-rev-parse HEAD)
+    git-rev-parse linus >${GIT_DIR-.}/HEAD
+    git-cherry linus OLD_HEAD |
+    while read commit
+    do
+        GIT_EXTERNAL_DIFF=git-apply-patch-script git-diff-tree -p "$commit" &&
+	git-commit-script -m "$commit"
+    done
+'
+
+case "$#" in
+1) linus=`git-rev-parse "$1"` &&
+   junio=`git-rev-parse HEAD` || exit
+   ;;
+2) linus=`git-rev-parse "$1"` &&
+   junio=`git-rev-parse "$2"` || exit
+   ;;
+*) echo >&2 "$usage"; exit 1 ;;
+esac
+
+# Note that these list commits in reverse order;
+# not that the order in inup matters...
+inup=`git-rev-list ^$junio $linus` &&
+ours=`git-rev-list $junio ^$linus` || exit
+
+tmp=.cherry-tmp$$
+patch=$tmp-patch
+mkdir $patch
+trap "rm -rf $tmp-*" 0 1 2 3 15
+
+_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
+_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+
+for c in $inup
+do
+	git-diff-tree -p $c
+done | git-patch-id |
+while read id name
+do
+	echo $name >>$patch/$id
+done
+
+LF='
+'
+
+O=
+for c in $ours
+do
+	set x `git-diff-tree -p $c | git-patch-id`
+	if test "$2" != ""
+	then
+		if test -f "$patch/$2"
+		then
+			sign=-
+		else
+			sign=+
+		fi
+		case "$O" in
+		'')	O="$sign $c" ;;
+		*)	O="$sign $c$LF$O" ;;
+		esac
+	fi
+done
+case "$O" in
+'') ;;
+*)  echo "$O" ;;
+esac
------------
Junio C Hamano· Jun 25, 2005, 09:23 UTC · re: Junio C Hamano · lore

[PATCH 4/9] git-rebase-script: rebase local commits to new upstream head.

Using git-cherry, forward port local commits missing from the new upstream head. This also depends on "-m" flag support in git-commit-script.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 Makefile          |    2 +-
 git-rebase-script |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletions(-)
 create mode 100755 git-rebase-script
39830aca0319e04ed6c45203614543418974f877
Show changes to 2 files +50 −1

Makefile, git-rebase-script

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-deltafy-script git-fetch-script git-status-script git-commit-script \
 	git-log-script git-shortlog git-cvsimport-script git-diff-script \
 	git-reset-script git-add-script git-checkout-script git-clone-script \
-	gitk git-cherry
+	gitk git-cherry git-rebase-script
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
diff --git a/git-rebase-script b/git-rebase-script
new file mode 100755
--- /dev/null
+++ b/git-rebase-script
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano.
+#
+
+usage="usage: $0 "'<upstream> [<head>]
+
+Uses output from git-cherry to rebase local commits to the new head of
+upstream tree.'
+
+: ${GIT_DIR=.git}
+
+case "$#" in
+1) linus=`git-rev-parse "$1"` &&
+   junio=`git-rev-parse HEAD` || exit
+   ;;
+2) linus=`git-rev-parse "$1"` &&
+   junio=`git-rev-parse "$2"` || exit
+   ;;
+*) echo >&2 "$usage"; exit 1 ;;
+esac
+
+git-read-tree -m -u $junio $linus &&
+echo "$linus" >"$GIT_DIR/HEAD" || exit
+
+tmp=.rebase-tmp$$
+fail=$tmp-fail
+trap "rm -rf $tmp-*" 0 1 2 3 15
+
+>$fail
+
+git-cherry $linus $junio |
+while read sign commit
+do
+	case "$sign" in
+	-) continue ;;
+	esac
+	S=`cat "$GIT_DIR/HEAD"` &&
+        GIT_EXTERNAL_DIFF=git-apply-patch-script git-diff-tree -p $commit &&
+	git-commit-script -m "$commit" || {
+		echo $commit >>$fail
+		git-read-tree --reset -u $S
+	}
+done
+if test -s $fail
+then
+	echo Some commits could not be rebased, check by hand:
+	cat $fail
+fi
------------
Junio C Hamano· Jun 25, 2005, 09:24 UTC · re: Junio C Hamano · lore

[PATCH 5/9] Add more tests for read-tree --emu23.

This adds more tests for --emu23. One is to show how it can carry forward more local changes than the straightforward two-way fast forward, and another is to show the recent overeager optimization of directory/file conflict check broke things, which will be fixed in the next commit.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 t/t1001-read-tree-m-2way.sh       |   70 +++++++++++++++++++++++++---
 t/t1005-read-tree-m-2way-emu23.sh |   94 ++++++++++++++++++++++++++++++++++---
 2 files changed, 150 insertions(+), 14 deletions(-)
633115eb1338884fd9488fe57ef4ea2fb91559d5
Show changes to 2 files +150 −14

t/t1001-read-tree-m-2way.sh, t/t1005-read-tree-m-2way-emu23.sh

diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -29,7 +29,6 @@ read_tree_twoway () {
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 compare_change () {
-    	cat current
 	sed -n >current \
 	    -e '/^--- /d; /^+++ /d; /^@@ /d;' \
 	    -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \
@@ -51,11 +50,22 @@ check_cache_at () {
 	esac
 }
 
+cat >bozbar-old <<\EOF
+This is a sample file used in two-way fast forward merge
+tests.  Its second line ends with a magic word bozbar
+which will be modified by the merged head to gnusto.
+It has some extra lines so that external tools can
+successfully merge independent changes made to later
+lines (such as this one), avoiding line conflicts.
+EOF
+
+sed -e 's/bozbar/gnusto (earlier bozbar)/' bozbar-old >bozbar-new
+
 test_expect_success \
     setup \
     'echo frotz >frotz &&
      echo nitfol >nitfol &&
-     echo bozbar >bozbar &&
+     cat bozbar-old >bozbar &&
      echo rezrov >rezrov &&
      echo yomin >yomin &&
      git-update-cache --add nitfol bozbar rezrov &&
@@ -63,7 +73,7 @@ test_expect_success \
      echo treeH $treeH &&
      git-ls-tree $treeH &&
 
-     echo gnusto >bozbar &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add frotz bozbar --force-remove rezrov &&
      git-ls-files --stage >M.out &&
      treeM=`git-write-tree` &&
@@ -86,6 +96,8 @@ echo '+100644 X 0	yomin' >expected
 test_expect_success \
     '4 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add yomin &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >4.out || exit
@@ -96,6 +108,8 @@ test_expect_success \
 test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo yomin >yomin &&
      git-update-cache --add yomin &&
      echo yomin yomin >yomin &&
@@ -108,6 +122,8 @@ test_expect_success \
 test_expect_success \
     '6 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add frotz &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >6.out &&
@@ -117,6 +133,8 @@ test_expect_success \
 test_expect_success \
     '7 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz frotz >frotz &&
@@ -128,6 +146,8 @@ test_expect_success \
 test_expect_success \
     '8 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -135,6 +155,8 @@ test_expect_success \
 test_expect_success \
     '9 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz >frotz &&
@@ -143,6 +165,8 @@ test_expect_success \
 test_expect_success \
     '10 - path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      read_tree_twoway $treeH $treeM &&
@@ -152,6 +176,8 @@ test_expect_success \
 test_expect_success \
     '11 - dirty path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov rezrov >rezrov &&
@@ -160,6 +186,8 @@ test_expect_success \
 test_expect_success \
     '12 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -167,6 +195,8 @@ test_expect_success \
 test_expect_success \
     '13 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov >rezrov &&
@@ -180,6 +210,8 @@ EOF
 test_expect_success \
     '14 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      read_tree_twoway $treeH $treeM &&
@@ -191,6 +223,8 @@ test_expect_success \
 test_expect_success \
     '15 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      echo nitfol nitfol nitfol >nitfol &&
@@ -203,6 +237,8 @@ test_expect_success \
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -210,6 +246,8 @@ test_expect_success \
 test_expect_success \
     '17 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      echo bozbar bozbar bozbar >bozbar &&
@@ -218,7 +256,9 @@ test_expect_success \
 test_expect_success \
     '18 - local change already having a good result.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >18.out &&
@@ -228,7 +268,9 @@ test_expect_success \
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      read_tree_twoway $treeH $treeM &&
@@ -239,7 +281,9 @@ test_expect_success \
 test_expect_success \
     '20 - no local change, use new tree.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >20.out &&
@@ -249,11 +293,23 @@ test_expect_success \
 test_expect_success \
     '21 - no local change, dirty cache.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
+# This fails with straight two-way fast forward.
+test_expect_success \
+    '22 - local change cache updated.' \
+    'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
+     git-update-cache --add bozbar &&
+     if read_tree_twoway $treeH $treeM; then false; else :; fi'
+
 # Also make sure we did not break DF vs DF/DF case.
 test_expect_success \
     'DF vs DF/DF case setup.' \
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -32,7 +32,6 @@ read_tree_twoway () {
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 compare_change () {
-    	cat current
 	sed -n >current \
 	    -e '/^--- /d; /^+++ /d; /^@@ /d;' \
 	    -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \
@@ -60,11 +59,22 @@ check_stages () {
     diff -u expected_stages current_stages
 }
 
+cat >bozbar-old <<\EOF
+This is a sample file used in two-way fast forward merge
+tests.  Its second line ends with a magic word bozbar
+which will be modified by the merged head to gnusto.
+It has some extra lines so that external tools can
+successfully merge independent changes made to later
+lines (such as this one), avoiding line conflicts.
+EOF
+
+sed -e 's/bozbar/gnusto (earlier bozbar)/' bozbar-old >bozbar-new
+
 test_expect_success \
     setup \
     'echo frotz >frotz &&
      echo nitfol >nitfol &&
-     echo bozbar >bozbar &&
+     cat bozbar-old >bozbar &&
      echo rezrov >rezrov &&
      echo yomin >yomin &&
      git-update-cache --add nitfol bozbar rezrov &&
@@ -72,7 +82,7 @@ test_expect_success \
      echo treeH $treeH &&
      git-ls-tree $treeH &&
 
-     echo gnusto >bozbar &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add frotz bozbar --force-remove rezrov &&
      git-ls-files --stage >M.out &&
      treeM=`git-write-tree` &&
@@ -106,6 +116,8 @@ echo '+100644 X 0	yomin' >expected
 test_expect_success \
     '4 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add yomin &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >4.out || exit
@@ -118,6 +130,8 @@ test_expect_success \
 test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo yomin >yomin &&
      git-update-cache --add yomin &&
      echo yomin yomin >yomin &&
@@ -132,6 +146,8 @@ test_expect_success \
 test_expect_success \
     '6 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      git-update-cache --add frotz &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >6.out &&
@@ -143,6 +159,8 @@ test_expect_success \
 test_expect_success \
     '7 - local addition already has the same.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz frotz >frotz &&
@@ -154,6 +172,8 @@ test_expect_success \
 test_expect_success \
     '8 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -161,6 +181,8 @@ test_expect_success \
 test_expect_success \
     '9 - conflicting addition.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo frotz frotz >frotz &&
      git-update-cache --add frotz &&
      echo frotz >frotz &&
@@ -169,6 +191,8 @@ test_expect_success \
 test_expect_success \
     '10 - path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      read_tree_twoway $treeH $treeM &&
@@ -178,6 +202,8 @@ test_expect_success \
 test_expect_success \
     '11 - dirty path removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov rezrov >rezrov &&
@@ -186,6 +212,8 @@ test_expect_success \
 test_expect_success \
     '12 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
@@ -193,6 +221,8 @@ test_expect_success \
 test_expect_success \
     '13 - unmatching local changes being removed.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
      git-update-cache --add rezrov &&
      echo rezrov >rezrov &&
@@ -206,6 +236,8 @@ EOF
 test_expect_success \
     '14 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      read_tree_twoway $treeH $treeM &&
@@ -217,6 +249,8 @@ test_expect_success \
 test_expect_success \
     '15 - unchanged in two heads.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
      git-update-cache --add nitfol &&
      echo nitfol nitfol nitfol >nitfol &&
@@ -233,6 +267,8 @@ test_expect_success \
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      git-read-tree --emu23 $treeH $treeM &&
@@ -249,6 +285,8 @@ EOF
 test_expect_success \
     '17 - conflicting local change.' \
     'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
      git-update-cache --add bozbar &&
      echo bozbar bozbar bozbar >bozbar &&
@@ -257,7 +295,9 @@ test_expect_success \
 test_expect_success \
     '18 - local change already having a good result.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >18.out &&
@@ -267,7 +307,9 @@ test_expect_success \
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
     'rm -f .git/index &&
-     echo gnusto >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-new >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      read_tree_twoway $treeH $treeM &&
@@ -278,7 +320,9 @@ test_expect_success \
 test_expect_success \
     '20 - no local change, use new tree.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git-ls-files --stage >20.out &&
@@ -288,11 +332,31 @@ test_expect_success \
 test_expect_success \
     '21 - no local change, dirty cache.' \
     'rm -f .git/index &&
-     echo bozbar >bozbar &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     cat bozbar-old >bozbar &&
      git-update-cache --add bozbar &&
      echo gnusto gnusto >bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
+echo '-100644 X 0	bozbar
++100644 X 0	bozbar' >expected
+
+# This fails with straight two-way fast forward, but emu23
+# can merge them.
+test_expect_success \
+    '22 - local change cache updated.' \
+    'rm -f .git/index &&
+     git-read-tree $treeH &&
+     git-checkout-cache -u -f -q -a &&
+     sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
+     git-update-cache --add bozbar &&
+     read_tree_twoway $treeH $treeM &&
+     git-ls-files --stage >22.out || exit
+     diff -u M.out 22.out >22diff.out
+     compare_change 22diff.out &&
+     check_cache_at bozbar clean'
+
 # Also make sure we did not break DF vs DF/DF case.
 test_expect_success \
     'DF vs DF/DF case setup.' \
@@ -324,4 +388,20 @@ test_expect_success \
      check_cache_at DF/DF clean && # different from pure 2-way
      :'
 
+# Emu23 can grok I having more than H.  Make sure we did not
+# botch the conflict tests (Linus code botches this test).
+test_expect_success \
+    'DF vs DF/DF case test (#2).' \
+    'rm -f .git/index &&
+     rm -fr DF &&
+     mkdir DF &&
+     echo DF/DF >DF/DF &&
+     git-update-cache --add DF/DF &&
+     # This should fail because I and H have a conflict
+     # at DF.
+     if git-read-tree --emu23 $treeDF $treeDFDF
+     then true  ;# should be false
+     else false ;# should be true
+     fi'
+
 test_done
------------
Junio C Hamano· Jun 25, 2005, 09:24 UTC · re: Junio C Hamano · lore

[PATCH 6/9] git-merge-one-file-script: do not misinterpret rm failure.

When a merge adds a file DF and removes a directory there by deleting a path DF/DF, git-merge-one-file-script can be called for the removal of DF/DF when the path DF is already created by "git-read-tree -m -u". When this happens, we get confused by a failure return from 'rm -f -- "$4"' (where $4 is DF/DF); finding file DF there the "rm -f" command complains that DF is not a directory.

What we want to ensure is that there is no file DF/DF in this case. Avoid getting ourselves confused by first checking if there is a file, and only then try to remove it (and check for failure from the "rm" command).

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 git-merge-one-file-script |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)
7edbb24f69809eb41de865701bc4f17774348043
Show changes to git-merge-one-file-script +5 −2
diff --git a/git-merge-one-file-script b/git-merge-one-file-script
--- a/git-merge-one-file-script
+++ b/git-merge-one-file-script
@@ -22,8 +22,11 @@ case "${1:-.}${2:-.}${3:-.}" in
 #
 "$1.." | "$1.$1" | "$1$1.")
 	echo "Removing $4"
-	rm -f -- "$4" &&
-		exec git-update-cache --remove -- "$4"
+	if test -f "$4"
+	then
+		rm -f -- "$4"
+	fi &&
+	exec git-update-cache --remove -- "$4"
 	;;
 
 #
------------
Junio C Hamano· Jun 25, 2005, 09:25 UTC · re: Junio C Hamano · lore

[PATCH 7/9] Fix oversimplified optimization for add_cache_entry().

An earlier change to optimize directory-file conflict check broke what "read-tree --emu23" expects. This is fixed by this commit.

(1) Introduces an explicit flag to tell add_cache_entry() not to
    check for conflicts and use it when reading an existing tree
    into an empty stage --- by definition this case can never
    introduce such conflicts.
(2) Makes read-cache.c:has_file_name() and read-cache.c:has_dir_name()
    aware of the cache stages, and flag conflict only with paths
    in the same stage.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 cache.h                           |    1 +
 read-cache.c                      |   32 +++++++++++++++++++++-----------
 t/t1005-read-tree-m-2way-emu23.sh |   25 ++++++++++++++++++++-----
 tree.c                            |    2 +-
 4 files changed, 43 insertions(+), 17 deletions(-)
904dbb145f2f42227ea5b94752146ef8d4c2b153
Show changes to 4 files +43 −17

cache.h, read-cache.c, t/t1005-read-tree-m-2way-emu23.sh, tree.c

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -130,6 +130,7 @@ extern int write_cache(int newfd, struct
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
+#define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */
 extern int add_cache_entry(struct cache_entry *ce, int option);
 extern int remove_cache_entry_at(int pos);
 extern int remove_file_from_cache(char *path);
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -179,6 +179,7 @@ static int has_file_name(const struct ca
 {
 	int retval = 0;
 	int len = ce_namelen(ce);
+	int stage = ce_stage(ce);
 	const char *name = ce->name;
 
 	while (pos < active_nr) {
@@ -188,6 +189,8 @@ static int has_file_name(const struct ca
 			break;
 		if (memcmp(name, p->name, len))
 			break;
+		if (ce_stage(p) != stage)
+			continue;
 		if (p->name[len] != '/')
 			continue;
 		retval = -1;
@@ -205,6 +208,7 @@ static int has_file_name(const struct ca
 static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
 {
 	int retval = 0;
+	int stage = ce_stage(ce);
 	const char *name = ce->name;
 	const char *slash = name + ce_namelen(ce);
 
@@ -219,7 +223,7 @@ static int has_dir_name(const struct cac
 		}
 		len = slash - name;
 
-		pos = cache_name_pos(name, len);
+		pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
 		if (pos >= 0) {
 			retval = -1;
 			if (ok_to_replace)
@@ -231,18 +235,23 @@ static int has_dir_name(const struct cac
 		/*
 		 * Trivial optimization: if we find an entry that
 		 * already matches the sub-directory, then we know
-		 * we're ok, and we can exit
+		 * we're ok, and we can exit.
 		 */
 		pos = -pos-1;
-		if (pos < active_nr) {
+		while (pos < active_nr) {
 			struct cache_entry *p = active_cache[pos];
-			if (ce_namelen(p) <= len)
-				continue;
-			if (p->name[len] != '/')
-				continue;
-			if (memcmp(p->name, name, len))
-				continue;
-			break;
+			if ((ce_namelen(p) <= len) ||
+			    (p->name[len] != '/') ||
+			    memcmp(p->name, name, len))
+				break; /* not our subdirectory */
+			if (ce_stage(p) == stage)
+				/* p is at the same stage as our entry, and
+				 * is a subdirectory of what we are looking
+				 * at, so we cannot have conflicts at our
+				 * level or anything shorter.
+				 */
+				return retval;
+			pos++;
 		}
 	}
 	return retval;
@@ -277,6 +286,7 @@ int add_cache_entry(struct cache_entry *
 	int pos;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
+	int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
 	pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
 
 	/* existing match? Just replace it */
@@ -302,7 +312,7 @@ int add_cache_entry(struct cache_entry *
 	if (!ok_to_add)
 		return -1;
 
-	if (!ce_stage(ce) && check_file_directory_conflict(ce, pos, ok_to_replace)) {
+	if (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
 		pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -366,6 +366,7 @@ test_expect_success \
      treeDF=`git-write-tree` &&
      echo treeDF $treeDF &&
      git-ls-tree $treeDF &&
+     git-ls-files --stage >DF.out
 
      rm -f DF &&
      mkdir DF &&
@@ -377,7 +378,7 @@ test_expect_success \
      git-ls-files --stage >DFDF.out'
 
 test_expect_success \
-    'DF vs DF/DF case test.' \
+    'DF vs DF/DF case test (#1)' \
     'rm -f .git/index &&
      rm -fr DF &&
      echo DF >DF &&
@@ -388,10 +389,24 @@ test_expect_success \
      check_cache_at DF/DF clean && # different from pure 2-way
      :'
 
+# The other way around
+test_expect_success \
+    'DF vs DF/DF case test (#2)' \
+    'rm -f .git/index &&
+     rm -fr DF &&
+     mkdir DF &&
+     echo DF/DF >DF/DF &&
+     git-update-cache --add DF/DF &&
+     read_tree_twoway $treeDFDF $treeDF &&
+     git-ls-files --stage >DFDFcheck.out &&
+     diff -u DF.out DFDFcheck.out &&
+     check_cache_at DF clean && # different from pure 2-way
+     :'
+
 # Emu23 can grok I having more than H.  Make sure we did not
-# botch the conflict tests (Linus code botches this test).
+# botch the conflict tests (fixed).
 test_expect_success \
-    'DF vs DF/DF case test (#2).' \
+    'DF vs DF/DF case test (#3).' \
     'rm -f .git/index &&
      rm -fr DF &&
      mkdir DF &&
@@ -400,8 +415,8 @@ test_expect_success \
      # This should fail because I and H have a conflict
      # at DF.
      if git-read-tree --emu23 $treeDF $treeDFDF
-     then true  ;# should be false
-     else false ;# should be true
+     then false
+     else true
      fi'
 
 test_done
diff --git a/tree.c b/tree.c
--- a/tree.c
+++ b/tree.c
@@ -18,7 +18,7 @@ static int read_one_entry(unsigned char 
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
 static int read_tree_recursive(void *buffer, unsigned long size,
------------
Junio C Hamano· Jun 25, 2005, 09:25 UTC · re: Junio C Hamano · lore

[PATCH 8/9] http-pull: documentation updates.

Describe -w option.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 Documentation/git-http-pull.txt |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
bce3da4d8421812b0eb1d433b0af0fc3fc9bb54a
Show changes to Documentation/git-http-pull.txt +4 −2
diff --git a/Documentation/git-http-pull.txt b/Documentation/git-http-pull.txt
--- a/Documentation/git-http-pull.txt
+++ b/Documentation/git-http-pull.txt
@@ -9,7 +9,7 @@ git-http-pull - Downloads a remote GIT r
 
 SYNOPSIS
 --------
-'git-http-pull' [-c] [-t] [-a] [-v] [-d] [--recover] commit-id url
+'git-http-pull' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
 
 DESCRIPTION
 -----------
@@ -30,7 +30,9 @@ Downloads a remote GIT repository via HT
 	usual, to recover after earlier pull that was interrupted.
 -v::
 	Report what is downloaded.
-
+-w::
+        Writes the commit-id into the filename under $GIT_DIR/refs/ on
+        the local end after the transfer is complete.
 
 Author
 ------
------------
Junio C Hamano· Jun 25, 2005, 09:26 UTC · re: Junio C Hamano · lore

[PATCH 9/9] Add a bit of developer documentation to pull.h

Describe what to implement in fetch() and fetch_ref() for pull backend writers a bit better.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 pull.h |   21 +++++++++++++++------
 1 files changed, 15 insertions(+), 6 deletions(-)
190061e326b73dcf76d301d8b17ce96c783d7251
Show changes to pull.h +15 −6
diff --git a/pull.h b/pull.h
--- a/pull.h
+++ b/pull.h
@@ -1,24 +1,33 @@
 #ifndef PULL_H
 #define PULL_H
 
-/** To be provided by the particular implementation. **/
+/*
+ * Fetch object given SHA1 from the remote, and store it locally under
+ * GIT_OBJECT_DIRECTORY.  Return 0 on success, -1 on failure.  To be
+ * provided by the particular implementation.
+ */
 extern int fetch(unsigned char *sha1);
 
+/*
+ * Fetch ref (relative to $GIT_DIR/refs) from the remote, and store
+ * the 20-byte SHA1 in sha1.  Return 0 on success, -1 on failure.  To
+ * be provided by the particular implementation.
+ */
 extern int fetch_ref(char *ref, unsigned char *sha1);
 
-/** If set, the ref filename to write the target value to. **/
+/* If set, the ref filename to write the target value to. */
 extern const char *write_ref;
 
-/** If set, the hash that the current value of write_ref must be. **/
+/* If set, the hash that the current value of write_ref must be. */
 extern const unsigned char *current_ref;
 
-/** Set to fetch the target tree. */
+/* Set to fetch the target tree. */
 extern int get_tree;
 
-/** Set to fetch the commit history. */
+/* Set to fetch the commit history. */
 extern int get_history;
 
-/** Set to fetch the trees in the commit history. **/
+/* Set to fetch the trees in the commit history. */
 extern int get_all;
 
 /* Set to zero to skip the check for delta object base;
------------
Junio C Hamano· Jun 26, 2005, 01:02 UTC · re: Junio C Hamano · lore

[RFD] consider "git" wrapper semi-Porcelain

Currently "git" wrapper suggests both low-level git-* commands and git-*-script commands as alternatives. Earlier I stated that git-*-script commands, like it or not, form a perfectly good set of barebone Porcelain, as opposed to all the other commands that do not end with "script" are low-level Plumbing. After reviewing the current set of commands and scripts again, I still think this view holds true [*1*, *2*].

I would propose the following, preferably before we go 1.0:
 (1) Do not suggest low-level Plumbing commands to "git" wrapper
     users, and do not call anything but git-*-script from "git"
     wrapper.  Once *-script Porcelain matures, hopefully
     everyday workflow would not require access to low-level
     Plumbing and can be done with git-*-script Porcelain.  When
     people know the GIT way, they can also work it around
     things that git-*-script Porcelain does not support well by
     writing their own git-*-script in terms of Plumbing-ish
     git-* commands, and if it is good enough for public
     consumption, propose it for inclusion upstream.
 (2) Make an alias git-whatchanged-script that just "exec"s
     git-whatchanged, to make things consistent.
 (3) Rename some git-*-script that are misnamed in the sense
     that they are not useful standalone scripts but more of
     Plumbing that happen to be written in shell [*3*].  I do
     not particularly like this proposal, because this breaks
     existing scripts.  However, if we go this route for
     consistency, I would further suggest renaming Porcelain-ish
     things git-*-cmd or something, call and suggest them from
     "git" wrapper, regardless of which language they are
     written in [*4*].
[Footnotes]
*1* One exception is git-whatchanged.

*2* That is the reason I did not name git-cherry "git-cherry-script". It is not useful standalone but meant to be useful in scripting environment.

*3* git-apply-patch-script (my fault) and git-merge-one-file-script fall into this category.

*4* Current naming and the proposal (1) above have a problem in that they muddy the definition of what is "script": the name "script" were originally used because they were written in shell, and all of the Porcelain-ish things happen to be "script". Writing Porcelain-ish things in shell should not be a requirement.

Junio C Hamano· Jun 26, 2005, 12:02 UTC · re: Linus Torvalds · lore

Re: [RFD] consider "git" wrapper semi-Porcelain

>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
LT> On Sat, 25 Jun 2005, Junio C Hamano wrote:
>> 
>> I would propose the following, preferably before we go 1.0:
LT> Agreed on all counts.

With holy Penguin pee blessings, I would send in a "flag day" patch sometime before July 4th weekend that:

 - renames most of the git-*-script to git-*-cmd;
 - renames git-whatchanged to git-whatchanged-cmd;
 - renames two misnamed git-*-script to git-*-helper
without any backward compatibility warts.

Unless people object and propose good transition plans, that is.

This message is for people who uses bare GIT and who writes Porcelain. Please consider yourselves warned ;-).

Martijn Kuipers· Jun 26, 2005, 12:36 UTC · re: Junio C Hamano · lore

Re: [RFD] consider "git" wrapper semi-Porcelain

Hi,
Junio C Hamano wrote:
> - renames most of the git-*-script to git-*-cmd;

Wouldn't this ruin the nice tab-completion? git-plumbing and git-porcelain will only be distinctable from their last part. Maybe I understood wrong, but if people are supposed to "just" use git-porcelain for every day use, then probably it would make more sense to rename to gitp-* for porcelain, as the tab-completion would work from the first word , which would be less confusing for us mere users (yes, any alternative first word would work).

Kind regards, Martijn

← back to recent threads