{"thread":{"id":"36736","subject":"Plumbing to rename a ref?","startedAt":"2014-05-23T10:11:55Z","lastAt":"2014-05-23T19:41:30Z","messageCount":8,"participants":["Sergei Organov","John Keeping","Jeff King","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"242559","messageId":"87ha4golck.fsf@osv.gnss.ru","threadId":"36736","inReplyTo":null,"subject":"Plumbing to rename a ref?","fromName":"Sergei Organov","fromEmail":"osv@javad.com","sentAt":"2014-05-23T10:11:55Z","receivedAt":"2014-05-23T10:11:55Z","isPatch":false,"sender":{"key":"osv@javad.com","avatar":null},"body":"Hello,\n\nAfter convertion of a project from CVS to git, I'd like to rename some\nreferences in the created git repository (before it's published, so no\nproblems here). Is there a plumbing that would do:\n\ngit rename-ref <old_name> <new_name>\n\nfor me?\n\nFor reference, the (ugly) solution I currrently use is:\n\n# Renamve branches/tags for brevity.\n#\n# e.g.: version-3-5-branch -> v3.5-branch\n#\n\nsed_cmd='sed \"s/version-/v/g\" | sed \"s/\\([0-9]\\)-\\([0-9]\\)/\\1.\\2/g\" | sed \"s/\\([0-9]\\)-\\([0-9]\\)/\\1.\\2/g\"'\n\nif [ -f \"packed-refs\" ]; then\n    rm -rf \"packed-refs.new\"\n    cat \"packed-refs\" | eval \"$sed_cmd\" > \"packed-refs.new\" && mv \"packed-refs.new\" \"packed-refs\"\nfi\n\ngit for-each-ref --format=\"%(refname)\" |\nwhile read -r; do\n    ref=\"$REPLY\"\n    if [ -f \"$ref\" ]; then\n        new_ref=`echo \"$ref\" | eval \"$sed_cmd\"`\n        if [ \"$ref\" != \"$new_ref\" ]; then\n            echo \"$ref -> $new_ref\"\n            mv \"$ref\" \"$new_ref\"\n        fi\n    fi\ndone\n\n-- Sergey.\n"},{"id":"242566","messageId":"20140523105047.GA2249@serenity.lan","threadId":"36736","inReplyTo":"87ha4golck.fsf@osv.gnss.ru","subject":"Re: Plumbing to rename a ref?","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2014-05-23T10:50:47Z","receivedAt":"2014-05-23T10:50:47Z","isPatch":false,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Fri, May 23, 2014 at 02:11:55PM +0400, Sergei Organov wrote:\n> Hello,\n> \n> After convertion of a project from CVS to git, I'd like to rename some\n> references in the created git repository (before it's published, so no\n> problems here). Is there a plumbing that would do:\n> \n> git rename-ref <old_name> <new_name>\n> \n> for me?\n\nI think the best you can get is two invocations of `git update-ref`:\n\n\tgit update-ref <new_name> <old_name> &&\n\tgit update-ref -d <old_name>\n\nAlthough if you're scripting it the `--stdin` mode may be easier:\n\n\tgit update-ref --stdin <<-\\EOF\n\tcreate <new_name> <old_name>\n\tdelete <old_name>\n\tEOF\n\nNote that \"<new_name>\" must be a fully-qualified ref (that is, it must\nstart with \"refs/\", so \"refs/heads/new_name\" for a branch or\n\"refs/tags/new_name\" for a tag).\n"},{"id":"242567","messageId":"87k39ck9r9.fsf@osv.gnss.ru","threadId":"36736","inReplyTo":"20140523105047.GA2249@serenity.lan","subject":"Re: Plumbing to rename a ref?","fromName":"Sergei Organov","fromEmail":"osv@javad.com","sentAt":"2014-05-23T11:35:54Z","receivedAt":"2014-05-23T11:35:54Z","isPatch":false,"sender":{"key":"osv@javad.com","avatar":null},"body":"John Keeping <john@keeping.me.uk> writes:\n> On Fri, May 23, 2014 at 02:11:55PM +0400, Sergei Organov wrote:\n>> Hello,\n>> \n>> After convertion of a project from CVS to git, I'd like to rename some\n>> references in the created git repository (before it's published, so no\n>> problems here). Is there a plumbing that would do:\n>> \n>> git rename-ref <old_name> <new_name>\n>> \n>> for me?\n>\n> I think the best you can get is two invocations of `git update-ref`:\n>\n> \tgit update-ref <new_name> <old_name> &&\n> \tgit update-ref -d <old_name>\n\nThis should be good enough. Thanks a lot!\n\n-- Sergey.\n"},{"id":"242568","messageId":"20140523123503.GB726@sigill.intra.peff.net","threadId":"36736","inReplyTo":"87k39ck9r9.fsf@osv.gnss.ru","subject":"Re: Plumbing to rename a ref?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-05-23T12:35:03Z","receivedAt":"2014-05-23T12:35:03Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, May 23, 2014 at 03:35:54PM +0400, Sergei Organov wrote:\n\n> John Keeping <john@keeping.me.uk> writes:\n> > On Fri, May 23, 2014 at 02:11:55PM +0400, Sergei Organov wrote:\n> >> Hello,\n> >> \n> >> After convertion of a project from CVS to git, I'd like to rename some\n> >> references in the created git repository (before it's published, so no\n> >> problems here). Is there a plumbing that would do:\n> >> \n> >> git rename-ref <old_name> <new_name>\n> >> \n> >> for me?\n> >\n> > I think the best you can get is two invocations of `git update-ref`:\n> >\n> > \tgit update-ref <new_name> <old_name> &&\n> > \tgit update-ref -d <old_name>\n> \n> This should be good enough. Thanks a lot!\n\nOne thing that this misses (as does your original script) is the\nreflogs. Doing \"branch -m\" to rename a branch will actually move the\nreflogs, too, but there is otherwise no way to access that\nfunctionality.\n\nIt does not seem unreasonable to teach \"git update-ref\" to do renames to\ntake advantage of this (it would be fairly simple; the logic is already\nencapsulated internally in a rename_ref function).\n\n-Peff\n"},{"id":"242582","messageId":"xmqqvbswjuaa.fsf@gitster.dls.corp.google.com","threadId":"36736","inReplyTo":"20140523105047.GA2249@serenity.lan","subject":"Re: Plumbing to rename a ref?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-05-23T17:10:05Z","receivedAt":"2014-05-23T17:10:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> On Fri, May 23, 2014 at 02:11:55PM +0400, Sergei Organov wrote:\n>> Hello,\n>> \n>> After convertion of a project from CVS to git, I'd like to rename some\n>> references in the created git repository (before it's published, so no\n>> problems here). Is there a plumbing that would do:\n>> \n>> git rename-ref <old_name> <new_name>\n>> \n>> for me?\n>\n> I think the best you can get is two invocations of `git update-ref`:\n>\n> \tgit update-ref <new_name> <old_name> &&\n> \tgit update-ref -d <old_name>\n>\n> Although if you're scripting it the `--stdin` mode may be easier:\n>\n> \tgit update-ref --stdin <<-\\EOF\n> \tcreate <new_name> <old_name>\n> \tdelete <old_name>\n> \tEOF\n>\n> Note that \"<new_name>\" must be a fully-qualified ref (that is, it must\n> start with \"refs/\", so \"refs/heads/new_name\" for a branch or\n> \"refs/tags/new_name\" for a tag).\n\nShouldn't <old_name> also be a full ref?\n"},{"id":"242583","messageId":"xmqqr43kju8o.fsf@gitster.dls.corp.google.com","threadId":"36736","inReplyTo":"20140523123503.GB726@sigill.intra.peff.net","subject":"Re: Plumbing to rename a ref?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-05-23T17:11:03Z","receivedAt":"2014-05-23T17:11:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> One thing that this misses (as does your original script) is the\n> reflogs. Doing \"branch -m\" to rename a branch will actually move the\n> reflogs, too, but there is otherwise no way to access that\n> functionality.\n>\n> It does not seem unreasonable to teach \"git update-ref\" to do renames to\n> take advantage of this (it would be fairly simple; the logic is already\n> encapsulated internally in a rename_ref function).\n\nSounds sensible.\n"},{"id":"242584","messageId":"20140523171407.GB2249@serenity.lan","threadId":"36736","inReplyTo":"xmqqvbswjuaa.fsf@gitster.dls.corp.google.com","subject":"Re: Plumbing to rename a ref?","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2014-05-23T17:14:07Z","receivedAt":"2014-05-23T17:14:07Z","isPatch":false,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Fri, May 23, 2014 at 10:10:05AM -0700, Junio C Hamano wrote:\n> John Keeping <john@keeping.me.uk> writes:\n> \n> > On Fri, May 23, 2014 at 02:11:55PM +0400, Sergei Organov wrote:\n> >> Hello,\n> >> \n> >> After convertion of a project from CVS to git, I'd like to rename some\n> >> references in the created git repository (before it's published, so no\n> >> problems here). Is there a plumbing that would do:\n> >> \n> >> git rename-ref <old_name> <new_name>\n> >> \n> >> for me?\n> >\n> > I think the best you can get is two invocations of `git update-ref`:\n> >\n> > \tgit update-ref <new_name> <old_name> &&\n> > \tgit update-ref -d <old_name>\n> >\n> > Although if you're scripting it the `--stdin` mode may be easier:\n> >\n> > \tgit update-ref --stdin <<-\\EOF\n> > \tcreate <new_name> <old_name>\n> > \tdelete <old_name>\n> > \tEOF\n> >\n> > Note that \"<new_name>\" must be a fully-qualified ref (that is, it must\n> > start with \"refs/\", so \"refs/heads/new_name\" for a branch or\n> > \"refs/tags/new_name\" for a tag).\n> \n> Shouldn't <old_name> also be a full ref?\n\nI tested this before sending the email, and it seemed to do the right\nthing specifying only the branch name; so it probably /should/ be a full\nref, but it seems like it doesn't /need/ to be.\n"},{"id":"242599","messageId":"20140523194129.GA19088@sigill.intra.peff.net","threadId":"36736","inReplyTo":"xmqqr43kju8o.fsf@gitster.dls.corp.google.com","subject":"Re: Plumbing to rename a ref?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-05-23T19:41:30Z","receivedAt":"2014-05-23T19:41:30Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, May 23, 2014 at 10:11:03AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > One thing that this misses (as does your original script) is the\n> > reflogs. Doing \"branch -m\" to rename a branch will actually move the\n> > reflogs, too, but there is otherwise no way to access that\n> > functionality.\n> >\n> > It does not seem unreasonable to teach \"git update-ref\" to do renames to\n> > take advantage of this (it would be fairly simple; the logic is already\n> > encapsulated internally in a rename_ref function).\n> \n> Sounds sensible.\n\nIt's not much code to do the basics, and a patch is below. There are a\nfew open ends, though:\n\n  1. There's no documentation (looking for where to put it, I feel like\n     the manpage could stand to be reorganized a bit).\n\n  2. It doesn't do anything with the --no-deref flag. I'm not sure what\n     specifying a symref for either argument would/should do.\n\n     As a side note, I also notice that you can specify --no-no-deref.\n     Probably that option should be using PARSE_OPT_NONEG and offering\n     \"--deref\" and \"--no-deref\" as opposites.\n\n  3. Should it overwrite, or fail if the destination exists? \"git\n     branch\" has a \"-f\" option, but we don't here.\n\n  4. It doesn't implement rename for --stdin mode. Not strictly\n     necessary, but it would be nice to keep that in sync with the\n     regular command-line options.\n\nThis isn't really my itch to scratch, so I'm not all that inclined to\nwork on it more[1]. But without addressing 1 and 2, I'm not sure it's\nreally fit for inclusion. Maybe somebody wants to try to pick it up and\nbuild on top?\n\n-Peff\n\n[1] Mostly when I say things like \"it would be fairly simple\", I wonder\n    if I am being accurate, so I sometimes try to back it up with code.\n    In this case the basics _are_ simple, but there are definitely some\n    details to be worked out. So I was half-right. ;)\n\n-- >8 --\nSubject: teach update-ref a \"--rename\" option\n\nYou can rename a branch with \"branch -m\", but there is no\nplumbing mechanism to rename an arbitrary ref. You can\nsimulate it with:\n\n  git update-ref newname oldname &&\n  git update-ref -d oldname\n\nbut that drops the reflog from oldname. This patch instead\nallows:\n\n  git update-ref --rename oldname newname\n\nwhich copies the reflog.\n\nUnlike \"git branch -m\", it does not munge the branch config\n(since this plumbing command is purely about refs), nor does\nit allow a missing \"oldname\" to mean an implicit HEAD\n(because it is plumbing, and we are better to make the\ncaller be explicit than risk a surprise).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/update-ref.c  | 23 ++++++++++++++++++++++-\n t/t1400-update-ref.sh | 23 ++++++++++++++++++++++-\n 2 files changed, 44 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/update-ref.c b/builtin/update-ref.c\nindex 5c208bb..ac97894 100644\n--- a/builtin/update-ref.c\n+++ b/builtin/update-ref.c\n@@ -8,6 +8,7 @@\n static const char * const git_update_ref_usage[] = {\n \tN_(\"git update-ref [options] -d <refname> [<oldval>]\"),\n \tN_(\"git update-ref [options]    <refname> <newval> [<oldval>]\"),\n+\tN_(\"git update-ref [options] --rename <refname> <refname>\"),\n \tN_(\"git update-ref [options] --stdin [-z]\"),\n \tNULL\n };\n@@ -19,6 +20,18 @@ static const struct ref_update **updates;\n static char line_termination = '\\n';\n static int update_flags;\n \n+static int do_rename_ref(const char *from, const char *to)\n+{\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tint ret;\n+\n+\tstrbuf_addf(&msg, \"update-ref: renamed %s to %s\", from, to);\n+\tret = rename_ref(from, to, msg.buf);\n+\tstrbuf_release(&msg);\n+\n+\treturn !!ret;\n+}\n+\n static struct ref_update *update_alloc(void)\n {\n \tstruct ref_update *update;\n@@ -251,9 +264,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)\n \tconst char *refname, *oldval, *msg = NULL;\n \tunsigned char sha1[20], oldsha1[20];\n \tint delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;\n+\tint rename = 0;\n \tstruct option options[] = {\n \t\tOPT_STRING( 'm', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n \t\tOPT_BOOL('d', NULL, &delete, N_(\"delete the reference\")),\n+\t\tOPT_BOOL( 0 , \"rename\", &rename, N_(\"rename the reference\")),\n \t\tOPT_BOOL( 0 , \"no-deref\", &no_deref,\n \t\t\t\t\tN_(\"update <refname> not the one it points to\")),\n \t\tOPT_BOOL('z', NULL, &end_null, N_(\"stdin has NUL-terminated arguments\")),\n@@ -268,7 +283,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)\n \t\tdie(\"Refusing to perform update with empty message.\");\n \n \tif (read_stdin) {\n-\t\tif (delete || no_deref || argc > 0)\n+\t\tif (delete || rename || no_deref || argc > 0)\n \t\t\tusage_with_options(git_update_ref_usage, options);\n \t\tif (end_null)\n \t\t\tline_termination = '\\0';\n@@ -279,6 +294,12 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)\n \tif (end_null)\n \t\tusage_with_options(git_update_ref_usage, options);\n \n+\tif (rename) {\n+\t\tif (delete || argc < 2 || argc > 2)\n+\t\t\tusage_with_options(git_update_ref_usage, options);\n+\t\treturn do_rename_ref(argv[0], argv[1]);\n+\t}\n+\n \tif (delete) {\n \t\tif (argc < 1 || argc > 2)\n \t\t\tusage_with_options(git_update_ref_usage, options);\ndiff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh\nindex e130c52..c4008e8 100755\n--- a/t/t1400-update-ref.sh\n+++ b/t/t1400-update-ref.sh\n@@ -23,6 +23,7 @@ test_expect_success setup '\n m=refs/heads/master\n n_dir=refs/heads/gu\n n=$n_dir/fixes\n+d=refs/heads/dst\n \n test_expect_success \\\n \t\"create $m\" \\\n@@ -255,8 +256,28 @@ test_expect_success \\\n \t test '\"$D\"' = $(cat o) &&\n \t test \"warning: Log .git/logs/'\"$m unexpectedly ended on $ld\"'.\" = \"$(cat e)\"'\n \n+test_expect_success 'rename a ref' '\n+\tgit rev-parse --verify $m >expect &&\n \n-rm -f .git/$m .git/logs/$m expect\n+\t# set the date to match the reflog entries we created\n+\t# above, which do not follow test_tick; otherwise\n+\t# the we write an out-of-order entry into the reflog,\n+\t# which confuses the reflog parser\n+\tGIT_COMMITTER_DATE=$ld \\\n+\tgit update-ref --rename $m $d &&\n+\n+\ttest_must_fail git rev-parse --verify $m &&\n+\tgit rev-parse --verify $d >o &&\n+\ttest_cmp expect o\n+'\n+\n+test_expect_success 'renames copy reflogs' '\n+\techo \"$C\" >expect &&\n+\tgit rev-parse --verify \"$d@{2005-05-26 23:32:00}\" >o &&\n+\ttest_cmp expect o\n+'\n+\n+rm -f .git/$m .git/logs/$m .git/$d .git/logs/$d expect\n \n test_expect_success \\\n     'creating initial files' \\\n-- \n2.0.0.rc1.436.g03cb729\n"}]}