* Re: Re: Re: write-tree is pasky-0.4
From: Linus Torvalds @ 2005-04-16 3:13 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.21.0504152221070.30848-100000@iabervon.org>
On Fri, 15 Apr 2005, Daniel Barkalow wrote:
>
> So you want to merge someone else's tree into your committed state, and
> then merge the result with your working directory to get the working
> directory you continue with, provided that the second merge is trivial?
No, you don't even "merge" the working directory.
The low-level tools should entirely ignore the working directory. To a
low-level merge, the working directory doesn't even exist. It just gets
three commits (or trees) and merges two of them with the third as a
parent, and does all of it in it's own temporary "merge working
directory".
So on a technical level, the "plumbing" part really really doesn't care at
all.
However, from a _usability_ part, you expect after a merge that your
working directory has been updated to be the merged tree. And that's where
the "if I have a working tree that is dirty, I want that part to fail"
comes in. In other words, the final phase (after the "tree-merge" has
actually successfully already finished) is to go back to the working
directory, and check out the merged results.
But that checkout would be a variation on "checkout-cache -a" which first
checks that none of the files it is going to overwrite are dirty.
Don't worry about this part. It's really totally separate from the true
merge itself. The "real work" has already been done by the time we notice
that "oops, we can't actually show him the newly merged tree, because he
has got dirty data where we want to show it".
> > I care. Even if the best common parent is 3 months ago, I care. I'd much
> > rather get a big explicit conflict than a "clean merge" that ends up being
> > debatable because people played games with per-file merging or something
> > questionable like that.
>
> Are you thinking that the best common ancestor is the one that ties up
> absolutely all of the chains of commits, or the closest one that the sides
> have in common?
The closest common one.
> For the latter, there are sometimes multiple ancestors which fit this
> criterion
Yes. Let's just pick one at random (or more likely, the latest one by
date - let's not actually be _random_ random) at first.
There are other heuristics we can try, ie if it turns out that it's common
to have a couple of alternatives (but no more than some small number, say
five or so), we can literally just -try- to do a tree-only merge, and see
how many lines out common output you get from "diff-tree".
Because that "how mnay files do we need to merge" is the number you want
to minimize, and doing a couple of extra "diff-tree" + "join" operations
should be so fast that nobody will notice that we actually tried five
different merges to see which one looked the best.
But hey, especially if the merge fails with real clashes (ie there are
changes in common and running "merge" leaves conflicts), and there were
other alternate parents to choose, there's nothing wrong with just
printing them out and saying "you might try to specify one of these
manually".
I really don't think we should worry too much about this until we've
actually used the system for a while and seen what it does. So just start
with "nearest common parent with most recent date". Which I think you
already implemented, no?
Linus
^ permalink raw reply
* Re: Add "clone" support to lntree
From: Daniel Barkalow @ 2005-04-16 3:06 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20050416024755.GX7417@pasky.ji.cz>
On Sat, 16 Apr 2005, Petr Baudis wrote:
> Dear diary, on Sat, Apr 16, 2005 at 03:56:03AM CEST, I got a letter
> where Daniel Barkalow <barkalow@iabervon.org> told me that...
> > I often want to take a base tree, which I keep tracking some remote head,
> > and make a local working tree that starts from it. This makes "git ln -c
> > <dest>" give you a tree that you can just start working in and then diff
> > against the head you'd started from and send off.
> >
> > Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
>
> I'm sorry but you are late, I added it about a hour and half ago or so.
> :-) Check git fork. (I *want* separate command than git lntree. In fact,
> I think I should make git lntree gitXlntree.sh instead, since it is
> really internal command for git-tools and the user should probably never
> need it for anything. git lntree is too lowlevel.)
Have you not pushed since? I don't see it.
I actually first made gitlntree.sh do the forking thing, because it didn't
seem useful as is, until I noticed that merge was already using it
internally.
> Actually, I don't like the name at all, though. Some people may find
> pondering about names pointless, but when I'm going to type them in
> every day for the rest of my life, they better should not be stupid. ;-)
>
> So, what are your clever ideas about git fork's proper name? Or should
> we leave it as is?
I think "fork" is as good as anything for describing the operation. I had
thought about "clone" because it seemed to fill the role that "bk
clone" had (although I never used BK, so I'm not sure). It doesn't seem
useful to me to try cloning multiple remote repositories, since you'd get
a copy of anything common from each; you just want to suck everything into
the same .git/objects and split off working directories.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: Re: Add "clone" support to lntree
From: Petr Baudis @ 2005-04-16 2:58 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <20050416024755.GX7417@pasky.ji.cz>
Dear diary, on Sat, Apr 16, 2005 at 04:47:55AM CEST, I got a letter
where Petr Baudis <pasky@ucw.cz> told me that...
> git branch --- creates a branch from a given commit
> (when passed empty commit, creates a branch
> from the current commit and sets the working
> tree to that branch)
> Note that there is a bug in current git update - it will allow you to
> bring several of your trees to follow the same branch, or even a remote
> branch. This is not even supposed to work, and will be fixed when I get
> some sleep. You will be able to do git pull even on local branches, and
> the proper solution for this will be just tracking the branch you want
> to follow.
I must admit that I'm not entirely decided yet, so I'd love to hear your
opinion.
I'm wondering, whether each tree should be fixed to a certain branch.
That is, you decide a name when you do git fork, and then the tree
always follows that branch. (It always has to follow [be bound to]
*some* branch, and each branch can be followed by only a single tree at
a time.)
Currently, you can at anytime "mark" a new branch (by git branch) and
you can freely "rebranch" your tree (by git update). An alternative
approach would be to disallow git update to "rebranch" and remove the
git branch command (you'd always do git fork).
From what I know, the alternative approach is nearer to what BK takes,
and it would be _slightly_ simpler (maybe). OTOH the current approach is
I believe more powerful, and could require less resources.
WWhat do you think,
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Re: [PATCH] write_sha1_buffer
From: Linus Torvalds @ 2005-04-16 2:59 UTC (permalink / raw)
To: Morten Welinder; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0504151942130.7211@ppc970.osdl.org>
On Fri, 15 Apr 2005, Linus Torvalds wrote:
>
> (This is also why we should write to a temp-file and then do an atomic
> "rename()").
Btw, before anybody asks: I do _not_ think that we should do fsync() etc.
We don't actually destroy any old state when we write a new object, so
even if the machine does go down, we really should just do an fsck and
then re-try the operation.
Anal people (or people with machines that crash) can add it later if they
really want.
Linus
^ permalink raw reply
* Re: [PATCH] write_sha1_buffer
From: Linus Torvalds @ 2005-04-16 2:55 UTC (permalink / raw)
To: Morten Welinder; +Cc: git
In-Reply-To: <118833cc05041517502fa52a89@mail.gmail.com>
On Fri, 15 Apr 2005, Morten Welinder wrote:
>
> This write will failing sooner or later when someone's disk fills up.
> That'll leave someone with a truncated file.
Yes. On the other hand, we could try to do this even better, ie make the
classic write loop that handles EAGAIN.
No POSIX filesystem is supposed to return EAGAIN, but there are tons of
"POSIX enough" filesystems. Notably NFS when mounted with "intr" (which
some people think is wrong, but it tends to be better than the
alternatives if your network is flaky enough).
But yes, even just a "write failed" is good enough, except you should also
make sure that you remove the corrupt file. Sure, fsck will catch it, but
if you don't do an fsck, somebody else might decide not to write the file
out simply because "it's already there".
(This is also why we should write to a temp-file and then do an atomic
"rename()").
Linus
^ permalink raw reply
* Re: Re: Re: write-tree is pasky-0.4
From: Daniel Barkalow @ 2005-04-16 2:49 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0504151913180.7211@ppc970.osdl.org>
On Fri, 15 Apr 2005, Linus Torvalds wrote:
> On Fri, 15 Apr 2005, Daniel Barkalow wrote:
> >
> > Is there some reason you don't commit before merging? All of the current
> > merge theory seems to want to merge two commits, using the information git
> > keeps about them.
>
> Note that the 3-way merge would _only_ merge the committed state. The
> thing is, 99% of all merges end up touching files that I never touch
> myself (ie other architectures), so me being able to merge them even when
> _I_ am in the middle of something is a good thing.
>
> So even when I have dirty state, the "merge" would only merge the clean
> state. And then before the merge information is put back into my working
> directory, I'd do a "check-files" on the result, making sure that nothing
> that got changed by the merge isn't up-to-date.
So you want to merge someone else's tree into your committed state, and
then merge the result with your working directory to get the working
directory you continue with, provided that the second merge is trivial?
> > How much do you care about the situation where there is no best common
> > ancestor
>
> I care. Even if the best common parent is 3 months ago, I care. I'd much
> rather get a big explicit conflict than a "clean merge" that ends up being
> debatable because people played games with per-file merging or something
> questionable like that.
Are you thinking that the best common ancestor is the one that ties up
absolutely all of the chains of commits, or the closest one that the sides
have in common? I have the feeling that the former isn't going to be
useful, because there will be lines you're considering merging which go
back to ancient kernels, where they keep merging in your changes, but
they still have a lineage back to 2.6.0 or something.
For the latter, there are sometimes multiple ancestors which fit this
criterion, and different ones of them are most helpful for different
portions of the merge. I think this primarily happens when a branch you
want to merge has accepted multiple patches that you've also
accepted (and the history identifies this fact); this may or may not be a
situation you want to allow on a regular basis.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: Add "clone" support to lntree
From: Petr Baudis @ 2005-04-16 2:47 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.21.0504152142360.30848-100000@iabervon.org>
Dear diary, on Sat, Apr 16, 2005 at 03:56:03AM CEST, I got a letter
where Daniel Barkalow <barkalow@iabervon.org> told me that...
> I often want to take a base tree, which I keep tracking some remote head,
> and make a local working tree that starts from it. This makes "git ln -c
> <dest>" give you a tree that you can just start working in and then diff
> against the head you'd started from and send off.
>
> Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
I'm sorry but you are late, I added it about a hour and half ago or so.
:-) Check git fork. (I *want* separate command than git lntree. In fact,
I think I should make git lntree gitXlntree.sh instead, since it is
really internal command for git-tools and the user should probably never
need it for anything. git lntree is too lowlevel.)
Actually, I don't like the name at all, though. Some people may find
pondering about names pointless, but when I'm going to type them in
every day for the rest of my life, they better should not be stupid. ;-)
So, what are your clever ideas about git fork's proper name? Or should
we leave it as is?
Summary of current related git commands (yes, they are already around
and should be actually all working):
git addremote --- registers a remote branch (name - URL pair)
git branch --- creates a branch from a given commit
(when passed empty commit, creates a branch
from the current commit and sets the working
tree to that branch)
git clone --- creates a local GIT repository from a remote one
git export --- checks out given commit to a separate directory
(without any GIT information)
git fork --- creates a new branch and working tree from
the current working tree, sharing the same
local GIT repository
git lntree --- creates a "treeshell" sharing the same GIT
repository with the current tree
If you think any other of those should be renamed, this is the time to
speak up. Oh well, I think I'll regret asking about this at all... ;-)
Note that there is a bug in current git update - it will allow you to
bring several of your trees to follow the same branch, or even a remote
branch. This is not even supposed to work, and will be fixed when I get
some sleep. You will be able to do git pull even on local branches, and
the proper solution for this will be just tracking the branch you want
to follow.
So, I'll fix that tomorrow, enable you to fork to an existing but unused
branch, fix git pull of remote branch by several local branches, and
write a lot of documentation.
Kind regards,
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Re: Re: Re: write-tree is pasky-0.4
From: Linus Torvalds @ 2005-04-16 2:18 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.21.0504152029410.30848-100000@iabervon.org>
On Fri, 15 Apr 2005, Daniel Barkalow wrote:
>
> Is there some reason you don't commit before merging? All of the current
> merge theory seems to want to merge two commits, using the information git
> keeps about them.
Note that the 3-way merge would _only_ merge the committed state. The
thing is, 99% of all merges end up touching files that I never touch
myself (ie other architectures), so me being able to merge them even when
_I_ am in the middle of something is a good thing.
So even when I have dirty state, the "merge" would only merge the clean
state. And then before the merge information is put back into my working
directory, I'd do a "check-files" on the result, making sure that nothing
that got changed by the merge isn't up-to-date.
> How much do you care about the situation where there is no best common
> ancestor
I care. Even if the best common parent is 3 months ago, I care. I'd much
rather get a big explicit conflict than a "clean merge" that ends up being
debatable because people played games with per-file merging or something
questionable like that.
> I think that the time spent on I/O will be overwhelmed by the time spent
> issuing the command at that rate.
There is no time at all spent on IO.
All my email is local, and if this all ends up working out well, I can
track the other peoples object trees in local subdirectories with some
daily rsyncs. And I have enough memory in my machines that there is
basically no disk IO - the only tree I normally touch is the kernel trees,
they all stay in cache.
Linus
^ permalink raw reply
* [PATCH] Add "clone" support to lntree
From: Daniel Barkalow @ 2005-04-16 1:56 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
I often want to take a base tree, which I keep tracking some remote head,
and make a local working tree that starts from it. This makes "git ln -c
<dest>" give you a tree that you can just start working in and then diff
against the head you'd started from and send off.
Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: gitlntree.sh
===================================================================
--- b068d3ec7c00cfe4a1f14a898f61c4807cd5bc8b/gitlntree.sh (mode:100755 sha1:17c4966ea64aeced96ae4f1b00f3775c1904b0f1)
+++ 0877e1b9b70a4305959b7f65ace4044e4ae0afdb/gitlntree.sh (mode:100755 sha1:84cbf0492996f1139b992147b4f53bc14342e3f2)
@@ -7,11 +7,14 @@
# same objects database as the current one. It also shares the
# branches and tags information.
#
-# The new directory is completely pristine - there's not even
-# a directory cache there yet.
-#
# Takes the new directory name.
+if [ "$1" = "-c" ]
+then
+ clone=yes
+ shift 1
+fi
+
destdir=$1
die () {
@@ -32,3 +35,12 @@
ln -s $srcdir/.git/objects $dgitdir/objects
ln -s $srcdir/.git/remotes $dgitdir/remotes
ln -s $srcdir/.git/tags $dgitdir/tags
+
+if [ "$clone" != "" ]
+then
+ cp $srcdir/.git/HEAD $dgitdir/HEAD
+ cd $destdir
+ read-tree $(tree-id)
+ checkout-cache -a
+ update-cache --refresh
+fi
^ permalink raw reply
* Re: Merge with git-pasky II.
From: Simon Fowler @ 2005-04-16 1:44 UTC (permalink / raw)
To: Linus Torvalds; +Cc: David Woodhouse, Junio C Hamano, Petr Baudis, git
In-Reply-To: <Pine.LNX.4.58.0504150753440.7211@ppc970.osdl.org>
[-- Attachment #1.1: Type: text/plain, Size: 1189 bytes --]
On Fri, Apr 15, 2005 at 08:32:46AM -0700, Linus Torvalds wrote:
> In other words, I'm right. I'm always right, but sometimes I'm more right
> than other times. And dammit, when I say "files don't matter", I'm really
> really Right(tm).
>
You're right, of course (All Hail Linus!), if you can make it work
efficiently enough.
Just to put something else on the table, here's how I'd go about
tracking renames and the like, in another world where Linus /does/
make the odd mistake - it's basically a unique id for files in the
repository, added when the file is first recognised and updated when
update-cache adds a new version to the cache. Renames copy the id
across to the new name, and add it into the cache.
This gives you an O(n) way to tell what file was what across
renames, and it might even be useful in Linus' world, or if someone
wanted to build a traditional SCM on top of a git-a-like.
Attached is a patch, and a rename-file.c to use it.
Simon
--
PGP public key Id 0x144A991C, or http://himi.org/stuff/himi.asc
(crappy) Homepage: http://himi.org
doe #237 (see http://www.lemuria.org/DeCSS)
My DeCSS mirror: ftp://himi.org/pub/mirrors/css/
[-- Attachment #1.2: guid2.patch --]
[-- Type: text/plain, Size: 19027 bytes --]
COPYING: fe2a4177a760fd110e78788734f167bd633be8de
Makefile: ca50293c4f211452d999b81f122e99babb9f2987
--- Makefile
+++ Makefile 2005-04-15 22:17:49.000000000 +1000
@@ -14,7 +14,7 @@
PROG= update-cache show-diff init-db write-tree read-tree commit-tree \
cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
- check-files ls-tree
+ check-files ls-tree rename-file
SCRIPT= parent-id tree-id git gitXnormid.sh gitadd.sh gitaddremote.sh \
gitcommit.sh gitdiff-do gitdiff.sh gitlog.sh gitls.sh gitlsobj.sh \
@@ -73,6 +73,9 @@
ls-tree: ls-tree.o read-cache.o
$(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
+rename-file: rename-file.o read-cache.o
+ $(CC) $(CFLAGS) -o rename-file rename-file.o read-cache.o $(LIBS)
+
read-cache.o: cache.h
show-diff.o: cache.h
README: ded1a3b20e9bbe1f40e487ba5f9361719a1b6b85
VERSION: c27bd67cd632cc15dd520fbfbf807d482efa2dcf
cache.h: 4d382549041d3281f8d44aa2e52f9f8ec47dd420
--- cache.h
+++ cache.h 2005-04-14 22:35:59.000000000 +1000
@@ -55,6 +55,7 @@
unsigned int st_gid;
unsigned int st_size;
unsigned char sha1[20];
+ unsigned char guid[20];
unsigned short namelen;
char name[0];
};
cat-file.c: 45be1badaa8517d4e3a69e0bf1cac2e90191e475
check-files.c: 927b0b9aca742183fc8e7ccd73d73d8d5427e98f
checkout-cache.c: f06871cdbc1b18ea93bdf4e17126aeb4cca1373e
commit-id: 65c81756c8f10d513d073ecbd741a3244663c4c9
commit-tree.c: 12196c79f31d004dff0df1f50dda67d8204f5568
diff-tree.c: 7dcc9eb7782fa176e27f1677b161ce78ac1d2070
--- diff-tree.c
+++ diff-tree.c 2005-04-16 10:46:52.000000000 +1000
@@ -1,33 +1,144 @@
+#include <sys/param.h>
#include "cache.h"
-static int recursive = 0;
+enum diff_type {
+ REMOVE,
+ ADD,
+ RENAME,
+ MODIFY,
+};
+
+struct guid_cache_entry {
+ enum diff_type diff;
+ unsigned char guid[20];
+ unsigned char sha1[20];
+ struct guid_cache_entry *old;
+ unsigned int mode;
+ unsigned int pathlen;
+ unsigned char path[0];
+};
+
+struct guid_cache {
+ unsigned int nr;
+ unsigned int alloc;
+ struct guid_cache_entry **cache;
+};
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
+struct guid_cache guid_cache;
+struct guid_cache *cache = &guid_cache;
-static void update_tree_entry(void **bufp, unsigned long *sizep)
+int guid_cache_pos(const char *guid)
{
- void *buf = *bufp;
- unsigned long size = *sizep;
- int len = strlen(buf) + 1 + 20;
+ int first, last;
- if (size < len)
- die("corrupt tree file");
- *bufp = buf + len;
- *sizep = size - len;
+ first = 0;
+ last = cache->nr;
+ while (last > first) {
+ int next = (last + first) >> 1;
+ struct guid_cache_entry *gce = cache->cache[next];
+ int cmp = memcmp(guid, gce->guid, 20);
+ if (!cmp)
+ return next;
+ if (cmp < 0) {
+ last = next;
+ continue;
+ }
+ first = next + 1;
+ }
+ return - first-1;
}
-static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep)
+int add_guid_cache_entry(struct guid_cache_entry *gce)
+{
+ int pos;
+
+ pos = guid_cache_pos(gce->guid);
+
+ /* if this is a rename or modify, the guid will show up a
+ * second time */
+ if (pos >= 0) {
+ struct guid_cache_entry *old = cache->cache[pos];
+ int cmp = cache_name_compare(old->path, old->pathlen, gce->path, gce->pathlen);
+
+ if (!cmp) {
+ /* pathname matches, so this must be a
+ * modify. */
+ gce->old = old;
+ gce->diff = MODIFY;
+ cache->cache[pos] = gce;
+ } else {
+ /* the pathnames are different, so the file
+ * must have been renamed somewhere along the
+ * line. */
+ gce->old = old;
+ gce->diff = RENAME;
+ cache->cache[pos] = gce;
+ }
+ return 0;
+ }
+ pos = -pos-1;
+
+ if (cache->nr == cache->alloc) {
+ cache->alloc = alloc_nr(cache->alloc);
+ cache->cache = realloc(cache->cache, cache->alloc * sizeof(struct guid_cache_entry *));
+ }
+
+ cache->nr++;
+ if (cache->nr > pos)
+ memmove(cache->cache + pos + 1, cache->cache + pos, (cache->nr - pos - 1) * sizeof(struct guid_cache_entry *));
+ cache->cache[pos] = gce;
+ return 0;
+}
+
+static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep, const unsigned char **guid)
{
int len = strlen(tree)+1;
const unsigned char *sha1 = tree + len;
const char *path = strchr(tree, ' ');
- if (!path || size < len + 20 || sscanf(tree, "%o", modep) != 1)
+ if (!path || size < len + 40 || sscanf(tree, "%o", modep) != 1)
die("corrupt tree file");
*pathp = path+1;
+ *guid = tree + len + 20;
return sha1;
}
+static void guid_cache_tree_entry(void *buf, unsigned int len, const char *base, enum diff_type diff)
+{
+ unsigned mode;
+ const char *path;
+ const unsigned char *guid;
+ const unsigned char *sha1 = extract(buf, len, &path, &mode, &guid);
+ struct guid_cache_entry *gce;
+ int baselen = strlen(base);
+
+ gce = calloc(1, sizeof(struct guid_cache_entry) + baselen + strlen(path) + 1);
+ memcpy(gce->guid, guid, 20);
+ memcpy(gce->sha1, sha1, 20);
+ gce->diff = diff;
+ gce->mode = mode;
+ gce->pathlen = snprintf(gce->path, MAXPATHLEN, "%s%s", base, path);
+ gce->path[gce->pathlen + 1] = '\0';
+
+ add_guid_cache_entry(gce);
+}
+
+static int recursive = 0;
+
+static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
+
+static void update_tree_entry(void **bufp, unsigned long *sizep)
+{
+ void *buf = *bufp;
+ unsigned long size = *sizep;
+ int len = strlen(buf) + 1 + 40;
+
+ if (size < len)
+ die("corrupt tree file");
+ *bufp = buf + len;
+ *sizep = size - len;
+}
+
static char *malloc_base(const char *base, const char *path, int pathlen)
{
int baselen = strlen(base);
@@ -38,23 +149,24 @@
return newbase;
}
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base);
+static void changed_file(void *tree, unsigned long size, const char *base, enum diff_type diff);
/* A whole sub-tree went away or appeared */
-static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base)
+static void changed_tree(void *tree, unsigned long size, const char *base, enum diff_type diff)
{
while (size) {
- show_file(prefix, tree, size, base);
+ changed_file(tree, size, base, diff);
update_tree_entry(&tree, &size);
}
}
/* A file entry went away or appeared */
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base)
+static void changed_file(void *tree, unsigned long size, const char *base, enum diff_type diff)
{
unsigned mode;
const char *path;
- const unsigned char *sha1 = extract(tree, size, &path, &mode);
+ const unsigned char *guid;
+ const unsigned char *sha1 = extract(tree, size, &path, &mode, &guid);
if (recursive && S_ISDIR(mode)) {
char type[20];
@@ -66,38 +178,96 @@
if (!tree || strcmp(type, "tree"))
die("corrupt tree sha %s", sha1_to_hex(sha1));
- show_tree(prefix, tree, size, newbase);
+ changed_tree(tree, size, newbase, diff);
free(tree);
free(newbase);
return;
}
- printf("%s%o\t%s\t%s\t%s%s%c", prefix, mode,
- S_ISDIR(mode) ? "tree" : "blob",
- sha1_to_hex(sha1), base, path, 0);
+ guid_cache_tree_entry(tree, size, base, diff);
}
+static void show_one_file(struct guid_cache_entry *gce)
+{
+ struct guid_cache_entry *old;
+ char old_sha1[50];
+ char old_sha2[50];
+
+ switch(gce->diff) {
+ case REMOVE:
+ sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1));
+ printf("-%o\t%s\t%s\t%s\t%s%c", gce->mode,
+ S_ISDIR(gce->mode) ? "tree" : "blob",
+ old_sha1, sha1_to_hex(gce->guid), gce->path, 0);
+ break;
+ case ADD:
+ sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1));
+ printf("+%o\t%s\t%s\t%s\t%s%c", gce->mode,
+ S_ISDIR(gce->mode) ? "tree" : "blob",
+ old_sha1, sha1_to_hex(gce->guid), gce->path, 0);
+ break;
+ case MODIFY:
+ old = gce->old;
+ if (old) {
+ sprintf(old_sha1, "%s", sha1_to_hex(old->sha1));
+ sprintf(old_sha2, "%s", sha1_to_hex(gce->sha1));
+
+ printf("*%o->%o\t%s\t%s->%s\t%s\t%s%c", old->mode, gce->mode,
+ S_ISDIR(old->mode) ? "tree" : "blob",
+ old_sha1, old_sha2, sha1_to_hex(gce->guid), gce->path, 0);
+ } else {
+ die("diff-tree: internal error");
+ }
+ break;
+ case RENAME:
+ old = gce->old;
+ if (old) {
+ sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1));
+ sprintf(old_sha2, "%s", sha1_to_hex(old->sha1));
+
+ printf("r%o->%o\t%s\t%s->%s\t%s\t%s%c", gce->mode, old->mode,
+ S_ISDIR(old->mode) ? "tree" : "blob",
+ old_sha1, old_sha2, sha1_to_hex(old->guid), old->path, 0);
+ } else {
+ die("diff-tree: internal error");
+ }
+ break;
+ default:
+ die("diff-tree: internal error");
+ }
+}
+
+/* simply iterate over both caches looking for matching guids,
+ * showing all files in both caches */
+static void show_cache(void)
+{
+ int i;
+
+ for (i = 0; i < cache->nr; i++)
+ show_one_file(cache->cache[i]);
+}
+
static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
{
unsigned mode1, mode2;
const char *path1, *path2;
const unsigned char *sha1, *sha2;
+ const unsigned char *guid1, *guid2;
int cmp, pathlen1, pathlen2;
- char old_sha1_hex[50];
- sha1 = extract(tree1, size1, &path1, &mode1);
- sha2 = extract(tree2, size2, &path2, &mode2);
+ sha1 = extract(tree1, size1, &path1, &mode1, &guid1);
+ sha2 = extract(tree2, size2, &path2, &mode2, &guid2);
pathlen1 = strlen(path1);
pathlen2 = strlen(path2);
cmp = cache_name_compare(path1, pathlen1, path2, pathlen2);
if (cmp < 0) {
- show_file("-", tree1, size1, base);
+ changed_file(tree1, size1, base, REMOVE);
return -1;
}
if (cmp > 0) {
- show_file("+", tree2, size2, base);
+ changed_file(tree2, size2, base, ADD);
return 1;
}
if (!memcmp(sha1, sha2, 20) && mode1 == mode2)
@@ -108,8 +278,8 @@
* file, we need to consider it a remove and an add.
*/
if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
- show_file("-", tree1, size1, base);
- show_file("+", tree2, size2, base);
+ changed_file(tree1, size1, base, REMOVE);
+ changed_file(tree2, size2, base, ADD);
return 0;
}
@@ -121,10 +291,14 @@
return retval;
}
- strcpy(old_sha1_hex, sha1_to_hex(sha1));
- printf("*%o->%o\t%s\t%s->%s\t%s%s%c", mode1, mode2,
- S_ISDIR(mode1) ? "tree" : "blob",
- old_sha1_hex, sha1_to_hex(sha2), base, path1, 0);
+ if (!memcmp(guid1, guid2, 20)) {
+ changed_file(tree1, size1, base, MODIFY);
+ changed_file(tree2, size2, base, MODIFY);
+ return 0;
+ }
+
+ changed_file(tree1, size1, base, REMOVE);
+ changed_file(tree2, size2, base, ADD);
return 0;
}
@@ -132,12 +306,12 @@
{
while (size1 | size2) {
if (!size1) {
- show_file("+", tree2, size2, base);
+ changed_file(tree2, size2, base, ADD);
update_tree_entry(&tree2, &size2);
continue;
}
if (!size2) {
- show_file("-", tree1, size1, base);
+ changed_file(tree1, size1, base, REMOVE);
update_tree_entry(&tree1, &size1);
continue;
}
@@ -179,6 +353,7 @@
int main(int argc, char **argv)
{
unsigned char old[20], new[20];
+ int retval;
while (argc > 3) {
char *arg = argv[1];
@@ -193,5 +368,7 @@
if (argc != 3 || get_sha1_hex(argv[1], old) || get_sha1_hex(argv[2], new))
usage("diff-tree <tree sha1> <tree sha1>");
- return diff_tree_sha1(old, new, "");
+ retval = diff_tree_sha1(old, new, "");
+ show_cache();
+ return retval;
}
fsck-cache.c: 9c900fe458cecd2bdb4c4571a584115b5cf24f22
--- fsck-cache.c
+++ fsck-cache.c 2005-04-15 20:39:49.000000000 +1000
@@ -165,9 +165,10 @@
while (size) {
int len = 1+strlen(data);
unsigned char *file_sha1 = data + len;
+ unsigned char *guid = file_sha1 + 20;
char *path = strchr(data, ' ');
unsigned int mode;
- if (size < len + 20 || !path || sscanf(data, "%o", &mode) != 1)
+ if (size < len + 40 || !path || sscanf(data, "%o", &mode) != 1)
return -1;
/* Warn about trees that don't do the recursive thing.. */
@@ -176,8 +177,8 @@
warn_old_tree = 0;
}
- data += len + 20;
- size -= len + 20;
+ data += len + 40;
+ size -= len + 40;
mark_needs_sha1(sha1, S_ISDIR(mode) ? "tree" : "blob", file_sha1);
}
return 0;
git: 2c557dcf2032325acc265b577ee104e605fdaede
gitXnormid.sh: a5d7a9f4a6e8d4860f35f69500965c2a493d80de
gitadd.sh: 3ed93ea0fcb995673ba9ee1982e0e7abdbe35982
gitaddremote.sh: bf1f28823da5b5270aa8fa05b321faa514a57a11
gitapply.sh: d0e3c46e2ce1ee74e1a87ee6137955fa9b35c27b
gitcancel.sh: ec58f7444a42cd3cbaae919fc68c70a3866420c0
gitcommit.sh: 3629f67bbd3f171d091552814908b67af7537f4d
gitdiff-do: d6174abceab34d22010c36a8453a6c3f3f184fe0
gitdiff.sh: 5e47c4779d73c3f2f39f6be714c0145175933197
gitexport.sh: dad00bf251b38ce522c593ea9631f842d8ccc934
gitlntree.sh: 17c4966ea64aeced96ae4f1b00f3775c1904b0f1
gitlog.sh: 177c6d12dd9fa4b4920b08451ffe4badde544a39
gitls.sh: b6f15d82f16c1e9982c5031f3be22eb5430273af
gitlsobj.sh: 128461d3de6a42cfaaa989fc6401bebdfa885b3f
gitmerge.sh: 23e4a3ff342c6005928ceea598a2f52de6fb9817
gitpull.sh: 0883898dda579e3fa44944b7b1d909257f6dc63e
gitrm.sh: 5c18c38a890c9fd9ad2b866ee7b529539d2f3f8f
gittag.sh: c8cb31385d5a9622e95a4e0b2d6a4198038a659c
gittrack.sh: 03d6db1fb3a70605ef249c632c04e542457f0808
init-db.c: aa00fbb1b95624f6c30090a17354c9c08a6ac596
ls-tree.c: 3e2a6c7d183a42e41f1073dfec6794e8f8a5e75c
--- ls-tree.c
+++ ls-tree.c 2005-04-15 15:55:40.000000000 +1000
@@ -10,6 +10,7 @@
void *buffer;
unsigned long size;
char type[20];
+ char old_sha1[50];
buffer = read_sha1_file(sha1, type, &size);
if (!buffer)
@@ -19,19 +20,21 @@
while (size) {
int len = strlen(buffer)+1;
unsigned char *sha1 = buffer + len;
+ unsigned char *guid = buffer + len + 20;
char *path = strchr(buffer, ' ')+1;
unsigned int mode;
unsigned char *type;
- if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
+ if (size < len + 40 || sscanf(buffer, "%o", &mode) != 1)
die("corrupt 'tree' file");
- buffer = sha1 + 20;
- size -= len + 20;
+ buffer = sha1 + 40;
+ size -= len + 40;
/* XXX: We do some ugly mode heuristics here.
* It seems not worth it to read each file just to get this
* and the file size. -- pasky@ucw.cz */
type = S_ISDIR(mode) ? "tree" : "blob";
- printf("%03o\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), path);
+ sprintf(old_sha1, sha1_to_hex(guid));
+ printf("%03o\t%s\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), old_sha1, path);
}
return 0;
}
parent-id: 1801c6fe426592832e7250f8b760fb9d2e65220f
read-cache.c: 7a6ae8b9b489f6b67c82e065dedd5716a6bfc0ef
--- read-cache.c
+++ read-cache.c 2005-04-16 10:52:51.000000000 +1000
@@ -4,6 +4,8 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include <stdarg.h>
+#include <time.h>
+#include <sys/param.h>
#include "cache.h"
const char *sha1_file_directory = NULL;
@@ -233,6 +235,22 @@
return 0;
}
+void new_guid(const char *filename, int namelen, unsigned char *returnguid)
+{
+ size_t size;
+ time_t now = time(NULL);
+ char buf[MAXPATHLEN + 20];
+ unsigned char guid[20];
+
+ size = snprintf(buf, MAXPATHLEN + 20, "%ld%s", now, filename) + 1;
+
+ SHA1(buf, size, guid);
+
+ if (returnguid)
+ memcpy(returnguid, guid, 20);
+ return;
+}
+
static inline int collision_check(char *filename, void *buf, unsigned int size)
{
#ifdef COLLISION_CHECK
@@ -363,11 +381,14 @@
int add_cache_entry(struct cache_entry *ce, int ok_to_add)
{
int pos;
+ unsigned char guid[20];
pos = cache_name_pos(ce->name, ce->namelen);
/* existing match? Just replace it */
if (pos >= 0) {
+ struct cache_entry *old_ce = active_cache[pos];
+ memcpy(ce->guid, old_ce->guid, 20);
active_cache[pos] = ce;
return 0;
}
@@ -376,6 +397,12 @@
if (!ok_to_add)
return -1;
+ memset(guid, 0, 20);
+ if (!memcmp(ce->guid, guid, 20)) {
+ new_guid(ce->name, ce->namelen, guid);
+ memcpy(ce->guid, guid, 20);
+ }
+
/* Make sure the array is big enough .. */
if (active_nr == active_alloc) {
active_alloc = alloc_nr(active_alloc);
read-tree.c: eb548148aa6d212f05c2c622ffbe62a06cd072f9
--- read-tree.c
+++ read-tree.c 2005-04-16 10:41:46.000000000 +1000
@@ -5,7 +5,9 @@
*/
#include "cache.h"
-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
+static int read_one_entry(unsigned char *sha1, unsigned char *guid,
+ const char *base, int baselen,
+ const char *pathname, unsigned mode)
{
int len = strlen(pathname);
unsigned int size = cache_entry_size(baselen + len);
@@ -18,6 +20,7 @@
memcpy(ce->name, base, baselen);
memcpy(ce->name + baselen, pathname, len+1);
memcpy(ce->sha1, sha1, 20);
+ memcpy(ce->guid, guid, 20);
return add_cache_entry(ce, 1);
}
@@ -35,14 +38,15 @@
while (size) {
int len = strlen(buffer)+1;
unsigned char *sha1 = buffer + len;
+ unsigned char *guid = buffer + len + 20;
char *path = strchr(buffer, ' ')+1;
unsigned int mode;
-
- if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
+
+ if (size < len + 40 || sscanf(buffer, "%o", &mode) != 1)
return -1;
- buffer = sha1 + 20;
- size -= len + 20;
+ buffer = sha1 + 40;
+ size -= len + 40;
if (S_ISDIR(mode)) {
int retval;
@@ -57,7 +61,7 @@
return -1;
continue;
}
- if (read_one_entry(sha1, base, baselen, path, mode) < 0)
+ if (read_one_entry(sha1, guid, base, baselen, path, mode) < 0)
return -1;
}
return 0;
rev-tree.c: 395b0b3bfadb0537ae0c62744b25ead4b487f3f6
show-diff.c: a531ca4078525d1c8dcf84aae0bfa89fed6e5d96
show-files.c: a9fa6767a418f870a34b39379f417bf37b17ee18
tree-id: cb70e2c508a18107abe305633612ed702aa3ee4f
update-cache.c: 62d0a6c41560d40863c44599355af10d9e089312
write-tree.c: 1534477c91169ebddcf953e3f4d2872495477f6b
--- write-tree.c
+++ write-tree.c 2005-04-15 13:46:05.000000000 +1000
@@ -47,6 +47,7 @@
const char *pathname = ce->name, *filename, *dirname;
int pathlen = ce->namelen, entrylen;
unsigned char *sha1;
+ unsigned char *guid;
unsigned int mode;
/* Did we hit the end of the directory? Return how many we wrote */
@@ -54,6 +55,7 @@
break;
sha1 = ce->sha1;
+ guid = ce->guid;
mode = ce->st_mode;
/* Do we have _further_ subdirectories? */
@@ -86,6 +88,8 @@
buffer[offset++] = 0;
memcpy(buffer + offset, sha1, 20);
offset += 20;
+ memcpy(buffer + offset, guid, 20);
+ offset += 20;
nr++;
} while (nr < maxentries);
[-- Attachment #1.3: rename-file.c --]
[-- Type: text/x-csrc, Size: 1703 bytes --]
/*
* rename files in a git repository, keeping the guid.
*
* Copyright Simon Fowler <simon@dreamcraft.com.au>, 2005.
*/
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include "cache.h"
static int remove_lock = 0;
static void remove_lock_file(void)
{
if (remove_lock)
unlink(".git/index.lock");
}
int main(int argc, char *argv[])
{
struct stat stats;
struct cache_entry *ce, *new;
int newfd, entries, pos, pos2;
if (argc != 3)
usage("rename-file <old> <new>");
if (stat(argv[1], &stats)) {
perror("rename-file: ");
exit(1);
}
if (!stat(argv[2], &stats))
die("rename-file: destination file already exists");
newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
if (newfd < 0)
die("unable to create new cachefile");
atexit(remove_lock_file);
remove_lock = 1;
entries = read_cache();
if (entries < 0)
die("cache corrupted");
pos = cache_name_pos(argv[1], strlen(argv[1]));
pos2 = cache_name_pos(argv[2], strlen(argv[2]));
if (pos < 0)
die("original file not in cache");
if (pos2 >= 0)
die("destination file already in cache");
ce = active_cache[pos];
new = malloc(sizeof(struct cache_entry) + strlen(argv[2]) + 1);
memcpy(new, ce, sizeof(struct cache_entry));
new->namelen = strlen(argv[2]);
memcpy(new->name, argv[2], new->namelen);
if (rename(argv[1], argv[2])) {
perror("rename-file: ");
exit(1);
}
remove_file_from_cache(argv[1]);
add_cache_entry(new, 1);
if (write_cache(newfd, active_cache, active_nr) ||
rename(".git/index.lock", ".git/index"))
die("Unable to write new cachefile");
remove_lock = 0;
return 0;
}
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [PATCH] Add '-z' to merge-tree.c
From: Junio C Hamano @ 2005-04-16 1:17 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
Linus,
this adds '-z' to merge-tree and changes its default line
termination to LF to make it consistent with your other recent
changes.
The patch is against
commit 028c5948257e763b3deb391e567b624eb7975ec2
tree 6b866e10b16183e630db8449c64899f6810d4270
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
merge-tree.c | 23 ++++++++++++++++++++---
1 files changed, 20 insertions(+), 3 deletions(-)
--- ,,linus/merge-tree.c 2005-04-15 18:09:29.000000000 -0700
+++ ./merge-tree.c 2005-04-15 17:55:42.000000000 -0700
@@ -1,5 +1,7 @@
#include "cache.h"
+static int line_termination = '\n';
+
struct tree_entry {
unsigned mode;
unsigned char *sha1;
@@ -35,7 +37,8 @@ static struct tree_entry *read_tree(unsi
static void show(const struct tree_entry *a, const char *path)
{
- printf("select %o %s %s%c", a->mode, sha1_to_hex(a->sha1), path, 0);
+ printf("select %o %s %s%c", a->mode, sha1_to_hex(a->sha1), path,
+ line_termination);
}
static void merge(const struct tree_entry *a, const struct tree_entry *b, const struct tree_entry *c, const char *path)
@@ -46,7 +49,7 @@ static void merge(const struct tree_entr
strcpy(hex_c, sha1_to_hex(c->sha1));
printf("merge %o->%o,%o %s->%s,%s %s%c",
a->mode, b->mode, c->mode,
- hex_a, hex_b, hex_c, path, 0);
+ hex_a, hex_b, hex_c, path, line_termination);
}
static int same(const struct tree_entry *a, const struct tree_entry *b)
@@ -114,15 +117,29 @@ static void merge_tree(struct tree_entry
}
}
+static const char *merge_tree_usage =
+ "merge-tree [-z] <src> <dst1> <dst2>";
+
int main(int argc, char **argv)
{
unsigned char src[20], dst1[20], dst2[20];
+ while ((1 < argc) && argv[1][0] == '-') {
+ switch (argv[1][1]) {
+ case 'z':
+ line_termination = 0;
+ break;
+ default:
+ usage(merge_tree_usage);
+ }
+ argc--; argv++;
+ }
+
if (argc != 4 ||
get_sha1_hex(argv[1], src) ||
get_sha1_hex(argv[2], dst1) ||
get_sha1_hex(argv[3], dst2))
- usage("merge-tree <src> <dst1> <dst2>");
+ usage(merge_tree_usage);
merge_tree(read_tree(src), read_tree(dst1), read_tree(dst2));
return 0;
}
^ permalink raw reply
* Re: Re: Re: write-tree is pasky-0.4
From: Daniel Barkalow @ 2005-04-16 1:13 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0504151709180.7211@ppc970.osdl.org>
On Fri, 15 Apr 2005, Linus Torvalds wrote:
> I think I've explained my name tracking worries. When it comes to "how to
> merge", there's three issues:
>
> - we do commonly have merge clashes where both trees have applied the
> exact same patch. That should merge perfectly well using the 3-way
> merge from a common parent that Junio has, but not your current "bring
> patches forward" kind of strategy.
I think 3-way merge is probably the best starting point, but I think that
there might be value in being able to identify the commits of each side
involved in a conflict. I think this would help with cases where both
sides pick up an identical patch, and then each side makes a further
change to a different part of the changed region (you find out that the
other guy's change was supposed to follow the patch, and don't conflict
with it).
> - I _do_ actually sometimes merge with dirty state in my working
> directory, which is why I want the merge to take place in a separate
> (and temporary) directory, which allows for a failed merge without
> having any major cleanup. If the merge fails, it's not a big deal, and
> I can just blow the merge directory away without losing the work I had
> in my "real" working directory.
Is there some reason you don't commit before merging? All of the current
merge theory seems to want to merge two commits, using the information git
keeps about them. It should be cheap to get a new clean working directory
to merge in, too, particularly if we add a cache of hardlinkable expanded
blobs.
> - reliability. I care much less for "clever" than I care for "guaranteed
> to never do the wrong thing". If I have to fix up some stuff by hand,
> I'll happily do so. But if I can't trust the merge and have to _check_
> things by hand afterwards, that will make me leery of the merges, and
> _that_ is bad.
>
> The third point is why I'm going to the ultra-conservative "three-way
> merge from the common parent". It's not fancy, but it's something I feel
> comfortable with as a merge strategy. For example, arch (and in particular
> darcs) seems to want to try to be "clever" about the merges, and I'd
> always live in fear.
How much do you care about the situation where there is no best common
ancestor (which can happen if you're merging two main lines, each of which
has merged with both of a pair of minor trees)? I think that arch is even
more conservative, in that it doesn't look for a common ancestor, and
reports conflicts whenever changes overlap at all. Of course, reliability
by virtue of never working without help is not a big win over living in
fear; you always have to check over it, not because you're afraid, but
because it needs you to.
> And, finally, there's obviously performance. I _think_ a normal merge with
> nary a conflict and just a few tens of files changed should be possible in
> a second. I realize that sounds crazy to some people, but I think it's
> entirely doable. Half of that is writing the new tree out (that is a
> relative costly op due to the compression). The other half is the "work".
I think that the time spent on I/O will be overwhelmed by the time spent
issuing the command at that rate. It might matter if you start getting
into merging lots of things at once, but that's more like a minute for a
merge group with 600 changes rather than a second per merge; we could
potentially save a lot of time based of having a bunch of information left
over from the previous merge when starting merge number 2. So 15 seconds
plus half a second per merge might be better than a second per merge in
the case that matters.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH 3/2] merge-trees script for Linus git
From: Linus Torvalds @ 2005-04-16 1:02 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vmzrzfwe4.fsf_-_@assigned-by-dhcp.cox.net>
On Fri, 15 Apr 2005, Junio C Hamano wrote:
>
> the merge-trees I sent you earlier was expecting the old
> diff-tree behaviour, and I did not realize that I need an
> explicit -z flag now.
You didn't need one - I just didn't want to merge your "ls-tree" change
without making things be consistent. Once we started using the "-z" flag
for ls-tree, it just didn't make any sense not to do the same thing for
diff-tree.
Just a heads-up - I'd really want to do the same thing to "merge-tree.c"
too, but since you said that you were working on extending that to do
recursion etc, I decided to hold off. So if you're working on it, maybe
you can add the "-z" flag there too?
I'm actually holding off merging the perl version exactly because you
seemed to be working on the C version. I don't mind perl per se, but if
there's a real solution coming down the line..
Linus
^ permalink raw reply
* (unknown)
From: Scott Wright @ 2005-04-16 0:51 UTC (permalink / raw)
To: git
subscribe git
^ permalink raw reply
* [PATCH] write_sha1_buffer
From: Morten Welinder @ 2005-04-16 0:50 UTC (permalink / raw)
To: git, torvalds
This write will failing sooner or later when someone's disk fills up.
That'll leave someone with
a truncated file.
Signed-off-by: Morten Welinder <mwelinder@gmail.com>
--- read-cache.c
+++ read-cache.c 2005-04-15 20:32:52.111187168 -0400
@@ -276,9 +276,13 @@
" This is bad, bad, BAD!\a\n");
return 0;
}
- write(fd, buf, size);
- close(fd);
- return 0;
+
+ if (write(fd, buf, size) != size) {
+ close(fd);
+ return error("Failed to write file %s\n", filename);
+ }
+
+ return close(fd);
}
^ permalink raw reply
* RE: Merge with git-pasky II.
From: Linus Torvalds @ 2005-04-16 0:32 UTC (permalink / raw)
To: Barry Silverman; +Cc: git
In-Reply-To: <000701c5420e$e89177b0$6400a8c0@gandalf>
On Fri, 15 Apr 2005, Barry Silverman wrote:
>
> The issue I am trying to come to grips with in the current design, is
> that the git repository of a number of interrelated projects will soon
> become the logical OR of all blobs, commits, and trees in ALL the
> projects.
Nope. I'm actually against the notion of sharing object directories
between projects. The git model _allows_ it, and I think it can be a valid
approach, but it's absolutely not an approach that I would personally
suggest be used for the kernel.
In other words, the default git behaviour - and the one I personally am a
proponent of - is to have one object directory per work tree, and really
consider all such trees independent. Then you can merge between trees if
you want to, and bring in objects that way, but normally you would _not_
have tons of objects from other trees, and _especially_ not from other
unrelated projects.
The reason git supports shared object archives is that (a) it falls out
trivially as part of the design, so not allowing it is silly and (b) it is
part of a merge, where you _do_ want to get the objects of the trees you
merge, and in particular you need to generate a seperate tree that has all
those objects without having to copy them.
(Before you do the merge, you need to bring the new objects into your
repository of course, but that I consider to be a separate issue, not
part of the actual technical merge process).
So normally, you'd probably have a totally pruned tree, with only the
objects you need (and you might even consider the "commit parent links"
less than necessary, especially if you're just a regular user and not a
developer who wants to merge).
But the ability to have extra objects is wonderful. It makes going
backwards in time basically free (while the equivalent "bk undo" in the BK
world is a very expensive operation), and it makes it easy to
incrementally keep up-to-date with trees that you know you're _eventually_
going to merge with. But it's not an excuse to put just any random crap in
that object directory..
Linus
^ permalink raw reply
* Re: Re: Re: write-tree is pasky-0.4
From: Linus Torvalds @ 2005-04-16 0:22 UTC (permalink / raw)
To: Petr Baudis; +Cc: Junio C Hamano, git
In-Reply-To: <20050415223648.GP7417@pasky.ji.cz>
On Sat, 16 Apr 2005, Petr Baudis wrote:
>
> But otherwise it is great news to me. Actually, in that case, is it
> worth renaming it to Cogito and using cg to invoke it? Wouldn't be that
> actually more confusing after it gets merged? IOW, should I stick to
> "git" or feel free to rename it to "cg"?
I'm perfectly happy for it to stay as "git", and in general I don't have
any huge preferences either way. You guys can discuss names as much as you
like, it's the "tracking renames" and "how to merge" things that worry me.
I think I've explained my name tracking worries. When it comes to "how to
merge", there's three issues:
- we do commonly have merge clashes where both trees have applied the
exact same patch. That should merge perfectly well using the 3-way
merge from a common parent that Junio has, but not your current "bring
patches forward" kind of strategy.
- I _do_ actually sometimes merge with dirty state in my working
directory, which is why I want the merge to take place in a separate
(and temporary) directory, which allows for a failed merge without
having any major cleanup. If the merge fails, it's not a big deal, and
I can just blow the merge directory away without losing the work I had
in my "real" working directory.
- reliability. I care much less for "clever" than I care for "guaranteed
to never do the wrong thing". If I have to fix up some stuff by hand,
I'll happily do so. But if I can't trust the merge and have to _check_
things by hand afterwards, that will make me leery of the merges, and
_that_ is bad.
The third point is why I'm going to the ultra-conservative "three-way
merge from the common parent". It's not fancy, but it's something I feel
comfortable with as a merge strategy. For example, arch (and in particular
darcs) seems to want to try to be "clever" about the merges, and I'd
always live in fear.
And, finally, there's obviously performance. I _think_ a normal merge with
nary a conflict and just a few tens of files changed should be possible in
a second. I realize that sounds crazy to some people, but I think it's
entirely doable. Half of that is writing the new tree out (that is a
relative costly op due to the compression). The other half is the "work".
Linus
^ permalink raw reply
* Re: Re: Plug memory leak in update-cache.c
From: Petr Baudis @ 2005-04-16 0:04 UTC (permalink / raw)
To: Martin Schlemmer; +Cc: GIT Mailing Lists
In-Reply-To: <1113609621.8582.12.camel@nosferatu.lan>
Dear diary, on Sat, Apr 16, 2005 at 02:00:21AM CEST, I got a letter
where Martin Schlemmer <azarah@nosferatu.za.org> told me that...
> On Sat, 2005-04-16 at 01:48 +0200, Petr Baudis wrote:
> > Dear diary, on Thu, Apr 14, 2005 at 10:53:50AM CEST, I got a letter
> > where Martin Schlemmer <azarah@nosferatu.za.org> told me that...
> > > Hi,
> > >
> > > Might not be that an big an issue as it should be freed on exit, but
> > > might cause problems with big trees.
> > >
> > > ----
> > >
> > > Plug memory leak in update-cache.c.
> > >
> > > Signed-off-by: Martin Schlemmer <azarah@nosferatu.za.org>
> > >
> > > update-cache.c: 22f3ccd47db4f0888901109a8cbf883d272d1cba
> > > --- 22f3ccd47db4f0888901109a8cbf883d272d1cba/update-cache.c
> > > +++ uncommitted/update-cache.c
> > > @@ -202,6 +202,7 @@
> > > printf("%s: needs update\n", ce->name);
> > > continue;
> > > }
> > > + free(active_cache[i]);
> > > active_cache[i] = new;
> > > }
> > > }
> >
> > FYI, new could've contained active_cache[i] at that time, so you needed
> > to check for that. Fixed though, thanks for pointing it out.
> >
>
> Urk, no, please drop. As Ingo pointed out, the memory was obtained via
> mmap ...
Yes, I've just noticed that. ;-)
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Re: Plug memory leak in update-cache.c
From: Martin Schlemmer @ 2005-04-16 0:00 UTC (permalink / raw)
To: Petr Baudis; +Cc: GIT Mailing Lists
In-Reply-To: <20050415234807.GS7417@pasky.ji.cz>
[-- Attachment #1: Type: text/plain, Size: 1155 bytes --]
On Sat, 2005-04-16 at 01:48 +0200, Petr Baudis wrote:
> Dear diary, on Thu, Apr 14, 2005 at 10:53:50AM CEST, I got a letter
> where Martin Schlemmer <azarah@nosferatu.za.org> told me that...
> > Hi,
> >
> > Might not be that an big an issue as it should be freed on exit, but
> > might cause problems with big trees.
> >
> > ----
> >
> > Plug memory leak in update-cache.c.
> >
> > Signed-off-by: Martin Schlemmer <azarah@nosferatu.za.org>
> >
> > update-cache.c: 22f3ccd47db4f0888901109a8cbf883d272d1cba
> > --- 22f3ccd47db4f0888901109a8cbf883d272d1cba/update-cache.c
> > +++ uncommitted/update-cache.c
> > @@ -202,6 +202,7 @@
> > printf("%s: needs update\n", ce->name);
> > continue;
> > }
> > + free(active_cache[i]);
> > active_cache[i] = new;
> > }
> > }
>
> FYI, new could've contained active_cache[i] at that time, so you needed
> to check for that. Fixed though, thanks for pointing it out.
>
Urk, no, please drop. As Ingo pointed out, the memory was obtained via
mmap ...
--
Martin Schlemmer
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: Yet another base64 patch
From: Paul Dickson @ 2005-04-15 23:55 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: git
In-Reply-To: <425DEF64.60108@zytor.com>
On Wed, 13 Apr 2005 21:19:48 -0700, H. Peter Anvin wrote:
> Checking out the total kernel tree (time checkout-cache -a into an empty
> directory):
>
> Cache cold Cache hot
> stock 3:46.95 19.95
> base64 5:56.20 23.74
> flat 2:44.13 15.68
>
> It seems that the flat format, at least on ext3 with dircache, is
> actually a major performance win, and that the second level loses quite
> a bit.
Since 160-bits does not go into base64 evenly anyways, what happens if
you use 2^10 instead of 2^12 for the subdir names? That will be 1/4 the
directories of the base64 given above.
-Paul
^ permalink raw reply
* Re: Re: Re: Re: Remove need to untrack before tracking new branch
From: Alex Riesen @ 2005-04-15 23:49 UTC (permalink / raw)
To: azarah; +Cc: Petr Baudis, git
In-Reply-To: <1113543914.23299.151.camel@nosferatu.lan>
On 4/15/05, Martin Schlemmer <azarah@nosferatu.za.org> wrote:
> > > + if (update_mode && changed & MODE_CHANGED)
> > > + chmod(ce->name, ce->st_mode);
> >
> > it's "if ((update_mode && changed) & MODE_CHANGED)"
> > Did you really mean that?
>
> No, '&' have a higher priority (weight?) than '&&'. Although, yes, it
> might be better style to add brackets.
I wasn't concerned about style
> But just to make you happy, let me prove it:
It's not to make me happy, it's just to prove you're right.
You did it, I stand corrected.
^ permalink raw reply
* Re: Plug memory leak in update-cache.c
From: Petr Baudis @ 2005-04-15 23:48 UTC (permalink / raw)
To: Martin Schlemmer; +Cc: GIT Mailing Lists
In-Reply-To: <1113468830.23299.85.camel@nosferatu.lan>
Dear diary, on Thu, Apr 14, 2005 at 10:53:50AM CEST, I got a letter
where Martin Schlemmer <azarah@nosferatu.za.org> told me that...
> Hi,
>
> Might not be that an big an issue as it should be freed on exit, but
> might cause problems with big trees.
>
> ----
>
> Plug memory leak in update-cache.c.
>
> Signed-off-by: Martin Schlemmer <azarah@nosferatu.za.org>
>
> update-cache.c: 22f3ccd47db4f0888901109a8cbf883d272d1cba
> --- 22f3ccd47db4f0888901109a8cbf883d272d1cba/update-cache.c
> +++ uncommitted/update-cache.c
> @@ -202,6 +202,7 @@
> printf("%s: needs update\n", ce->name);
> continue;
> }
> + free(active_cache[i]);
> active_cache[i] = new;
> }
> }
FYI, new could've contained active_cache[i] at that time, so you needed
to check for that. Fixed though, thanks for pointing it out.
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* [PATCH 3/2] merge-trees script for Linus git
From: Junio C Hamano @ 2005-04-15 23:33 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <7vfyxrhfsw.fsf_-_@assigned-by-dhcp.cox.net>
Linus,
the merge-trees I sent you earlier was expecting the old
diff-tree behaviour, and I did not realize that I need an
explicit -z flag now. Here is a fix.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
merge-trees | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
--- merge-trees 2005-04-15 13:21:35.000000000 -0700
+++ merge-trees+ 2005-04-15 16:27:34.000000000 -0700
@@ -78,8 +78,8 @@
local ($_, $/);
$/ = "\0";
my %path;
- open $fhi, '-|', 'diff-tree', '-r', @tree
- or die "$!: diff-tree -r @tree";
+ open $fhi, '-|', 'diff-tree', '-r', '-z', @tree
+ or die "$!: diff-tree -r -z @tree";
while (<$fhi>) {
chomp;
if (/^\*($reM)->($reM)\tblob\t($reID)->($reID)\t(.*)$/so) {
^ permalink raw reply
* Re: write-tree is pasky-0.4
From: Junio C Hamano @ 2005-04-15 23:16 UTC (permalink / raw)
To: C. Scott Ananian; +Cc: Linus Torvalds, Petr Baudis, git
In-Reply-To: <Pine.LNX.4.61.0504151617170.27637@cag.csail.mit.edu>
>>>>> "CSA" == C Scott Ananian <cscott@cscott.net> writes:
CSA> On Fri, 15 Apr 2005, Junio C Hamano wrote:
>> to yours is no problem for me. Currently I see your HEAD is at
>> 461aef08823a18a6c69d472499ef5257f8c7f6c8, so I will generate a
>> set of patches against it.
CSA> Have you considered using an s/key-like system to make these hashes
CSA> more human-readable? Using the S/Key translation (11-bit chunks map
CSA> to a 1-4
CSA> letter word), Linus' HEAD is at:
CSA> WOW-SCAN-NAVE-AUK-JILL-BASH-HI-LACE-LID-RIDE-RUSE-LINE-GLEE-WICK-A
CSA> ...which is a little longer, but speaking of branch "wow-scan" (which
CSA> gives 22 bits of disambiguation) is probably less error-prone than
CSA> discussing branch '461...' (only 12 bits).
I understand monotone folks have the same issue and they let you
use unambiguous prefix string. And why do you stop counting at
"461" in your example? To my eyes, "461aef" in this particular
string stands out and is easily typable, which gives me 24 bits
;-).
But seriously I doubt the hex format is needed to be shown to
humans very often. E-mail communications like this one being a
very special exception. I do not expect for people to be
talking about "Hey, Junio's patch against 461aef... from Linus
is a total crap" like that.
The only reason I mentioned his then-HEAD by hex is because I do
not have a public archive for him to pull from, and I wanted to
make it easy for him to do:
$ export SHA1_FILE_DIRECTORY
$ mkdir junk && cd junk && mkdir .git &&
read-tree `cat-file commit 461aef... | sed -e 's/^tree //;q'`
$ patch < ../stupid-patch-from-junio-01
$ show-diff
(it might have been better if I used the tree ID for this purpose).
For Cogito users the hex format does not matter. "git pull"
will get whatever HEAD recorded in the file on the sending end
and the end user does not even have to know about it.
CSA> This is obviously a cogito issue, rather than a git-fs thing.
Yes.
^ permalink raw reply
* RE: Merge with git-pasky II.
From: Barry Silverman @ 2005-04-15 23:00 UTC (permalink / raw)
To: 'Linus Torvalds'; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0504151313450.7211@ppc970.osdl.org>
The issue I am trying to come to grips with in the current design, is
that the git repository of a number of interrelated projects will soon
become the logical OR of all blobs, commits, and trees in ALL the
projects.
This will involve horrendous amounts of replication, as developers end
interchanging objects that originated from third parties who are not
party to the merge (and which happen to be in the repository because of
previous merge activity).
It would be really nice if the repositories for each project stay
distinct (and maybe even living on different servers). Merges should the
one of the few points of contact where the state be exchanged between
the repositories.
>> If you don't keep track of the incremental merges, you end up with
one
>> really _difficult_ merge that may not be mergable at all. Not
>> automatically, and perhaps not even with help.
No argument from me.... In my example, I didn't intend A2,A3,A4 to be
considered hash's of points where you did a merge - rather they are
hashes of individual points where you did a commit BETWEEN the points
where you merged. A1 and A5 are the "merge points"!
It makes perfect sense to define some subset of commits as "merge-like"
commits, and only have those copied over from one repository to the
other. You could also only use merge-points in the common ancestor
calculation, and not worry about intermediate commits.
Only small changes to the existing logic are necessary to do a merge by
"distributing" out the merge algorithm to each repository. This involves
querying each repository, and communicating the results, followed by
copying over only those blob objects necessary for the merge.
After the merge, you would create a "merge-point commit" record that has
one of the parents pointing to a hash in the other repository!
But the BIG issue with this scheme, is that you will not be replicating
over any of the intermediate commits, trees, or blobs (not really needed
by the merge), but currently being traversed by various plumbing
components.
Hence my question....
-----Original Message-----
From: Linus Torvalds [mailto:torvalds@osdl.org]
Sent: Friday, April 15, 2005 4:31 PM
To: Barry Silverman
Cc: git@vger.kernel.org
Subject: RE: Merge with git-pasky II.
[ I'm cc'ing the git list even though Barry's question wasn't cc'd.
Because I think his question is interesting and astute per se, even
if I disagree with the proposal ]
On Fri, 15 Apr 2005, Barry Silverman wrote:
>
> If git is totally project based, and each commit represents total
state
> of the project, then how important is the intermediate commit
> information between two states.
You need it in order to do further merges.
> IE, Area maintainer has A1->A2->A3->A4->A5 in a repository with 5
> commits, and 5 comments. And I last synced with A1.
>
> A few days later I sync again. Couldn't I just pull the "diff-tree A5
> A1" and then commit to my tree just the record A1->A5. Why does MY
> repository need trees A2,A3,A4?
Because that second merge needs the first merge to work well. The first
merge might have had some small differences that ended up auto-merging
(or
even needing some manual help from you). The second time you sync, there
migth be some more automatic merging. And so on.
If you don't keep track of the incremental merges, you end up with one
really _difficult_ merge that may not be mergable at all. Not
automatically, and perhaps not even with help.
So in order to keep things mergable, you need to not diverge. And the
intermediate merges are the "anchor-points" for the next merge, keeping
the divergences minimal.
I'm personally convinced that one of the reasons CVS is a pain to merge
is
obviously that it doesn't do a good job of finding parents, but also
exactly _because_ it makes merges so painful that people wait longer to
do
them, so you never end up fixing the simple stuff. In contrast, if you
have all these small merges going on all the time, the hope is that
there's never any really painful nasty "final merge".
So you're right - the small merges do end up cluttering up the revision
history. But it's a small price to pay if it means that you avoid having
the painful ones.
> Isn't preserving the A1,A2,A3,A4,A5 a legacy of BK, which required all
> the changesets to be loaded in order, and so is a completely "file"
> driven concept?
Nope. In fact, to some degree git will need this even _more_, since the
git merger is likely to be _weaker_ than BK, and thus more easily
confused.
I do believe that BK has these things for the same reason.
Linus
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox