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

Re: [BUG] Cannot push some grafted branches

From
Junio C Hamano <gitster@pobox.com>
Date
Dec 18, 2012, 16:09 UTC
Message-ID
<7vehinibpc.fsf@alter.siamese.dyndns.org>
In-Reply-To
<20121218120058.0c558ba5@chalon.bertin.fr>
Yann Dirson <dirson@bertin.fr> writes:
Show 19 quoted lines
> On Mon, 17 Dec 2012 13:14:56 -0800
> Junio C Hamano <gitster@pobox.com> wrote:
>
>> Andreas Schwab <schwab@linux-m68k.org> writes:
>> 
>> > Christian Couder <christian.couder@gmail.com> writes:
>> >
>> >> Yeah, at one point I wanted to have a command that created to craft a
>> >> new commit based on an existing one.
>> >
>> > This isn't hard to do, you only have to resort to plumbing:
>> >
>> > $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w
>> > bb45cc6356eac6c7fa432965090045306dab7026
>> 
>> Good.  I do not think an extra special-purpose command is welcome
>> here.
>
> Well, I'm not sure this is intuitive enough to be useful to the average user :)

I do not understand why you even want to go in the harder route in the first place, only to complicate things?

All you want to do is to craft a commit object that records a specific tree shape, has a set of parents you want, and has the log information you want. Once you have the commit, you can replace an unwanted commit with it.

    ----A----B----o---- ....
           X----Y----Z---- ....

Suppose you want to pretend that X is a child of A, even though it is not in the real life. So you want to create a commit that

    - has the same tree as X;
    - has A as its parent; and
    - records log and authorship of X.

and then use "git replace" to replace X, right? How about doing it this way?

    $ git checkout X^0 ;# detach
    $ git reset --soft A
    $ git commit -C X

The first gives you the index and the working tree that is the same as X, the second moves HEAD while keeping the index and the working tree so that the commit you create will be a child of A, and the last makes that commit with the metainformation from X [*1*]. If you want, you can even tweak the contents of the tree before making the commit in the final step, or tweak the log message during the final step.

Then you can take the resulting commit and replace X with it, no?
Alternatively, you can do:
    $ git checkout X^0 ;# detach
    $ git reset --soft B
    $ git commit --amend -C X

that is, find an existing commit B that has the desired set of parents, and amend it with the same tree and the metainformation as X. This would even work when you want to come up with a commit that replaces a merge. For example, if you want to pretend that B were a merge between A and X in the above topology, you could

    $ git checkout -b temp A
    $ git merge -s ours X ;# the recorded tree does not matter
    $ git checkout B^0 ;# detach
    $ git reset --soft temp
    $ git commit --amend -c B

which would create one merge that has the desired set of parents (i.e. A and X) in the first two steps on temp branch, prepares the index and the working tree to match the tree of B, and with that tree and the metainformation from B, amends that merge. The resulting commit will be a merge between A and X that has the tree of B and metainformation of B (with a chance to edit it further, as I used -c there).

Is this not intuitive enough?
[Footnote]

*1* If you are not tweaking the tree contents, you can do this all in the index without affecting the working tree, e.g.

    $ git checkout HEAD^0 ;# totally random state unrelated to X nor A
    $ git read-tree X ;# just update the index to match tree of X
    $ git reset --soft A ;# next commit will be child of A
    $ git commit -C X ;# and with metainformation from X

After you are done, you can "read-tree $branch" followed by "checkout $branch" to come back to where you were.

Previous: Jeff KingNext: Yann Dirson
Message 23 of 29 in “[BUG] Cannot push some grafted branches”
  1. Yann DirsonDec 11, 2012
  2. Junio C HamanoDec 11, 2012
  3. Yann DirsonDec 12, 2012
  4. Yann DirsonDec 12, 2012
  5. Junio C HamanoDec 12, 2012
  6. Yann DirsonDec 17, 2012
  7. Junio C HamanoDec 17, 2012
  8. Yann DirsonDec 17, 2012
  9. Thomas RastDec 17, 2012
  10. Yann DirsonDec 17, 2012
  11. Christian CouderDec 17, 2012
  12. Yann DirsonDec 17, 2012
  13. Andreas SchwabDec 17, 2012
  14. Junio C HamanoDec 17, 2012
  15. Yann DirsonDec 18, 2012
  16. Johannes SixtDec 18, 2012
  17. Thomas RastDec 18, 2012
  18. Yann DirsonDec 18, 2012
  19. Thomas RastDec 18, 2012
  20. Jeff KingDec 18, 2012
  21. Johannes SixtDec 19, 2012
  22. Jeff KingDec 19, 2012
  23. Junio C HamanoDec 18, 2012
  24. Yann DirsonDec 19, 2012
  25. Thomas RastDec 19, 2012
  26. Junio C HamanoDec 19, 2012
  27. Michael J GruberDec 21, 2012
  28. Junio C HamanoDec 21, 2012
  29. Michael J GruberDec 22, 2012

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.