threads / discuss / 19313

How to create a new commit with the content of some commit?

Subject: How to create a new commit with the content of some commit?

## tl;dr

10 messages between May 12, 2009 and May 13, 2009.

replies: 9people: 5as markdown or json

Ping Yin· May 12, 2009, 14:35 UTC · lore
a----b
 \----c

Given the graph above, I want to create a commit b1 on top of c, where b1 and b have the same content. i.e.

a----b
 \----c----b1    ( content(b) == content(b1) )
If there are no untracked files in the working directory, i can do

git checkout b git reset c git add . git commit -m "the copy of b"

Is there any simpler way? And if there are untracked files in the working directory, how to do it?

Ping Yin
Ping Yin· May 12, 2009, 15:47 UTC · re: Ping Yin · lore

Re: How to create a new commit with the content of some commit?

On Tue, May 12, 2009 at 10:35 PM, Ping Yin <pkufranky@gmail.com> wrote:
Show 8 quoted lines
> a----b
>  \----c
>
> Given the graph above, I want to create a commit b1 on top of c, where
> b1 and b have the same content. i.e.
>
> a----b
>  \----c----b1    ( content(b) == content(b1) )
More precisely, b1 and b point to the same tree object
Tomas Carnecky· May 12, 2009, 16:04 UTC · re: Ping Yin · lore

Re: How to create a new commit with the content of some commit?

On May 12, 2009, at 5:47 PM, Ping Yin wrote:
Show 13 quoted lines
> On Tue, May 12, 2009 at 10:35 PM, Ping Yin <pkufranky@gmail.com>  
> wrote:
>> a----b
>>  \----c
>>
>> Given the graph above, I want to create a commit b1 on top of c,  
>> where
>> b1 and b have the same content. i.e.
>>
>> a----b
>>  \----c----b1    ( content(b) == content(b1) )
>
> More precisely, b1 and b point to the same tree object

git checkout c git cherry-pick b

tom
Sitaram Chamarty· May 13, 2009, 14:36 UTC · re: Tomas Carnecky · lore

Re: How to create a new commit with the content of some commit?

On 2009-05-12, Tomas Carnecky <tom@dbservice.com> wrote:
Show 19 quoted lines
>
> On May 12, 2009, at 5:47 PM, Ping Yin wrote:
>
>> On Tue, May 12, 2009 at 10:35 PM, Ping Yin <pkufranky@gmail.com>  
>> wrote:
>>> a----b
>>>  \----c
>>>
>>> Given the graph above, I want to create a commit b1 on top of c,  
>>> where
>>> b1 and b have the same content. i.e.
>>>
>>> a----b
>>>  \----c----b1    ( content(b) == content(b1) )
>>
>> More precisely, b1 and b point to the same tree object
>
> git checkout c
> git cherry-pick b

I do not think this does what was wanted. Applying the change from a->b onto c may not give you "b" unless a==c.

Junio C Hamano· May 12, 2009, 15:59 UTC · re: Ping Yin · lore

Re: How to create a new commit with the content of some commit?

Ping Yin <pkufranky@gmail.com> writes:
Show 8 quoted lines
> a----b
>  \----c
>
> Given the graph above, I want to create a commit b1 on top of c, where
> b1 and b have the same content. i.e.
>
> a----b
>  \----c----b1    ( content(b) == content(b1) )
On "c", you can:
    git read-tree -m -u b
    git commit
I think with newer git you can say
    git reset --merge b
    git commit
instead, to save some typing.
Ping Yin· May 12, 2009, 16:38 UTC · re: Junio C Hamano · lore

Re: How to create a new commit with the content of some commit?

On Tue, May 12, 2009 at 11:59 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 15 quoted lines
> Ping Yin <pkufranky@gmail.com> writes:
>
>> a----b
>>  \----c
>>
>> Given the graph above, I want to create a commit b1 on top of c, where
>> b1 and b have the same content. i.e.
>>
>> a----b
>>  \----c----b1    ( content(b) == content(b1) )
>
> On "c", you can:
>
>    git read-tree -m -u b
>    git commit
is -u necessary?
Show 6 quoted lines
>
> I think with newer git you can say
>
>    git reset --merge b
>    git commit
>

When the working directory is clean, it seems "reset --hard" and "reset --merge" behave the same. So after "git reset --merge b", the HEAD is moved to b, and i have nothing to commit.

Jeff King· May 12, 2009, 16:07 UTC · re: Ping Yin · lore

Re: How to create a new commit with the content of some commit?

On Tue, May 12, 2009 at 10:35:30PM +0800, Ping Yin wrote:
Show 18 quoted lines
> a----b
>  \----c
> 
> Given the graph above, I want to create a commit b1 on top of c, where
> b1 and b have the same content. i.e.
> 
> a----b
>  \----c----b1    ( content(b) == content(b1) )
> 
> If there are no untracked files in the working directory, i can do
> 
> git checkout b
> git reset c
> git add .
> git commit -m "the copy of b"
> 
> Is there any simpler way? And if there are untracked files in the
> working directory, how to do it?

You can just munge the index directly, and skip the working tree entirely:

  rm .git/index
  git read-tree b
  git commit -m 'the copy of b'

You would probably want to "git checkout -f" afterwards to update the working tree with what's in the index.

You can also do it without even touching the index by using the commit plumbing:

  echo 'copy of b' >message
  tree=`git rev-parse b^{tree}`
  commit=`git commit-tree $tree -p c <message`
  git update-ref c $commit
-Peff
Ping Yin· May 12, 2009, 16:43 UTC · re: Jeff King · lore

Re: How to create a new commit with the content of some commit?

On Wed, May 13, 2009 at 12:07 AM, Jeff King <peff@peff.net> wrote:
Show 27 quoted lines
> On Tue, May 12, 2009 at 10:35:30PM +0800, Ping Yin wrote:
>
>> a----b
>>  \----c
>>
>> Given the graph above, I want to create a commit b1 on top of c, where
>> b1 and b have the same content. i.e.
>>
>> a----b
>>  \----c----b1    ( content(b) == content(b1) )
>>
>> If there are no untracked files in the working directory, i can do
>>
>> git checkout b
>> git reset c
>> git add .
>> git commit -m "the copy of b"
>>
>> Is there any simpler way? And if there are untracked files in the
>> working directory, how to do it?
>
> You can just munge the index directly, and skip the working tree
> entirely:
>
>  rm .git/index
>  git read-tree b
>  git commit -m 'the copy of b'

In a non-conflict status, "git read-tree b" will update the index to full match the tree of b, so "rm .git/index" is unnecessary, right?

Show 7 quoted lines
> You can also do it without even touching the index by using the commit
> plumbing:
>
>  echo 'copy of b' >message
>  tree=`git rev-parse b^{tree}`
>  commit=`git commit-tree $tree -p c <message`
>  git update-ref c $commit
Nice solution. Thank you and thank so powerful git!
Maybe a -c option can be added to git-commit-tree?
Jeff King· May 12, 2009, 16:51 UTC · re: Ping Yin · lore

Re: How to create a new commit with the content of some commit?

On Wed, May 13, 2009 at 12:43:33AM +0800, Ping Yin wrote:
Show 9 quoted lines
> > You can just munge the index directly, and skip the working tree
> > entirely:
> >
> >  rm .git/index
> >  git read-tree b
> >  git commit -m 'the copy of b'
> 
> In a non-conflict status, "git read-tree b" will update the index to
> full match the tree of b, so "rm .git/index" is unnecessary, right?

For some reason, I was thinking that entries in the index that were not in "b" would remain, but that is not actually the case. So yes, I think you can do it without removing the index (and you are better off to do so, since the index also contains the stat cache for your worktree, so it is more efficient).

You can also add "-u" as Junio suggested to update the working tree during that step, which should be more efficient.

Show 6 quoted lines
> >  echo 'copy of b' >message
> >  tree=`git rev-parse b^{tree}`
> >  commit=`git commit-tree $tree -p c <message`
> >  git update-ref c $commit
> 
> Maybe a -c option can be added to git-commit-tree?

I doubt there is much interest in that, as commit-tree is meant to be a low-level building block, not a user tool. If you wanted to pull the message from another commit, you could just do:

  git cat-file commit b | sed '1,/^$/d' | git commit-tree ...
-Peff
Ping Yin· May 12, 2009, 16:59 UTC · re: Jeff King · lore

Re: How to create a new commit with the content of some commit?

On Wed, May 13, 2009 at 12:51 AM, Jeff King <peff@peff.net> wrote:
Show 20 quoted lines
> On Wed, May 13, 2009 at 12:43:33AM +0800, Ping Yin wrote:
>
>> > You can just munge the index directly, and skip the working tree
>> > entirely:
>> >
>> >  rm .git/index
>> >  git read-tree b
>> >  git commit -m 'the copy of b'
>>
>> In a non-conflict status, "git read-tree b" will update the index to
>> full match the tree of b, so "rm .git/index" is unnecessary, right?
>
> For some reason, I was thinking that entries in the index that were not
> in "b" would remain, but that is not actually the case. So yes, I think
> you can do it without removing the index (and you are better off to do
> so, since the index also contains the stat cache for your worktree, so
> it is more efficient).
>
> You can also add "-u" as Junio suggested to update the working tree
> during that step, which should be more efficient.

I don't want to touch the working directory, and -m will keep the stat cache in the index, so i think "git read-tree -m b" is the best.

← back to recent threads