{"thread":{"id":"59793","subject":"How to publish a fork","startedAt":"2023-05-26T11:13:59Z","lastAt":"2023-05-26T11:13:59Z","messageCount":1,"participants":["Sebastian Tennant"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"477732","messageId":"87pm6ne45u.fsf@sebyte.me","threadId":"59793","inReplyTo":null,"subject":"How to publish a fork","fromName":"Sebastian Tennant","fromEmail":"sdt@sebyte.me","sentAt":"2023-05-26T11:13:49Z","receivedAt":"2023-05-26T11:13:59Z","isPatch":false,"sender":{"key":"sdt@sebyte.me","avatar":null},"body":"Hello list,\n\nI wish to publish a fork of an upstream git repository (as a means of\ndistributing modifications to upstream across multiple machines).\n\nLet's call the publishing repo fork.git, the machine which hosts\nfork.git the fork host, and the machines which clone fork.git clients\nof the fork host.\n\nfork.git includes unmodified upstream branches and additional branches\nnot found upstream.  The additional branches all share a common\nnamespace; mod-*.  For example, mod-master is an additional branch\nbased on upstream branch master.  A cron job running on the fork host\nautomatically fetches from upstream every 30 minutes using a mirror\nrefspec, e.g. +refs/heads/master:refs/heads/master.  Clients of the\nfork host also use a mirror refspec for upstream branches and an\nordinary fetch refspec for the additional branches,\ne.g. +refs/heads/mod-master:refs/remotes/forkhost/mod-master.\n\nTo summarise, the resulting configs look something like this:\n\nFork host config (extract):\n--8<---------------cut here---------------start------------->8---\n[remote \"upstream\"]\n\turl = https://example.com/upstream.git\n\tfetch = +refs/heads/master:refs/heads/master\n--8<---------------cut here---------------end--------------->8---\n\nFork host client config (extract):\n--8<---------------cut here---------------start------------->8---\n[remote \"forkhost\"]\n\turl = https://fork.host/fork.git\n\tfetch = +refs/heads/master:refs/heads/master\n\tfetch = +refs/heads/mod-master:refs/remotes/forkhost/mod-master\n[branch \"mod-master\"]\n\tremote = forkhost\n\tmerge = refs/heads/mod-master\n--8<---------------cut here---------------end--------------->8---\n\nIn order to keep an additional branch up to date with upstream, a\nclient need only fetch from the fork host, rebase on the upstream\nbranch, and then push (back to the fork host).  For example:\n\n $ cd mod-master\n\n $ git fetch --verbose forkhost\n […]\n 4b3de748b0..f35648ba0c  master     -> master\n = [up to date]          mod-master -> forkhost/mod-master\n\n $ git status --short --branch\n ## mod-master...forkhost/mod-master\n\n $ git log --oneline ..master | wc -l\n 1\n\n $ git rebase master\n Successfully rebased and updated refs/heads/mod-master.\n\n $ git status --short --branch\n ## mod-master...forkhost/mod-master [ahead 3, behind 2]\n\nNote that, although there was only one ‘incoming’ commit, mod-master\nand forkhost/mod-master have diverged (by 3 and 2 commits\nrespectively).  This is because there were (and are) two commits on\nmod-master not found on master.\n\nAfter fetching, C is the ‘incoming’ commit:\n\n               master:  ---A---B---C\n\n           mod-master:  ---A---B---X---Y\n\n  forkhost/mod-master:  ---A---B---X---Y\n\nAfter reabsing:\n\n               master:  ---A---B---C\n\n           mod-master:  ---A---B---C---X'---Y'\n\n  forkhost/mod-master:  ---A---B---X---Y\n\nAs you can see, mod-master and forkhost/mod-master now diverge after B\n(by 3 and 2 commits respectively).\n\nThis means that when the client tries to push, the updates are\nrejected:\n\n $ git push\n To [forkhost]\n  ! [rejected]              mod-master -> mod-master (non-fast-forward)\n error: failed to push some refs to [forkhost]\n hint: Updates were rejected because the tip of your current branch is behind\n hint: its remote counterpart. Integrate the remote changes (e.g.\n hint: 'git pull ...') before pushing again.\n hint: See the 'Note about fast-forwards' in 'git push --help' for details.\n\nunless force is used:\n\n $ git push --force\n […]\n  + cbb90030a9...5299b8bf0d mod-master -> mod-master (forced update)\n\nIt is obviously dangerous and wrong for a client to use force every\ntime it pushes to fork.git.  What if the client failed to notice\nincoming commits on mod-master (as well as on master)?  Those missed,\nincoming commits might be irretrievably lost.\n\nSo, how should one _safely_ publish a fork?\n\nSebastian\n"}]}