{"thread":{"id":"43074","subject":"Re: [RFC] Teach git-branch howto rename a branch","startedAt":"2006-11-24T23:03:49Z","lastAt":"2006-11-26T23:56:34Z","messageCount":13,"participants":["Jakub Narebski","Josef Weidendorfer","Lars Hjemli","Junio C Hamano","Fredrik Kuivinen","Shawn Pearce"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"294380","messageId":"1164409429445-git-send-email-hjemli@gmail.com","threadId":"43074","inReplyTo":null,"subject":"[RFC] Teach git-branch howto rename a branch","fromName":"Lars Hjemli","fromEmail":"hjemli@gmail.com","sentAt":"2006-11-24T23:03:49Z","receivedAt":"2006-11-24T23:03:49Z","isPatch":false,"sender":{"key":"hjemli@gmail.com","avatar":null},"body":"This adds a '--rename' option to git branch. If specified, branch\ncreation becomes branch renaming.\n\nWith a single branchname, the current branch is renamed and .git/HEAD is\nupdated.\n\nWith two branchnames, the second name is renamed to the first.\n\nSigned-off-by: Lars Hjemli <hjemli@gmail.com>\n---\n builtin-branch.c |  117 +++++++++++++++++++++++++++++++++++------------------\n 1 files changed, 77 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex f14d814..e714569 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -11,7 +11,7 @@\n #include \"builtin.h\"\n \n static const char builtin_branch_usage[] =\n-\"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r | -a] [-v] [--abbrev=<length>] \";\n+\"git-branch (-d | -D) <branchname> | [-l] [-f] [--rename] <branchname> [<start-point>] | [-r | -a] [-v] [--abbrev=<length>] \";\n \n \n static const char *head;\n@@ -36,47 +36,55 @@ static int in_merge_bases(const unsigned\n \treturn ret;\n }\n \n-static void delete_branches(int argc, const char **argv, int force)\n+static void delete_branch(const char *branch, int force, struct commit *head_rev)\n {\n-\tstruct commit *rev, *head_rev;\n-\tunsigned char sha1[20];\n+\tstruct commit *rev;\n \tchar *name;\n-\tint i;\n+\tunsigned char sha1[20];\n \n-\thead_rev = lookup_commit_reference(head_sha1);\n-\tfor (i = 0; i < argc; i++) {\n-\t\tif (!strcmp(head, argv[i]))\n-\t\t\tdie(\"Cannot delete the branch you are currently on.\");\n-\n-\t\tname = xstrdup(mkpath(\"refs/heads/%s\", argv[i]));\n-\t\tif (!resolve_ref(name, sha1, 1, NULL))\n-\t\t\tdie(\"Branch '%s' not found.\", argv[i]);\n-\n-\t\trev = lookup_commit_reference(sha1);\n-\t\tif (!rev || !head_rev)\n-\t\t\tdie(\"Couldn't look up commit objects.\");\n-\n-\t\t/* This checks whether the merge bases of branch and\n-\t\t * HEAD contains branch -- which means that the HEAD\n-\t\t * contains everything in both.\n-\t\t */\n-\n-\t\tif (!force &&\n-\t\t    !in_merge_bases(sha1, rev, head_rev)) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"The branch '%s' is not a strict subset of your current HEAD.\\n\"\n-\t\t\t\t\"If you are sure you want to delete it, run 'git branch -D %s'.\\n\",\n-\t\t\t\targv[i], argv[i]);\n-\t\t\texit(1);\n-\t\t}\n+\tif (!strcmp(head, branch))\n+\t\tdie(\"Cannot delete the branch you are currently on.\");\n+\n+\tname = xstrdup(mkpath(\"refs/heads/%s\", branch));\n+\tif (!resolve_ref(name, sha1, 1, NULL))\n+\t\tdie(\"Branch '%s' not found.\", branch);\n+\n+\trev = lookup_commit_reference(sha1);\n+\tif (!rev)\n+\t\tdie(\"Couldn't look up commit objects for %s\", branch);\n+\n+\t/* This checks whether the merge bases of branch and\n+\t * HEAD contains branch -- which means that the HEAD\n+\t * contains everything in both.\n+\t */\n+\n+\tif (head_rev && !force &&\n+\t    !in_merge_bases(sha1, rev, head_rev)) {\n+\t\tfprintf(stderr,\n+\t\t\t\"The branch '%s' is not a strict subset of your current HEAD.\\n\"\n+\t\t\t\"If you are sure you want to delete it, run 'git branch -D %s'.\\n\",\n+\t\t\tbranch, branch);\n+\t\texit(1);\n+\t}\n \n-\t\tif (delete_ref(name, sha1))\n-\t\t\tprintf(\"Error deleting branch '%s'\\n\", argv[i]);\n-\t\telse\n-\t\t\tprintf(\"Deleted branch %s.\\n\", argv[i]);\n+\tif (delete_ref(name, sha1))\n+\t\tprintf(\"Error deleting branch '%s'\\n\", branch);\n+\telse\n+\t\tprintf(\"Deleted branch %s.\\n\", branch);\n \n-\t\tfree(name);\n-\t}\n+\tfree(name);\n+}\n+\n+static void delete_branches(int argc, const char **argv, int force)\n+{\n+\tstruct commit *head_rev;\n+\tint i;\n+\t\n+\thead_rev = lookup_commit_reference(head_sha1);\n+\tif (!head_rev)\n+\t\tdie(\"Couldn't look up commit object for current HEAD.\");\n+\tfor (i = 0; i < argc; i++) \n+\t\tdelete_branch(argv[i], force, head_rev);\n }\n \n #define REF_UNKNOWN_TYPE    0x00\n@@ -200,15 +208,18 @@ static void print_ref_list(int kinds, in\n \tfree_ref_list(&ref_list);\n }\n \n-static void create_branch(const char *name, const char *start,\n+static char *create_branch(const char *name, const char *start,\n \t\t\t  int force, int reflog)\n {\n \tstruct ref_lock *lock;\n \tstruct commit *commit;\n \tunsigned char sha1[20];\n-\tchar ref[PATH_MAX], msg[PATH_MAX + 20];\n+\tchar *ref, msg[PATH_MAX + 20];\n+\tint reflen;\n \n-\tsnprintf(ref, sizeof ref, \"refs/heads/%s\", name);\n+\treflen = strlen(name) + 12;\n+\tref = xmalloc(reflen+1);\n+\tsnprintf(ref, reflen, \"refs/heads/%s\", name);\n \tif (check_ref_format(ref))\n \t\tdie(\"'%s' is not a valid branch name.\", name);\n \n@@ -235,12 +246,30 @@ static void create_branch(const char *na\n \n \tif (write_ref_sha1(lock, sha1, msg) < 0)\n \t\tdie(\"Failed to write ref: %s.\", strerror(errno));\n+\treturn ref;\n+}\n+\n+static void rename_branch(const char *newname, const char *oldname, int force, int reflog)\n+{\n+\tchar ref[PATH_MAX];\n+\n+\tsnprintf(ref, sizeof ref, \"refs/heads/%s\", oldname);\n+\tif (check_ref_format(ref))\n+\t\tdie(\"'%s' is not a valid branch name.\", oldname);\n+\n+\tnewname = create_branch(newname, oldname, force, reflog);\n+\tif (!strcmp(oldname, head)) {\n+\t\tcreate_symref(\"HEAD\", newname);\n+\t\thead = newname + 11;\n+\t}\n+\tdelete_branch(oldname, force, NULL);\n }\n \n int cmd_branch(int argc, const char **argv, const char *prefix)\n {\n \tint delete = 0, force_delete = 0, force_create = 0;\n \tint verbose = 0, abbrev = DEFAULT_ABBREV;\n+\tint rename = 0;\n \tint reflog = 0;\n \tint kinds = REF_LOCAL_BRANCH;\n \tint i;\n@@ -269,6 +298,10 @@ int cmd_branch(int argc, const char **ar\n \t\t\tforce_create = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--rename\")) {\n+\t\t\trename = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-r\")) {\n \t\t\tkinds = REF_REMOTE_BRANCH;\n \t\t\tcontinue;\n@@ -303,6 +336,10 @@ int cmd_branch(int argc, const char **ar\n \t\tdelete_branches(argc - i, argv + i, force_delete);\n \telse if (i == argc)\n \t\tprint_ref_list(kinds, verbose, abbrev);\n+\telse if (rename && (i == argc - 1))\n+\t\trename_branch(argv[i], head, force_create, reflog);\n+\telse if (rename && (i == argc - 2))\n+\t\trename_branch(argv[i], argv[i + 1], force_create, reflog);\n \telse if (i == argc - 1)\n \t\tcreate_branch(argv[i], head, force_create, reflog);\n \telse if (i == argc - 2)\n-- \n1.4.4\n"},{"id":"297119","messageId":"7v1wns6q41.fsf@assigned-by-dhcp.cox.net","threadId":"43074","inReplyTo":"1164409429445-git-send-email-hjemli@gmail.com","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-11-25T05:40:30Z","receivedAt":"2006-11-25T05:40:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lars Hjemli <hjemli@gmail.com> writes:\n\n> +static void delete_branch(const char *branch, int force, struct commit *head_rev)\n>  {\n>...\n> +}\n\nRefactoring the single ref deletion into this function feels\nsane.  I think you do not need a separate force parameter to\nthis function anymore; if the caller wants to force the deletion\nit can send in a NULL for head_rev to signal that there is no\nneed for the \"subset\" check.\n\n> +static void delete_branches(int argc, const char **argv, int force)\n> +{\n> +\tstruct commit *head_rev;\n> +\tint i;\n> +\t\n> +\thead_rev = lookup_commit_reference(head_sha1);\n> +\tif (!head_rev)\n> +\t\tdie(\"Couldn't look up commit object for current HEAD.\");\n> +\tfor (i = 0; i < argc; i++) \n> +\t\tdelete_branch(argv[i], force, head_rev);\n>  }\n\nI do not think this die() is a good idea.  I think it is\nreasonable to allow the following sequence:\n\n\t$ mkdir newdir && cd newdir\n\t$ git init-db\n        $ git fetch $other_repo refs/heads/master:refs/heads/othre\n        $ git branch -D othre ;# oops, typo\n        $ git fetch $other_repo refs/heads/master:refs/heads/other\n\nWhen forcing a deletion, we do not care about ancestry relation\nbetween the HEAD and the branch being deleted, so we should not\neven bother checking if HEAD is already valid.  The original\ncode before your patch shares the same problem.\n\n> -static void create_branch(const char *name, const char *start,\n> +static char *create_branch(const char *name, const char *start,\n>  \t\t\t  int force, int reflog)\n\nThis makes the returned names leak but probably we do not care\nabout it too much.  However, the only caller that cares about\nthe new refname is rename_branch, and we are talking only about\nbranches, so I think handcrafting the refname just like you\nhandcraft the refname for oldname in rename_branch() would be\na better solution without introducing new leaks.\n\n> +static void rename_branch(const char *newname, const char *oldname, int force, int reflog)\n> +{\n> +\tchar ref[PATH_MAX];\n> +\n> +\tsnprintf(ref, sizeof ref, \"refs/heads/%s\", oldname);\n> +\tif (check_ref_format(ref))\n> +\t\tdie(\"'%s' is not a valid branch name.\", oldname);\n> +\n> +\tnewname = create_branch(newname, oldname, force, reflog);\n\nThis does not feel right.  The 'start' parameter to\ncreate_branch is arbitrary SHA-1 expression so it can take\n'master', 'heads/master' and 'refs/heads/master' to mean the\nsame thing, as long as they are unambiguous, but here you would\nwant to accept only 'master' because the paramter is supposed to\nbe the name of the branch you are renaming.  create_branch()\ndoes not want to do that check for its start parameter, so you\nshould do the checking yourself here, and check_ref_format() is\nnot good enough for that.  Probably calling resolve_ref() on ref\n(= \"refs/heads/oldname\") for reading (because you also want to\nmake sure oldname talks about an existing branch) is needed.\n\n> +\tif (!strcmp(oldname, head)) {\n> +\t\tcreate_symref(\"HEAD\", newname);\n> +\t\thead = newname + 11;\n> +\t}\n> +\tdelete_branch(oldname, force, NULL);\n>  }\n\nWhat is the right thing that should happen when newname talks\nabout an existing branch (I am not asking \"what does your code\ndo?\")?\n\nWithout -f, it should barf.  With -f, we would want the rename\nto happen.  In the latter case, I think it should work the same\nway as deleting it and creating it anew, and that would make\nsure that reflog for the old one will be lost and a new log is\nstarted afresh; otherwise, the log would say old history for\nthat branch and it won't be a \"rename\" anymore.\n\nAlso what happens when oldname is \"frotz\" and newname is\n\"frotz/nitfol\"?  You would need to read the value of \"frotz\",\nmake sure you can delete it (perhaps the usual fast-forward\ncheck as needed), and delete it to make room and then create\n\"frotz/nitfol\".  I suspect your patch does not handle that\ncase.\n\n"},{"id":"297920","messageId":"20061125064901.GB4528@spearce.org","threadId":"43074","inReplyTo":"7v1wns6q41.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-11-25T06:49:01Z","receivedAt":"2006-11-25T06:49:01Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Without -f, it should barf.  With -f, we would want the rename\n> to happen.  In the latter case, I think it should work the same\n> way as deleting it and creating it anew, and that would make\n> sure that reflog for the old one will be lost and a new log is\n> started afresh; otherwise, the log would say old history for\n> that branch and it won't be a \"rename\" anymore.\n\nThis patch doesn't rename the reflog when the branch renames.\nMyself and a few other users I support want the reflog preserved\nwhen a branch renames, we all see the reflog as part of the history\nof that branch and a rename is the same branch but stored under a\ndifferent name...\n\nI had planned to do a rename branch command myself, but its been\nlower priority than everything else, so I have just never gotten\naround to it.  I'm glad to see someone is attempting it!\n\n-- \n"},{"id":"294649","messageId":"7vr6vs579y.fsf_-_@assigned-by-dhcp.cox.net","threadId":"43074","inReplyTo":"7v1wns6q41.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] git-branch -D: make it work even when on a yet-to-be-born branch","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-11-25T07:12:41Z","receivedAt":"2006-11-25T07:12:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This makes \"git branch -D other_branch\" work even when HEAD\npoints at a yet-to-be-born branch.\n\nEarlier, we checked the HEAD ref for the purpose of \"subset\"\ncheck even when the deletion was forced (i.e. not -d but -D).\nBecause of this, you cannot delete a branch even with -D while\non a yet-to-be-born branch.\n\nWith this change, the following sequence that now works:\n\n\tmkdir newdir && cd newdir\n\tgit init-db\n\tgit fetch -k $other_repo refs/heads/master:refs/heads/othre\n\t# oops, typo\n\tgit branch other othre\n\tgit branch -D othre\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n  Junio C Hamano <junkio@cox.net> writes:\n\n  > When forcing a deletion, we do not care about ancestry relation\n  > between the HEAD and the branch being deleted, so we should not\n  > even bother checking if HEAD is already valid.  The original\n  > code before your patch shares the same problem.\n\n  And here is a fix for that.  This is on top of your -v change\n  which I've applied.\n\n builtin-branch.c |   12 ++++++++----\n 1 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex 69b7b55..3d5cb0e 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -38,12 +38,16 @@ static int in_merge_bases(const unsigned char *sha1,\n \n static void delete_branches(int argc, const char **argv, int force)\n {\n-\tstruct commit *rev, *head_rev;\n+\tstruct commit *rev, *head_rev = head_rev;\n \tunsigned char sha1[20];\n \tchar *name;\n \tint i;\n \n-\thead_rev = lookup_commit_reference(head_sha1);\n+\tif (!force) {\n+\t\thead_rev = lookup_commit_reference(head_sha1);\n+\t\tif (!head_rev)\n+\t\t\tdie(\"Couldn't look up commit object for HEAD\");\n+\t}\n \tfor (i = 0; i < argc; i++) {\n \t\tif (!strcmp(head, argv[i]))\n \t\t\tdie(\"Cannot delete the branch you are currently on.\");\n@@ -53,8 +57,8 @@ static void delete_branches(int argc, const char **argv, int force)\n \t\t\tdie(\"Branch '%s' not found.\", argv[i]);\n \n \t\trev = lookup_commit_reference(sha1);\n-\t\tif (!rev || !head_rev)\n-\t\t\tdie(\"Couldn't look up commit objects.\");\n+\t\tif (!rev)\n+\t\t\tdie(\"Couldn't look up commit object for '%s'\", name);\n \n \t\t/* This checks whether the merge bases of branch and\n \t\t * HEAD contains branch -- which means that the HEAD\n-- \n1.4.4.1.g61fba\n\n"},{"id":"294782","messageId":"8c5c35580611250052k19bf54aelcc3833506c2a09f9@mail.gmail.com","threadId":"43074","inReplyTo":"7v1wns6q41.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Lars Hjemli","fromEmail":"hjemli@gmail.com","sentAt":"2006-11-25T08:52:45Z","receivedAt":"2006-11-25T08:52:45Z","isPatch":false,"sender":{"key":"hjemli@gmail.com","avatar":null},"body":"On 11/25/06, Junio C Hamano <junkio@cox.net> wrote:\n> Lars Hjemli <hjemli@gmail.com> writes:\n>\n> > +static void rename_branch(const char *newname, const char *oldname, int force, int reflog)\n> > +{\n> > +     char ref[PATH_MAX];\n> > +\n> > +     snprintf(ref, sizeof ref, \"refs/heads/%s\", oldname);\n> > +     if (check_ref_format(ref))\n> > +             die(\"'%s' is not a valid branch name.\", oldname);\n> > +\n> > +     newname = create_branch(newname, oldname, force, reflog);\n>\n> This does not feel right.  The 'start' parameter to\n> create_branch is arbitrary SHA-1 expression so it can take\n> 'master', 'heads/master' and 'refs/heads/master' to mean the\n> same thing, as long as they are unambiguous, but here you would\n> want to accept only 'master' because the paramter is supposed to\n> be the name of the branch you are renaming.  create_branch()\n> does not want to do that check for its start parameter, so you\n> should do the checking yourself here, and check_ref_format() is\n> not good enough for that.  Probably calling resolve_ref() on ref\n> (= \"refs/heads/oldname\") for reading (because you also want to\n> make sure oldname talks about an existing branch) is needed.\n\nI forgot to use the handcrafted ref when calling 'create_branch':\n\n   newname = create_branch(newname, ref, force, reflog);\n\nThis would force the 'refs/heads' prefix, but let 'create_branch'\ncheck if it's a valid commit reference. I _think_ this would be good\nenough....\n\n\n>\n> > +     if (!strcmp(oldname, head)) {\n> > +             create_symref(\"HEAD\", newname);\n> > +             head = newname + 11;\n> > +     }\n> > +     delete_branch(oldname, force, NULL);\n> >  }\n>\n> What is the right thing that should happen when newname talks\n> about an existing branch (I am not asking \"what does your code\n> do?\")?\n>\n> Without -f, it should barf.  With -f, we would want the rename\n> to happen.  In the latter case, I think it should work the same\n> way as deleting it and creating it anew, and that would make\n> sure that reflog for the old one will be lost and a new log is\n> started afresh; otherwise, the log would say old history for\n> that branch and it won't be a \"rename\" anymore.\n\nYes, the missing piece here is to copy the 'old' reflog to it's new\nlocation after the call to create_branch. I belive create_branch\nhandles the -f cases.\n\n\n> Also what happens when oldname is \"frotz\" and newname is\n> \"frotz/nitfol\"?  You would need to read the value of \"frotz\",\n> make sure you can delete it (perhaps the usual fast-forward\n> check as needed), and delete it to make room and then create\n> \"frotz/nitfol\".  I suspect your patch does not handle that\n> case.\n\nHmm, you're right, I didn't think of such renaming. But I don't want\nto delete the old ref before the new one is in place. How about\nrenaming the old one to a temporary name first?\n\n\nI'l redo the patch on top of your 'git-branch -D' fix\n\n-- \n"},{"id":"293811","messageId":"ek9078$m2j$1@sea.gmane.org","threadId":"43074","inReplyTo":"20061125064901.GB4528@spearce.org","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-11-25T08:53:34Z","receivedAt":"2006-11-25T08:53:34Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Shawn Pearce wrote:\n\n> Junio C Hamano <junkio@cox.net> wrote:\n>> Without -f, it should barf.  With -f, we would want the rename\n>> to happen.  In the latter case, I think it should work the same\n>> way as deleting it and creating it anew, and that would make\n>> sure that reflog for the old one will be lost and a new log is\n>> started afresh; otherwise, the log would say old history for\n>> that branch and it won't be a \"rename\" anymore.\n> \n> This patch doesn't rename the reflog when the branch renames.\n> Myself and a few other users I support want the reflog preserved\n> when a branch renames, we all see the reflog as part of the history\n> of that branch and a rename is the same branch but stored under a\n> different name...\n\nAnd of course reflog should store the fact of renaming branch.\n\n> I had planned to do a rename branch command myself, but its been\n> lower priority than everything else, so I have just never gotten\n> around to it.  I'm glad to see someone is attempting it!\n\nI have thought that command to rename branch was created to deal\nwith simultaneous renaming of reflog + marking rename in reflog.\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n\n"},{"id":"297882","messageId":"20061125085731.GG4528@spearce.org","threadId":"43074","inReplyTo":"ek9078$m2j$1@sea.gmane.org","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-11-25T08:57:31Z","receivedAt":"2006-11-25T08:57:31Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> wrote:\n> Shawn Pearce wrote:\n> \n> > Junio C Hamano <junkio@cox.net> wrote:\n> >> Without -f, it should barf.  With -f, we would want the rename\n> >> to happen.  In the latter case, I think it should work the same\n> >> way as deleting it and creating it anew, and that would make\n> >> sure that reflog for the old one will be lost and a new log is\n> >> started afresh; otherwise, the log would say old history for\n> >> that branch and it won't be a \"rename\" anymore.\n> > \n> > This patch doesn't rename the reflog when the branch renames.\n> > Myself and a few other users I support want the reflog preserved\n> > when a branch renames, we all see the reflog as part of the history\n> > of that branch and a rename is the same branch but stored under a\n> > different name...\n> \n> And of course reflog should store the fact of renaming branch.\n\nYes, I think that's a worthwhile thing to log.  Problem is the\nlogging system tends to throw away pointless entries (sha1 ->\nsame sha1) so the rename log entry needs to be forced somehow...\n\nAlthough without a UI to show the content of the reflog having the\nrename entry in there isn't all that critical.\n \n> > I had planned to do a rename branch command myself, but its been\n> > lower priority than everything else, so I have just never gotten\n> > around to it.  I'm glad to see someone is attempting it!\n> \n> I have thought that command to rename branch was created to deal\n> with simultaneous renaming of reflog + marking rename in reflog.\n\nYes, that's one of the complex parts of it. :-)\n\n-- \n"},{"id":"294958","messageId":"8c5c35580611250116h466e3649p2630ee6641b6e6f4@mail.gmail.com","threadId":"43074","inReplyTo":"20061125085731.GG4528@spearce.org","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Lars Hjemli","fromEmail":"lh@elementstorage.no","sentAt":"2006-11-25T09:16:19Z","receivedAt":"2006-11-25T09:16:19Z","isPatch":false,"sender":{"key":"lh@elementstorage.no","avatar":null},"body":"On 11/25/06, Shawn Pearce <spearce@spearce.org> wrote:\n> Jakub Narebski <jnareb@gmail.com> wrote:\n> >\n> > And of course reflog should store the fact of renaming branch.\n>\n> Yes, I think that's a worthwhile thing to log.  Problem is the\n> logging system tends to throw away pointless entries (sha1 ->\n> same sha1) so the rename log entry needs to be forced somehow...\n\nIs it ok to put\n\nstatic int log_ref_write(struct ref_lock *lock,\n\tconst unsigned char *sha1, const char *msg)\n\ninto refs.h?\n\nThen it should be possibly to do something like this:\n\n  lock = lock_ref_sha1(ref, sha1);\n  lock->force_write = 1;\n  log_ref_write(lock, sha1, \"Renamed oldname to newname\");\n  unlock_ref(lock);\n\n...after moving the reflog...\n\n-- \n"},{"id":"294625","messageId":"7vd57b3jc2.fsf@assigned-by-dhcp.cox.net","threadId":"43074","inReplyTo":"8c5c35580611250116h466e3649p2630ee6641b6e6f4@mail.gmail.com","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-11-25T10:35:09Z","receivedAt":"2006-11-25T10:35:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Lars Hjemli\" <lh@elementstorage.no> writes:\n\n> Is it ok to put\n>\n> static int log_ref_write(struct ref_lock *lock,\n> \tconst unsigned char *sha1, const char *msg)\n>\n> into refs.h?\n\nI think a cleaner implementation that does not have such a\nlayering violation would involve defining rename_refs()\ninterface in refs.c, next to the delete_ref() that exists there.\n\nThe division of labor would be for builtin-branch.c to make sure\nboth oldname and newname are branch names, and rename_refs() to\nrename the reflog (if exists) and the ref at the same time.  To\ndeal with D/F conflicts sanely, I suspect it would involve a\ncall to rename(2) to move the reflog to a temporary location,\nperhaps $GIT_DIR/.tmp-renamed-log, deletion of the old ref by\ncalling delete_ref(), and then another rename(2) to move that\ntemporary one to its final location, followed by the usual \"ref\ncreation dance\" of calling lock_any_ref_for_update() and\nwrite_ref_sha1().\n\nSide note:\n\nIf we do not mind losing the reflog of oldname, then \"delete and\nthen create\" would be sufficient, but that is not the case.\n\nUnlike \"git does not track individual files so we do not record\nrenames\" mantra, branches, and more in general, refs, have\nmeaningful identity (at least locally), and unlike the file\ncontents, the \"contents\" of a ref does not migrate _partially_\nfrom ref to ref.  It would make sense to keep track of renames\nfor them.\n"},{"id":"296768","messageId":"4c8ef70611250239h4e03b9c7k971b60187aa0f56d@mail.gmail.com","threadId":"43074","inReplyTo":"1164409429445-git-send-email-hjemli@gmail.com","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Fredrik Kuivinen","fromEmail":"frekui@gmail.com","sentAt":"2006-11-25T10:39:03Z","receivedAt":"2006-11-25T10:39:03Z","isPatch":false,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"On 11/25/06, Lars Hjemli <hjemli@gmail.com> wrote:\n> This adds a '--rename' option to git branch. If specified, branch\n> creation becomes branch renaming.\n>\n> With a single branchname, the current branch is renamed and .git/HEAD is\n> updated.\n>\n> With two branchnames, the second name is renamed to the first.\n\nNice idea. But wouldn't it be more sensible to rename the first branch to the\nsecond instead of the other way around? That is, the syntax would be\n\n    git branch --rename FROM TO\n\nwhich is more similar to how \"mv\" works.\n\n"},{"id":"297619","messageId":"8c5c35580611250252r50539e4ere98bb38c7b8c9c9@mail.gmail.com","threadId":"43074","inReplyTo":"7vd57b3jc2.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Lars Hjemli","fromEmail":"hjemli@gmail.com","sentAt":"2006-11-25T10:52:48Z","receivedAt":"2006-11-25T10:52:48Z","isPatch":false,"sender":{"key":"hjemli@gmail.com","avatar":null},"body":"On 11/25/06, Junio C Hamano <junkio@cox.net> wrote:\n> \"Lars Hjemli\" <lh@elementstorage.no> writes:\n>\n> > Is it ok to put\n> >\n> > static int log_ref_write(struct ref_lock *lock,\n> >       const unsigned char *sha1, const char *msg)\n> >\n> > into refs.h?\n>\n> I think a cleaner implementation that does not have such a\n> layering violation would involve defining rename_refs()\n> interface in refs.c, next to the delete_ref() that exists there.\n\nYes, that looks a lot nicer. I'll give it a try.\n\n-- \n"},{"id":"295554","messageId":"8c5c35580611250300q521c5723t2d356d73d4c4fdb6@mail.gmail.com","threadId":"43074","inReplyTo":"4c8ef70611250239h4e03b9c7k971b60187aa0f56d@mail.gmail.com","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Lars Hjemli","fromEmail":"hjemli@gmail.com","sentAt":"2006-11-25T11:00:08Z","receivedAt":"2006-11-25T11:00:08Z","isPatch":false,"sender":{"key":"hjemli@gmail.com","avatar":null},"body":"On 11/25/06, Fredrik Kuivinen <frekui@gmail.com> wrote:\n> On 11/25/06, Lars Hjemli <hjemli@gmail.com> wrote:\n> > This adds a '--rename' option to git branch. If specified, branch\n> > creation becomes branch renaming.\n> >\n> > With a single branchname, the current branch is renamed and .git/HEAD is\n> > updated.\n> >\n> > With two branchnames, the second name is renamed to the first.\n>\n> Nice idea. But wouldn't it be more sensible to rename the first branch to the\n> second instead of the other way around? That is, the syntax would be\n>\n>     git branch --rename FROM TO\n>\n> which is more similar to how \"mv\" works.\n>\n\nPossibly, but then we would have\n\n  git branch newbranch [oldbranch]\n\nwhen creating a new branch, and\n\n  git branch --rename [oldbranch] newbranch\n\nfor rename/move.\n\nI'd prefer to be \"internally consistent\", but it does look and feel a\nlittle strange...\n\nAnother option would be:\n\n  git branch [--rename] [--from <branch>] newbranch\n\nand deprecate the usage of two unnamed argumens for create/rename\n\n-- \n"},{"id":"294301","messageId":"200611270056.35053.Josef.Weidendorfer@gmx.de","threadId":"43074","inReplyTo":"1164409429445-git-send-email-hjemli@gmail.com","subject":"Re: [RFC] Teach git-branch howto rename a branch","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2006-11-26T23:56:34Z","receivedAt":"2006-11-26T23:56:34Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Saturday 25 November 2006 00:03, Lars Hjemli wrote:\n> This adds a '--rename' option to git branch. If specified, branch\n> creation becomes branch renaming.\n\nThis probably also should rename all config keys\n branch.<oldname>.*\ninto\n branch.<newname>.*\n\n"}]}