{"thread":{"id":"8891","subject":"[PATCH] Enable \"git rerere\" by the config variable rerere.enabled","startedAt":"2007-07-06T12:05:59Z","lastAt":"2007-07-08T22:00:49Z","messageCount":5,"participants":["Johannes Schindelin","Junio C Hamano","Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"46614","messageId":"Pine.LNX.4.64.0707061303450.4093@racer.site","threadId":"8891","inReplyTo":null,"subject":"[PATCH] Enable \"git rerere\" by the config variable rerere.enabled","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-06T12:05:59Z","receivedAt":"2007-07-06T12:05:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nEarlier, \"git rerere\" was enabled by creating the directory\n.git/rr-cache.  That is definitely not in line with most other\nfeatures, which are enabled by a config variable.\n\nSo, check the config variable \"rerere.enabled\". If it is set\nto \"false\" explicitely, do not activate rerere, even if\n.git/rr-cache exists. This should help when you want to disable\nrerere temporarily.\n\nIf \"rerere.enabled\" is not set at all, fall back to detection\nof the directory .git/rr-cache.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tTouches quite some parts, doesn't it?\n\n\tAnd yeah, the git-gui part should be factored out, I guess. Shawn?\n\n Documentation/config.txt     |    5 +++++\n Documentation/git-rerere.txt |    4 ++--\n builtin-rerere.c             |   31 +++++++++++++++++++++++++++----\n contrib/emacs/git.el         |    3 +--\n git-am.sh                    |   15 +++------------\n git-commit.sh                |    5 +----\n git-gui/lib/commit.tcl       |    4 +---\n git-merge.sh                 |    5 +----\n git-rebase.sh                |   12 +++---------\n t/t4200-rerere.sh            |   23 ++++++++++++++++++++---\n 10 files changed, 64 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 66a55b0..4b67f0a 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -448,6 +448,11 @@ gc.rerereunresolved::\n \tkept for this many days when `git rerere gc` is run.\n \tThe default is 15 days.  See gitlink:git-rerere[1].\n \n+rerere.enabled::\n+\tActivate recording of resolved conflicts, so that identical\n+\tconflict hunks can be resolved automatically, should they\n+\tbe encountered again.  See gitlink:git-rerere[1].\n+\n gitcvs.enabled::\n \tWhether the cvs server interface is enabled for this repository.\n \tSee gitlink:git-cvsserver[1].\ndiff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt\nindex 7ff9b05..c4d4263 100644\n--- a/Documentation/git-rerere.txt\n+++ b/Documentation/git-rerere.txt\n@@ -23,7 +23,7 @@ initial manual merge, and later by noticing the same automerge\n results and applying the previously recorded hand resolution.\n \n [NOTE]\n-You need to create `$GIT_DIR/rr-cache` directory to enable this\n+You need to set the config variable rerere.enabled to enable this\n command.\n \n \n@@ -171,7 +171,7 @@ records it if it is a new conflict, or reuses the earlier hand\n resolve when it is not.  `git-commit` also invokes `git-rerere`\n when recording a merge result.  What this means is that you do\n not have to do anything special yourself (Note: you still have\n-to create `$GIT_DIR/rr-cache` directory to enable this command).\n+to set the config variable rerere.enabled to enable this command).\n \n In our example, when you did the test merge, the manual\n resolution is recorded, and it will be reused when you do the\ndiff --git a/builtin-rerere.c b/builtin-rerere.c\nindex 29fb075..af4d35a 100644\n--- a/builtin-rerere.c\n+++ b/builtin-rerere.c\n@@ -12,6 +12,9 @@ static const char git_rerere_usage[] =\n static int cutoff_noresolve = 15;\n static int cutoff_resolve = 60;\n \n+/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */\n+static int rerere_enabled = -1;\n+\n static char *merge_rr_path;\n \n static const char *rr_path(const char *name, const char *file)\n@@ -387,21 +390,40 @@ static int git_rerere_config(const char *var, const char *value)\n \t\tcutoff_resolve = git_config_int(var, value);\n \telse if (!strcmp(var, \"gc.rerereunresolved\"))\n \t\tcutoff_noresolve = git_config_int(var, value);\n+\telse if (!strcmp(var, \"rerere.enabled\"))\n+\t\trerere_enabled = git_config_bool(var, value);\n \telse\n \t\treturn git_default_config(var, value);\n \treturn 0;\n }\n \n-int cmd_rerere(int argc, const char **argv, const char *prefix)\n+int is_rerere_enabled(void)\n {\n-\tstruct path_list merge_rr = { NULL, 0, 0, 1 };\n-\tint i, fd = -1;\n \tstruct stat st;\n+\tconst char *rr_cache = git_path(\"rr-cache\");\n+\tint rr_cache_exists;\n \n-\tif (stat(git_path(\"rr-cache\"), &st) || !S_ISDIR(st.st_mode))\n+\tif (!rerere_enabled)\n \t\treturn 0;\n \n+\trr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);\n+\tif (rerere_enabled < 0)\n+\t\treturn rr_cache_exists;\n+\n+\tif (!rr_cache_exists && (mkdir(rr_cache, 0777) ||\n+\t\t\tadjust_shared_perm(rr_cache)))\n+\t\tdie(\"Could not create directory %s\", rr_cache);\n+\treturn 1;\n+}\n+\n+int cmd_rerere(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct path_list merge_rr = { NULL, 0, 0, 1 };\n+\tint i, fd = -1;\n+\n \tgit_config(git_rerere_config);\n+\tif (!is_rerere_enabled())\n+\t\treturn 0;\n \n \tmerge_rr_path = xstrdup(git_path(\"rr-cache/MERGE_RR\"));\n \tfd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);\n@@ -411,6 +433,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)\n \t\treturn do_plain_rerere(&merge_rr, fd);\n \telse if (!strcmp(argv[1], \"clear\")) {\n \t\tfor (i = 0; i < merge_rr.nr; i++) {\n+\t\t\tstruct stat st;\n \t\t\tconst char *name = (const char *)merge_rr.items[i].util;\n \t\t\tif (!stat(git_path(\"rr-cache/%s\", name), &st) &&\n \t\t\t\t\tS_ISDIR(st.st_mode) &&\ndiff --git a/contrib/emacs/git.el b/contrib/emacs/git.el\nindex f600179..457f95f 100644\n--- a/contrib/emacs/git.el\n+++ b/contrib/emacs/git.el\n@@ -681,8 +681,7 @@ and returns the process output as a string.\"\n                             (condition-case nil (delete-file \".git/MERGE_MSG\") (error nil))\n                             (with-current-buffer buffer (erase-buffer))\n                             (git-set-files-state files 'uptodate)\n-                            (when (file-directory-p \".git/rr-cache\")\n-                              (git-run-command nil nil \"rerere\"))\n+                            (git-run-command nil nil \"rerere\")\n                             (git-refresh-files)\n                             (git-refresh-ewoc-hf git-status)\n                             (message \"Committed %s.\" commit)\ndiff --git a/git-am.sh b/git-am.sh\nindex d57a3e2..e5e6f2c 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -95,10 +95,7 @@ It does not apply to blobs recorded in its index.\"\n     eval GITHEAD_$his_tree='\"$SUBJECT\"'\n     export GITHEAD_$his_tree\n     git-merge-recursive $orig_tree -- HEAD $his_tree || {\n-\t    if test -d \"$GIT_DIR/rr-cache\"\n-\t    then\n-\t\tgit rerere\n-\t    fi\n+\t    git rerere\n \t    echo Failed to merge in the changes.\n \t    exit 1\n     }\n@@ -252,10 +249,7 @@ last=`cat \"$dotest/last\"`\n this=`cat \"$dotest/next\"`\n if test \"$skip\" = t\n then\n-\tif test -d \"$GIT_DIR/rr-cache\"\n-\tthen\n-\t\tgit rerere clear\n-\tfi\n+\tgit rerere clear\n \tthis=`expr \"$this\" + 1`\n \tresume=\n fi\n@@ -420,10 +414,7 @@ do\n \t\t\tstop_here_user_resolve $this\n \t\tfi\n \t\tapply_status=0\n-\t\tif test -d \"$GIT_DIR/rr-cache\"\n-\t\tthen\n-\t\t\tgit rerere\n-\t\tfi\n+\t\tgit rerere\n \t\t;;\n \tesac\n \ndiff --git a/git-commit.sh b/git-commit.sh\nindex f866f95..9106a74 100755\n--- a/git-commit.sh\n+++ b/git-commit.sh\n@@ -610,10 +610,7 @@ rm -f \"$GIT_DIR/COMMIT_MSG\" \"$GIT_DIR/COMMIT_EDITMSG\" \"$GIT_DIR/SQUASH_MSG\"\n \n cd_to_toplevel\n \n-if test -d \"$GIT_DIR/rr-cache\"\n-then\n-\tgit rerere\n-fi\n+git rerere\n \n if test \"$ret\" = 0\n then\ndiff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl\nindex f9791f6..578bef8 100644\n--- a/git-gui/lib/commit.tcl\n+++ b/git-gui/lib/commit.tcl\n@@ -331,9 +331,7 @@ A rescan will be automatically started now.\n \n \t# -- Let rerere do its thing.\n \t#\n-\tif {[file isdirectory [gitdir rr-cache]]} {\n-\t\tcatch {git rerere}\n-\t}\n+\tcatch {git rerere}\n \n \t# -- Run the post-commit hook.\n \t#\ndiff --git a/git-merge.sh b/git-merge.sh\nindex 4852530..5ccf282 100755\n--- a/git-merge.sh\n+++ b/git-merge.sh\n@@ -496,9 +496,6 @@ Conflicts:\n \t\tsed -e 's/^[^\t]*\t/\t/' |\n \t\tuniq\n \t} >>\"$GIT_DIR/MERGE_MSG\"\n-\tif test -d \"$GIT_DIR/rr-cache\"\n-\tthen\n-\t\tgit rerere\n-\tfi\n+\tgit rerere\n \tdie \"Automatic merge failed; fix conflicts and then commit the result.\"\n fi\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 7a02f29..cbafa14 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -101,7 +101,7 @@ call_merge () {\n \t\treturn\n \t\t;;\n \t1)\n-\t\ttest -d \"$GIT_DIR/rr-cache\" && git rerere\n+\t\tgit rerere\n \t\tdie \"$RESOLVEMSG\"\n \t\t;;\n \t2)\n@@ -160,10 +160,7 @@ do\n \t--skip)\n \t\tif test -d \"$dotest\"\n \t\tthen\n-\t\t\tif test -d \"$GIT_DIR/rr-cache\"\n-\t\t\tthen\n-\t\t\t\tgit rerere clear\n-\t\t\tfi\n+\t\t\tgit rerere clear\n \t\t\tprev_head=\"`cat $dotest/prev_head`\"\n \t\t\tend=\"`cat $dotest/end`\"\n \t\t\tmsgnum=\"`cat $dotest/msgnum`\"\n@@ -181,10 +178,7 @@ do\n \t\texit\n \t\t;;\n \t--abort)\n-\t\tif test -d \"$GIT_DIR/rr-cache\"\n-\t\tthen\n-\t\t\tgit rerere clear\n-\t\tfi\n+\t\tgit rerere clear\n \t\tif test -d \"$dotest\"\n \t\tthen\n \t\t\trm -r \"$dotest\"\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 71d364a..6f55ba0 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -39,15 +39,32 @@ sed -e 's/To die, t/To die! T/' > a1\n echo \"* END *\" >>a1\n git commit -q -a -m second\n \n-# activate rerere\n-mkdir .git/rr-cache\n+test_expect_success 'nothing recorded without rerere' '\n+\t(rm -rf .git/rr-cache; git config rerere.enabled false) &&\n+\t! git merge first &&\n+\t! test -d .git/rr-cache\n+'\n \n-test_expect_failure 'conflicting merge' 'git pull . first'\n+# activate rerere, old style\n+test_expect_success 'conflicting merge' '\n+\tgit reset --hard &&\n+\tmkdir .git/rr-cache &&\n+\tgit config --unset rerere.enabled &&\n+\t! git merge first\n+'\n \n sha1=$(sed -e 's/\t.*//' .git/rr-cache/MERGE_RR)\n rr=.git/rr-cache/$sha1\n test_expect_success 'recorded preimage' \"grep ======= $rr/preimage\"\n \n+test_expect_success 'rerere.enabled works, too' '\n+\trm -rf .git/rr-cache &&\n+\tgit config rerere.enabled true &&\n+\tgit reset --hard &&\n+\t! git merge first &&\n+\tgrep ======= $rr/preimage\n+'\n+\n test_expect_success 'no postimage or thisimage yet' \\\n \t\"test ! -f $rr/postimage -a ! -f $rr/thisimage\"\n \n-- \n1.5.3.rc0.2689.g99ca2-dirty\n"},{"id":"46676","messageId":"7vejjkdaqe.fsf@assigned-by-dhcp.cox.net","threadId":"8891","inReplyTo":"Pine.LNX.4.64.0707061303450.4093@racer.site","subject":"Re: [PATCH] Enable \"git rerere\" by the config variable rerere.enabled","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-07T05:49:29Z","receivedAt":"2007-07-07T05:49:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Earlier, \"git rerere\" was enabled by creating the directory\n> .git/rr-cache.  That is definitely not in line with most other\n> features, which are enabled by a config variable.\n>\n> So, check the config variable \"rerere.enabled\". If it is set\n> to \"false\" explicitely, do not activate rerere, even if\n> .git/rr-cache exists. This should help when you want to disable\n> rerere temporarily.\n>\n> If \"rerere.enabled\" is not set at all, fall back to detection\n> of the directory .git/rr-cache.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>\n> \tTouches quite some parts, doesn't it?\n>\n> \tAnd yeah, the git-gui part should be factored out, I guess. Shawn?\n\nI'll exclude git-gui part and commit with a minor tweaks; having\nextra \"does the directory exist\" check in git-gui would not hurt\npeople who are used to how rerere works in the short term, and I\nthink I read somewhere that I should expect git-gui updates over\nthe weekend anyway.\n\n> -int cmd_rerere(int argc, const char **argv, const char *prefix)\n> +int is_rerere_enabled(void)\n>  {\n\nThis will be \"static\".\n\n> -\tstruct path_list merge_rr = { NULL, 0, 0, 1 };\n> -\tint i, fd = -1;\n>  \tstruct stat st;\n> +\tconst char *rr_cache = git_path(\"rr-cache\");\n> +\tint rr_cache_exists;\n>  \n> -\tif (stat(git_path(\"rr-cache\"), &st) || !S_ISDIR(st.st_mode))\n> +\tif (!rerere_enabled)\n>  \t\treturn 0;\n\nAs git_path() is not zero-cost, assignment to rr_cache will be\nmoved here.\n>  \n> +\trr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);\n> +\tif (rerere_enabled < 0)\n> +\t\treturn rr_cache_exists;\n> +\n> +\tif (!rr_cache_exists && (mkdir(rr_cache, 0777) ||\n> +\t\t\tadjust_shared_perm(rr_cache)))\n> +\t\tdie(\"Could not create directory %s\", rr_cache);\n> +\treturn 1;\n> +}\n\nIf rr-cache is a regular file, we will hit \"Could not create\ndirectory\" which is exactly what we want anyway.  Even if it is\na dangling symlink, it would fail with \"File exists\", so that\nshould be Ok.\n"},{"id":"46686","messageId":"Pine.LNX.4.64.0707071333520.4093@racer.site","threadId":"8891","inReplyTo":"7vejjkdaqe.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Enable \"git rerere\" by the config variable rerere.enabled","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-07T12:41:14Z","receivedAt":"2007-07-07T12:41:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 6 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > \tAnd yeah, the git-gui part should be factored out, I guess. Shawn?\n> \n> I'll exclude git-gui part and commit with a minor tweaks;\n\nThank you. I planned to redo the patch when consensus is reached that this \nis actually a good patch. But as usual, you're faster.\n\n> > -int cmd_rerere(int argc, const char **argv, const char *prefix)\n> > +int is_rerere_enabled(void)\n> >  {\n> \n> This will be \"static\".\n\nBut of course!\n\n> > +\tconst char *rr_cache = git_path(\"rr-cache\");\n> > +\tint rr_cache_exists;\n> >  \n> > -\tif (stat(git_path(\"rr-cache\"), &st) || !S_ISDIR(st.st_mode))\n> > +\tif (!rerere_enabled)\n> >  \t\treturn 0;\n> \n> As git_path() is not zero-cost, assignment to rr_cache will be\n> moved here.\n\nYes, fully agree. It probably does not matter much right now, as \ngit-rerere is mostly called from scripts, and thus does a fork() && exec() \nanyway, but I am smilingly awaiting the first full-fledged builtin \nimplementation of \"git commit\", in which case this very function should \nmove somewhere else, and there it does matter a bit more.\n\n> > +\trr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);\n> > +\tif (rerere_enabled < 0)\n> > +\t\treturn rr_cache_exists;\n> > +\n> > +\tif (!rr_cache_exists && (mkdir(rr_cache, 0777) ||\n> > +\t\t\tadjust_shared_perm(rr_cache)))\n> > +\t\tdie(\"Could not create directory %s\", rr_cache);\n> > +\treturn 1;\n> > +}\n> \n> If rr-cache is a regular file, we will hit \"Could not create\n> directory\" which is exactly what we want anyway.  Even if it is\n> a dangling symlink, it would fail with \"File exists\", so that\n> should be Ok.\n\nThat was the intended error path, yes. It does not safeguard against old \nbehaviour, where you could \": > .git/rr-cache\", and be wondering why it is \nnot activating rr-cache ;-)\n\nCiao,\nDscho\n"},{"id":"46796","messageId":"20070708213639.GB4436@spearce.org","threadId":"8891","inReplyTo":"Pine.LNX.4.64.0707061303450.4093@racer.site","subject":"Re: [PATCH] Enable \"git rerere\" by the config variable rerere.enabled","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-07-08T21:36:39Z","receivedAt":"2007-07-08T21:36:39Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Earlier, \"git rerere\" was enabled by creating the directory\n> .git/rr-cache.  That is definitely not in line with most other\n> features, which are enabled by a config variable.\n> \n> So, check the config variable \"rerere.enabled\". If it is set\n> to \"false\" explicitely, do not activate rerere, even if\n> .git/rr-cache exists. This should help when you want to disable\n> rerere temporarily.\n...\n> diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl\n> index f9791f6..578bef8 100644\n> --- a/git-gui/lib/commit.tcl\n> +++ b/git-gui/lib/commit.tcl\n> @@ -331,9 +331,7 @@ A rescan will be automatically started now.\n>  \n>  \t# -- Let rerere do its thing.\n>  \t#\n> -\tif {[file isdirectory [gitdir rr-cache]]} {\n> -\t\tcatch {git rerere}\n> -\t}\n> +\tcatch {git rerere}\n>  \n>  \t# -- Run the post-commit hook.\n>  \t#\n\nWhile I applaud the idea of someone else doing the dirty work for me,\nthe patch above to git-gui always runs rerere, even if the user has\ndisabled it with rerere.enabled=false.  Not very nice to do.\n\nThe master branch of git-gui will (very soon) have a change that\nactually honors rerere.enabled, as described in the commit message\nof git.git's b4372ef136b0a5a2c1dbd88a11dd72b478d0e0a5, aka the text\nI quoted above.\n\n-- \nShawn.\n"},{"id":"46802","messageId":"20070708220049.GD4436@spearce.org","threadId":"8891","inReplyTo":"7vejjkdaqe.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Enable \"git rerere\" by the config variable rerere.enabled","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-07-08T22:00:49Z","receivedAt":"2007-07-08T22:00:49Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> I'll exclude git-gui part and commit with a minor tweaks; having\n> extra \"does the directory exist\" check in git-gui would not hurt\n> people who are used to how rerere works in the short term, and I\n> think I read somewhere that I should expect git-gui updates over\n> the weekend anyway.\n\nThere is a slew of git-gui updates already made but not yet pulled\nin by you, and a pile yet still coming.\n\nI'm going to be hacking on git-gui pretty much the rest of today,\nand probably a good deal tomorrow too.  I'm trying to simplify\nthe workflow for users in my 400+ branch production repository.\nThey are actively using git-gui now and really need the tool to\nhandle things for them.  Especially since all but 1 of the users\nis _not_ command-line friendly.\n\nSo you can feel free to pull maint and master over if you want,\nbut you might just want to wait another day or two.\n\nAre you thinking of doing a git 1.5.2.4?  I'd like to get the bug\nfixes accumulating in git-gui's maint into 1.5.2.4 as gitgui-0.7.5.\nIf you are doing a 1.5.2.4 release that is...\n\n-- \nShawn.\n"}]}