{"thread":{"id":"59376","subject":"[RFC PATCH 0/3] Support for tail (branch point) experiment","startedAt":"2023-03-10T21:48:56Z","lastAt":"2023-03-11T03:27:11Z","messageCount":6,"participants":["Felipe Contreras","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"473386","messageId":"20230310214515.39154-1-felipe.contreras@gmail.com","threadId":"59376","inReplyTo":null,"subject":"[RFC PATCH 0/3] Support for tail (branch point) experiment","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-03-10T21:45:12Z","receivedAt":"2023-03-10T21:48:56Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"This is *not* meant a serious proposal, it's just an exploration of an\nidea.\n\nThe topic of finding the actual point a branch started to fork has been\ndiscussed for decades [1] and yet no clear solution is in sight. That's\nwhy this idea I had in 2013 keeps coming back.\n\nThe idea is simple: add the concept of a branch tail (e.g.\n`master@{tail}`.\n\nThe motivation is that Git's main competitor--Mercurial--does have the\nability to tell with 100% accuracy where a branch started, Git does not.\n\nMany hacks have been proposed, such as parsing the commit messages for\n\"Merge branch\", using the reflog, adding options like\n--exclude-first-parent-only. All these clever solutions fail in one way\nor another.\n\nIf we stopped trying to be clever we could go for the easy solution:\nsimply add a tail marker.\n\nThis has many advantages:\n\n * `git rebase` can simply use that\n * `git send-email` can use that\n * `git range-diff` can use that\n * `git name-rev` will now be accurate\n\nI know most of my tools (`git send-seriels`, `git related`, and `git\nsmart-list`) would greatly benefit from this information.\n\nMoreover, for one the most important commands of git, it makes much more\nsense semantically:\n\n    git rebase --onto branch@{upstream} branch@{tail} branch\n\nThan the current:\n\n    git rebase --onto something branch@{upstream} branch\n\nI'm not expecting this to be seriously considered (given the track\nrecord of my proposals), but now the idea is on the record, so it can be\nreferenced in future discussions (which are likely not going to just\nstop).\n\nCheers.\n\n[1] https://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git/71193866#71193866\n\nFelipe Contreras (3):\n  branch: add new 'tail' concept\n  sha1-name: add @{tail} helpers\n  rebase: update branch tail after rebasing\n\n branch.c                  | 12 ++++++++++++\n branch.h                  |  1 +\n builtin/clone.c           |  1 +\n builtin/rebase.c          | 15 +++++++++++++++\n object-name.c             | 30 +++++++++++++++++++++++++++++-\n t/t1514-rev-parse-tail.sh | 39 +++++++++++++++++++++++++++++++++++++++\n 6 files changed, 97 insertions(+), 1 deletion(-)\n create mode 100755 t/t1514-rev-parse-tail.sh\n\n-- \n2.40.0.rc2.1.gf652911b76.dirty\n\n"},{"id":"473387","messageId":"20230310214515.39154-2-felipe.contreras@gmail.com","threadId":"59376","inReplyTo":"20230310214515.39154-1-felipe.contreras@gmail.com","subject":"[RFC PATCH 1/3] branch: add new 'tail' concept","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-03-10T21:45:13Z","receivedAt":"2023-03-10T21:49:11Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"The 'tail' of a branch points to the first parent commit of the branch\nwhen it was created.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n branch.c                  | 12 ++++++++++++\n branch.h                  |  1 +\n builtin/clone.c           |  1 +\n t/t1514-rev-parse-tail.sh | 23 +++++++++++++++++++++++\n 4 files changed, 37 insertions(+)\n create mode 100755 t/t1514-rev-parse-tail.sh\n\ndiff --git a/branch.c b/branch.c\nindex e5614b53b3..e43a164ddb 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -234,6 +234,16 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)\n \treturn 0;\n }\n \n+void install_branch_base(const char *local, const struct object_id *tail)\n+{\n+\tstruct strbuf ref = STRBUF_INIT;\n+\n+\tstrbuf_addf(&ref, \"refs/tails/%s\", local);\n+\tupdate_ref(NULL, ref.buf, tail, NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n+\n+\tstrbuf_release(&ref);\n+}\n+\n /*\n  * Used internally to set the branch.<new_ref>.{remote,merge} config\n  * settings so that branch 'new_ref' tracks 'orig_ref'. Unlike\n@@ -623,6 +633,8 @@ void create_branch(struct repository *r,\n \tif (real_ref && track)\n \t\tsetup_tracking(ref.buf + 11, real_ref, track, quiet);\n \n+\tinstall_branch_base(ref.buf + 11, &oid);\n+\n cleanup:\n \tstrbuf_release(&ref);\n \tfree(real_ref);\ndiff --git a/branch.h b/branch.h\nindex ef56103c05..f020d5be5d 100644\n--- a/branch.h\n+++ b/branch.h\n@@ -142,6 +142,7 @@ void remove_branch_state(struct repository *r, int verbose);\n  */\n #define BRANCH_CONFIG_VERBOSE 01\n int install_branch_config(int flag, const char *local, const char *origin, const char *remote);\n+void install_branch_base(const char *local, const struct object_id *tail);\n \n /*\n  * Read branch description\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 65b5b7db6d..62afcff2ba 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -624,6 +624,7 @@ static void update_head(const struct ref *our, const struct ref *remote,\n \t\t\tupdate_ref(msg, \"HEAD\", &our->old_oid, NULL, 0,\n \t\t\t\t   UPDATE_REFS_DIE_ON_ERR);\n \t\t\tinstall_branch_config(0, head, remote_name, our->name);\n+\t\t\tinstall_branch_base(head, &our->old_oid);\n \t\t}\n \t} else if (our) {\n \t\tstruct commit *c = lookup_commit_reference(the_repository,\ndiff --git a/t/t1514-rev-parse-tail.sh b/t/t1514-rev-parse-tail.sh\nnew file mode 100755\nindex 0000000000..da8e9ceef1\n--- /dev/null\n+++ b/t/t1514-rev-parse-tail.sh\n@@ -0,0 +1,23 @@\n+#!/bin/sh\n+\n+test_description='test <branch>@{upstream} syntax'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\techo one > content &&\n+\tgit add content &&\n+\tgit commit -m one &&\n+\tgit checkout -b test master &&\n+\techo two > new &&\n+\tgit add new &&\n+\tgit commit -a -m two\n+'\n+\n+test_expect_success 'test tail creation' '\n+\tgit rev-parse refs/tails/test > actual &&\n+\tgit rev-parse master > expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.40.0.rc2.1.gf652911b76.dirty\n\n"},{"id":"473388","messageId":"20230310214515.39154-3-felipe.contreras@gmail.com","threadId":"59376","inReplyTo":"20230310214515.39154-1-felipe.contreras@gmail.com","subject":"[RFC PATCH 2/3] sha1-name: add @{tail} helpers","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-03-10T21:45:14Z","receivedAt":"2023-03-10T21:49:20Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n object-name.c             | 30 +++++++++++++++++++++++++++++-\n t/t1514-rev-parse-tail.sh |  6 ++++++\n 2 files changed, 35 insertions(+), 1 deletion(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 2dd1a0f56e..a0f845c927 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -877,6 +877,20 @@ static inline int push_mark(const char *string, int len)\n \treturn at_mark(string, len, suffix, ARRAY_SIZE(suffix));\n }\n \n+static inline int tail_mark(const char *string, int len)\n+{\n+\tconst char *suffix[] = { \"@{tail}\", \"@{t}\" };\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(suffix); i++) {\n+\t\tint suffix_len = strlen(suffix[i]);\n+\t\tif (suffix_len <= len\n+\t\t    && !memcmp(string, suffix[i], suffix_len))\n+\t\t\treturn suffix_len;\n+\t}\n+\treturn 0;\n+}\n+\n static enum get_oid_result get_oid_1(struct repository *r, const char *name, int len, struct object_id *oid, unsigned lookup_flags);\n static int interpret_nth_prior_checkout(struct repository *r, const char *name, int namelen, struct strbuf *buf);\n \n@@ -925,7 +939,8 @@ static int get_oid_basic(struct repository *r, const char *str, int len,\n \t\t\t\t\tcontinue;\n \t\t\t\t}\n \t\t\t\tif (!upstream_mark(str + at, len - at) &&\n-\t\t\t\t    !push_mark(str + at, len - at)) {\n+\t\t\t\t    !push_mark(str + at, len - at) &&\n+\t\t\t\t    !tail_mark(str + at, len - at)) {\n \t\t\t\t\treflog_len = (len-1) - (at+2);\n \t\t\t\t\tlen = at;\n \t\t\t\t}\n@@ -1608,6 +1623,13 @@ static int interpret_branch_mark(struct repository *r,\n \treturn len + at;\n }\n \n+const char *branch_get_tail(struct branch *branch, struct strbuf *err)\n+{\n+\tstatic struct strbuf tmp = STRBUF_INIT; /* TODO: find a proper place */\n+\tstrbuf_addf(&tmp, \"refs/tails/%s\", branch->name);\n+\treturn tmp.buf;\n+}\n+\n int repo_interpret_branch_name(struct repository *r,\n \t\t\t       const char *name, int namelen,\n \t\t\t       struct strbuf *buf,\n@@ -1655,6 +1677,12 @@ int repo_interpret_branch_name(struct repository *r,\n \t\t\t\t\t    options);\n \t\tif (len > 0)\n \t\t\treturn len;\n+\n+\t\tlen = interpret_branch_mark(r, name, namelen, at - name, buf,\n+\t\t\t\t\t    tail_mark, branch_get_tail,\n+\t\t\t\t\t    options);\n+\t\tif (len > 0)\n+\t\t\treturn len;\n \t}\n \n \treturn -1;\ndiff --git a/t/t1514-rev-parse-tail.sh b/t/t1514-rev-parse-tail.sh\nindex da8e9ceef1..6024b4276c 100755\n--- a/t/t1514-rev-parse-tail.sh\n+++ b/t/t1514-rev-parse-tail.sh\n@@ -20,4 +20,10 @@ test_expect_success 'test tail creation' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'test @{tail}' '\n+\tgit rev-parse test@{tail} > actual &&\n+\tgit rev-parse master > expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.40.0.rc2.1.gf652911b76.dirty\n\n"},{"id":"473389","messageId":"20230310214515.39154-4-felipe.contreras@gmail.com","threadId":"59376","inReplyTo":"20230310214515.39154-1-felipe.contreras@gmail.com","subject":"[RFC PATCH 3/3] rebase: update branch tail after rebasing","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-03-10T21:45:15Z","receivedAt":"2023-03-10T21:49:23Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n builtin/rebase.c          | 15 +++++++++++++++\n t/t1514-rev-parse-tail.sh | 10 ++++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 6635f10d52..19cfb0d0e4 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -252,6 +252,16 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n \treturn write_basic_state(opts, head_name, onto, orig_head);\n }\n \n+static void update_tail(struct rebase_options *opts)\n+{\n+\tconst char *shortname = NULL;\n+\tstruct strbuf ref = STRBUF_INIT;\n+\tskip_prefix(opts->head_name, \"refs/heads/\", &shortname);\n+\tstrbuf_addf(&ref, \"refs/tails/%s\", shortname);\n+\tupdate_ref(NULL, ref.buf, &opts->onto->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n+\tstrbuf_release(&ref);\n+}\n+\n static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n {\n \tint ret = -1;\n@@ -294,6 +304,9 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n \t\t\tshortrevisions, opts->onto_name, opts->onto,\n \t\t\t&opts->orig_head->object.oid, &opts->exec,\n \t\t\topts->autosquash, opts->update_refs, &todo_list);\n+\n+\t\tif (!ret)\n+\t\t\tupdate_tail(opts);\n \t}\n \n cleanup:\n@@ -564,6 +577,8 @@ static int finish_rebase(struct rebase_options *opts)\n \t\tstrbuf_release(&dir);\n \t}\n \n+\tupdate_tail(opts);\n+\n \treturn ret;\n }\n \ndiff --git a/t/t1514-rev-parse-tail.sh b/t/t1514-rev-parse-tail.sh\nindex 6024b4276c..7b3482de55 100755\n--- a/t/t1514-rev-parse-tail.sh\n+++ b/t/t1514-rev-parse-tail.sh\n@@ -26,4 +26,14 @@ test_expect_success 'test @{tail}' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'test rebase tail update' '\n+\tgit checkout -b next master &&\n+\techo three > content &&\n+\tgit commit -a -m three &&\n+\tgit rebase --onto next test@{tail} test &&\n+\tgit rev-parse test@{tail} > actual &&\n+\tgit rev-parse next > expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.40.0.rc2.1.gf652911b76.dirty\n\n"},{"id":"473394","messageId":"xmqq7cvoywzx.fsf@gitster.g","threadId":"59376","inReplyTo":"20230310214515.39154-1-felipe.contreras@gmail.com","subject":"Re: [RFC PATCH 0/3] Support for tail (branch point) experiment","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-03-11T00:04:02Z","receivedAt":"2023-03-11T00:04:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> This is *not* meant a serious proposal, it's just an exploration of an\n> idea.\n\nIt is easy to explain and understand the benefit of keeping a\nseparate pointer to the bottom [*] of the branch on top of which the\nhistory leading to the commit at the tip of the branch has been\nbuilt, but the devil is in the details of how such a bottom pointer\nwill be maintained.\n\n    side note: below, I use \"bottom\" because for me it is the most\n    natural term to refer to the starting end of the range of\n    commits.  In the context of this topic, readers can replace any\n    \"bottom\" they see with \"tail\", if they prefer.\n\nIn a sense, this is very similar to the idea of \"notes\".  It is easy\nto explain and understand that a bag of objects, in which additional\ndata can be associated with an object name, can be used to keep\ntrack of extra data on commits (and other objects) after they are\ncreated without invalidating their object name.  As long as they are\ncopied/moved when a commit is used to create another copy of it.\nThe \"notes\" are automatically copied across \"rebasing\", which is one\nof the many details that makes the \"notes\" usable, but cherry-pick\nthat does not honor notes.rewriteRef sometimes leads to frustration.\n\nCreation of a new branch with \"git branch\" would be an obvious point\nto add such a bottom pointer, and \"git rebase\" is a good point to\nupdate such a bottom pointer.  But there are many other ways that\npeople update their branches, depending on the workflow, and\nguessing when to update the bottom pointer and trying to be complete\nwith the heuristics will lead to the same \"no, we do not know all\nusers' workflows\" that made approaches based on reflog parsing\netc. fail to solve the \"where did the branch start?\" puzzle.\n\nAnd I think what is sketched in these RFC patches can be a good\nstarting point for a solution that strikes a good balance.  \"git\nrebase\", which is the most common way to mangle branches, is taught\nto update the bottom pointer automatically.\n\nGiving users an explicit way to set the bottom when manipulating\nbranches would help those who mangle their branches with something\nother than \"git rebase\" in the most trivial form.  I suspect that is\nstill missing in this RFC?  Of course other things on the consuming\nside may be missing, like send-email or format-patch, but they are a\nlot more trivial to add and will be useful.  As long as the bottom\npointer is properly maintained, that is.\n\nA few of the things that I often do to mangle my branches are\nlisted.  Some of them are not application of \"git rebase\" in the\ntrivial form:\n\n * I have a patch series (single strand of pearls).  I update on\n   top of the updated upstream:\n\n    $ git rebase -i --onto master @{bottom}\n    $ git range-diff @{bottom}@{1}..@{1} @{bottom}..HEAD\n\n   No, this is not what \"I often do\" yet, but I hope to see become\n   doable.  Rebase the current branch from its bottom on top of the\n   master, and then take the range diff between the old branch\n   (i.e. @{bottom} refers to the bottom pointer, but because it is\n   implemented as a ref, its reflog knows what the previous value of\n   it was---@{bottom}@{1}..@{1} would be the range of commits on the\n   branch before I did the above rebase) and the new one.\n\n * I have 7 patch series (single strand of pearls).  I only need to\n   touch the top 3.\n\n    $ git rebase -i HEAD~3\n    $ git range-diff @{1}...\n\n   In this case, I am not updating the bottom to HEAD~3 and reducing\n   the branch into 3-patch series.  I am keeping the bottom of the\n   branch, and the commits that happen to be updated are only the\n   topmost 3.\n\n * In the same situation, but the top 3 in the original are so bad\n   that I am better off redoing them from scratch, taking advantage\n   of new features in 'master'.\n\n    $ git checkout --detach master\n    ... work on detached HEAD ...\n    ... first pick the bottom commits ...\n    $ git cherry-pick master..@{-1}~3\n    ... still working on detached HEAD ...\n    ... redo the topmost commits from scratch ...\n    $ git range-diff master..@{-1} master..\n    $ git checkout -B @{-1}\n\n   I do not mind \"checkout -B\" *not* learning any trick to\n   automatically update the bottom pointer for the branch to\n   'master' in this case, but I should be able to manually update\n   the bottom of the branch easily.  Something like \"git checkout -B\n   @{-1} --set-bottom=master\" might be acceptable here.\n\n * I have an existing series, and want to replace it.  To keep the\n   reflog of these branches useful, I apply patches, fix author's\n   mistakes, etc., on detached HEAD and update the original branch\n   after everything is done.\n\n    $ git checkout --detach master... \n    # This could  be \"git checkout --detach @{bottom}\"\n    $ git am -s mbox\n    $ git range-diff @{-1}...\n    $ git checkout -B @{-1}\n\n   In this case, the bottom of the branch should stay the same.\n\n * I tried to do the above, but failed at \"git am\" step, because new\n   iteration requires to be on updated master.\n\n    $ git checkout --detach master... \n    # This could  be \"git checkout --detach @{bottom}\"\n    $ git am -s mbox\n    $ git am --abort\n    $ git reset --hard master\n    $ git am -s mbox\n    $ git range-diff master..@{-1} master..\n    $ git checkout -B @{-1}\n    # or \"git branch -f @{-1}\"\n\n   In this case, I should be able to manually update the bottom of\n   the branch, and making it easy (e.g. \"git checkout -B @{-1}\n   --set-bottom=master\") is much easier and more robust than\n   teaching \"checkout -B\" to guess my intention.\n\nIOW, I do not mind if maintenance of the bottom of the branch is not\nalways automatic (and prone to heuristic making an incorrect guess).\nBut I think we should make sure it is easy for the user to assist\nthe tool to maintain it correctly [*].\n\n    Side note: and that is what I find \"frustrating\" in the \"notes\"\n    world.  \"notes\" can be copied after cherry-pick manually, but\n    that is a very tedious process, and at some point, being \"merely\n    possible\" stops to have much value, unless it is \"easily\n    doable\".\n\nThere are of course other things people do to their branches, and I\ndo not think we need to teach all the tools used in these workflows\nto update the bottom pointer automatically (even though the more we\ncan do automatically would make it easier for users, as long as the\nautomation never makes any mistakes).  Again, I think the key to the\nsuccess for this \"we record the fork point of a branch\" idea is to\nmake it easy and simple for users to help the tools to maintain it\ncorrectly.\n\nThanks.\n"},{"id":"473397","messageId":"CAMP44s0CBum1JZyP57NinikWSXg9KuGBKDAoozmnen1akvGMDA@mail.gmail.com","threadId":"59376","inReplyTo":"xmqq7cvoywzx.fsf@gitster.g","subject":"Re: [RFC PATCH 0/3] Support for tail (branch point) experiment","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-03-11T03:26:54Z","receivedAt":"2023-03-11T03:27:11Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Fri, Mar 10, 2023 at 6:04 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>\n> > This is *not* meant a serious proposal, it's just an exploration of an\n> > idea.\n>\n> It is easy to explain and understand the benefit of keeping a\n> separate pointer to the bottom [*] of the branch on top of which the\n> history leading to the commit at the tip of the branch has been\n> built, but the devil is in the details of how such a bottom pointer\n> will be maintained.\n>\n>     side note: below, I use \"bottom\" because for me it is the most\n>     natural term to refer to the starting end of the range of\n>     commits.  In the context of this topic, readers can replace any\n>     \"bottom\" they see with \"tail\", if they prefer.\n\nPerhaps @{base} would be better (I think that was my original name).\nMercurial has an experimental feature called \"topics\", and that's the\nname they use for the starting point of a topic.\n\n> In a sense, this is very similar to the idea of \"notes\".  It is easy\n> to explain and understand that a bag of objects, in which additional\n> data can be associated with an object name, can be used to keep\n> track of extra data on commits (and other objects) after they are\n> created without invalidating their object name.  As long as they are\n> copied/moved when a commit is used to create another copy of it.\n> The \"notes\" are automatically copied across \"rebasing\", which is one\n> of the many details that makes the \"notes\" usable, but cherry-pick\n> that does not honor notes.rewriteRef sometimes leads to frustration.\n\nI implemented that in 2014 [1].\n\nThere's no actual reason for that to not work in 2023 if we wanted.\n\nBut this is an argument in favor of @{base} (or whatever): even if\nnotes are not perfect, they still can be useful in certain situations,\nand it's certainly better than not having that information. Similarly,\n@{base} doesn't have to be perfect in the first iteration, the natural\npoints in which it's updated can be implemented later, by just\nexisting it would provide some potentially useful information to the\nuser, which is better than nothing.\n\n> Creation of a new branch with \"git branch\" would be an obvious point\n> to add such a bottom pointer, and \"git rebase\" is a good point to\n> update such a bottom pointer.  But there are many other ways that\n> people update their branches, depending on the workflow, and\n> guessing when to update the bottom pointer and trying to be complete\n> with the heuristics will lead to the same \"no, we do not know all\n> users' workflows\" that made approaches based on reflog parsing\n> etc. fail to solve the \"where did the branch start?\" puzzle.\n>\n> And I think what is sketched in these RFC patches can be a good\n> starting point for a solution that strikes a good balance.  \"git\n> rebase\", which is the most common way to mangle branches, is taught\n> to update the bottom pointer automatically.\n>\n> Giving users an explicit way to set the bottom when manipulating\n> branches would help those who mangle their branches with something\n> other than \"git rebase\" in the most trivial form.  I suspect that is\n> still missing in this RFC?\n\nYes, we would want a way to update the base manually, just like with\n@{upstream}.\n\n> Of course other things on the consuming side may be missing, like\n> send-email or format-patch, but they are a lot more trivial to add and\n> will be useful.  As long as the bottom pointer is properly maintained,\n> that is.\n\nYes, but that can be done later. If @{base} is useful and updated in a\ngood enough manner, users are obviously going to want it used in tools\nlike `git send-email`, but even before that, just being able to do\n`@{base}..` is useful (even if manually).\n\n> A few of the things that I often do to mangle my branches are\n> listed.  Some of them are not application of \"git rebase\" in the\n> trivial form:\n>\n>  * I have a patch series (single strand of pearls).  I update on\n>    top of the updated upstream:\n>\n>     $ git rebase -i --onto master @{bottom}\n>     $ git range-diff @{bottom}@{1}..@{1} @{bottom}..HEAD\n>\n>    No, this is not what \"I often do\" yet, but I hope to see become\n>    doable.  Rebase the current branch from its bottom on top of the\n>    master, and then take the range diff between the old branch\n>    (i.e. @{bottom} refers to the bottom pointer, but because it is\n>    implemented as a ref, its reflog knows what the previous value of\n>    it was---@{bottom}@{1}..@{1} would be the range of commits on the\n>    branch before I did the above rebase) and the new one.\n\nThat would work only if the last update was a rebase. To make it work\nreliably we would need some sort of branchlog.\n\nPersonally I have a similar use case, but I want to use range-diff\nmainly before sending a patch series. What my tool `git send-series`\ndoes is store for example `refs/sent/test-aggregate/v2` and\n`refs/sent/test-aggregate/v2-tail`. Conceptually this is v2 of the\npatch series.\n\n>  * I have 7 patch series (single strand of pearls).  I only need to\n>    touch the top 3.\n>\n>     $ git rebase -i HEAD~3\n>     $ git range-diff @{1}...\n>\n>    In this case, I am not updating the bottom to HEAD~3 and reducing\n>    the branch into 3-patch series.  I am keeping the bottom of the\n>    branch, and the commits that happen to be updated are only the\n>    topmost 3.\n\nRight, maybe the base should be updated only when --onto is supplied,\nor perhaps even a new --base option so it's clear the user wants the\nnew behavior.\n\n>  * In the same situation, but the top 3 in the original are so bad\n>    that I am better off redoing them from scratch, taking advantage\n>    of new features in 'master'.\n>\n>     $ git checkout --detach master\n>     ... work on detached HEAD ...\n>     ... first pick the bottom commits ...\n>     $ git cherry-pick master..@{-1}~3\n>     ... still working on detached HEAD ...\n>     ... redo the topmost commits from scratch ...\n>     $ git range-diff master..@{-1} master..\n>     $ git checkout -B @{-1}\n>\n>    I do not mind \"checkout -B\" *not* learning any trick to\n>    automatically update the bottom pointer for the branch to\n>    'master' in this case, but I should be able to manually update\n>    the bottom of the branch easily.  Something like \"git checkout -B\n>    @{-1} --set-bottom=master\" might be acceptable here.\n\nYes, something like that would be needed.\n\nOne obvious use case for me is \"show me the current branch\", as in\n`git log @{base}..@`. Because `git log` is very efficient that's\nusually not necessary, but I often launch `gitk`, and it's annoying\nthat it tried to load *all* the commits reachable, wasting resources\nand polluting the view, which is why I started developing a tool that\nessentially did `gitk $1@{u}..$1`, but that quickly becomes complex if\nupstream isn't configured. With my tool I can do `git vs` (show the\ncurrent branch visually), or `git ls` (show the current branch on the\ncommand line).\n\nWeirdly enough, Mercurial's new topic extension has a command that\nshows precisely that `hg stack` shows only the commits on the current\ntopic (starting from a base).\n\nAnd this reminds me of the previous discussion: What actually is a branch? [2]\n\nIf we can agree that `branch@{base}..branch` semantically is\n*something* (whatever you want to call it), then it might make sense\nto have a way to refer to it, for example `branch^b` or `branch+`.\n\nThen interesting combinations immediately become obvious, for example your:\n\n    git range-diff @{bottom}@{1}..@{1} @@{bottom}..@\n\nBecomes:\n\n    git range-diff @{1}+ @+\n\nThen if we expand that we can see that @{base} should be an operation\non @{1} (@{1}@{base}), not the other way around.\n\n> IOW, I do not mind if maintenance of the bottom of the branch is not\n> always automatic (and prone to heuristic making an incorrect guess).\n> But I think we should make sure it is easy for the user to assist\n> the tool to maintain it correctly [*].\n>\n>     Side note: and that is what I find \"frustrating\" in the \"notes\"\n>     world.  \"notes\" can be copied after cherry-pick manually, but\n>     that is a very tedious process, and at some point, being \"merely\n>     possible\" stops to have much value, unless it is \"easily\n>     doable\".\n\nAgreed. Similarly, I did not start to use @{upstream} until it was easy to use.\n\nBut again: @{upstream} was not easy to use at the start, and @{base}\ndoesn't have to be either.\n\nI think the important thing to not forget is that this is useful\ninformation, and many would argue git is missing it.\n\nCheers.\n\n[1] https://lore.kernel.org/git/1398307491-21314-13-git-send-email-felipe.contreras@gmail.com/\n[2] https://lore.kernel.org/git/60e61bbd7a37d_3030aa2081a@natae.notmuch/\n\n-- \nFelipe Contreras\n"}]}