threads / discuss / 3279

RE: What's in git.git

Subject: RE: What's in git.git

## tl;dr

6 messages between Feb 9, 2006 and Feb 14, 2006.

replies: 5people: 3as markdown or json

Luck, Tony· Feb 9, 2006, 23:49 UTC · lore
Looks very close to what I want.
> git checkout topic
> git format-patch --stdout origin > topic-diff
 topic-diff contains each commit as a separate message
> $VISUAL topic-diff
> # Fix comments
 so this needs some skill & care to rearrange the pieces
 and end up with legal input to git-am
Perhaps I'd like to have:
 git diff SHA-where-I-branched..HEAD
but I don't see the way to compute the SHA-where-I-branched
-Tony
Junio C Hamano· Feb 10, 2006, 00:28 UTC · re: Luck, Tony · lore

Re: What's in git.git

"Luck, Tony" <tony.luck@intel.com> writes:
Show 20 quoted lines
> Looks very close to what I want.
>
>> git checkout topic
>> git format-patch --stdout origin > topic-diff
>
>  topic-diff contains each commit as a separate message
>
>> $VISUAL topic-diff
>> # Fix comments
>
>  so this needs some skill & care to rearrange the pieces
>  and end up with legal input to git-am
>
> Perhaps I'd like to have:
>
>  git diff SHA-where-I-branched..HEAD
>
> but I don't see the way to compute the SHA-where-I-branched
>
> -Tony

If what you want to end up with is a single commit, that is easy.

If your topic branch is only "fork from master and never re-merge with master but just pile new commits on top of the tip, single strand of pearls" kind,

        git-merge-base master topic
would find the 'x' commit, where you forked from:
                           "master"
        ---x---o---o---o---o
            \
             o---o---o---o
                          "topic"

If you have "my topic will conflict with a change recently done in master so let's merge up from master to resolve conflict before going further" kind of merge commit on your topic branch, then you cannot have a single two-tree diff easily anyway, but in such a case, the following steps would work.

                           "master"
        ---o---o---o---o---o
            \       \
             o---o---*---o
                          "topic"
  (1) First merge "master" into "topic":
        $ git checkout topic
        $ git pull . master
                           "master"
        ---o---o---o---o---o
            \       \       \ 
             o---o---*---o---*
                             "topic"
      which would give you the rightmost '*' merge.
  (2) Extract diff from "master" to '*':
        $ git diff HEAD^2 HEAD >P.diff
      HEAD^1 is previous "topic" head and HEAD^2 is what you
      merged ("master").
  (3) Pick commits only on "topic" branch but not on "master"
        $ git rev-list --pretty --no-merges master..topic >P.log
      This will pick up the three 'o' commits on the lower
      development track and show their commit log message.
  (4) Reset the "topic" branch to "master", and do the squashed
      commit:
	$ git reset --hard master
        $ git apply --index P.diff
        $ git commit -F P.log -e

This obviously would work equally well for single strand of pearls case. Maybe you can package the above up, and send in a patch to add "git-squash" command?

Junio C Hamano· Feb 10, 2006, 00:35 UTC · re: Junio C Hamano · lore

Re: What's in git.git

Junio C Hamano <junkio@cox.net> writes:
Show 90 quoted lines
> "Luck, Tony" <tony.luck@intel.com> writes:
>
>> Looks very close to what I want.
>>
>>> git checkout topic
>>> git format-patch --stdout origin > topic-diff
>>
>>  topic-diff contains each commit as a separate message
>>
>>> $VISUAL topic-diff
>>> # Fix comments
>>
>>  so this needs some skill & care to rearrange the pieces
>>  and end up with legal input to git-am
>>
>> Perhaps I'd like to have:
>>
>>  git diff SHA-where-I-branched..HEAD
>>
>> but I don't see the way to compute the SHA-where-I-branched
>>
>> -Tony
>
> If what you want to end up with is a single commit, that is
> easy.
>
> If your topic branch is only "fork from master and never
> re-merge with master but just pile new commits on top of the
> tip, single strand of pearls" kind,
>
>         git-merge-base master topic
>
> would find the 'x' commit, where you forked from:
>
>                            "master"
>         ---x---o---o---o---o
>             \
>              o---o---o---o
>                           "topic"
>
> If you have "my topic will conflict with a change recently done
> in master so let's merge up from master to resolve conflict
> before going further" kind of merge commit on your topic branch,
> then you cannot have a single two-tree diff easily anyway, but
> in such a case, the following steps would work.
>
>                            "master"
>         ---o---o---o---o---o
>             \       \
>              o---o---*---o
>                           "topic"
>
>   (1) First merge "master" into "topic":
>
>         $ git checkout topic
>         $ git pull . master
>
>                            "master"
>         ---o---o---o---o---o
>             \       \       \ 
>              o---o---*---o---*
>                              "topic"
>
>       which would give you the rightmost '*' merge.
>
>   (2) Extract diff from "master" to '*':
>
>         $ git diff HEAD^2 HEAD >P.diff
>
>       HEAD^1 is previous "topic" head and HEAD^2 is what you
>       merged ("master").
>
>   (3) Pick commits only on "topic" branch but not on "master"
>
>         $ git rev-list --pretty --no-merges master..topic >P.log
>
>       This will pick up the three 'o' commits on the lower
>       development track and show their commit log message.
>
>
>   (4) Reset the "topic" branch to "master", and do the squashed
>       commit:
>
> 	$ git reset --hard master
>         $ git apply --index P.diff
>         $ git commit -F P.log -e
>
> This obviously would work equally well for single strand of
> pearls case.  Maybe you can package the above up, and send in a
> patch to add "git-squash" command?

I am stupid. (4) can be done a lot more easily. Do not do step (2) -- you do not need a diff at all. But do do step (3) to get the logs. Then:

	$ git reset --soft master
        $ git commit -F P.log -e

What --soft reset does is to keep the index and the working tree as is, but just change the current branch head to point at the named commit. So, immediately after the above soft reset, your commit ancestry graph looks like this:

                            "master"
         ---o---o---o---o---o
                            "topic"
and the last commit finally would give you:
                            "master"
         ---o---o---o---o---o
                             \
                              o
                              "topic"
Luck, Tony· Feb 14, 2006, 23:10 UTC · re: Junio C Hamano · lore

Re: What's in git.git

Show 23 quoted lines
> >   (1) First merge "master" into "topic":
> >
> >         $ git checkout topic
> >         $ git pull . master
> >
> >   (3) Pick commits only on "topic" branch but not on "master"
> >
> >         $ git rev-list --pretty --no-merges master..topic >P.log
> >
> >       This will pick up the three 'o' commits on the lower
> >       development track and show their commit log message.
> >
> >
> > This obviously would work equally well for single strand of
> > pearls case.  Maybe you can package the above up, and send in a
> > patch to add "git-squash" command?
> 
> I am stupid.  (4) can be done a lot more easily.  Do not do step
> (2) -- you do not need a diff at all.  But do do step (3) to get
> the logs.  Then:
> 
> 	$ git reset --soft master
>         $ git commit -F P.log -e

Yes, that all seems to work as advertised. One extra wrinkle was to preserve the author information by grepping out the last Author: line from the log. Here's the work-in-progress version of git-squash (I don't have a "master" branch, so I stuck in the "mbranch" shell variable so there is only one place for me to change ... to mbranch=linus).

Any style (or other) comments? If not I'll package into patch format with a manual page in a few days.

-Tony
#!/bin/sh
. git-sh-setup

branch="$1" mbranch=master

if [ ! -f .git/refs/heads/"$branch" ]
then
	die "Can't see branch '$branch'"
fi
if [ -f .git/refs/heads/"$branch"-unsquashed ]
then
	die "Branch '$branch' has been squashed before"
fi
cp .git/refs/heads/"$branch" .git/refs/heads/"$branch"-unsquashed
git checkout "$branch" || die "Couldn't checkout '$branch'"
git pull . $mbranch || die "Can't merge $mbranch into $branch"
git-rev-list --pretty --no-merges $mbranch..$branch > /tmp/git-squash-$$
git reset --soft $mbranch
author=$(sed -n -e  '/^Author: /s///p' /tmp/git-squash-$$ | tail -1)
git commit --author "$author" -F /tmp/git-squash-$$ -e
rm -f /tmp/git-squash-$$
Ryan Anderson· Feb 10, 2006, 00:40 UTC · re: Luck, Tony · lore

Re: What's in git.git

On Thu, Feb 09, 2006 at 03:49:16PM -0800, Luck, Tony wrote:
Show 12 quoted lines
> Looks very close to what I want.
> 
> > git checkout topic
> > git format-patch --stdout origin > topic-diff
> 
>  topic-diff contains each commit as a separate message
> 
> > $VISUAL topic-diff
> > # Fix comments
> 
>  so this needs some skill & care to rearrange the pieces
>  and end up with legal input to git-am

Doh, right, I was thinking "git apply" actually. (Apply the whole thing as single diff - the comments from each commit in the middle should get ignored.)

Note that I don't believe there is any need to combine the hunks, just stick them there in order and it *should* do the right thing.

Show 5 quoted lines
> Perhaps I'd like to have:
> 
>  git diff SHA-where-I-branched..HEAD
> 
> but I don't see the way to compute the SHA-where-I-branched
git-merge-base topic master ?
-- 
Ryan Anderson
  sometimes Pug Majere
Junio C Hamano· Feb 10, 2006, 00:46 UTC · re: Ryan Anderson · lore

Re: What's in git.git

Ryan Anderson <ryan@michonline.com> writes:
> Note that I don't believe there is any need to combine the hunks, just
> stick them there in order and it *should* do the right thing.

Probably not. I suspect it would not like two pieces of diffs touching the same path in a batch.

Feeding one at a time is OK, though.

← back to recent threads