Git development
 help / color / mirror / Atom feed
* Re: several quick questions
From: Nicolas Vilz 'niv' @ 2006-02-14 21:30 UTC (permalink / raw)
  To: git
In-Reply-To: <43F20D4B.3060606@op5.se>

Andreas Ericsson wrote:
> 
> git will recognize the merge-base as being the current HEAD and simply
> sets HEAD to point to that of topic-branch. This is why it's called a
> fast-forward, since no heavy computing needs to be done to combine the
> two development tracks.

well finaly, if nothing happened in one of the lines, then the two lines
become the same, when merging back into one line. and the two lines
overlay each other. That is what i saw during playing with git-merge,
git-pull and git-reset.. ok.

> 
>> do you have to make a new private branch out of the tag 1.1.6?
>>
> 
> No, you don't, but you can if you wish. It's nifty if you want to fork
> the development from a particular branch. In your case, if you really,
> really *want* the arrows pointing to one line, you can do
> 
> $ git branch topic-branch HEAD^
> # work, work, work
> $ git checkout master
> $ git pull . topic-branch
> 
> That would create one pretty arrow. When multiple tracks of development
> (rather than just two) are combined into one it's called an octopus
> merge. Unless you really know what you're doing, you should try to avoid
> those for small projects, and doing it just for the pretty arrows is....
> well, let's call it "interesting from the behaviour science scholars
> point of view".

its just the thought "cool, it looks like there at the git repo"... just
to realize "ok, that happens, when i merge two trees.

>> i used svn and there i could go back some revisions. I haven't found
>> such a feature in git, yet... but i think i am blind all the time.
>>
> 
> Most likely. I believe at least the reset command is mentioned in the
> tutorial. I trust you've read it before asking, so something is amiss
> either with your eyesight or the tutorial.

well the namespace of the references confused me, before i realized,
that HEAD finally points to an sha1sum (which symbolizes a certain commit)

mh.. I use pull if i want to get an external development tree, right? I
still search for a possibility to replace the svn:externals, which were
quite handy some times.

lets imagine, i want to reuse work i did in another repository, then I
can easily pull from that repository, which my work i want to reuse is
stored at... i see... i just will have to pull frequently.... and hope
there is no conflict between some files.


once more... thank you all and good work.

Nicolas

^ permalink raw reply

* Re: several quick questions
From: Junio C Hamano @ 2006-02-14 21:40 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: git
In-Reply-To: <200602142230.11442.Josef.Weidendorfer@gmx.de>

Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:

> Why not allow something like
>
> 	git-checkout master~5
>
> which implicitly does create a read-only branch "seek-point"?

Now what does "git-checkout branch" mean?  Does it switch to the
branch, or does it force tip of seek-point to be the tip of
branch and switch to seek-point branch?  More interestingly,
what does "git-checkout seek-point" mean? 

If we _were_ to do something like cg-seek where an implicit
throw-away branch is used, you at least need a way to
disambiguate these cases, and "git seek" originally suggested is
far clearer than what you said above.

Having said that, I am not convinced in either way, though.

> A branch could be marked readonly by above command with
>
> 	chmod a-w .git/refs/heads/seek

I do not think that would work.  Have you tried it?

> And git-commit should refuse to commit on a readonly ref, telling
> the user to create a writable branch before with "git-branch new".

Now, read-only ref does not interest me, but "do not commit on
top of this yourself, only fast-forward from somewhere else is
allowed" may be useful, for the reason why you mentioned
"origin".

^ permalink raw reply

* Re: several quick questions
From: Petr Baudis @ 2006-02-14 21:41 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: Carl Worth, git, Linus Torvalds
In-Reply-To: <200602142230.11442.Josef.Weidendorfer@gmx.de>

Dear diary, on Tue, Feb 14, 2006 at 10:30:11PM CET, I got a letter
where Josef Weidendorfer <Josef.Weidendorfer@gmx.de> said that...
> Why not allow something like
> 
> 	git-checkout master~5
> 
> which implicitly does create a read-only branch "seek-point"?
> I do not think that it is important to remember the branch name you seek
> from.
> 
> A branch could be marked readonly by above command with
> 
> 	chmod a-w .git/refs/heads/seek
> 
> And git-commit should refuse to commit on a readonly ref, telling
> the user to create a writable branch before with "git-branch new".

We just abolished symlinks. Can we afford doing this, from the
portability standpoint?

> This would also help "cg-seek" to prohibit the user to commit on
> "cg-seek-point" via "git-commit" (by setting cg-seek-point read-only).

For now, this is accomplished (in Cogito, but we just introduced this to
git-bisect as well) by creating .git/head-name. This has the advantage
that you know to which branch to return after the seeking is over, and
it also marks the current head "read-only" (in the commit sense) for
Cogito (and git-bisect start).

It is obviously less flexible since it lets you mark only the current
head read-only, but noone asked for more before. ;)

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply

* Re: several quick questions
From: Carl Worth @ 2006-02-14 21:53 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Nicolas Vilz 'niv', git
In-Reply-To: <Pine.LNX.4.64.0602141224110.3691@g5.osdl.org>

[-- Attachment #1: Type: text/plain, Size: 1802 bytes --]

On Tue, 14 Feb 2006 12:40:24 -0800 (PST), Linus Torvalds wrote:
>
> That's really my point. It all boils down to the same three operations: 
> "git branch", "git checkout" and "git reset".

Yes. I understand that much.

> I think that does exactly what you ask for, I just don't really see the 
> point. The downside of cg-seek is that you're really really limited to 
> what you can do with it.

Well, I think it would be useful to generalize and export what
git-bisect currently does even if there are no limitations added to
it. If nothing else, it's a tiny bit of sugar to allow exploring the
tree without having to invent a branch name first.

So I'd be happy with "git seek" even if git-commit didn't refuse to
commit on the seek branch, (but I still think that limitation makes
sense---see below).

> For example, if you hit a compile error, you can _literally_ fix that 
> compile error AND COMMIT that state, and when you then mark that commit 
> "good" or "bad" when you continue to bisect, bisection will actually do 
> the right thing. Something that would be impossible in a "seek" 
> environment, where you don't have a branch that you can do
> development on.

The only difference in the "seek" case would be that you would be
required to create a branch before committing, right?

And this would have the benefit of not leaving the commit object
dangling after continuing the bisect, wouldn't it?

You've pointed out that branches are free in terms of what git has to
do. I'm saying that they're not free for the user who bears the cost
of inventing a name. And in the case of any commit-while-seeking, it's
at the time of the commit itself that the user has enough information
to invent a useful name, not prior to seeking, (when the user is still
trying to figure things out).

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: Handling large files with GIT
From: Linus Torvalds @ 2006-02-14 22:01 UTC (permalink / raw)
  To: Sam Vilain; +Cc: Johannes Schindelin, Ian Molton, git
In-Reply-To: <43F249F7.5060008@vilain.net>



On Wed, 15 Feb 2006, Sam Vilain wrote:
> 
> This seems to me to be another use case where git could gain orders of
> magnitude speed improvement by either explicit ("forensic") history
> objects, or a history analysis cache.

Well, the thing is, it could get that _without_ any cache too.

The problem really isn't that we couldn't make things faster, the problem 
is that at least for _me_ the thing is fast enough.

If somebody is interested in making the "lots of filename changes" case go 
fast, I'd be more than happy to walk them through what they'd need to 
change. I'm just not horribly motivated to do it myself. Hint, hint.

			Linus

^ permalink raw reply

* Re: several quick questions
From: Josef Weidendorfer @ 2006-02-14 22:17 UTC (permalink / raw)
  To: git
In-Reply-To: <7v7j7xr54u.fsf@assigned-by-dhcp.cox.net>

On Tuesday 14 February 2006 22:40, you wrote:
> Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:
> 
> > Why not allow something like
> >
> > 	git-checkout master~5
> >
> > which implicitly does create a read-only branch "seek-point"?
> 
> Now what does "git-checkout branch" mean?  Does it switch to the
> branch, or does it force tip of seek-point to be the tip of
> branch and switch to seek-point branch?  More interestingly,
> what does "git-checkout seek-point" mean? 

You are right; it would get quite confusing.
But perhaps the current error message

  git checkout: you need to specify a new branch name

should be a little bit more explaining by appending

  "... to switch to for being able to checkout the requested revision"

> Having said that, I am not convinced in either way, though.

Me too. Specifying a branch name is easy enough.

> > And git-commit should refuse to commit on a readonly ref, telling
> > the user to create a writable branch before with "git-branch new".
> 
> Now, read-only ref does not interest me, but "do not commit on
> top of this yourself, only fast-forward from somewhere else is
> allowed" may be useful, for the reason why you mentioned
> "origin".

Yes. The idea to make the ref readonly to specify this intent was
a quick (not so good) idea.

Still, being able to specify that you can not commit on some branch
(as you said) is very useful to prohibit doing things by accident.
.git/config does not sound very good for such a thing, especially
if there could be other branch-specific properties in the future.

Josef

^ permalink raw reply

* Re: several quick questions
From: Junio C Hamano @ 2006-02-14 22:26 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: git
In-Reply-To: <200602142317.29626.Josef.Weidendorfer@gmx.de>

Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:

> On Tuesday 14 February 2006 22:40, you wrote:
>> Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:
>> 
>> > Why not allow something like
>> >
>> > 	git-checkout master~5
>> >
>> > which implicitly does create a read-only branch "seek-point"?
>> 
>> Now what does "git-checkout branch" mean?  Does it switch to the
>> branch, or does it force tip of seek-point to be the tip of
>> branch and switch to seek-point branch?  More interestingly,
>> what does "git-checkout seek-point" mean? 
>
> You are right; it would get quite confusing.
> But perhaps the current error message
>
>   git checkout: you need to specify a new branch name
>
> should be a little bit more explaining by appending
>
>   "... to switch to for being able to checkout the requested revision"

While we are on the subject of improving the error message to
better guide users in a likely-to-be-what-he-meant direction,
there is another confusing message (I am assuming you are
interested in this enough to come up with a patch to fix that
"... to switch to ..." thing):

	$ git checkout -b test v2.6.10

The user wanted to create a new branch test based on tag
v2.6.10, alas that tag does not exist.  We give quite confusing
error message because we are confused that the user meant to
checkout only "./v2.6.10" file and that operation and switching
branches are incompatible.

^ permalink raw reply

* Re: [ANNOUNCE] pg - A patch porcelain for GIT
From: Petr Baudis @ 2006-02-14 22:29 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Karl Hasselström, Catalin Marinas, git
In-Reply-To: <43F2445A.6020109@citi.umich.edu>

Dear diary, on Tue, Feb 14, 2006 at 09:58:02PM CET, I got a letter
where Chuck Lever <cel@citi.umich.edu> said that...
> my impression of git is that you don't change stuff that's already 
> committed.  you revert changes by applying a new commit that backs out 
> the original changes.  i'm speculating, but i suspect that's why there's 
> a "stg pick --reverse" and not a "stg uncommit."

It is ok as long as you know what are you doing - if you don't push out
the commits you've just "undid" (or work on a public accessible
repository in the first place, but I think that's kind of rare these
days; quick survey - does anyone reading these lines do that?), there's
nothing wrong on it, and it gives you nice flexibility.

For example, to import bunch of patches (I guess that's the original
intention behind this) you just run git-am on them and then stg uncommit
all of the newly added commits.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply

* Re: diffstat wierdness with 'git format-patch' output
From: Fredrik Kuivinen @ 2006-02-14 22:30 UTC (permalink / raw)
  To: Greg KH; +Cc: git
In-Reply-To: <20060214055425.GA32261@kroah.com>

On Mon, Feb 13, 2006 at 09:54:25PM -0800, Greg KH wrote:
> I was trying to use the built-in git tools to send patches off, instead
> of my horribly hacked up scripts that use the git low-level stuff, when
> I noticed that git format-patch's output confuses diffstat a bit, and
> causes it to add another line to it's count.
> 
> This isn't good when I do a 'diffstat -p1 *.txt' of the output and add
> it to an email to send off for someone to pull from, as the result will
> be off from what is really there.
> 
> Here's what I get:
> 
>  $ git format-patch -n origin..HEAD
>  0001-USB-fix-up-the-usb-early-handoff-logic-for-EHCI.txt
>  0002-USB-add-new-device-ids-to-ldusb.txt
>  0003-USB-change-ldusb-s-experimental-state.txt
>  0004-USB-PL2303-Leadtek-9531-GPS-Mouse.txt
>  0005-USB-sl811_cs-needs-platform_device-conversion-too.txt
>  0006-usb-storage-new-unusual_devs-entry.txt
>  0007-usb-storage-unusual_devs-entry.txt
>  0008-USB-unusual_devs.h-entry-TrekStor-i.Beat.txt
>  0009-USB-unusual_devs.h-entry-iAUDIO-M5.txt
>  0010-USB-unusual-devs-bugfix.txt
> 
>  $ git log | head -n 1
>  commit 16f05be7be0bf121491d83bd97337fe179b3b323
> 
>  $ git show 16f05be7be0bf121491d83bd97337fe179b3b323 | diffstat -p1
>   drivers/usb/storage/unusual_devs.h |   25 ++++++++++++++++++-------
>   1 file changed, 18 insertions(+), 7 deletions(-)
> 
>  $ diffstat -p1 0010-USB-unusual-devs-bugfix.txt
>   drivers/usb/storage/unusual_devs.h |   26 ++++++++++++++++++--------
>   1 file changed, 18 insertions(+), 8 deletions(-)
> 
> Any thoughts?
> 

If you don't have to generate the diffstat from the individual patches
then

    git-diff-tree -p origin HEAD | git-apply --stat

should give you what you want.


BTW when I tried the above command on two random tags in the git tree
I got:

    $ git-diff-tree -p v1.2.0 v1.0.8 | diffstat -p1 | tail -1
    165 files changed, 3913 insertions(+), 8092 deletions(-)

and

    $ git-diff-tree -p v1.2.0 v1.0.8 | git apply --stat | tail -1
    160 files changed, 3925 insertions(+), 8092 deletions(-)

The difference seems to be caused by diffstat which seems to think
that all lines starting with '---' are diff headers. Hence, there are
some bogus files in the diffstat output such as:

    [master]                                          |  177 ++
    [master^2~4]                                      |    9 
    [master^]                                         |   24 
    [mybranch]                                        |   56 
    [mybranch^]                                       |  616 +++++++

- Fredrik

^ permalink raw reply

* Re: Handling large files with GIT
From: Junio C Hamano @ 2006-02-14 22:30 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds
In-Reply-To: <Pine.LNX.4.64.0602141357300.3691@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> If somebody is interested in making the "lots of filename changes" case go 
> fast, I'd be more than happy to walk them through what they'd need to 
> change. I'm just not horribly motivated to do it myself. Hint, hint.

In case anybody is wondering, I share the same feeling.  I
cannot say I'd be "more than happy to" clean up potential
breakages during the development of such changes, but if the
change eventually would help certain use cases, I can be
persuaded to help debugging such a mess ;-).

^ permalink raw reply

* Re: several quick questions
From: Junio C Hamano @ 2006-02-14 22:39 UTC (permalink / raw)
  To: Carl Worth; +Cc: git, Linus Torvalds
In-Reply-To: <87d5hpvc8p.wl%cworth@cworth.org>

Carl Worth <cworth@cworth.org> writes:

> You've pointed out that branches are free in terms of what git has to
> do. I'm saying that they're not free for the user who bears the cost
> of inventing a name. And in the case of any commit-while-seeking, it's
> at the time of the commit itself that the user has enough information
> to invent a useful name, not prior to seeking, (when the user is still
> trying to figure things out).

I think this is a very valid point and I am happy to accept a
workable proposal (does not have to be a working patch, but a
general semantics that covers most of if not all the corner
cases).

^ permalink raw reply

* Re: several quick questions
From: Andreas Ericsson @ 2006-02-14 23:00 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Josef Weidendorfer, git
In-Reply-To: <7v7j7xr54u.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:
> 
> 
>>Why not allow something like
>>
>>	git-checkout master~5
>>
>>which implicitly does create a read-only branch "seek-point"?
> 
> 
> Now what does "git-checkout branch" mean?  Does it switch to the
> branch, or does it force tip of seek-point to be the tip of
> branch and switch to seek-point branch?  More interestingly,
> what does "git-checkout seek-point" mean? 
> 
> If we _were_ to do something like cg-seek where an implicit
> throw-away branch is used, you at least need a way to
> disambiguate these cases, and "git seek" originally suggested is
> far clearer than what you said above.
> 

Nah. What's the point of having another protected name. Just allow

	$ git checkout -b discard HEAD~15

and we're good to go.

> Having said that, I am not convinced in either way, though.
> 
> 
>>A branch could be marked readonly by above command with
>>
>>	chmod a-w .git/refs/heads/seek
> 
> 
> I do not think that would work.  Have you tried it?
> 

It wouldn't on cygwin, for one. I'm against having things work 
differently on different platforms. If nothing else it usually worsens 
the bitrot that always happens to documentation.

> 
>>And git-commit should refuse to commit on a readonly ref, telling
>>the user to create a writable branch before with "git-branch new".
> 
> 
> Now, read-only ref does not interest me, but "do not commit on
> top of this yourself, only fast-forward from somewhere else is
> allowed" may be useful, for the reason why you mentioned
> "origin".
> 

Do my suggestion and you wouldn't have to worry about read-only 
branches, and although merging any changes from it might be more trouble 
than its worth, it might be possible to cherry-pick the commit rather 
than reverting and re-applying it.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: cg-clean, cg-status improvements
From: Petr Baudis @ 2006-02-14 23:02 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: git
In-Reply-To: <1139941032.26723.4.camel@dv>

Dear diary, on Tue, Feb 14, 2006 at 07:17:12PM CET, I got a letter
where Pavel Roskin <proski@gnu.org> said that...
> On Tue, 2006-02-14 at 16:53 +0100, Petr Baudis wrote:
> >   I didn't plan to require git 1.2.0 with 0.17, so it would be better if
> > you could do the workaround. But if the workaround means significant
> > hassle, it's no biggie if git 1.2.0 will be required.
> 
> It turns out a proper workaround can only be implemented in cg-Xlib, not
> in cg-clean.  It's a bit hairy for my taste (a bash guru could write it
> better, I believe), but it's a compact blob of code that can be easily
> removed at any time.

Wow, how you managed to simplify and shrink cg-clean sounds really
impressive! :)

Thanks, both applied and pushed out.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply

* Re: What's in git.git
From: Luck, Tony @ 2006-02-14 23:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v3bis59un.fsf@assigned-by-dhcp.cox.net>

> >   (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-$$

^ permalink raw reply

* Re: several quick questions
From: Johannes Schindelin @ 2006-02-14 23:23 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: Junio C Hamano, Josef Weidendorfer, git
In-Reply-To: <43F26129.4040804@op5.se>

Hi,

On Wed, 15 Feb 2006, Andreas Ericsson wrote:

> What's the point of having another protected name. Just allow
> 
> 	$ git checkout -b discard HEAD~15
> 
> and we're good to go.

Last time I checked (2 hours ago) it did exactly what you want it to.

Hth,
Dscho

^ permalink raw reply

* Re: several quick questions
From: Andreas Ericsson @ 2006-02-15  0:08 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, Josef Weidendorfer, git
In-Reply-To: <Pine.LNX.4.63.0602150022470.24570@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin wrote:
> Hi,
> 
> On Wed, 15 Feb 2006, Andreas Ericsson wrote:
> 
> 
>>What's the point of having another protected name. Just allow
>>
>>	$ git checkout -b discard HEAD~15
>>
>>and we're good to go.
> 
> 
> Last time I checked (2 hours ago) it did exactly what you want it to.
> 

Heh. You're right. :) Didn't grok that from the man-page. I'm so used to 
seeing <commit-ish> everywhere that when it says "<branch> can be any 
object that refers to a commit" I get confused.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: [ANNOUNCE] pg - A patch porcelain for GIT
From: Sam Vilain @ 2006-02-15  0:22 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Chuck Lever, Karl Hasselström, Catalin Marinas, git
In-Reply-To: <20060214222913.GK31278@pasky.or.cz>

Petr Baudis wrote:
>>my impression of git is that you don't change stuff that's already 
>>committed.  you revert changes by applying a new commit that backs out 
>>the original changes.  i'm speculating, but i suspect that's why there's 
>>a "stg pick --reverse" and not a "stg uncommit."
> It is ok as long as you know what are you doing - if you don't push out
> the commits you've just "undid" (or work on a public accessible
> repository in the first place, but I think that's kind of rare these
> days; quick survey - does anyone reading these lines do that?), there's
> nothing wrong on it, and it gives you nice flexibility.

Yes, and this is one problem I envision with publishing a git repository
with an stgit stack applied - somebody later doing a pull of it will not
find the head revision they had.  I'm not sure what the net effect of
this will be, though.

Sam.

^ permalink raw reply

* Re: several quick questions
From: Junio C Hamano @ 2006-02-15  0:34 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: Johannes Schindelin, Josef Weidendorfer, git
In-Reply-To: <43F270F5.7070804@op5.se>

Andreas Ericsson <ae@op5.se> writes:

> Heh. You're right. :) Didn't grok that from the man-page. I'm so used
> to seeing <commit-ish> everywhere that when it says "<branch> can be
> any object that refers to a commit" I get confused.

You are right; the documentation is wrong.  It says

'git-checkout' [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]

It should have said something like:

git-checkout [ -f | -m ] <branch>    		or
git-checkout [-b <new_branch>] <committish>	or
git-checkout [<committish> | -- ] <paths>...

The first form is to switch to a branch (with flag to say what
to do when conflict can lose local modification); the second
form is to create a new branch out of comittish and switch to
it; and the third is not switching branches but just checking
out named paths out of index or arbitrary comittish (I think any
ent should do but I have not verified it).

^ permalink raw reply

* Re: [ANNOUNCE] pg - A patch porcelain for GIT
From: Shawn Pearce @ 2006-02-15  0:35 UTC (permalink / raw)
  To: Sam Vilain
  Cc: Petr Baudis, Chuck Lever, Karl Hasselström, Catalin Marinas,
	git
In-Reply-To: <43F2745D.4010800@vilain.net>

Sam Vilain <sam@vilain.net> wrote:
> Petr Baudis wrote:
> >>my impression of git is that you don't change stuff that's already 
> >>committed.  you revert changes by applying a new commit that backs out 
> >>the original changes.  i'm speculating, but i suspect that's why there's 
> >>a "stg pick --reverse" and not a "stg uncommit."
> >It is ok as long as you know what are you doing - if you don't push out
> >the commits you've just "undid" (or work on a public accessible
> >repository in the first place, but I think that's kind of rare these
> >days; quick survey - does anyone reading these lines do that?), there's
> >nothing wrong on it, and it gives you nice flexibility.
> 
> Yes, and this is one problem I envision with publishing a git repository
> with an stgit stack applied - somebody later doing a pull of it will not
> find the head revision they had.  I'm not sure what the net effect of
> this will be, though.

It would cause some pain for anyone pulling from it with git-pull, as
git-pull won't happily go backwards from what I've seen. But I think
you can force it to do so even if it won't make sense during the
resulting merge, which then leaves the user in an interesting state.

This is actually why pg-rebase doesn't care what you move to
when you grab the remote's commit; it just jumps to that commit
and pushes your patch stack back down onto it.  So if the remote
rebuilds itself through a new commit lineage which you have never
seen before the next pg-rebase will still update to it.  But on
the other hand if you have a commit that isn't in your local patch
stack its gone into the bit bucket.

Publishing a repository with a stg (or pg) patch series isn't
a problem; the problem is that no clients currently know how to
follow along with the remote repository's patch series.  And I can't
think of a sensible behavior for doing so that isn't what git-core is
already doing today for non patch series type clients (as in don't go
backwards by popping but instead by pushing a negative delta).  :-)

-- 
Shawn.

^ permalink raw reply

* Re: Handling large files with GIT
From: Sam Vilain @ 2006-02-15  0:40 UTC (permalink / raw)
  To: Junio C Hamano, Martin Langhoff; +Cc: git, Linus Torvalds
In-Reply-To: <7vy80dpo9g.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Linus Torvalds <torvalds@osdl.org> writes:
> 
>>If somebody is interested in making the "lots of filename changes" case go 
>>fast, I'd be more than happy to walk them through what they'd need to 
>>change. I'm just not horribly motivated to do it myself. Hint, hint.
> 
> In case anybody is wondering, I share the same feeling.  I
> cannot say I'd be "more than happy to" clean up potential
> breakages during the development of such changes, but if the
> change eventually would help certain use cases, I can be
> persuaded to help debugging such a mess ;-).

Excellent.  Any speculations on where they might fit?  Clearly, it needs
to be out of the "tree".

Dealing with the three cases I mentioned before in my Warnocked post;

   1. caching - I'll consider this an "under the hood" thing, it really
                doesn't matter, so long as the tools all know.

   2. forensic - extra stuff at the end of the commit object?

      eg
         Copied: /new/path from /old/path:commit:c0bb171d..
           (for SVN case where history matters)
         Copied: /new/path from blob:b10b1d..
           (for general pre-caching case)
         Merged: /new/path from /old/path:commit:C0bb171d..
           (for an SVK clone, so we know that subsequent merges on
            /new/path need only merge from /old/path starting at commit
            C0bb171d..)

   3. retrospective - as above, but allow to specify old versions.

      eg
         Copied: /new/path:C0bb171d1 from /old/path:commit:c0bb171d2...
           (for SVN case where history matters)

Martin, is that enough for your CVS case?

Sam.

^ permalink raw reply

* Cogito turbo-introduction
From: Petr Baudis @ 2006-02-15  1:12 UTC (permalink / raw)
  To: Keith Packard; +Cc: git
In-Reply-To: <1139963183.4341.117.camel@evo.keithp.com>

I suppose this might be interesting for others (and Google) as well, so
I'm bringing it back to the mailing list...

Dear diary, on Wed, Feb 15, 2006 at 01:26:23AM CET, I got a letter
where Keith Packard <keithp@keithp.com> said that...
> I will see about learning enough cogito to point appropriate people at
> it in place of full-on git exposure.

Actually, everything should be really trivial, since Cogito is very
similar to CVS or SVN in practice. A turbo introduction to Cogito, which
actually proved to be enough to get started fast with the regular work,
was:

	* cg-clone URL to get the stuff
	* cg-commit just like in CVS (but cooler)
	* cg-update just like in CVS (or rather SVN)
	* cg-status to get the status letters produced by cvs update
	  (just like in SVN)
	* cg-diff, cg-log, cg-add, cg-rm just like in CVS (but cooler)

	* After committing for a while, you need to run cg-push
	* Merge commits are perfectly ok, don't mind them; no really,
	  you will get used; in reality, they are cool
	* If you hit conflicts during merge, the software will tell you
	  how to proceed
	* If you need something different / more advanced, look it up
	  in cg-help list (there is actually significantly less Cogito
	  commands to go through than in CVS, yet in most areas Cogito
	  is much more powerful)
	* If you are confused about the distributed concept or want to
	  learn about branching, try Cogito README

I've been trying to design Cogito's UI pretty carefully to really
absolutely minimize the learning curve from CVS/SVN, while also making
it consistent on its own so that people who learn it as their first VCS
will get actually something nice. Well, the users shall judge. ;-)
(At this stage I would probably design few bits of the UI slightly
differently than how they have evolved, but the gripes are pretty
minor.)

In this sense, the good UI goal has indeed higher priority than the
powerfulness goal, but most of the time we hopefully manage to make it
go together well. The significant areas where Cogito is fundamentally
less powerful than GIT itself are:

	* No git-whatchanged -p - this is huge deficiency, and I'm
	  entirely at fault here
	* Consequently, no pickaxe and renames detection - same
	* Recursive merge strategy - not much of a UI problem, it just
	  needs the time and work to get integrated
	* Remote branches handling - Cogito's handling is strictly 1:1
	  while GIT's remotes are much more powerful and allow you to
	  fetch/push many branches at once (and in fact do so by
	  default); I did not invent a good UI for something similarly
	  powerful yet, and it is no high priority for me so far;
	  I think you actually want 1:1 in by far the most common usage
	  pattern
	* No email interface - but you can trivially just fall back to
	  GIT in this area

Note that Cogito's goal is not to reproduce and wrap all GIT commands -
e.g. I have currently no plans to wrap up git-bisect.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply

* Re: [ANNOUNCE] pg - A patch porcelain for GIT
From: Petr Baudis @ 2006-02-15  1:14 UTC (permalink / raw)
  To: Sam Vilain, Chuck Lever, Karl Hasselström, Catalin Marinas,
	git
In-Reply-To: <20060215003510.GA25715@spearce.org>

Dear diary, on Wed, Feb 15, 2006 at 01:35:10AM CET, I got a letter
where Shawn Pearce <spearce@spearce.org> said that...
> Publishing a repository with a stg (or pg) patch series isn't
> a problem; the problem is that no clients currently know how to
> follow along with the remote repository's patch series.  And I can't
> think of a sensible behavior for doing so that isn't what git-core is
> already doing today for non patch series type clients (as in don't go
> backwards by popping but instead by pushing a negative delta).  :-)

New Cogito will automagically do the right thing if you are just
fast-forwarding and you are using cg-update - if the branch rebased, it
will happily follow (but cg-fetch + cg-merge will NOT and it will fall
back to the tree merge).

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply

* Re: Cogito turbo-introduction
From: Petr Baudis @ 2006-02-15  1:32 UTC (permalink / raw)
  To: Keith Packard; +Cc: git
In-Reply-To: <20060215011210.GG30316@pasky.or.cz>

Dear diary, on Wed, Feb 15, 2006 at 02:12:11AM CET, I got a letter
where Petr Baudis <pasky@ucw.cz> said that...
> In this sense, the good UI goal has indeed higher priority than the
> powerfulness goal, but most of the time we hopefully manage to make it
> go together well. The significant areas where Cogito is fundamentally
> less powerful than GIT itself are:
> 
> 	* No git-whatchanged -p - this is huge deficiency, and I'm
> 	  entirely at fault here
> 	* Consequently, no pickaxe and renames detection - same
> 	* Recursive merge strategy - not much of a UI problem, it just
> 	  needs the time and work to get integrated
> 	* Remote branches handling - Cogito's handling is strictly 1:1
> 	  while GIT's remotes are much more powerful and allow you to
> 	  fetch/push many branches at once (and in fact do so by
> 	  default); I did not invent a good UI for something similarly
> 	  powerful yet, and it is no high priority for me so far;
> 	  I think you actually want 1:1 in by far the most common usage
> 	  pattern

(And you can pretty easily script/alias multi-branch fetches, it just
won't be as super-efficient as if you would fetch/push at once.)


The above is though not to say that Cogito is strict subset of GIT!
Cogito has many cool things GIT doesn't have. ;-) To pick some random
examples:

	* cg-clean
	* cg-commit - packed with convenience stuff, from multiple -m's
	  to --review
	* cg-init's initial commit
	* resumable cg-clone
	* cg-fetch's cute progressbars ;-)
	* things which are rather thin wrappers automating sequence of
	  few commands, nevertheless providing much convenience
	  (cg-admin-setuprepo, cg-admin-uncommit, cg-seek, cg-export...)

(Perhaps some of this GIT can already do, I don't watch the core
porcelain that closely.)

> Note that Cogito's goal is not to reproduce and wrap all GIT commands -
> e.g. I have currently no plans to wrap up git-bisect.

To explain, that's not because I consider git-bisect to be bad, but the
very opposite - because it is so cool and I couldn't really add much
value by adding it to Cogito. When Cogito will have good tutorial
documentation (I think it already has _very_ good reference
documentation - please prove me wrong so that we can improve it
further), I will just happily reference people to those GIT core
commands.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply

* Re: Handling large files with GIT
From: Junio C Hamano @ 2006-02-15  1:39 UTC (permalink / raw)
  To: Sam Vilain; +Cc: git
In-Reply-To: <43F27878.50701@vilain.net>

Sam Vilain <sam@vilain.net> writes:

> ...  Clearly, it needs to be out of the "tree".

OK.

>   2. forensic - extra stuff at the end of the commit object?

(except "extra at the end of commit", which does not make it out
of the tree).

>      eg
>         Copied: /new/path from /old/path:commit:c0bb171d..
>           (for SVN case where history matters)
>         Copied: /new/path from blob:b10b1d..
>           (for general pre-caching case)
>         Merged: /new/path from /old/path:commit:C0bb171d..
>           (for an SVK clone, so we know that subsequent merges on
>            /new/path need only merge from /old/path starting at commit
>            C0bb171d..)

I am not sure if recording the bare SVN ``copied'' is very
useful.  You would need to infer things from what SVN did to
tell if the copy is a tree copy inside a project (e.g. cp -r
i386 x86_64), tagging (e.g. svn-cp rHEAD trunk tags/v1.2), or
branching, wouldn't you?  SVK merge ticket is a bit more useful
in that sense.

So far, git philosophy is to record things you _know_ about and
defer such guesswork to the future, so limiting what you record
to what you can actually see from the foreign SCM would be more
in line with it.  For the same reason, if you are talking about
maildir managed under git, you should not have record anything
other than what git already records: "we used to have these
files, now we have these instead".

But I thought you were talking about caching what earlier
inference declared what happened, so that you do not have to do
the same inference every time.  If that is the case, SVN level
"Copied:" is probably not what you would want to record, I
suspect.  You would do some inference with the given information
("SVN says it copied this tree to that tree, what was it that it
really wanted to do?  Was it a copy, or was it to create a
branch which was implemented as a copy?"), and record that,
hoping that information would help your other operations this
time and later.

So I think the order of questions you should be asking is:

   - what operations are you trying to help?

   - what information you would need to achieve those operations
     better?

   - among the second one, what will be necessary to be set in
     stone (IOW, cannot be computed later), and what are
     computable but expensive to recompute every time?

An example from an ancient thread.

With criss-cross merge between renamed trees, it was conjectured
that recording renames detected earlier would help later merges.
I think you should arrive at the list of "what we should record"
by thinking things in this order:

 (1) currently criss-cross merge between renamed trees does not
     work well (realization of the status quo);

 (2) if we had this kind of information it would work better,
     here are the things we need to record when a new commit is
     made, and here is how to compute other information that can
     be inferred, and here is how to use that information to
     make the merge work better (solution without caching);

 (3) but it is expensive to recompute information we said
     computable in (2) if we were to do so every time.  Let's
     cache it.

I am getting an impression that you are doing only the first
half of (2) without other parts, which somewhat bothers me.

^ permalink raw reply

* Re: Handling large files with GIT
From: Linus Torvalds @ 2006-02-15  2:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vy80dpo9g.fsf@assigned-by-dhcp.cox.net>



On Tue, 14 Feb 2006, Junio C Hamano wrote:

> Linus Torvalds <torvalds@osdl.org> writes:
> 
> > If somebody is interested in making the "lots of filename changes" case go 
> > fast, I'd be more than happy to walk them through what they'd need to 
> > change. I'm just not horribly motivated to do it myself. Hint, hint.
> 
> In case anybody is wondering, I share the same feeling.  I
> cannot say I'd be "more than happy to" clean up potential
> breakages during the development of such changes, but if the
> change eventually would help certain use cases, I can be
> persuaded to help debugging such a mess ;-).

Actually, I got interested in seeing how hard this is, and wrote a simple 
first cut at doing a tree-optimized merger.

Let me shout a bit first:

  THIS IS WORKING CODE, BUT BE CAREFUL: IT'S A TECHNOLOGY DEMONSTRATION 
  RATHER THAN THE FINAL PRODUCT!

With that out of the way, let me descibe what this does (and then describe 
the missing parts).

This is basically a three-way merge that works entirely on the "tree" 
level, rather than on the index. A lot of the _concepts_ are the same, 
though, and if you're familiar with the results of an index merge, some of 
the output will make more sense.

You give it three trees: the base tree (tree 0), and the two branches to 
be merged (tree 1 and tree 2 respectively). It will then walk these three 
trees, and resolve them as it goes along.

The interesting part is:
 - it can resolve whole sub-directories in one go, without actually even 
   looking recursively at them. A whole subdirectory will resolve the same 
   way as any individual files will (although that may need some 
   modification, see later).
 - if it has a "content conflict", for subdirectories that means "try to 
   do a recursive tree merge", while for non-subdirectories it's just a 
   content conflict and we'll output the stage 1/2/3 information.
 - a successful merge will output a single stage 0 ("merged") entry, 
   potentially for a whole subdirectory.
 - it outputs all the resolve information on stdout, so something like the 
   recursive resolver can pretty easily parse it all.

Now, the caveats:
 - we probably need to be more careful about subdirectory resolves. The 
   trivial case (both branches have the exact same subdirectory) is a 
   trivial resolve, but the other cases ("branch1 matches base, branch2 is 
   different" probably can't be silently just resolved to the "branch2" 
   subdirectory state, since it might involve renames into - or out of - 
   that subdirectory)
 - we do not track the current index file at all, so this does not do the 
   "check that index matches branch1" logic that the three-way merge in 
   git-read-tree does. The theory is that we'd do a full three-way merge 
   (ignoring the index and working directory), and then to update the 
   working tree, we'd do a two-way "git-read-tree branch1->result"
 - I didn't actually make it do all the trivial resolve cases that 
   git-read-tree does. It's a technology demonstration.

Finally (a more serious caveat):
 - doing things through stdout may end up being so expensive that we'd 
   need to do something else. In particular, it's likely that I should 
   not actually output the "merge results", but instead output a "merge 
   results as they _differ_ from branch1"

However, I think this patch is already interesting enough that people who 
are interested in merging trees might want to look at it. Please keep in 
mind that tech _demo_ part, and in particular, keep in mind the final 
"serious caveat" part.

In many ways, the really _interesting_ part of a merge is not the result, 
but how it _changes_ the branch we're merging into. That's particularly 
important as it should hopefully also mean that the output size for any 
reasonable case is minimal (and tracks what we actually need to do to the 
current state to create the final result).

The code very much is organized so that doing the result as a "diff 
against branch1" should be quite easy/possible. I was actually going to do 
it, but I decided that it probably makes the output harder to read. I 
dunno.

Anyway, let's think about this kind of approach.. Note how the code itself 
is actually quite small and short, although it's prbably pretty "dense".

As an interesting test-case, I'd suggest this merge in the kernel:

	git-merge-tree $(git-merge-base 4cbf876 7d2babc) 4cbf876 7d2babc

which resolves beautifully (there are no actual file-level conflicts), and 
you can look at the output of that command to start thinking about what 
it does.

The interesting part (perhaps) is that timing that command for me shows 
that it takes all of 0.004 seconds.. (the git-merge-base thing takes 
considerably more ;)

The point is, we _can_ do the actual merge part really really quickly. 

		Linus

PS. Final note: when I say that it is "WORKING CODE", that is obviously by 
my standards. IOW, I tested it once and it gave reasonable results - so it 
must be perfect.

Whether it works for anybody else, or indeed for any other test-case, is 
not my problem ;)

---
diff-tree f0e6b454ff873429237322c846603d2e1fffc867 (from 6a9b87972f27edfe53da4ce016adf4c0cd42f5e6)
Author: Linus Torvalds <torvalds@osdl.org>
Date:   Tue Feb 14 17:39:15 2006 -0800

    Add "git-merge-tree" functionality
    
    This is basically a tree-optimized merge.  Or rather, it is the first
    stages _towards_ such a merge.
    
    Given a base tree and two branches to merge, it will do a trivial merge,
    optimizing away the case of identical subdirectories, and resolving
    trivial merges.  It outputs the list of file/directory resolves.
    
    Signed-off-by: Linus Torvalds <torvalds@osdl.org>

diff --git a/Makefile b/Makefile
index d40aa6a..4d04f49 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@ PROGRAMS = \
 	git-upload-pack$X git-verify-pack$X git-write-tree$X \
 	git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
 	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
-	git-describe$X
+	git-describe$X git-merge-tree$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
diff --git a/merge-tree.c b/merge-tree.c
new file mode 100644
index 0000000..0d6d434
--- /dev/null
+++ b/merge-tree.c
@@ -0,0 +1,238 @@
+#include "cache.h"
+#include "diff.h"
+
+static const char merge_tree_usage[] = "git-merge-tree <base-tree> <branch1> <branch2>";
+static int resolve_directories = 1;
+
+static void merge_trees(struct tree_desc t[3], const char *base);
+
+static void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
+{
+	unsigned long size = 0;
+	void *buf = NULL;
+
+	if (sha1) {
+		buf = read_object_with_reference(sha1, "tree", &size, NULL);
+		if (!buf)
+			die("unable to read tree %s", sha1_to_hex(sha1));
+	}
+	desc->size = size;
+	desc->buf = buf;
+	return buf;
+}
+
+struct name_entry {
+	const unsigned char *sha1;
+	const char *path;
+	unsigned int mode;
+	int pathlen;
+};
+
+static void entry_clear(struct name_entry *a)
+{
+	memset(a, 0, sizeof(*a));
+}
+
+static int entry_compare(struct name_entry *a, struct name_entry *b)
+{
+	return base_name_compare(
+			a->path, a->pathlen, a->mode,
+			b->path, b->pathlen, b->mode);
+}
+
+static void entry_extract(struct tree_desc *t, struct name_entry *a)
+{
+	a->sha1 = tree_entry_extract(t, &a->path, &a->mode);
+	a->pathlen = strlen(a->path);
+}
+
+/* An empty entry never compares same, not even to another empty entry */
+static int same_entry(struct name_entry *a, struct name_entry *b)
+{
+	return	a->sha1 &&
+		b->sha1 &&
+		!memcmp(a->sha1, b->sha1, 20) &&
+		a->mode == b->mode;
+}
+
+static void resolve(const char *base, struct name_entry *result)
+{
+	printf("0 %06o %s %s%s\n", result->mode, sha1_to_hex(result->sha1), base, result->path);
+}
+
+static int unresolved_directory(const char *base, struct name_entry n[3])
+{
+	int baselen;
+	char *newbase;
+	struct name_entry *p;
+	struct tree_desc t[3];
+	void *buf0, *buf1, *buf2;
+
+	if (!resolve_directories)
+		return 0;
+	p = n;
+	if (!p->mode) {
+		p++;
+		if (!p->mode)
+			p++;
+	}
+	if (!S_ISDIR(p->mode))
+		return 0;
+	baselen = strlen(base);
+	newbase = xmalloc(baselen + p->pathlen + 2);
+	memcpy(newbase, base, baselen);
+	memcpy(newbase + baselen, p->path, p->pathlen);
+	memcpy(newbase + baselen + p->pathlen, "/", 2);
+
+	buf0 = fill_tree_descriptor(t+0, n[0].sha1);
+	buf1 = fill_tree_descriptor(t+1, n[1].sha1);
+	buf2 = fill_tree_descriptor(t+2, n[2].sha1);
+	merge_trees(t, newbase);
+
+	free(buf0);
+	free(buf1);
+	free(buf2);
+	free(newbase);
+	return 1;
+}
+
+static void unresolved(const char *base, struct name_entry n[3])
+{
+	if (unresolved_directory(base, n))
+		return;
+	printf("1 %06o %s %s%s\n", n[0].mode, sha1_to_hex(n[0].sha1), base, n[0].path);
+	printf("2 %06o %s %s%s\n", n[1].mode, sha1_to_hex(n[1].sha1), base, n[1].path);
+	printf("3 %06o %s %s%s\n", n[2].mode, sha1_to_hex(n[2].sha1), base, n[2].path);
+}
+
+/*
+ * Merge two trees together (t[1] and t[2]), using a common base (t[0])
+ * as the origin.
+ *
+ * This walks the (sorted) trees in lock-step, checking every possible
+ * name. Note that directories automatically sort differently from other
+ * files (see "base_name_compare"), so you'll never see file/directory
+ * conflicts, because they won't ever compare the same.
+ *
+ * IOW, if a directory changes to a filename, it will automatically be
+ * seen as the directory going away, and the filename being created.
+ *
+ * Think of this as a three-way diff.
+ *
+ * The output will be either:
+ *  - successful merge
+ *	 "0 mode sha1 filename"
+ *    NOTE NOTE NOTE! FIXME! We really really need to walk the index
+ *    in parallel with this too!
+ * 
+ *  - conflict:
+ *	"1 mode sha1 filename"
+ *	"2 mode sha1 filename"
+ *	"3 mode sha1 filename"
+ *    where not all of the 1/2/3 lines may exist, of course.
+ *
+ * The successful merge rules are the same as for the three-way merge
+ * in git-read-tree.
+ */
+static void merge_trees(struct tree_desc t[3], const char *base)
+{
+	for (;;) {
+		struct name_entry entry[3];
+		unsigned int mask = 0;
+		int i, last;
+
+		last = -1;
+		for (i = 0; i < 3; i++) {
+			if (!t[i].size)
+				continue;
+			entry_extract(t+i, entry+i);
+			if (last >= 0) {
+				int cmp = entry_compare(entry+i, entry+last);
+
+				/*
+				 * Is the new name bigger than the old one?
+				 * Ignore it
+				 */
+				if (cmp > 0)
+					continue;
+				/*
+				 * Is the new name smaller than the old one?
+				 * Ignore all old ones
+				 */
+				if (cmp < 0)
+					mask = 0;
+			}
+			mask |= 1u << i;
+			last = i;
+		}
+		if (!mask)
+			break;
+
+		/*
+		 * Update the tree entries we've walked, and clear
+		 * all the unused name-entries.
+		 */
+		for (i = 0; i < 3; i++) {
+			if (mask & (1u << i)) {
+				update_tree_entry(t+i);
+				continue;
+			}
+			entry_clear(entry + i);
+		}
+
+		/* Same in both? */
+		if (same_entry(entry+1, entry+2)) {
+			if (entry[0].sha1) {
+				resolve(base, entry+1);
+				continue;
+			}
+		}
+
+		if (same_entry(entry+0, entry+1)) {
+			if (entry[2].sha1) {
+				resolve(base, entry+2);
+				continue;
+			}
+		}
+
+		if (same_entry(entry+0, entry+2)) {
+			if (entry[1].sha1) {
+				resolve(base, entry+1);
+				continue;
+			}
+		}
+
+		unresolved(base, entry);
+	}
+}
+
+static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
+{
+	unsigned char sha1[20];
+	void *buf;
+
+	if (get_sha1(rev, sha1) < 0)
+		die("unknown rev %s", rev);
+	buf = fill_tree_descriptor(desc, sha1);
+	if (!buf)
+		die("%s is not a tree", rev);
+	return buf;
+}
+
+int main(int argc, char **argv)
+{
+	struct tree_desc t[3];
+	void *buf1, *buf2, *buf3;
+
+	if (argc < 4)
+		usage(merge_tree_usage);
+
+	buf1 = get_tree_descriptor(t+0, argv[1]);
+	buf2 = get_tree_descriptor(t+1, argv[2]);
+	buf3 = get_tree_descriptor(t+2, argv[3]);
+	merge_trees(t, "");
+	free(buf1);
+	free(buf2);
+	free(buf3);
+	return 0;
+}

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox