git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v2] git checkout -b: unparent the new branch with -o

From
Junio C Hamano <gitster@pobox.com>
Date
Mar 13, 2010, 09:10 UTC
Message-ID
<7v4okkegdy.fsf@alter.siamese.dyndns.org>
In-Reply-To
<7v8w9whd3g.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
Show 6 quoted lines
> As I already said, I do not think "mostly common paths" case should be
> encouraged to begin with.  As far as I know (and you can guess by now that
> I know reasonably well about git), you do not gain anything by not having
> the ancestry link between '?' and 'B', except that it would make conflict
> resolution at '*' extremely difficult.  There is only downside without any
> upside in "mostly common paths" disjoint merge.
There is one case "mostly common paths" disjoint history can be useful.

Imagine you have a hitherto proprietary software project and want to go open source. Perhaps your intention is to have an open source version and an enhanced commercial version. The project contains some third-party vendor software outside your control, and you have replaced them with open source equivalents or disabled features that depend on them.

Your history may look like this:
      o---o---A oss-base
     /
 ---o---o---o---o master

where master is the primary version you will continue shipping to your paying customers, with proprietary third-party components and features that depend on them. Commits on oss-base were your work to prepare the tree into a releasable shape, removing these proprietary stuff along with some features.

But you cannot publish oss-base (commit A) to the public. "git log" will show all the history that leads to it, with all the third-party stuff you do not have license to distribute in the source form. The older parts of the history may even have site password at customer installation you have committed by mistake and eradicated long time ago.

If you run this three command sequence (in this message, I am assuming that you keep the index and the working tree files intact in an updated implementation of --orphan, which is different from the suggestion to support "no common paths" case I mentioned in the previous message):

    $ git checkout --orphan oss oss-base
    $ git checkout oss-base
    $ git merge -s ours oss
you will get a history of this shape:
                X oss
                 \
      o---o---A---B oss-base
     /
 ---o---o---o---o master

with commits X, A and B all recording an identical tree. The oss branch (commit X) is now safe to publish.

Once you have done this, further you can:
    $ git checkout master
    $ git merge oss-base
which gives you a history of this shape:
                X oss
                 \
      o---o---A---B oss-base
     /             \
 ---o---o---o---o---Y master

This merge Y has to be done carefully. It inherently has to be an evil merge because oss-base wants to replace some proprietary stuff with open source counterparts while you may want to keep using the proprietary ones you have support contract for in your paying customer release you will make from the master branch. So at Y, you will most likely be reverting some work you did on oss-base branch since it forked from master.

After setting it up, this arrangement allows you to:
 - accept changes from public, and/or build changes for public, to advance
   "community version" on the oss branch on top of X;
 - from time to time, merge oss to oss-base;
 - from time to time, merge oss-base to master.
and the histories will continue like this:
                X---C---C---C---C oss
                 \           \
      o---o---A---B-----------* oss-base
     /             \           \ 
 ---o---o---o---o---Y---P---P---*---P---P master

with community commits C (either contributed from the public or you developed yourself and gave to the community) on oss branch, with proprietary commits P that record your own proprietary work on master branch. Note that oss-base branch is not used to produce nor record any commit on its own---it is merely to ease the merging from oss and master by providing X-B link to serve as a convenient common ancestor to make later merges easier.

Note also that it would be the most convenient if you kept both the index and the working tree intact, if "checkout --orphan" is to be used as an ingredient for this workflow. It _might_ actually make sense not to make the "git checkout --orphan" an independent feature that can be randomly abused or misused, but package the three-command sequence to create the A-B-X open triangle above into a separate command, i.e.

    $ git branch --orphan oss

would create a new branch "oss" with its own root commit X that records the same tree as the current HEAD A, and immediately merge X back into A to produce B, again recording the same tree, and advance the current HEAD to point at B, like so:

                                             X oss
                                              \
    ---o---A HEAD       -->         ---o---A---B HEAD
Previous: Junio C HamanoNext: Erick Mattos
Message 7 of 17 in “git checkout -b: unparent the new branch with -o”
  1. git checkout -b: unparent the new branch with -oErick Mattos, Mar 9, 2010
  2. Junio C HamanoMar 12, 2010
  3. Bert WesargMar 12, 2010
  4. David KågedalApr 27, 2010
  5. Erick MattosMar 12, 2010
  6. Junio C HamanoMar 13, 2010
  7. Junio C HamanoMar 13, 2010
  8. Erick MattosMar 14, 2010
  9. Junio C HamanoMar 15, 2010
  10. Erick MattosMar 16, 2010
  11. Jakub NarebskiMar 13, 2010
  12. Junio C HamanoMar 13, 2010
  13. Erick MattosMar 14, 2010
  14. Junio C HamanoMar 15, 2010
  15. Erick MattosMar 16, 2010
  16. Erick MattosMar 14, 2010
  17. Erick MattosMar 14, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.