Re: gitweb wishlist
- From
- David Mansfield <david@cobite.com>
- Date
- May 24, 2005, 20:03 UTC
- Message-ID
- <42938893.9010608@cobite.com>
- In-Reply-To
- <Pine.LNX.4.58.0505240911050.2307@ppc970.osdl.org>
Linus Torvalds wrote:
Show 18 quoted lines
> > On Tue, 24 May 2005, Linus Torvalds wrote: > >>Fixing the branch handling shows that cvsps does some really strange >>things with the newly added "Ancestor grpah". Here's one example: > > > Ahh, looking at cvsps source, I think I see what's going on. > > It's deciding the "previous branch" by looking at what the previous branch > for the first individual file in the PatchSet was, which fails because in > this case, PatchSet 372 was changing "syslinux.doc", and Patchset 374 was > changing "syslinux.c", and thus the previous version of the individual > _files_ were both in the HEAD branch. > > So it does look like I should just ignore the "Ancestor branch" > information if the new branch already existed. >
I've attached what I just committed. The previous 'show ancestor' patch needs to be reversed and this applied. It works for me on a half-dozen repos including syslinux.
You no longer should need to work around multiple reporting of the ancestor for a given branch, though it couldn't hurt.
I'm going to finish getting some of Thomas's patches in and make an actual release so people won't have to scour the lists.
David
--------------------- PatchSet 176 Date: 2005/05/24 19:57:37 Author: david Branch: HEAD Tag: (none) Log: show branch ancestry
Members: cvsps.c:4.99->4.100 cvsps_types.h:4.9->4.10
Index: cvsps/cvsps.c diff -u cvsps/cvsps.c:4.99 cvsps/cvsps.c:4.100 --- cvsps/cvsps.c:4.99 Wed Jan 26 14:46:41 2005 +++ cvsps/cvsps.c Tue May 24 15:57:37 2005 @@ -26,7 +26,7 @@ #include "cap.h" #include "cvs_direct.h" -RCSID("$Id: cvsps.c,v 4.99 2005/01/26 19:46:41 david Exp $"); +RCSID("$Id: cvsps.c,v 4.100 2005/05/24 19:57:37 david Exp $"); #define CVS_LOG_BOUNDARY "----------------------------\n" #define CVS_FILE_BOUNDARY "=============================================================================\n" @@ -75,6 +75,7 @@ static int do_write_cache; static int statistics; static const char * test_log_file; +static struct hash_table * branch_heads; /* settable via options */ static int timestamp_fuzz_factor = 300; @@ -101,6 +102,7 @@ static int cvs_direct; static int compress; static char compress_arg[8]; +static int track_branch_ancestry; static void check_norc(int, char *[]); static int parse_args(int, char *[]); @@ -112,7 +114,7 @@ static void assign_pre_revision(PatchSetMember *, CvsFileRevision * rev); static void check_print_patch_set(PatchSet *); static void print_patch_set(PatchSet *); -static void set_ps_id(const void *, const VISIT, const int); +static void walk_all_ps(const void *, const VISIT, const int); static void show_ps_tree_node(const void *, const VISIT, const int); static int compare_patch_sets_bk(const void *, const void *); static int compare_patch_sets(const void *, const void *); @@ -131,6 +133,7 @@ static int check_rev_funk(PatchSet *, CvsFileRevision *); static CvsFileRevision * rev_follow_branch(CvsFileRevision *, const char *); static int before_tag(CvsFileRevision * rev, const char * tag); +static void determine_branch_ancestor(PatchSet * ps, PatchSet * head_ps); int main(int argc, char *argv[]) { @@ -164,6 +167,7 @@ file_hash = create_hash_table(1023); global_symbols = create_hash_table(111); + branch_heads = create_hash_table(1023); /* this parses some of the CVS/ files, and initializes * the repository_path and other variables @@ -197,7 +201,7 @@ } ps_counter = 0; - twalk(ps_tree_bytime, set_ps_id); + twalk(ps_tree_bytime, walk_all_ps); resolve_global_symbols(); @@ -536,7 +540,7 @@ debug(DEBUG_APPERROR, " [--test-log <captured cvs log file>] [--bkcvs]"); debug(DEBUG_APPERROR, " [--no-rlog] [--diff-opts <option string>] [--cvs-direct]"); debug(DEBUG_APPERROR, " [--debuglvl <bitmask>] [-Z <compression>] [--root <cvsroot>]"); - debug(DEBUG_APPERROR, " [<repository>] [-q]"); + debug(DEBUG_APPERROR, " [-q] [-A] [<repository>]"); debug(DEBUG_APPERROR, ""); debug(DEBUG_APPERROR, "Where:"); debug(DEBUG_APPERROR, " -h display this informative message"); @@ -569,6 +573,7 @@ debug(DEBUG_APPERROR, " -Z <compression> A value 1-9 which specifies amount of compression"); debug(DEBUG_APPERROR, " --root <cvsroot> specify cvsroot. overrides env. and working directory"); debug(DEBUG_APPERROR, " -q be quiet about warnings"); + debug(DEBUG_APPERROR, " -A track and report branch ancestry"); debug(DEBUG_APPERROR, " <repository> apply cvsps to repository. overrides working directory"); debug(DEBUG_APPERROR, "\ncvsps version %s\n", VERSION); @@ -867,6 +872,13 @@ continue; } + if (strcmp(argv[i], "-A") == 0) + { + track_branch_ancestry = 1; + i++; + continue; + } + if (argv[i][0] == '-') return usage("invalid argument", argv[i]); @@ -1398,6 +1410,8 @@ tm->tm_hour, tm->tm_min, tm->tm_sec); printf("Author: %s\n", ps->author); printf("Branch: %s\n", ps->branch); + if (ps->ancestor_branch) + printf("Ancestor branch: %s\n", ps->ancestor_branch); printf("Tag: %s %s\n", ps->tag ? ps->tag : "(none)", tag_flag_descr[ps->tag_flags]); printf("Log:\n%s\n", ps->descr); printf("Members: \n"); @@ -1425,7 +1439,10 @@ printf("\n"); } -static void set_ps_id(const void * nodep, const VISIT which, const int depth) +/* walk all the patchsets to assign monotonic psid, + * and to establish branch ancestry + */ +static void walk_all_ps(const void * nodep, const VISIT which, const int depth) { PatchSet * ps; @@ -1442,6 +1459,18 @@ { ps_counter++; ps->psid = ps_counter; + + if (track_branch_ancestry && strcmp(ps->branch, "HEAD") != 0) + { + PatchSet * head_ps = (PatchSet*)get_hash_object(branch_heads, ps->branch); + if (!head_ps) + { + head_ps = ps; + put_hash_object(branch_heads, ps->branch, head_ps); + } + + determine_branch_ancestor(ps, head_ps); + } } else { @@ -1912,6 +1941,7 @@ ps->tag_flags = 0; ps->branch_add = 0; ps->funk_factor = 0; + ps->ancestor_branch = NULL; } return ps; @@ -2235,21 +2265,25 @@ return 0; } -/* - * When importing vendor sources, (apparently people do this) - * the code is added on a 'vendor' branch, which, for some reason - * doesn't use the magic-branch-tag format. Try to detect that now - */ -static int is_vendor_branch(const char * rev) +static int count_dots(const char * p) { int dots = 0; - const char *p = rev; while (*p) if (*p++ == '.') dots++; - return !(dots&1); + return dots; +} + +/* + * When importing vendor sources, (apparently people do this) + * the code is added on a 'vendor' branch, which, for some reason + * doesn't use the magic-branch-tag format. Try to detect that now + */ +static int is_vendor_branch(const char * rev) +{ + return !(count_dots(rev)&1); } void patch_set_add_member(PatchSet * ps, PatchSetMember * psm) @@ -2395,5 +2429,69 @@ break; } i++; + } +} + +static void determine_branch_ancestor(PatchSet * ps, PatchSet * head_ps) +{ + struct list_head * next; + CvsFileRevision * rev; + + /* PatchSet 1 has no ancestor */ + if (ps->psid == 1) + return; + + /* HEAD branch patchsets have no ancestry, but callers should know that */ + if (strcmp(ps->branch, "HEAD") == 0) + { + debug(DEBUG_APPMSG1, "WARNING: no branch ancestry for HEAD"); + return; + } + + for (next = ps->members.next; next != &ps->members; next = next->next) + { + PatchSetMember * psm = list_entry(next, PatchSetMember, link); + rev = psm->pre_rev; + int d1, d2; + + /* the reason this is at all complicated has to do with a + * branch off of a branch. it is possible (and indeed + * likely) that some file would not have been modified + * from the initial branch point to the branch-off-branch + * point, and therefore the branch-off-branch point is + * really branch-off-HEAD for that specific member (file). + * in that case, rev->branch will say HEAD but we want + * to know the symbolic name of the first branch + * so we continue to look member after member until we find + * the 'deepest' branching. deepest can actually be determined + * by considering the revision currently indicated by + * ps->ancestor_branch (by symbolic lookup) and rev->rev. the + * one with more dots wins + * + * also, the first commit in which a branch-off-branch is + * mentioned may ONLY modify files never committed since + * original branch-off-HEAD was created, so we have to keep + * checking, ps after ps to be sure to get the deepest ancestor + * + * note: rev is the pre-commit revision, not the post-commit + */ + if (!head_ps->ancestor_branch) + d1 = 0; + else if (strcmp(ps->branch, rev->branch) == 0) + continue; + else if (strcmp(head_ps->ancestor_branch, "HEAD") == 0) + d1 = 1; + else { + /* branch_rev may not exist if the file was added on this branch for example */ + const char * branch_rev = (char *)get_hash_object(rev->file->branches_sym, head_ps->ancestor_branch); + d1 = branch_rev ? count_dots(branch_rev) : 1; + } + + d2 = count_dots(rev->rev); + + if (d2 > d1) + head_ps->ancestor_branch = rev->branch; + + //printf("-----> %d ancestry %s %s %s\n", ps->psid, ps->branch, head_ps->ancestor_branch, rev->file->filename); } } Index: cvsps/cvsps_types.h diff -u cvsps/cvsps_types.h:4.9 cvsps/cvsps_types.h:4.10 --- cvsps/cvsps_types.h:4.9 Mon Mar 31 18:06:18 2003 +++ cvsps/cvsps_types.h Tue May 24 15:57:37 2005 @@ -110,6 +110,7 @@ char *tag; int tag_flags; char *branch; + char *ancestor_branch; struct list_head members; /* * A 'branch add' patch set is a bogus patch set created automatically