{"thread":{"id":"60425","subject":"[PATCH] merge: --ff-one-only to apply FF if commit is one","startedAt":"2023-10-25T08:58:06Z","lastAt":"2023-11-01T23:05:32Z","messageCount":15,"participants":["Ruslan Yakauleu via GitGitGadget","Kristoffer Haugsbakk","Ruslan Yakauleu","Taylor Blau","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"483846","messageId":"pull.1599.git.git.1698224280816.gitgitgadget@gmail.com","threadId":"60425","inReplyTo":null,"subject":"[PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Ruslan Yakauleu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-10-25T08:58:00Z","receivedAt":"2023-10-25T08:58:06Z","isPatch":true,"sender":{"key":"ruslan.yakauleu@gmail.com","avatar":"https://gravatar.com/avatar/009e83bff73ed1a205cb2104df0c830c39f8a9b168bcfba36b0f2c08a4e6d30a?d=mp&s=160"},"body":"From: Ruslan Yakauleu <ruslan.yakauleu@gmail.com>\n\nA new option --ff-one-only to control the merging strategy.\nFor one commit option works like -ff to avoid extra merge commit.\nIn other cases the option works like --no-ff to create merge commit for\ncomplex features.\n\nSigned-off-by: Ruslan Yakauleu <ruslan.yakauleu@gmail.com>\n---\n    merge: --ff-one-only to apply FF if commit is one\n    \n    A new option --ff-one-only to control the merging strategy. For one\n    commit option works like -ff to avoid extra merge commit. In other cases\n    the option works like --no-ff to create merge commit for complex\n    features.\n    \n    Plenty of developers want to simplify merge history. We have two main\n    merging strategies:\n    \n     * Fast-forward (--ff) - There we can lose merge commits for complex\n       features and if we need to roll back some feature we can't revert\n       just one commit.\n     * Merge (--no-ff) - There we have extra merges for extra simple\n       changes.\n    \n    Before, the user had to choose between --ff/--no-ff every time to have\n    history without extra merges for simple changes and to use merges for\n    complex features.\n    \n    Ways to use the new option: git merge --ff-one-only git config merge.ff\n    one-only git config branch.master.mergeoptions --ff-one-only\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1599%2FQuAzI%2Fmerge%2Fff-one-only-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1599/QuAzI/merge/ff-one-only-v1\nPull-Request: https://github.com/git/git/pull/1599\n\n Documentation/config/merge.txt |  3 +++\n builtin/merge.c                | 18 +++++++++++++++++-\n 2 files changed, 20 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config/merge.txt b/Documentation/config/merge.txt\nindex 8851b6cedef..6cd5daa4d64 100644\n--- a/Documentation/config/merge.txt\n+++ b/Documentation/config/merge.txt\n@@ -31,6 +31,9 @@ merge.ff::\n \ta case (equivalent to giving the `--no-ff` option from the command\n \tline). When set to `only`, only such fast-forward merges are\n \tallowed (equivalent to giving the `--ff-only` option from the\n+\tcommand line). When set to `one-only`, fast-forward merge allowed\n+\tonly for one commit, in other way extra merge commit should be\n+\tcreated (equivalent to giving the `--ff-one-only` option from the\n \tcommand line).\n \n merge.verifySignatures::\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex d748d46e135..100f0021e56 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -110,7 +110,8 @@ static const char *pull_twohead, *pull_octopus;\n enum ff_type {\n \tFF_NO,\n \tFF_ALLOW,\n-\tFF_ONLY\n+\tFF_ONLY,\n+\tFF_ONE_ONLY\n };\n \n static enum ff_type fast_forward = FF_ALLOW;\n@@ -258,6 +259,7 @@ static struct option builtin_merge_options[] = {\n \t\tN_(\"edit message before committing\")),\n \tOPT_CLEANUP(&cleanup_arg),\n \tOPT_SET_INT(0, \"ff\", &fast_forward, N_(\"allow fast-forward (default)\"), FF_ALLOW),\n+\tOPT_SET_INT(0, \"ff-one-only\", &fast_forward, N_(\"allow fast-forward if only one commit\"), FF_ONE_ONLY),\n \tOPT_SET_INT_F(0, \"ff-only\", &fast_forward,\n \t\t      N_(\"abort if fast-forward is not possible\"),\n \t\t      FF_ONLY, PARSE_OPT_NONEG),\n@@ -631,6 +633,8 @@ static int git_merge_config(const char *k, const char *v,\n \t\t\tfast_forward = boolval ? FF_ALLOW : FF_NO;\n \t\t} else if (v && !strcmp(v, \"only\")) {\n \t\t\tfast_forward = FF_ONLY;\n+\t\t} else if (v && !strcmp(v, \"one-only\")) {\n+\t\t\tfast_forward = FF_ONE_ONLY;\n \t\t} /* do not barf on values from future versions of git */\n \t\treturn 0;\n \t} else if (!strcmp(k, \"merge.defaulttoupstream\")) {\n@@ -1527,6 +1531,18 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tfree(list);\n \t}\n \n+\tif (fast_forward == FF_ONE_ONLY) {\n+\t\tfast_forward = FF_NO;\n+\n+\t\t/* check that we have one and only one commit to merge */\n+\t\tif (squash || ((!remoteheads->next &&\n+\t\t\t\t!common->next &&\n+\t\t\t\toideq(&common->item->object.oid, &head_commit->object.oid)) &&\n+\t\t\t\toideq(&remoteheads->item->parents->item->object.oid, &head_commit->object.oid))) {\n+\t\t\tfast_forward = FF_ALLOW;\n+\t\t}\n+\t}\n+\n \tupdate_ref(\"updating ORIG_HEAD\", \"ORIG_HEAD\",\n \t\t   &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n \n\nbase-commit: 2e8e77cbac8ac17f94eee2087187fa1718e38b14\n-- \ngitgitgadget\n"},{"id":"483860","messageId":"da246287-8530-4680-8fcc-f68f881bc24b@app.fastmail.com","threadId":"60425","inReplyTo":"pull.1599.git.git.1698224280816.gitgitgadget@gmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2023-10-25T16:27:03Z","receivedAt":"2023-10-25T16:27:27Z","isPatch":true,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"Hi\n\nOn Wed, Oct 25, 2023, at 10:58, Ruslan Yakauleu via GitGitGadget wrote:\n> A new option --ff-one-only to control the merging strategy.\n> For one commit option works like -ff to avoid extra merge commit.\n> In other cases the option works like --no-ff to create merge commit for\n> complex features.\n\nI do something similar for my pull requests:\n\n- If more than one commit: `--no-ff`\n- One commit: rebase/squash\n\nYour change would (according to the commit message) only *not* create a\nmerge if it so happens to be the case that you can fast-forward the\nbranch. So it would create a merge commit if (say) your branch was three\ncommits behind and one ahead (your commit) of the target branch. But isn’t\nit fine to just rebase/squash in this case? That seems more general.\n\n(Maybe `--squash-one-only`.)\n\nBut it seems that your new option would work nicely with “semi-linear”\nmerges:[1]\n\n- Rebase on the target branch\n- `--ff-one-only`\n- Now you either get:\n  - a “semi-linear merge”; or\n  - a single commit (as opposed to a merge which joins together a branch\n    which is 0 behind and 1 ahead of the target branch)\n\n-- \nKristoffer\n"},{"id":"483862","messageId":"e38ebf04-cf92-c80b-3432-bf86ecda1054@gmail.com","threadId":"60425","inReplyTo":"da246287-8530-4680-8fcc-f68f881bc24b@app.fastmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Ruslan Yakauleu","fromEmail":"ruslan.yakauleu@gmail.com","sentAt":"2023-10-25T18:31:03Z","receivedAt":"2023-10-25T18:31:08Z","isPatch":true,"sender":{"key":"ruslan.yakauleu@gmail.com","avatar":"https://gravatar.com/avatar/009e83bff73ed1a205cb2104df0c830c39f8a9b168bcfba36b0f2c08a4e6d30a?d=mp&s=160"},"body":"Hi\n\nIf we use squash we will lose some context and occasionally, we need\nmultiple small features combined into one big release. We would rather\nnot mix it into one monolithic non-readable blob. For us, sometimes it\nis better to rebase something to make history more accurate than squash\neverything into one commit. We can use squash only for one story.\n\nAnyway, squash is a different feature.\nSame as rebase (of course we're doing the rebase before merge to clarify\nhistory and to make some regression tests)\n\nThen we have a set of branches. Some branches contain only one commit.\n\nFor example, we have 4 branches:\n- two commits\n- one commit\n- one commit\n- three commits\n\nWith --no-ff (only merges) we have next graph with extra merges (E', F')\nfor branches with one commit\n\n   B---C   E   F   G---H---I\n  /     \\ / \\ / \\ /         \\\nA-------D---E'--F'----------J\n\nWith --ff (fast-forward everything) we miss merge branches (D, J) and\nit's harder to fast revert some problematic releases properly, because\nit's not clear that commits G-H-I - is one release\n\nA---B---C---E---F---G---H---I\n\nStory which --ff-one-only should build without manual control\n\n   B---C           G---H---I\n  /     \\         /         \\\nA-------D---E---F-----------J\n\nThere we have merge commits (D, J) only for complex branches.\nBranches E and F fast-forwarded to prevent extra merges.\n\nSorry if my explanation isn't clear enough\n\n--\nRuslan\n"},{"id":"483866","messageId":"840358e1-05b4-4730-a89d-1efae568d04d@app.fastmail.com","threadId":"60425","inReplyTo":"e38ebf04-cf92-c80b-3432-bf86ecda1054@gmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2023-10-25T19:04:02Z","receivedAt":"2023-10-25T19:04:30Z","isPatch":true,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"On Wed, Oct 25, 2023, at 20:31, Ruslan Yakauleu wrote:\n> Hi\n>\n> If we use squash we will lose some context and occasionally, we need\n> multiple small features combined into one big release. We would rather\n> not mix it into one monolithic non-readable blob.\n\nThe only context you lose is the point where your branch started, if that\nmatters. (Later in the email you say that you rebase before you merge so\napparently it does not matter to you.)\n\nTo squash one single commit doesn’t make a “monolithic” commit—it is\nexactly as monolithic as the commit you started with.\n\n> For us, sometimes it is better to rebase something to make history more\n> accurate than squash everything into one commit. We can use squash only\n> for one story.\n\nNo, squash one single commit. Not multiple.\n\n> Anyway, squash is a different feature.  Same as rebase (of course we're\n> doing the rebase before merge to clarify history and to make some\n> regression tests)\n\nSquash and rebase are functionally identical in this case. And since you\nrebase before merge anyway it is identical to the flow of\n\n1. Rebase before merge\n2. Merge with your new option\n\nExcept you don’t have to split it into two steps.\n"},{"id":"483921","messageId":"877d95d2-b978-4fa7-8216-8743fe155019@gmail.com","threadId":"60425","inReplyTo":"c37ba153-7239-49ff-b40f-370bc695986e@gmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Ruslan Yakauleu","fromEmail":"ruslan.yakauleu@gmail.com","sentAt":"2023-10-26T13:40:02Z","receivedAt":"2023-10-26T13:40:08Z","isPatch":true,"sender":{"key":"ruslan.yakauleu@gmail.com","avatar":"https://gravatar.com/avatar/009e83bff73ed1a205cb2104df0c830c39f8a9b168bcfba36b0f2c08a4e6d30a?d=mp&s=160"},"body":" > Squash and rebase are functionally identical in this case.\nSorry, but for me `git merge --squash` doesn't work.\n\n\nCurrently, I have a global option --no-ff for master\n$ git config branch.master.mergeoptions --no-ff\nIn this way `git merge --squash` crashes with message\n > fatal: options '--squash' and '--no-ff.' cannot be used together\n\nIn other way it writes something like\n > Fast-forward\n > Squash commit -- not updating HEAD\nand... not updates parent branch.\n\nFor example, GitHub propose for PR's:\n- Create a merge commit - the same as `git merge --no-ff`\n- Rebase and merge - the same as `git rebase ...; git merge --ff-only`\n- Squash AND commit - like two different operations. So after squash we\nstill have to merge our commit properly into parent branch.\n\nThe new option just dynamically selects between --ff and --no-ff for\n`git merge`. Nothing else.\n\n-- \nRuslan\n"},{"id":"484144","messageId":"ZUALkdSJZ70+KBYq@nand.local","threadId":"60425","inReplyTo":"pull.1599.git.git.1698224280816.gitgitgadget@gmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2023-10-30T20:01:21Z","receivedAt":"2023-10-30T20:01:28Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"Hi Ruslan,\n\nOn Wed, Oct 25, 2023 at 08:58:00AM +0000, Ruslan Yakauleu via GitGitGadget wrote:\n> From: Ruslan Yakauleu <ruslan.yakauleu@gmail.com>\n>\n> A new option --ff-one-only to control the merging strategy.\n> For one commit option works like -ff to avoid extra merge commit.\n> In other cases the option works like --no-ff to create merge commit for\n> complex features.\n\nThis seems like a pretty niche feature to want to introduce a new option\nfor. I would imagine the alternative is something like:\n\n    ff=\"--no-ff\"\n    if test 1 -eq $(git rev-list @{u}..)\n    then\n        ff=\"--ff\"\n    fi\n\n    [on upstream @{u}]\n    git merge \"$ff\" \"$branch\"\n\nI don't have a great sense of how many users might want or benefit from\nsomething like this. My sense is that there aren't many, but I could\nvery easily be wrong here.\n\nIn any case, my sense is that this is probably too niche to introduce a\nnew command-line option just to implement this behavior when the above\nimplementation is pretty straightforward. Regardless, here's my review\nof the patch...\n\n> @@ -631,6 +633,8 @@ static int git_merge_config(const char *k, const char *v,\n>  \t\t\tfast_forward = boolval ? FF_ALLOW : FF_NO;\n>  \t\t} else if (v && !strcmp(v, \"only\")) {\n>  \t\t\tfast_forward = FF_ONLY;\n> +\t\t} else if (v && !strcmp(v, \"one-only\")) {\n> +\t\t\tfast_forward = FF_ONE_ONLY;\n\nThe configuration handling and documentation all look good.\n\n>  \t\t} /* do not barf on values from future versions of git */\n>  \t\treturn 0;\n>  \t} else if (!strcmp(k, \"merge.defaulttoupstream\")) {\n> @@ -1527,6 +1531,18 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n>  \t\tfree(list);\n>  \t}\n>\n> +\tif (fast_forward == FF_ONE_ONLY) {\n> +\t\tfast_forward = FF_NO;\n> +\n> +\t\t/* check that we have one and only one commit to merge */\n> +\t\tif (squash || ((!remoteheads->next &&\n> +\t\t\t\t!common->next &&\n> +\t\t\t\toideq(&common->item->object.oid, &head_commit->object.oid)) &&\n> +\t\t\t\toideq(&remoteheads->item->parents->item->object.oid, &head_commit->object.oid))) {\n> +\t\t\tfast_forward = FF_ALLOW;\n> +\t\t}\n\nAnd this rather long conditional looks right, too. This patch could\ndefinitely benefit from some tests, though...\n\nThanks,\nTaylor\n"},{"id":"484169","messageId":"xmqq1qdb8wzk.fsf@gitster.g","threadId":"60425","inReplyTo":"ZUALkdSJZ70+KBYq@nand.local","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-10-31T00:19:11Z","receivedAt":"2023-10-31T00:19:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Taylor Blau <me@ttaylorr.com> writes:\n\n> This seems like a pretty niche feature to want to introduce a new option\n> for. I would imagine the alternative is something like:\n>\n>     ff=\"--no-ff\"\n>     if test 1 -eq $(git rev-list @{u}..)\n>     then\n>         ff=\"--ff\"\n>     fi\n>\n>     [on upstream @{u}]\n>     git merge \"$ff\" \"$branch\"\n>\n> I don't have a great sense of how many users might want or benefit from\n> something like this. My sense is that there aren't many, but I could\n> very easily be wrong here.\n\nAnother more fundamental objection is \"Why do we special case only a\nsingleton commit?\"\n\nWhy isn't a trivial two-patch series also OK to fast-forward?\nThree?  There is no inherent reason to draw a line on one commit\ntopic---given that a single commit could be a large and involved one\nthat could have been a multi commmit series.\n\nAnd you cannot decide if the \"topic\" is large enough to deserve a\nbinding merge commit even if it is a single commit topic, or if is\nsmall enough and you want to allow fast-forward, without looking at\nit first.  So from that point of view, too, I do not think this new\noption is a good idea.  Let's not add an option to encourage a bad\ndiscipline.\n\nThanks.\n\n\n"},{"id":"484191","messageId":"9f584927-7506-421e-a363-953eebb0ef90@gmail.com","threadId":"60425","inReplyTo":"xmqq1qdb8wzk.fsf@gitster.g","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Ruslan Yakauleu","fromEmail":"ruslan.yakauleu@gmail.com","sentAt":"2023-10-31T05:48:40Z","receivedAt":"2023-10-31T05:48:46Z","isPatch":true,"sender":{"key":"ruslan.yakauleu@gmail.com","avatar":"https://gravatar.com/avatar/009e83bff73ed1a205cb2104df0c830c39f8a9b168bcfba36b0f2c08a4e6d30a?d=mp&s=160"},"body":"Hi Junio,\n\nCommand of developers can decide which policy use and why.\nIf a team decides to avoid extra merges - why not?\n\n > a single commit could be a large and involved\nCreate one non-reviewable commit or losing feature scope is much worse\npractice\n\nFor me `git log --graph` is the most representative form to describe\nwhat's going on with a project and I prefer not to complicate it. But\nit must show changes properly.\n\n--ff-one-only is handy for keeping the appearance of a linear commit\nhistory and makes merge commit messages (from other branches) more\nmeaningful because they actually do represent some branch being folded\ninto the master.\n\nAs an example, merge commit for one commit is overkill and doesn't bring\nnew meaning. All one-commit meanings described in the commit message. In\nthis case extra branching (extra merges) just adds confusion. Plenty of\nextra merges turns into merge hell when you have countless merge messages,\nbut you can't get sense what's going on with project.\n\nPeople use rebase and fast-forward to make commit history more linear,\navoid merge hell and keep the repository tree clear - it's fine.\nBut it's a big mistake to merge complex features as one non-reviewable\ncommit. And even worse to make all history absolutely linear when you\ncan't find where a complex feature starts and where it finishes. If it\nwasn't combined in a special branch, it looks in the main branch like a\nset of different, not connected features.\nIn the case of problems with absolutely linear history, you don't know\nhow many commits you have to revert.\nIn case when one commit (merge commit for complex features) brings all\nchanges into the main branch - you know that you can revert feature or,\nfor complex changes, even part of a specific feature. You can revert just\nA/B tests for example, if you don't need them anymore but keep complex\nfeatures - this case makes squash even more useless.\nYou can try to use branch names to find where each branch merged into the\nmain branch, but it's not as descriptive as a graph and every so often you\ncan lose branch names. As an example, GitLab has an option \"Delete source\nbranch when merge request accepted\" and many teams use it.\n\n--\nRuslan\n\n"},{"id":"484194","messageId":"xmqqwmv32ukp.fsf@gitster.g","threadId":"60425","inReplyTo":"9f584927-7506-421e-a363-953eebb0ef90@gmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-10-31T06:07:50Z","receivedAt":"2023-10-31T06:18:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ruslan Yakauleu <ruslan.yakauleu@gmail.com> writes:\n\n> Command of developers can decide which policy use and why.\n> If a team decides to avoid extra merges - why not?\n\nI never said \"--ff\" is a bad option that should not exist, and I am\nnot sure why I had to be thrown such a rhetorical question at.\n"},{"id":"484196","messageId":"f99b99ed-1e24-49fc-9d61-2cdddf0fe860@gmail.com","threadId":"60425","inReplyTo":"ZUALkdSJZ70+KBYq@nand.local","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Ruslan Yakauleu","fromEmail":"ruslan.yakauleu@gmail.com","sentAt":"2023-10-31T06:01:31Z","receivedAt":"2023-10-31T06:18:53Z","isPatch":true,"sender":{"key":"ruslan.yakauleu@gmail.com","avatar":"https://gravatar.com/avatar/009e83bff73ed1a205cb2104df0c830c39f8a9b168bcfba36b0f2c08a4e6d30a?d=mp&s=160"},"body":"Hi Taylor,\n\nThank you so much for the review and feedback.\n\nWe use a mixed environment (Linux, MacOS and Windows) on\nmultiple projects. And some members can work some days from home and\nsome days from the office (on different PC).\nSo, using of scripts a bit uncomfortable.\n\nBetter to apply once for everybody in the domain\ngit config --global merge.ff one-only\n\nI'll try to fill the proper test a bit later.\n\n--\nRuslan\n\n\n"},{"id":"484222","messageId":"cb166ed4-b8b5-4120-b546-e878445573b6@app.fastmail.com","threadId":"60425","inReplyTo":"xmqq1qdb8wzk.fsf@gitster.g","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2023-10-31T08:32:55Z","receivedAt":"2023-10-31T08:33:20Z","isPatch":true,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"On Tue, Oct 31, 2023, at 01:19, Junio C Hamano wrote:\n> Another more fundamental objection is \"Why do we special case only a\n> singleton commit?\"\n>\n> Why isn't a trivial two-patch series also OK to fast-forward?\n> Three?  There is no inherent reason to draw a line on one commit\n> topic---given that a single commit could be a large and involved one\n> that could have been a multi commmit series.\n\nI think it’s about the `--first-parent` view. Then you get a one-commit\nview of each pull request that was merged. For a merge commit it serves as\na summary of multiple commits. And a merge commit of one commit would\nserve as a summary of one commit. So in that case you remove that extra\nlevel of indirection.\n\n> And you cannot decide if the \"topic\" is large enough to deserve a\n> binding merge commit even if it is a single commit topic, or if is\n> small enough and you want to allow fast-forward, without looking at\n> it first.\n\nBut the pull request is already given: it either has one commit or\nseveral. And you can for sure look at it and either argue that it should\nbe reduced (squashed) to one commit or maybe expanded (split out) into\nseveral commits.\n\nThe point at which you use such a merge feature is when you are already\nhappy with the pull request (or patch series or whatever else). And then\nyou (according to this strategy) prefer to avoid merge commits for\nsingle-commit pull requests.\n\n— —\n\nThis is not an argument for making this a built-in strategy. Just an\nexplanation from my vantage point.\n\n-- \nKristoffer Haugsbakk\n"},{"id":"484274","messageId":"xmqqa5ryxn8i.fsf@gitster.g","threadId":"60425","inReplyTo":"cb166ed4-b8b5-4120-b546-e878445573b6@app.fastmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-01T01:42:53Z","receivedAt":"2023-11-01T01:43:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Kristoffer Haugsbakk\" <code@khaugsbakk.name> writes:\n\n> I think it’s about the `--first-parent` view. Then you get a one-commit\n> view of each pull request that was merged. For a merge commit it serves as\n> a summary of multiple commits. And a merge commit of one commit would\n> serve as a summary of one commit. So in that case you remove that extra\n> level of indirection.\n\nYeah, I understand that position very well. After all, I was heavily\ninvolved in the introduction of the first-parent view to the system\nat around 0053e902 (git-log --first-parent: show only the first\nparent log, 2007-03-13).  Soon after that, d66424c4 (git-merge: add\n--ff and --no-ff options, 2007-09-24) added --no-ff to make it easier\nto maintain the first-parent worldview.\n\nStrictly speaking, the log message on a merge commit serves two\npurposes, one is to summarize commit(s) on the side branch that gets\nmerged with the merge, and as you said above, it is not needed when\nmerging a topic with just one commit.  But the other is to justify\nwhy the topic suits the objective of the line of history (which is\nneeded even when merging a single commit topic---imagine a commit\nthat is not incorrect per-se.  It may or may not be suitable for the\nmaintenance track, and a merge commit of such a commit into the\ntrack can explain if/how the commit being merged is maint-worthy).\n\nA project that does not need the latter can do without a \"--no-ff\"\nmerge of a single commit topic.\n\n> But the pull request is already given: it either has one commit or\n> several. And you can for sure look at it and either argue that it should\n> be reduced (squashed) to one commit or maybe expanded (split out) into\n> several commits.\n>\n> The point at which you use such a merge feature is when you are already\n> happy with the pull request (or patch series or whatever else). And then\n> you (according to this strategy) prefer to avoid merge commits for\n> single-commit pull requests.\n\nBut that argues against the \"--ff-one-only\" option, doesn't it?\n\nIf you looked at the side branch before you decide to merge it, you\nknow if the topic has only one commit (in which case you decide not\nto use \"--no-ff\"), or if the topic consists of multiple commits (in\nwhich case you decide to use \"--no-ff\").  And the only effect to\nhave the \"--ff-one-only\" option is to allow you *not* to look at\nwhat is on the side branch.\n\nThanks.\n\n"},{"id":"484286","messageId":"aa3559d6-0e05-4c7a-818e-8a0cb05e908b@gmail.com","threadId":"60425","inReplyTo":"xmqqa5ryxn8i.fsf@gitster.g","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Ruslan Yakauleu","fromEmail":"ruslan.yakauleu@gmail.com","sentAt":"2023-11-01T06:34:15Z","receivedAt":"2023-11-01T06:34:21Z","isPatch":true,"sender":{"key":"ruslan.yakauleu@gmail.com","avatar":"https://gravatar.com/avatar/009e83bff73ed1a205cb2104df0c830c39f8a9b168bcfba36b0f2c08a4e6d30a?d=mp&s=160"},"body":" > And the only effect to have the \"--ff-one-only\" option is to allow\n > you *not* to look at what is on the side branch.\n\nMoreover, it allows not to forget choose the right way and allow use\na lot of external tools (GitExtensions for example) as not all in command\nare console ninja\n\nCurrently, when complex features merged with --ff accidentally we have\nto do in main branch something like\n$ git reset ...\n$ git checkout <some_old_commit_which_we_have_to_find>\n$ git merge --no-ff <latest commit>\n$ git push --force\n\nAnd that's what I prefer to avoid\n\n--\nRuslan\n"},{"id":"484288","messageId":"a457e24c-3375-49c6-8cf7-d2dd945827fe@app.fastmail.com","threadId":"60425","inReplyTo":"xmqqa5ryxn8i.fsf@gitster.g","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2023-11-01T10:09:34Z","receivedAt":"2023-11-01T10:10:26Z","isPatch":true,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"On Wed, Nov 1, 2023, at 02:42, Junio C Hamano wrote:\n> Strictly speaking, the log message on a merge commit serves two\n> purposes, one is to summarize commit(s) on the side branch that gets\n> merged with the merge, and as you said above, it is not needed when\n> merging a topic with just one commit.  But the other is to justify\n> why the topic suits the objective of the line of history (which is\n> needed even when merging a single commit topic---imagine a commit\n> that is not incorrect per-se.  It may or may not be suitable for the\n> maintenance track, and a merge commit of such a commit into the\n> track can explain if/how the commit being merged is maint-worthy).\n\nYes. If you have multiple release/maintenance branches which you need to\napply something to then you can’t use this .\n\n>> The point at which you use such a merge feature is when you are already\n>> happy with the pull request (or patch series or whatever else). And then\n>> you (according to this strategy) prefer to avoid merge commits for\n>> single-commit pull requests.\n>\n> But that argues against the \"--ff-one-only\" option, doesn't it?\n>\n> If you looked at the side branch before you decide to merge it, you\n> know if the topic has only one commit (in which case you decide not\n> to use \"--no-ff\"), or if the topic consists of multiple commits (in\n> which case you decide to use \"--no-ff\").  And the only effect to\n> have the \"--ff-one-only\" option is to allow you *not* to look at\n> what is on the side branch.\n\nNo. The only effect is that you streamline the process of “decide not to\nuse `--no-ff`” since the strategy does it for you.\n\nIt would act like a small `git my-merge` alias. That is all.\n\n-- \nKristoffer Haugsbakk\n"},{"id":"484317","messageId":"xmqqv8aloz0q.fsf@gitster.g","threadId":"60425","inReplyTo":"a457e24c-3375-49c6-8cf7-d2dd945827fe@app.fastmail.com","subject":"Re: [PATCH] merge: --ff-one-only to apply FF if commit is one","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-01T23:05:25Z","receivedAt":"2023-11-01T23:05:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Kristoffer Haugsbakk\" <code@khaugsbakk.name> writes:\n\n> On Wed, Nov 1, 2023, at 02:42, Junio C Hamano wrote:\n>> Strictly speaking, the log message on a merge commit serves two\n>> purposes, one is to summarize commit(s) on the side branch that gets\n>> merged with the merge, and as you said above, it is not needed when\n>> merging a topic with just one commit.  But the other is to justify\n>> why the topic suits the objective of the line of history (which is\n>> needed even when merging a single commit topic---imagine a commit\n>> that is not incorrect per-se.  It may or may not be suitable for the\n>> maintenance track, and a merge commit of such a commit into the\n>> track can explain if/how the commit being merged is maint-worthy).\n>\n> Yes. If you have multiple release/maintenance branches which you need to\n> apply something to then you can’t use this .\n\nOK.  I do not mind a feature to help maintain the first-parent worldview\nbetter to exist, but have a few comments on the patch.\n\n * Nowhere in the name of feature --ff-one-only, the proposed commit\n   log message, added documentation and in-code comments, it is made\n   clear to readers that it is to maintain the first-parent view\n   better.  The \"first-parent\" was only brought up between you and I\n   as our conjecture on what the feature is for.  The should explain\n   the feature a bit better to our readers and users.\n\n   SIDE NOTE: in general, it is not the best way to name and explain\n   a feature after what it does (e.g., \"fast-forward only when it\n   has one commit\"); it is better to include why the user want it to\n   do what it does.  It it especially true because \"fast-forward\n   only when the other branch is ahead by one commit\" may later turn\n   out not to be the best design to ensure \"maintain first-parent\n   worldview\", if the latter is what the feature is really about.\n\n * The proposed commit log message needs a bit of proofreading and\n   polishing, paying attention to the grammar.\n\n * The \"allow fast-forward only when the other branch is ahead by\n   one commit\" design misses an important case you would want to,\n   and you can detect easily, fast-forward.\n\n   Imagine that a developer has a rather complex topic with multiple\n   commits, asks the maintainer (or the auto-merger at their forge)\n   to pull, but due to modification on the upstream side, there are\n   heavy conflicts.  The maintainer can tell (and Git was designed\n   to support this mode of operation better---it is called\n   \"distributed development\") the developer: \n\n       Since you know your topic much better than I do, can you do\n       the merge into the upstream for me?\n\n   The contributor would then help the maintainer, perhaps like so:\n\n    $ git checkout origin/main\n    $ git merge [--no-ff] my-topic\n\n   to pretend as if the contributer were the maintainer, merge and\n   resolve the conflicts, and then summarizes the topic in the log\n   message of the merge commit.  The contributor then updates their\n   topic locally, perhaps with\n\n    $ git push . HEAD:my-topic\n\n   which would of course fast-forward, and then ask the maintainer\n   (or the auto-merger at their forge) to pull again from \"my-topic\".\n\n   Now, the updated \"my-topic\" is ahead of the origin by many\n   commits (i.e., the number of commits on the topic, plus the merge\n   commit the controbutor created to help the maintainer), but if we\n   want to see the resulting history as if the original pull request\n   was handled with the \"--ff-one-only\" option by the maintainer who\n   did the merge themself, then we should fast-forward this merge.\n   Even though the tip commit of \"my-topic\" has more commits behind\n   it, it is already the binding merge of the side topic that\n   \"--ff-one-only\" would have forced to create if the maintainer did\n   the merge.\n\n   So, a better design than \"allow fast-forward, only if the branch\n   being merged is ahead by one commit\" is to allow fast-forward\n   when the branch's first-parent is the current tip of the branch\n   pull/merge is trying to update.  \"only by one commit\" can be\n   handled as a natural degenerate case of this more general\n   criteria, and a good thing is that it is much easier and more\n   efficient to compute (i.e., in \"git merge OTHER\", allow ff if\n   \"OTHER^1\" and \"HEAD\" are the same).\n\nAs I said, I do not mind a feature to help maintain the first-parent\nworldview better to exist; thanks for working on the topic.\n"}]}