* Joining Repositories
@ 2006-01-18 12:25 Mathias Waack
2006-01-18 12:51 ` Petr Baudis
2006-01-18 16:38 ` H. Peter Anvin
0 siblings, 2 replies; 25+ messages in thread
From: Mathias Waack @ 2006-01-18 12:25 UTC (permalink / raw)
To: git
Hello everybody,
we're using git with cogito as a frontend. For some reasons I forgot we have
some repositories which belong to the same project. To simplify the whole
thing I would like to join these repositories. It mainly means to move some
directories. So lets say I have:
/r1/.git
/r2/.git
and what I would like to have is
/r/.git
r1
r2
Of course the history should remain (otherwise it would be to easy).
How should I do this?
Thanks for your answers
Mathias
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 12:25 Joining Repositories Mathias Waack
@ 2006-01-18 12:51 ` Petr Baudis
2006-01-18 12:58 ` Petr Baudis
2006-01-18 14:09 ` Ryan Anderson
2006-01-18 16:38 ` H. Peter Anvin
1 sibling, 2 replies; 25+ messages in thread
From: Petr Baudis @ 2006-01-18 12:51 UTC (permalink / raw)
To: Mathias Waack; +Cc: git
Hello,
Dear diary, on Wed, Jan 18, 2006 at 01:25:59PM CET, I got a letter
where Mathias Waack <Mathias.Waack@rantzau.de> said that...
> we're using git with cogito as a frontend. For some reasons I forgot we have
> some repositories which belong to the same project. To simplify the whole
> thing I would like to join these repositories. It mainly means to move some
> directories. So lets say I have:
>
> /r1/.git
> /r2/.git
>
> and what I would like to have is
>
> /r/.git
> r1
> r2
>
> Of course the history should remain (otherwise it would be to easy).
>
> How should I do this?
The crucial question is what the joined repository's directory
structure should be. If from r1/a, r2/b you want r/a, r/b then it's
easy:
cd r1
cg-branch-add r2 ../r2/.git
cg-fetch r2
cg-merge -j r2
But if you want r1/a, r2/b to turn to r/r1/a, r/r2/b, you will have
to rewrite the history of each (and then do the above). One rough
and untested sketch...
mkdir r1-rewritten
cd r1-rewritten
cp -a ../r1/.git .
for commit in $(git-rev-list --topo-order HEAD | tac); do
git-read-tree --prefix=r1/ $commit
# here, setup the AUTHOR/COMMITTER variables
# appropriately (you can look at cg-commit's
# $copy_commit handler)
git-cat-file commit "$commit" | sed -e '1,/^$/d' | \
git-commit-tree $(git-write-tree) \
$(for parent in $(cg-object-id -p $commit); do
cat commitmap/$parent
done) >commitmap/$commit
last_commit=$commit
done
git-update-ref HEAD $(cat commitmap/$last_commit)
--
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 [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 12:51 ` Petr Baudis
@ 2006-01-18 12:58 ` Petr Baudis
2006-01-18 14:01 ` Mathias Waack
2006-01-18 14:09 ` Ryan Anderson
1 sibling, 1 reply; 25+ messages in thread
From: Petr Baudis @ 2006-01-18 12:58 UTC (permalink / raw)
To: Mathias Waack; +Cc: git
Dear diary, on Wed, Jan 18, 2006 at 01:51:58PM CET, I got a letter
where Petr Baudis <pasky@suse.cz> said that...
> But if you want r1/a, r2/b to turn to r/r1/a, r/r2/b, you will have
> to rewrite the history of each (and then do the above). One rough
> and untested sketch...
>
> mkdir r1-rewritten
> cd r1-rewritten
> cp -a ../r1/.git .
mkdir commitmap
> for commit in $(git-rev-list --topo-order HEAD | tac); do
> git-read-tree --prefix=r1/ $commit
> # here, setup the AUTHOR/COMMITTER variables
> # appropriately (you can look at cg-commit's
> # $copy_commit handler)
> git-cat-file commit "$commit" | sed -e '1,/^$/d' | \
> git-commit-tree $(git-write-tree) \
> $(for parent in $(cg-object-id -p $commit); do
echo -p
> cat commitmap/$parent
> done) >commitmap/$commit
> last_commit=$commit
> done
> git-update-ref HEAD $(cat commitmap/$last_commit)
rm -rf commitmap
cg-reset
And at this point, git-prune will have plenty of work to do (many of
your tree and commit objects will be outdated - you just rewrote them).
It's quite beautiful that you can do this all without checkouting a
single thing - you just load the tree to the index, prepend "r1/" to all
the paths, and commit it back.
--
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 [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 12:58 ` Petr Baudis
@ 2006-01-18 14:01 ` Mathias Waack
2006-01-18 14:14 ` Petr Baudis
2006-01-18 14:14 ` Andreas Ericsson
0 siblings, 2 replies; 25+ messages in thread
From: Mathias Waack @ 2006-01-18 14:01 UTC (permalink / raw)
To: git
Hello Petr,
thanks for your quick answer, but...
On Wednesday 18 January 2006 01:58 pm, Petr Baudis wrote:
> Dear diary, on Wed, Jan 18, 2006 at 01:51:58PM CET, I got a letter
> where Petr Baudis <pasky@suse.cz> said that...
>
> > But if you want r1/a, r2/b to turn to r/r1/a, r/r2/b, you will have
> > to rewrite the history of each (and then do the above). One rough
> > and untested sketch...
> >
> > mkdir r1-rewritten
> > cd r1-rewritten
> > cp -a ../r1/.git .
>
> mkdir commitmap
>
> > for commit in $(git-rev-list --topo-order HEAD | tac); do
> > git-read-tree --prefix=r1/ $commit
...git-read-tree doesn't know the parameter --prefix (just downloaded and
tried it on 0.99.9i). What version shall I use?
Mathias
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 12:51 ` Petr Baudis
2006-01-18 12:58 ` Petr Baudis
@ 2006-01-18 14:09 ` Ryan Anderson
2006-01-18 14:21 ` Petr Baudis
2006-01-18 16:23 ` Linus Torvalds
1 sibling, 2 replies; 25+ messages in thread
From: Ryan Anderson @ 2006-01-18 14:09 UTC (permalink / raw)
To: Petr Baudis; +Cc: Mathias Waack, git
On Wed, Jan 18, 2006 at 01:51:58PM +0100, Petr Baudis wrote:
> Hello,
>
> Dear diary, on Wed, Jan 18, 2006 at 01:25:59PM CET, I got a letter
> where Mathias Waack <Mathias.Waack@rantzau.de> said that...
> > we're using git with cogito as a frontend. For some reasons I forgot we have
> > some repositories which belong to the same project. To simplify the whole
> > thing I would like to join these repositories. It mainly means to move some
> > directories. So lets say I have:
> >
> > /r1/.git
> > /r2/.git
> >
> > and what I would like to have is
> >
> > /r/.git
> > r1
> > r2
> >
> > Of course the history should remain (otherwise it would be to easy).
> >
> > How should I do this?
>
> The crucial question is what the joined repository's directory
> structure should be. If from r1/a, r2/b you want r/a, r/b then it's
> easy:
>
> cd r1
> cg-branch-add r2 ../r2/.git
> cg-fetch r2
> cg-merge -j r2
>
> But if you want r1/a, r2/b to turn to r/r1/a, r/r2/b, you will have
> to rewrite the history of each (and then do the above). One rough
> and untested sketch...
... Why would that be the optimal method?
Assuming both repositories are clean, no extraneous files, and without
testing, of course:
In r1:
mkdir r1
# move everything into the subdirectory called r1.
git mv $(ls -a | grep -v -e ^.git$ -e ^r1$) r1/
git commit -a "Restructure directory"
In r2:
mkdir r2
# move all files into r2/
git mv $(ls -a | grep -v -e ^.git$ -e ^r2$) r2/
git commit -a "Restructure directory"
git fetch ../r1/
GIT_INDEX_FILE=.git/tmp-index git-read-tree FETCH_HEAD
GIT_INDEX_FILE=.git/tmp-index git-checkout-cache -a -u
git-update-cache --add -- $(GIT_INDEX_FILE=.git/tmp-index git-ls-files)
cp .git/FETCH_HEAD .git/MERGE_HEAD
git commit
No history rewritten, merging with the old repositories should, at least
theoretically, work, etc.
(This is just a restatement of Linus's "Coolest merge ever" / union
merge)
--
Ryan Anderson
sometimes Pug Majere
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:01 ` Mathias Waack
@ 2006-01-18 14:14 ` Petr Baudis
2006-01-19 11:36 ` Mathias Waack
2006-01-19 18:24 ` Junio C Hamano
2006-01-18 14:14 ` Andreas Ericsson
1 sibling, 2 replies; 25+ messages in thread
From: Petr Baudis @ 2006-01-18 14:14 UTC (permalink / raw)
To: Mathias Waack; +Cc: git
Hello,
Dear diary, on Wed, Jan 18, 2006 at 03:01:38PM CET, I got a letter
where Mathias Waack <Mathias.Waack@rantzau.de> said that...
> On Wednesday 18 January 2006 01:58 pm, Petr Baudis wrote:
> > Dear diary, on Wed, Jan 18, 2006 at 01:51:58PM CET, I got a letter
> > where Petr Baudis <pasky@suse.cz> said that...
> >
> > > But if you want r1/a, r2/b to turn to r/r1/a, r/r2/b, you will have
> > > to rewrite the history of each (and then do the above). One rough
> > > and untested sketch...
> > >
> > > mkdir r1-rewritten
> > > cd r1-rewritten
> > > cp -a ../r1/.git .
> >
> > mkdir commitmap
> >
> > > for commit in $(git-rev-list --topo-order HEAD | tac); do
> > > git-read-tree --prefix=r1/ $commit
>
> ...git-read-tree doesn't know the parameter --prefix (just downloaded and
> tried it on 0.99.9i). What version shall I use?
oops, it seems this is only in the latest pu branch of git. If you are
not brave enough for that, you will need to use the prefix facility of
checkout-index instead, and it'll take much longer:
git-read-tree $commit
git-checkout-index -a --prefix=r1/
rm .git/index
cg-add -r r1/
rm -rf r1
.. then proceed with git-cat-file etc ..
Note that I'm not sure when which feature was introduced. Your best
bet is to just use the latest stable GIT/Cogito versions.
--
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 [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:01 ` Mathias Waack
2006-01-18 14:14 ` Petr Baudis
@ 2006-01-18 14:14 ` Andreas Ericsson
1 sibling, 0 replies; 25+ messages in thread
From: Andreas Ericsson @ 2006-01-18 14:14 UTC (permalink / raw)
To: Mathias Waack; +Cc: git
Mathias Waack wrote:
> Hello Petr,
>
> thanks for your quick answer, but...
>
> On Wednesday 18 January 2006 01:58 pm, Petr Baudis wrote:
>
>>Dear diary, on Wed, Jan 18, 2006 at 01:51:58PM CET, I got a letter
>>where Petr Baudis <pasky@suse.cz> said that...
>>
>>
>>> But if you want r1/a, r2/b to turn to r/r1/a, r/r2/b, you will have
>>>to rewrite the history of each (and then do the above). One rough
>>>and untested sketch...
>>>
>>> mkdir r1-rewritten
>>> cd r1-rewritten
>>> cp -a ../r1/.git .
>>
>> mkdir commitmap
>>
>>
>>> for commit in $(git-rev-list --topo-order HEAD | tac); do
>>> git-read-tree --prefix=r1/ $commit
>
>
> ...git-read-tree doesn't know the parameter --prefix (just downloaded and
> tried it on 0.99.9i). What version shall I use?
>
If you're using 0.99.9i you're missing out on the 584 commits that has
been committed since then. 1.1.3 was released a couple of days ago. I
suggest you upgrade.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:09 ` Ryan Anderson
@ 2006-01-18 14:21 ` Petr Baudis
2006-01-18 14:39 ` Ryan Anderson
2006-01-18 16:23 ` Linus Torvalds
1 sibling, 1 reply; 25+ messages in thread
From: Petr Baudis @ 2006-01-18 14:21 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Mathias Waack, git
Dear diary, on Wed, Jan 18, 2006 at 03:09:17PM CET, I got a letter
where Ryan Anderson <ryan@michonline.com> said that...
> ... Why would that be the optimal method?
Ow. I suppose that's what you call "blinded by invalid implicit
assumptions". Obviously, if you are ok with such a grand move, this is
the best.
This also reminds me that I should finally merge the cg-mv patch.
> git fetch ../r1/
> GIT_INDEX_FILE=.git/tmp-index git-read-tree FETCH_HEAD
> GIT_INDEX_FILE=.git/tmp-index git-checkout-cache -a -u
> git-update-cache --add -- $(GIT_INDEX_FILE=.git/tmp-index git-ls-files)
> cp .git/FETCH_HEAD .git/MERGE_HEAD
> git commit
But if you want to have an idea what's actually going on on the high
level, perhaps the
cd r2
cg-branch-add r1 ../r1/.git
cg-fetch r1
cg-merge -j r1
might be easier. ;-)
--
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 [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:21 ` Petr Baudis
@ 2006-01-18 14:39 ` Ryan Anderson
0 siblings, 0 replies; 25+ messages in thread
From: Ryan Anderson @ 2006-01-18 14:39 UTC (permalink / raw)
To: Petr Baudis; +Cc: Mathias Waack, git
[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]
Petr Baudis wrote:
>Dear diary, on Wed, Jan 18, 2006 at 03:09:17PM CET, I got a letter
>where Ryan Anderson <ryan@michonline.com> said that...
>
>
>>... Why would that be the optimal method?
>>
>Ow. I suppose that's what you call "blinded by invalid implicit
>assumptions". Obviously, if you are ok with such a grand move, this is
>the best.
>
>
Sorry, that came out a bit harsher than I had intended.
>This also reminds me that I should finally merge the cg-mv patch.
>
>> git fetch ../r1/
>> GIT_INDEX_FILE=.git/tmp-index git-read-tree FETCH_HEAD
>> GIT_INDEX_FILE=.git/tmp-index git-checkout-cache -a -u
>> git-update-cache --add -- $(GIT_INDEX_FILE=.git/tmp-index git-ls-files)
>> cp .git/FETCH_HEAD .git/MERGE_HEAD
>> git commit
>>
>>
>
>But if you want to have an idea what's actually going on on the high
>level, perhaps the
>
> cd r2
> cg-branch-add r1 ../r1/.git
> cg-fetch r1
> cg-merge -j r1
>
>might be easier. ;-)
>
Ah, yes, cg-merge seems like it might be somewhat simpler here.
--
Ryan Anderson
sometimes Pug Majere
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:09 ` Ryan Anderson
2006-01-18 14:21 ` Petr Baudis
@ 2006-01-18 16:23 ` Linus Torvalds
2006-01-18 17:05 ` Petr Baudis
` (2 more replies)
1 sibling, 3 replies; 25+ messages in thread
From: Linus Torvalds @ 2006-01-18 16:23 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Petr Baudis, Mathias Waack, git
On Wed, 18 Jan 2006, Ryan Anderson wrote:
>
> Assuming both repositories are clean, no extraneous files, and without
> testing, of course:
>
> In r1:
> mkdir r1
> # move everything into the subdirectory called r1.
> git mv $(ls -a | grep -v -e ^.git$ -e ^r1$) r1/
> git commit -a "Restructure directory"
>
> In r2:
> mkdir r2
> # move all files into r2/
> git mv $(ls -a | grep -v -e ^.git$ -e ^r2$) r2/
> git commit -a "Restructure directory"
>
> git fetch ../r1/
> GIT_INDEX_FILE=.git/tmp-index git-read-tree FETCH_HEAD
> GIT_INDEX_FILE=.git/tmp-index git-checkout-cache -a -u
> git-update-cache --add -- $(GIT_INDEX_FILE=.git/tmp-index git-ls-files)
> cp .git/FETCH_HEAD .git/MERGE_HEAD
> git commit
>
> No history rewritten,
Right.
> merging with the old repositories should, at least theoretically, work,
> etc.
No. This - and the history rewriting - both have a fundamental problem: it
becomes totally impossible to merge back any changes of the subprojects,
at least automatically. The renaming just ends up making pretty much any
merge a manual affair (git can _help_, but it's going to be a matter of
luck if it works or not - and it usually won't work very well, because
you'll probably end up having files that have the same name in the new and
the old repo, and eventually you'll just have tons of confusion).
So it works only if you want to _really_ join the projects (like in the
"git tools" case), and never touch the old one again but it sucks
otherwise.
In the "gitk" case, we could actually continue to merge stuff after a
join, but that was largaly because there was no renaming. That's a very
special case, and it also became impossible to merge back.
Now, let's see what Junio comes up with, but in the meantime, I'd almost
suggest just something like
git clone oldrepo r1
cd r1
git checkout -b join-branch
cd ..
git add r1/.git/refs/heads/join-branch
git commit -m "Join repo 'oldrepo' at 'r1'"
which should actually work except for the fact that we don't like the
".git" component even as part of a sub-component (ie small hack to git
required to make it not ignore that path).
Linus
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 12:25 Joining Repositories Mathias Waack
2006-01-18 12:51 ` Petr Baudis
@ 2006-01-18 16:38 ` H. Peter Anvin
1 sibling, 0 replies; 25+ messages in thread
From: H. Peter Anvin @ 2006-01-18 16:38 UTC (permalink / raw)
To: Mathias Waack; +Cc: git
Mathias Waack wrote:
> Hello everybody,
>
> we're using git with cogito as a frontend. For some reasons I forgot we have
> some repositories which belong to the same project. To simplify the whole
> thing I would like to join these repositories. It mainly means to move some
> directories. So lets say I have:
>
> /r1/.git
> /r2/.git
>
> and what I would like to have is
>
> /r/.git
> r1
> r2
>
> Of course the history should remain (otherwise it would be to easy).
>
> How should I do this?
>
Rename the files in each repository independently (with a checkin), then
merge the repositories.
Git *should* track across the rename, as long as it's "obvious".
-hpa
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 16:23 ` Linus Torvalds
@ 2006-01-18 17:05 ` Petr Baudis
2006-01-18 17:33 ` Junio C Hamano
2006-01-18 18:03 ` Linus Torvalds
2006-01-18 17:30 ` Junio C Hamano
2006-01-18 18:55 ` Ryan Anderson
2 siblings, 2 replies; 25+ messages in thread
From: Petr Baudis @ 2006-01-18 17:05 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Ryan Anderson, Mathias Waack, git
Dear diary, on Wed, Jan 18, 2006 at 05:23:03PM CET, I got a letter
where Linus Torvalds <torvalds@osdl.org> said that...
> On Wed, 18 Jan 2006, Ryan Anderson wrote:
> > merging with the old repositories should, at least theoretically, work,
> > etc.
>
> No. This - and the history rewriting - both have a fundamental problem: it
> becomes totally impossible to merge back any changes of the subprojects,
> at least automatically. The renaming just ends up making pretty much any
> merge a manual affair (git can _help_, but it's going to be a matter of
> luck if it works or not - and it usually won't work very well, because
> you'll probably end up having files that have the same name in the new and
> the old repo, and eventually you'll just have tons of confusion).
Well, the recursive merge strategy is at least advertised to be able to
merge across renames (as long as they are autodetected). Not that I
would have any practical experiences with it and I don't know how smart
is it done (if it just runs rename detection between the merge base and
current head, yes, that might not give very good results in this case).
--
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 [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 16:23 ` Linus Torvalds
2006-01-18 17:05 ` Petr Baudis
@ 2006-01-18 17:30 ` Junio C Hamano
2006-01-18 18:22 ` Linus Torvalds
2006-01-19 2:12 ` Junio C Hamano
2006-01-18 18:55 ` Ryan Anderson
2 siblings, 2 replies; 25+ messages in thread
From: Junio C Hamano @ 2006-01-18 17:30 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
Linus Torvalds <torvalds@osdl.org> writes:
> On Wed, 18 Jan 2006, Ryan Anderson wrote:
>>
>> Assuming both repositories are clean, no extraneous files, and without
>> testing, of course:
>>
>> ... "coolest merge ever" recipe here ...
>>
>> No history rewritten,
>
> Right.
>> merging with the old repositories should, at least theoretically, work,
>> etc.
>
> No. This - and the history rewriting - both have a fundamental problem: it
> becomes totally impossible to merge back any changes of the subprojects,
> at least automatically.
Right.
> In the "gitk" case, we could actually continue to merge stuff after a
> join, but that was largaly because there was no renaming. That's a very
> special case, and it also became impossible to merge back.
Correct.
> Now, let's see what Junio comes up with,...
Well, since the reason the original RFI came was "somehow we
forgot these things are together but ended up having to and need
a way to rectify the situation", in this particular case,
merging back the changes to subprojects (which is very awkward
if not impossible after a "coolest merge ever") is a non issue.
Tracking history across renames is something we have only half
of the needed support. We can notice rename points but there is
no way to tell our usability tools to automatically follow it.
IOW "whatchanged r1/hello.c" will stop at the point the
original project renamed hello.c to r1/hello.c in preparation
for the coolest merge and you have to restart whatchanged at
that commit with "whatchanged $that_commit hello.c" to go
further back; but that is true when no project merge is involved
so it may be an issue but it is not a new issue.
So for this case, I think the "coolest merge" is the right thing
to do.
> suggest just something like
>
> git clone oldrepo r1
> cd r1
> git checkout -b join-branch
> cd ..
> git add r1/.git/refs/heads/join-branch
> git commit -m "Join repo 'oldrepo' at 'r1'"
>
> which should actually work except for the fact that we don't like the
> ".git" component even as part of a sub-component (ie small hack to git
> required to make it not ignore that path).
Sorry you lost me with this. The "join-branch" is a file with
commit object name in it, so is this "recording the revision of
the other project this particular version of the project is
linked to" idea?
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 17:05 ` Petr Baudis
@ 2006-01-18 17:33 ` Junio C Hamano
2006-01-18 18:03 ` Linus Torvalds
1 sibling, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2006-01-18 17:33 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Petr Baudis <pasky@suse.cz> writes:
> Well, the recursive merge strategy is at least advertised to be able to
> merge across renames (as long as they are autodetected). Not that I
> would have any practical experiences with it and I don't know how smart
> is it done (if it just runs rename detection between the merge base and
> current head, yes, that might not give very good results in this case).
If I understand and remember the code correctly, it is based on
rename detection between two heads. When the versions have
diverged greatly beyond recognition, obviously this would not
work well.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 17:05 ` Petr Baudis
2006-01-18 17:33 ` Junio C Hamano
@ 2006-01-18 18:03 ` Linus Torvalds
1 sibling, 0 replies; 25+ messages in thread
From: Linus Torvalds @ 2006-01-18 18:03 UTC (permalink / raw)
To: Petr Baudis; +Cc: Ryan Anderson, Mathias Waack, git
On Wed, 18 Jan 2006, Petr Baudis wrote:
>
> Well, the recursive merge strategy is at least advertised to be able to
> merge across renames (as long as they are autodetected).
Yes. It can. However, the git merge approach fundamentally expects that
the merged trees _converge_.
So what happens is that if two trees continue to be developed as separate
trees, and the merges never converge (ie they happen just one way, with
the other way seldom or never merging back), the merge strategy will get
increasingly bad.
That's pretty unavoidable, btw. I can pretty much guarantee that nobody
else will really do it any better, although any particular strategy will
always handle one particular case perfectly (*).
Linus
(*) I think merging is like scheduling: you can always find a perfect
scheduling algorithm _after_the_fact_ when you know the load, but finding
one that works for all loads inevitably means that some cases won't work
well. You also find scheduling getting an inordinate amount of time in CS
literature, while in real life it's one of the least important problems of
a kernel.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 17:30 ` Junio C Hamano
@ 2006-01-18 18:22 ` Linus Torvalds
2006-01-18 19:09 ` Junio C Hamano
2006-01-19 2:12 ` Junio C Hamano
1 sibling, 1 reply; 25+ messages in thread
From: Linus Torvalds @ 2006-01-18 18:22 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On Wed, 18 Jan 2006, Junio C Hamano wrote:
>
> Tracking history across renames is something we have only half
> of the needed support. We can notice rename points but there is
> no way to tell our usability tools to automatically follow it.
> IOW "whatchanged r1/hello.c" will stop at the point the
> original project renamed hello.c
Note that "whatchanged" really really _really_ must not follow renames.
Why? The whole _point_ of whatchanged is that it takes a path limiter. A
path limiter is much more useful (to me) that following files. A path
limiter works even when the file doesn't _currently_ exist, and you don't
know what happened to it. A path limiter also fundamentally works for
directories and for multiple files.
If you want "git annotate", then do a "git annotate". Don't change what
"git whatchanged" does. The "pathname only" behaviour is in my opinion THE
MOST SINGLE BIGGEST FEATURE of git.
I _much_ more often use a directory to "git-whatchanged" than I look at an
individual file. Maybe other people don't do that, because they don't tend
to look at the "big picture", or because they are stuck in the "single
file only" mentality, but trust me, especially for maintaining big things,
the "track directories" is a lot more important than single-file tracking.
A _LOT_ more.
I realize that this is heresy to people who are used to "annotate" and
want to follow not the path, but the "conceptual inode", but the thing is,
paths really really are a lot more important to a maintainer. Following an
individual file is a secondary issue.
Now, the fact that we still don't have an efficient "git annotate" is not
because we don't have the capability. It _should_ be perfectly easy to do
(and efficient) by just parsing the output of
git-rev-list HEAD -- <filename>
and when you see a "delete" event, you'd look if it was really a rename.
I think qgit does this, but we don't have the textual version in core git.
So the reason core git tracks PATHNAMES and not files is:
- it's fundamentally a much more powerful operation
- it's possible (and not that much harder) to track renames efficiently
using it anyway, so you can emulate the "track file" behaviour using
"track pathname", but you can NOT emulate it the other way around.
In other words, tracking pathnames is really _fundamentally_ a more
powerful operation.
Git does this right. It is - together with multiple branches - the thing
that makes git work better than BK did for me.
> > suggest just something like
> >
> > git clone oldrepo r1
> > cd r1
> > git checkout -b join-branch
> > cd ..
> > git add r1/.git/refs/heads/join-branch
> > git commit -m "Join repo 'oldrepo' at 'r1'"
> >
> > which should actually work except for the fact that we don't like the
> > ".git" component even as part of a sub-component (ie small hack to git
> > required to make it not ignore that path).
>
> Sorry you lost me with this. The "join-branch" is a file with
> commit object name in it, so is this "recording the revision of
> the other project this particular version of the project is
> linked to" idea?
Yes. It also means that if you update the other project (commit, pull,
whatever), "git diff" in the top level will do the right thing: it won't
be readable, but you'll always have the SHA1 visible, and you can "commit"
the fact that you updated the sub-project in the top project. It's
basically a poor mans "gitlink".
Linus
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 16:23 ` Linus Torvalds
2006-01-18 17:05 ` Petr Baudis
2006-01-18 17:30 ` Junio C Hamano
@ 2006-01-18 18:55 ` Ryan Anderson
2 siblings, 0 replies; 25+ messages in thread
From: Ryan Anderson @ 2006-01-18 18:55 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Petr Baudis, Mathias Waack, git
[-- Attachment #1: Type: text/plain, Size: 1594 bytes --]
Linus Torvalds wrote:
>
> On Wed, 18 Jan 2006, Ryan Anderson wrote:
>
>>Assuming both repositories are clean, no extraneous files, and without
>>testing, of course:
>>
>>In r1:
>> mkdir r1
>> # move everything into the subdirectory called r1.
>> git mv $(ls -a | grep -v -e ^.git$ -e ^r1$) r1/
>> git commit -a "Restructure directory"
>>
>>In r2:
>> mkdir r2
>> # move all files into r2/
>> git mv $(ls -a | grep -v -e ^.git$ -e ^r2$) r2/
>> git commit -a "Restructure directory"
>>
>> git fetch ../r1/
>> GIT_INDEX_FILE=.git/tmp-index git-read-tree FETCH_HEAD
>> GIT_INDEX_FILE=.git/tmp-index git-checkout-cache -a -u
>> git-update-cache --add -- $(GIT_INDEX_FILE=.git/tmp-index git-ls-files)
>> cp .git/FETCH_HEAD .git/MERGE_HEAD
>> git commit
>>
>>No history rewritten,
>
>
> Right.
>
>
>>merging with the old repositories should, at least theoretically, work,
>>etc.
>
>
> No. This - and the history rewriting - both have a fundamental problem: it
> becomes totally impossible to merge back any changes of the subprojects,
> at least automatically. The renaming just ends up making pretty much any
> merge a manual affair (git can _help_, but it's going to be a matter of
> luck if it works or not - and it usually won't work very well, because
> you'll probably end up having files that have the same name in the new and
> the old repo, and eventually you'll just have tons of confusion).
What I meant was that an old repository can continue to be developed in,
and, in theory, the recursive merge should be able to merge those
changes into this new, joined, repository.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 18:22 ` Linus Torvalds
@ 2006-01-18 19:09 ` Junio C Hamano
2006-01-18 20:09 ` Linus Torvalds
0 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2006-01-18 19:09 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
Linus Torvalds <torvalds@osdl.org> writes:
> On Wed, 18 Jan 2006, Junio C Hamano wrote:
>>
>> Tracking history across renames is something we have only half
>> of the needed support. We can notice rename points but there is
>> no way to tell our usability tools to automatically follow it.
>> IOW "whatchanged r1/hello.c" will stop at the point the
>> original project renamed hello.c
>
> Note that "whatchanged" really really _really_ must not follow renames.
Sorry for having brought up the issue again. I personally do
not disagree with you. Because I did not want to waste your
time rehashing it, I attempted to make it absolutely clear that
I was talking about an _optional_ way to tell the tool to do so,
when somebody so used to "annotate" wants to. Obviously my
attempt did not work well X-<.
> I realize that this is heresy to people who are used to "annotate" and
> want to follow not the path, but the "conceptual inode", but the thing is,
> paths really really are a lot more important to a maintainer. Following an
> individual file is a secondary issue.
> ...
> In other words, tracking pathnames is really _fundamentally_ a more
> powerful operation.
I agree with you including this part. At the same time, I think
annotate-minded people would find it useful if there were an
option (or a separate program similar to whatchanged) that
notices file or directory renames, and adjusts the initial path
limiter, probably by adding not replacing the new "possibly
relevant" paths it discovered to it.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 19:09 ` Junio C Hamano
@ 2006-01-18 20:09 ` Linus Torvalds
2006-01-18 22:47 ` Linus Torvalds
0 siblings, 1 reply; 25+ messages in thread
From: Linus Torvalds @ 2006-01-18 20:09 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On Wed, 18 Jan 2006, Junio C Hamano wrote:
>
> Sorry for having brought up the issue again. I personally do
> not disagree with you. Because I did not want to waste your
> time rehashing it, I attempted to make it absolutely clear that
> I was talking about an _optional_ way to tell the tool to do so,
> when somebody so used to "annotate" wants to. Obviously my
> attempt did not work well X-<.
Well, the main reason I did the "limit git-rev-list with pathnames" was
literally to try to help the "annotate one file".
So I don't think file following has anything to do with "git-whatchanged".
It's literally an op we don't have yet - and that we should have. It
really should be pretty straighforward to do a "git annotate" these days.
It will never be as fast as git-whatchanged, but it shouldn't be horribly
inefficient either.
The one thing I've considered doing (I really should) is to add a "stop
when you don't find the file" option to "git-rev-list". This patch does
some of the work towards that: it removes the "parent" thing when the
file disappears, so a "git annotate" could do do something like
git-rev-list --remove-empty --parents HEAD -- "$filename"
and it would get a good graph that stops when the filename disappears
(it's not perfect though: it won't remove all the unintersting commits).
Linus
----
diff --git a/rev-list.c b/rev-list.c
index d060966..3906674 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -54,6 +54,7 @@ static int stop_traversal = 0;
static int topo_order = 0;
static int no_merges = 0;
static const char **paths = NULL;
+static int remove_empty_trees = 0;
static void show_commit(struct commit *commit)
{
@@ -424,14 +425,33 @@ static void mark_edges_uninteresting(str
}
}
-static int is_different = 0;
+#define TREE_SAME 0
+#define TREE_NEW 1
+#define TREE_DIFFERENT 2
+static int tree_difference = TREE_SAME;
static void file_add_remove(struct diff_options *options,
int addremove, unsigned mode,
const unsigned char *sha1,
const char *base, const char *path)
{
- is_different = 1;
+ int diff = TREE_DIFFERENT;
+
+ /*
+ * Is it an add of a new file? It means that
+ * the old tree didn't have it at all, so we
+ * will turn "TREE_SAME" -> "TREE_NEW", but
+ * leave any "TREE_DIFFERENT" alone (and if
+ * it already was "TREE_NEW", we'll keep it
+ * "TREE_NEW" of course).
+ */
+ if (addremove == '+') {
+ diff = tree_difference;
+ if (diff != TREE_SAME)
+ return;
+ diff = TREE_NEW;
+ }
+ tree_difference = diff;
}
static void file_change(struct diff_options *options,
@@ -440,7 +460,7 @@ static void file_change(struct diff_opti
const unsigned char *new_sha1,
const char *base, const char *path)
{
- is_different = 1;
+ tree_difference = TREE_DIFFERENT;
}
static struct diff_options diff_opt = {
@@ -449,12 +469,16 @@ static struct diff_options diff_opt = {
.change = file_change,
};
-static int same_tree(struct tree *t1, struct tree *t2)
+static int compare_tree(struct tree *t1, struct tree *t2)
{
- is_different = 0;
+ if (!t1)
+ return TREE_NEW;
+ if (!t2)
+ return TREE_DIFFERENT;
+ tree_difference = TREE_SAME;
if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &diff_opt) < 0)
- return 0;
- return !is_different;
+ return TREE_DIFFERENT;
+ return tree_difference;
}
static int same_tree_as_empty(struct tree *t1)
@@ -474,26 +498,38 @@ static int same_tree_as_empty(struct tre
empty.buf = "";
empty.size = 0;
- is_different = 0;
+ tree_difference = 0;
retval = diff_tree(&empty, &real, "", &diff_opt);
free(tree);
- return retval >= 0 && !is_different;
+ return retval >= 0 && !tree_difference;
}
-static struct commit *try_to_simplify_merge(struct commit *commit, struct commit_list *parent)
+static struct commit *try_to_simplify_merge(struct commit *commit)
{
+ struct commit_list **pp, *parent;
+
if (!commit->tree)
return NULL;
- while (parent) {
+ pp = &commit->parents;
+ while ((parent = *pp) != NULL) {
struct commit *p = parent->item;
- parent = parent->next;
parse_commit(p);
- if (!p->tree)
- continue;
- if (same_tree(commit->tree, p->tree))
+ switch (compare_tree(p->tree, commit->tree)) {
+ case TREE_SAME:
return p;
+ case TREE_NEW:
+ if (remove_empty_trees) {
+ *pp = parent->next;
+ continue;
+ }
+ /* fallthrough */
+ case TREE_DIFFERENT:
+ pp = &parent->next;
+ continue;
+ }
+ die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
}
return NULL;
}
@@ -538,7 +574,7 @@ static void add_parents_to_list(struct c
if (paths && parent && parent->next) {
struct commit *preferred;
- preferred = try_to_simplify_merge(commit, parent);
+ preferred = try_to_simplify_merge(commit);
if (preferred) {
parent->item = preferred;
parent->next = NULL;
@@ -576,10 +612,18 @@ static void compress_list(struct commit_
* unchanged
*/
if (!parent->next) {
- struct tree *t1 = commit->tree;
- struct tree *t2 = parent->item->tree;
- if (!t1 || !t2 || same_tree(t1, t2))
+ struct tree *t1 = parent->item->tree;
+ struct tree *t2 = commit->tree;
+ switch (compare_tree(t1, t2)) {
+ case TREE_SAME:
continue;
+ case TREE_NEW:
+ if (remove_empty_trees)
+ commit->parents = NULL;
+ break;
+ case TREE_DIFFERENT:
+ break;
+ }
}
commit->object.flags |= TREECHANGE;
}
@@ -808,6 +852,10 @@ int main(int argc, const char **argv)
dense = 0;
continue;
}
+ if (!strcmp(arg, "--remove-empty")) {
+ remove_empty_trees = 1;
+ continue;
+ }
if (!strcmp(arg, "--")) {
i++;
break;
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 20:09 ` Linus Torvalds
@ 2006-01-18 22:47 ` Linus Torvalds
2006-01-18 23:15 ` Linus Torvalds
0 siblings, 1 reply; 25+ messages in thread
From: Linus Torvalds @ 2006-01-18 22:47 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On Wed, 18 Jan 2006, Linus Torvalds wrote:
>
> The one thing I've considered doing (I really should) is to add a "stop
> when you don't find the file" option to "git-rev-list". This patch does
> some of the work towards that: it removes the "parent" thing when the
> file disappears, so a "git annotate" could do do something like
>
> git-rev-list --remove-empty --parents HEAD -- "$filename"
>
> and it would get a good graph that stops when the filename disappears
> (it's not perfect though: it won't remove all the unintersting commits).
Here is a somewhat better version of this patch.
It also simplifies the logic of finding tree differences a bit, at the
cost of making it a tad less efficient.
The old logic was two-phase: it would first simplify _only_ merges tree as
it traversed the tree, and then simplify the linear parts of the remainder
independently. That was pretty optimal from an efficiency standpoint
because it avoids doing any comparisons that we can see are unnecessary,
but it made it much harder to understand than it really needed to be.
The new logic is a lot more straightforward, and compares the trees as it
traverses the graph (ie everything is a single phase). That makes it much
easier to stop graph traversal at any point where a file disappears.
As an example, let's say that you have a git repository that has had a
file called "A" some time in the past. That file gets renamed to B, and
then gets renamed back again to A. The old "git-rev-list" would show two
commits commits: the commit that renames B to A (because it changes A)
_and_ as its parent the commit that renames A to B (because it changes A).
With the new --remove-empty flag, git-rev-list will show just the commit
that renames B to A as the "root" commit, and stop traversal there
(because that's what you want for "annotate" - you want to stop there, and
for every "root" commit you then separately see if it really is a new
file, or if the paths history disappeared because it was renamed from some
other file).
With this patch, you should be able to basically do a "poor mans 'git
annotate'" with a fairly simple loop:
push("HEAD", "$filename")
while (revision,filename = pop()) {
for each i in $(git-rev-list --parents --remove-empty $revision -- "$filename")
pseudo-parents($i) = git-rev-list parents for that line
if (pseudo-parents($i) is non-empty) {
show diff of $i against pseudo-parents
continue
}
/* See if the _real_ parents of $i had a rename */
parent($i) = real-parent($i)
if (find-rename in $parent($i)->$i)
push $parent($i), "old-name"
}
which should be doable in perl or something (doing stacks in shell is just
too painful to be worth it, so I'm not going to do this).
Anybody want to try?
Linus
---
diff --git a/rev-list.c b/rev-list.c
index d060966..912071d 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -54,6 +54,7 @@ static int stop_traversal = 0;
static int topo_order = 0;
static int no_merges = 0;
static const char **paths = NULL;
+static int remove_empty_trees = 0;
static void show_commit(struct commit *commit)
{
@@ -424,14 +425,33 @@ static void mark_edges_uninteresting(str
}
}
-static int is_different = 0;
+#define TREE_SAME 0
+#define TREE_NEW 1
+#define TREE_DIFFERENT 2
+static int tree_difference = TREE_SAME;
static void file_add_remove(struct diff_options *options,
int addremove, unsigned mode,
const unsigned char *sha1,
const char *base, const char *path)
{
- is_different = 1;
+ int diff = TREE_DIFFERENT;
+
+ /*
+ * Is it an add of a new file? It means that
+ * the old tree didn't have it at all, so we
+ * will turn "TREE_SAME" -> "TREE_NEW", but
+ * leave any "TREE_DIFFERENT" alone (and if
+ * it already was "TREE_NEW", we'll keep it
+ * "TREE_NEW" of course).
+ */
+ if (addremove == '+') {
+ diff = tree_difference;
+ if (diff != TREE_SAME)
+ return;
+ diff = TREE_NEW;
+ }
+ tree_difference = diff;
}
static void file_change(struct diff_options *options,
@@ -440,7 +460,7 @@ static void file_change(struct diff_opti
const unsigned char *new_sha1,
const char *base, const char *path)
{
- is_different = 1;
+ tree_difference = TREE_DIFFERENT;
}
static struct diff_options diff_opt = {
@@ -449,12 +469,16 @@ static struct diff_options diff_opt = {
.change = file_change,
};
-static int same_tree(struct tree *t1, struct tree *t2)
+static int compare_tree(struct tree *t1, struct tree *t2)
{
- is_different = 0;
+ if (!t1)
+ return TREE_NEW;
+ if (!t2)
+ return TREE_DIFFERENT;
+ tree_difference = TREE_SAME;
if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &diff_opt) < 0)
- return 0;
- return !is_different;
+ return TREE_DIFFERENT;
+ return tree_difference;
}
static int same_tree_as_empty(struct tree *t1)
@@ -474,28 +498,55 @@ static int same_tree_as_empty(struct tre
empty.buf = "";
empty.size = 0;
- is_different = 0;
+ tree_difference = 0;
retval = diff_tree(&empty, &real, "", &diff_opt);
free(tree);
- return retval >= 0 && !is_different;
+ return retval >= 0 && !tree_difference;
}
-static struct commit *try_to_simplify_merge(struct commit *commit, struct commit_list *parent)
+static void try_to_simplify_commit(struct commit *commit)
{
+ struct commit_list **pp, *parent;
+
if (!commit->tree)
- return NULL;
+ return;
- while (parent) {
+ if (!commit->parents) {
+ if (!same_tree_as_empty(commit->tree))
+ commit->object.flags |= TREECHANGE;
+ return;
+ }
+
+ pp = &commit->parents;
+ while ((parent = *pp) != NULL) {
struct commit *p = parent->item;
- parent = parent->next;
+
+ if (p->object.flags & UNINTERESTING) {
+ pp = &parent->next;
+ continue;
+ }
+
parse_commit(p);
- if (!p->tree)
+ switch (compare_tree(p->tree, commit->tree)) {
+ case TREE_SAME:
+ parent->next = NULL;
+ commit->parents = parent;
+ return;
+
+ case TREE_NEW:
+ if (remove_empty_trees && same_tree_as_empty(p->tree)) {
+ *pp = parent->next;
+ continue;
+ }
+ /* fallthrough */
+ case TREE_DIFFERENT:
+ pp = &parent->next;
continue;
- if (same_tree(commit->tree, p->tree))
- return p;
+ }
+ die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
}
- return NULL;
+ commit->object.flags |= TREECHANGE;
}
static void add_parents_to_list(struct commit *commit, struct commit_list **list)
@@ -531,20 +582,14 @@ static void add_parents_to_list(struct c
}
/*
- * Ok, the commit wasn't uninteresting. If it
- * is a merge, try to find the parent that has
- * no differences in the path set if one exists.
+ * Ok, the commit wasn't uninteresting. Try to
+ * simplify the commit history and find the parent
+ * that has no differences in the path set if one exists.
*/
- if (paths && parent && parent->next) {
- struct commit *preferred;
-
- preferred = try_to_simplify_merge(commit, parent);
- if (preferred) {
- parent->item = preferred;
- parent->next = NULL;
- }
- }
+ if (paths)
+ try_to_simplify_commit(commit);
+ parent = commit->parents;
while (parent) {
struct commit *p = parent->item;
@@ -558,33 +603,6 @@ static void add_parents_to_list(struct c
}
}
-static void compress_list(struct commit_list *list)
-{
- while (list) {
- struct commit *commit = list->item;
- struct commit_list *parent = commit->parents;
- list = list->next;
-
- if (!parent) {
- if (!same_tree_as_empty(commit->tree))
- commit->object.flags |= TREECHANGE;
- continue;
- }
-
- /*
- * Exactly one parent? Check if it leaves the tree
- * unchanged
- */
- if (!parent->next) {
- struct tree *t1 = commit->tree;
- struct tree *t2 = parent->item->tree;
- if (!t1 || !t2 || same_tree(t1, t2))
- continue;
- }
- commit->object.flags |= TREECHANGE;
- }
-}
-
static struct commit_list *limit_list(struct commit_list *list)
{
struct commit_list *newlist = NULL;
@@ -614,8 +632,6 @@ static struct commit_list *limit_list(st
}
if (tree_objects)
mark_edges_uninteresting(newlist);
- if (paths && dense)
- compress_list(newlist);
if (bisect_list)
newlist = find_bisection(newlist);
return newlist;
@@ -808,6 +824,10 @@ int main(int argc, const char **argv)
dense = 0;
continue;
}
+ if (!strcmp(arg, "--remove-empty")) {
+ remove_empty_trees = 1;
+ continue;
+ }
if (!strcmp(arg, "--")) {
i++;
break;
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 22:47 ` Linus Torvalds
@ 2006-01-18 23:15 ` Linus Torvalds
0 siblings, 0 replies; 25+ messages in thread
From: Linus Torvalds @ 2006-01-18 23:15 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On Wed, 18 Jan 2006, Linus Torvalds wrote:
>
> As an example, let's say that you have a git repository that has had a
> file called "A" some time in the past. That file gets renamed to B, and
> then gets renamed back again to A. The old "git-rev-list" would show two
> commits commits: the commit that renames B to A (because it changes A)
> _and_ as its parent the commit that renames A to B (because it changes A).
Btw, in case somebody doesn't see what's wrong with that (because those
two commits happen to be the only ones that matter), let's point out that
the file may have changed while it was called "B". So to do annotation, we
really need to _stop_ following the filename, start following the previous
one.
Now, the logic to do that could have been in the "annotate" parts, but the
decision to stop following the chain actually makes sense as part of
git-rev-list, since it does the tree difference tracking anyway.
Linus
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 17:30 ` Junio C Hamano
2006-01-18 18:22 ` Linus Torvalds
@ 2006-01-19 2:12 ` Junio C Hamano
2006-01-19 9:03 ` Petr Baudis
1 sibling, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2006-01-19 2:12 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Ryan Anderson, Petr Baudis, Mathias Waack, git
Junio C Hamano <junkio@cox.net> writes:
> Linus Torvalds <torvalds@osdl.org> writes:
>
>> Now, let's see what Junio comes up with,...
>
> Well, since the reason the original RFI came was...
> ...
> So for this case, I think the "coolest merge" is the right
> thing to do.
I said this only because I wanted to recommend a solution
available today to the original requester.
If I were to talk about (one potential) future solution, I would
say "bind" commit would work naturally for this case, without
disrupting the development histories of the projects being
combined. After all, the "bind" commit approach is not much
different from what you did with "the coolest merge ever", with
a few twists, such as (1) not overlaying but requiring each
subproject to be bound at a non-overlapping subdirectory, and
(2) letting a subproject keep its own independent history that
does not know about other subprojects even after combination
happens (as opposed to the coolest merge, after which there is
no git history that does not have gitk as its part).
Of course, "gitlink" would equally work well and have similar
characteristics. The implementation details will certainly
differ and the user interaction may somewhat be different as
well, but I do not think of any reason either approach would not
work well in this situation.
So would Cogito subprojects support (will it be in the 0.17?),
but it might look less powerful when compared with the "bind" or
"gitlink", if it comes in the form of the patch Pasky sent to
the list, since it does not attempt to tie the versions of two
projects together. Certainly that makes it the easiest to use
and understand what is going on, though.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-19 2:12 ` Junio C Hamano
@ 2006-01-19 9:03 ` Petr Baudis
0 siblings, 0 replies; 25+ messages in thread
From: Petr Baudis @ 2006-01-19 9:03 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, Ryan Anderson, Mathias Waack, git
Dear diary, on Thu, Jan 19, 2006 at 03:12:00AM CET, I got a letter
where Junio C Hamano <junkio@cox.net> said that...
> (2) letting a subproject keep its own independent history that
> does not know about other subprojects even after combination
> happens (as opposed to the coolest merge, after which there is
> no git history that does not have gitk as its part).
Which can be an advantage or disadvantage depending on the situation,
but I suspect that it would be rather a disadvantage here.
> So would Cogito subprojects support (will it be in the 0.17?),
Probably in 0.18. I would have the subprojects support complete when
it's already in, and it will be some work, while I don't want to
postpone 0.17 much anymore. But we'll see. ;)
> but it might look less powerful when compared with the "bind" or
> "gitlink", if it comes in the form of the patch Pasky sent to
> the list, since it does not attempt to tie the versions of two
> projects together. Certainly that makes it the easiest to use
> and understand what is going on, though.
By now (I wanted to note that in the original thread when I get to make
a new patch), I've decided to extend the format to allow extra
information stored for the subprojects:
path\t...
This means that I will have to do preprocessing when using this as an
exclude file, but it will let me do the stuff like read-only
subprojects. I could also tie it to a specific version here, but if
gitlink/binds are after all going to get included in Git, I'd rather use
that when it is ready (although the single-git-directory approach does
not make sense to me; but I didn't read part of the thread very
carefully yet).
I think the approaches might be complementary, Cogito subprojects are
just designed for different scenarios than gitlinks.
--
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 [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:14 ` Petr Baudis
@ 2006-01-19 11:36 ` Mathias Waack
2006-01-19 18:24 ` Junio C Hamano
1 sibling, 0 replies; 25+ messages in thread
From: Mathias Waack @ 2006-01-19 11:36 UTC (permalink / raw)
To: git
Hello Petr,
On Wednesday 18 January 2006 03:14 pm, Petr Baudis wrote:
> > ...git-read-tree doesn't know the parameter --prefix (just downloaded and
> > tried it on 0.99.9i). What version shall I use?
>
> oops, it seems this is only in the latest pu branch of git. If you are
> not brave enough for that,
I think I am;)
> you will need to use the prefix facility of
> checkout-index instead, and it'll take much longer:
>
> git-read-tree $commit
> git-checkout-index -a --prefix=r1/
> rm .git/index
> cg-add -r r1/
> rm -rf r1
> .. then proceed with git-cat-file etc ..
Time doesn't matter (in this case). This solution seems to work.
> Note that I'm not sure when which feature was introduced. Your best
> bet is to just use the latest stable GIT/Cogito versions.
Thanks for your suggestions, I've got a working solution. Now I'm going to
spend the remaining days of this week by trying to understand why it works.
Mathias
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Joining Repositories
2006-01-18 14:14 ` Petr Baudis
2006-01-19 11:36 ` Mathias Waack
@ 2006-01-19 18:24 ` Junio C Hamano
1 sibling, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2006-01-19 18:24 UTC (permalink / raw)
To: Petr Baudis; +Cc: Mathias Waack, git
Petr Baudis <pasky@suse.cz> writes:
> oops, it seems this is only in the latest pu branch of git. If you are
> not brave enough for that, you will need to use the prefix facility of
> checkout-index instead, and it'll take much longer:
>...
> Note that I'm not sure when which feature was introduced. Your best
> bet is to just use the latest stable GIT/Cogito versions.
The "read-tree --prefix" and friends were only talked about
during the "bind" commit discussion, and with some experimental
code in "pu". Here is my thought on their readiness:
- "read-tree --prefix=<prefix>/" may independently be useful
even if we choose not to go "bind" commit approach. However
what it does when the index already has something at
<prefix>/ has room for improvement. I think it should have
an option to do an equivalent of either one-way merge or
two-way merge for that part of subtree. Currently it always
rejects if the current index has anything there.
- "write-tree --prefix=<prefix>/" is redundant for the purpose
of "bind" commit, because we would write the whole tree to be
recorded in the enclosing project and it is easy to pick the
subproject part with ls-tree from such a tree. So it needs
an independent advocate / rationale before graduating from
"pu".
- "write-tree --bound=<prefix>/ --bound=<prefix>/ ..." cannot
be emulated by any other way and may be independently useful
outside "bind" commit context. Maybe the option should be
renamed to --exclude=<prefix>/ or somesuch before going to
"master".
- "commit-tree --bind" should stay in "pu" until other pieces
to correctly deal with commit objects with "bind" lines are
ready, including fsck-objects and rev-list. It _might_ be
safer to bump the core.repositoryformatversion automatically
once you have such a commit object in your repo.
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2006-01-19 18:24 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-18 12:25 Joining Repositories Mathias Waack
2006-01-18 12:51 ` Petr Baudis
2006-01-18 12:58 ` Petr Baudis
2006-01-18 14:01 ` Mathias Waack
2006-01-18 14:14 ` Petr Baudis
2006-01-19 11:36 ` Mathias Waack
2006-01-19 18:24 ` Junio C Hamano
2006-01-18 14:14 ` Andreas Ericsson
2006-01-18 14:09 ` Ryan Anderson
2006-01-18 14:21 ` Petr Baudis
2006-01-18 14:39 ` Ryan Anderson
2006-01-18 16:23 ` Linus Torvalds
2006-01-18 17:05 ` Petr Baudis
2006-01-18 17:33 ` Junio C Hamano
2006-01-18 18:03 ` Linus Torvalds
2006-01-18 17:30 ` Junio C Hamano
2006-01-18 18:22 ` Linus Torvalds
2006-01-18 19:09 ` Junio C Hamano
2006-01-18 20:09 ` Linus Torvalds
2006-01-18 22:47 ` Linus Torvalds
2006-01-18 23:15 ` Linus Torvalds
2006-01-19 2:12 ` Junio C Hamano
2006-01-19 9:03 ` Petr Baudis
2006-01-18 18:55 ` Ryan Anderson
2006-01-18 16:38 ` H. Peter Anvin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).