summaryrefslogtreecommitdiff
path: root/rev-list.c
AgeCommit message (Collapse)AuthorFilesLines
2006-04-17Merge branch 'lt/logopt' into nextLibravatar Junio C Hamano1-4/+8
* lt/logopt: combine-diff: show diffstat with the first parent. git.c: LOGSIZE is unused after log printing cleanup. Log message printout cleanups (#3): fix --pretty=oneline Log message printout cleanups (#2) Log message printout cleanups rev-list --header: output format fix
2006-04-17Log message printout cleanupsLibravatar Linus Torvalds1-4/+5
On Sun, 16 Apr 2006, Junio C Hamano wrote: > > In the mid-term, I am hoping we can drop the generate_header() > callchain _and_ the custom code that formats commit log in-core, > found in cmd_log_wc(). Ok, this was nastier than expected, just because the dependencies between the different log-printing stuff were absolutely _everywhere_, but here's a patch that does exactly that. The patch is not very easy to read, and the "--patch-with-stat" thing is still broken (it does not call the "show_log()" thing properly for merges). That's not a new bug. In the new world order it _should_ do something like if (rev->logopt) show_log(rev, rev->logopt, "---\n"); but it doesn't. I haven't looked at the --with-stat logic, so I left it alone. That said, this patch removes more lines than it adds, and in particular, the "cmd_log_wc()" loop is now a very clean: while ((commit = get_revision(rev)) != NULL) { log_tree_commit(rev, commit); free(commit->buffer); commit->buffer = NULL; } so it doesn't get much prettier than this. All the complexity is entirely hidden in log-tree.c, and any code that needs to flush the log literally just needs to do the "if (rev->logopt) show_log(...)" incantation. I had to make the combined_diff() logic take a "struct rev_info" instead of just a "struct diff_options", but that part is pretty clean. This does change "git whatchanged" from using "diff-tree" as the commit descriptor to "commit", and I changed one of the tests to reflect that new reality. Otherwise everything still passes, and my other tests look fine too. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-17rev-list --header: output format fixLibravatar Junio C Hamano1-0/+3
Initial fix prepared by Johannes, but I did it slightly differently. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-16Merge branch 'jc/boundary' into nextLibravatar Junio C Hamano1-2/+2
* jc/boundary: rev-list --boundary: show boundary commits even when limited otherwise. Makefile fixups. gitk: Fix bug caused by missing commitlisted elements
2006-04-16rev-list --boundary: show boundary commits even when limited otherwise.Libravatar Junio C Hamano1-2/+2
The boundary commits are shown for UI like gitk to draw them as soon as topo-order sorting allows, and should not be omitted by get_revision() filtering logic. As long as their immediate child commits are shown, we should not filter them out. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-16Merge branch 'lt/logopt' into nextLibravatar Junio C Hamano1-61/+27
* lt/logopt: Tentative built-in "git show" Built-in git-whatchanged. rev-list option parser fix. Split init_revisions() out of setup_revisions()
2006-04-15rev-list option parser fix.Libravatar Junio C Hamano1-59/+23
The big option parser unification broke rev-list the big way; this makes it use options from the parsed revs structure. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-15Merge branch 'jc/logopt' into nextLibravatar Junio C Hamano1-4/+2
* jc/logopt: Revert all the rev-list option parsing changes.
2006-04-15Revert all the rev-list option parsing changes.Libravatar Junio C Hamano1-4/+2
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-14Merge branch 'lt/logopt' into nextLibravatar Junio C Hamano1-2/+4
* lt/logopt: Fix up rev-list option parsing. Fix up default abbrev in setup_revisions() argument parser. Common option parsing for "git log --diff" and friends
2006-04-14Fix up rev-list option parsing.Libravatar Junio C Hamano1-2/+4
rev-list does not take diff options, so barf after seeing some. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-14rev-list --bisect: limit list before bisecting.Libravatar Junio C Hamano1-0/+2
I noticed bisect does not work well without both good and bad. Running this script in git.git repository would give you quite different results: #!/bin/sh initial=e83c5163316f89bfbde7d9ab23ca2e25604af290 mid0=`git rev-list --bisect ^$initial --all` git rev-list $mid0 | wc -l git rev-list ^$mid0 --all | wc -l mid1=`git rev-list --bisect --all` git rev-list $mid1 | wc -l git rev-list ^$mid1 --all | wc -l The $initial commit is the very first commit you made. The first midpoint bisects things evenly as designed, but the latter does not. The reason I got interested in this was because I was wondering if something like the following would help people converting a huge repository from foreign SCM, or preparing a repository to be fetched over plain dumb HTTP only: #!/bin/sh N=4 P=.git/objects/pack bottom= while test 0 \< $N do N=$((N-1)) if test -z "$bottom" then newbottom=`git rev-list --bisect --all` else newbottom=`git rev-list --bisect ^$bottom --all` fi if test -z "$bottom" then rev_list="$newbottom" elif test 0 = $N then rev_list="^$bottom --all" else rev_list="^$bottom $newbottom" fi p=$(git rev-list --unpacked --objects $rev_list | git pack-objects $P/pack) git show-index <$P/pack-$p.idx | wc -l bottom=$newbottom done The idea is to pack older half of the history to one pack, then older half of the remaining history to another, to continue a few times, using finer granularity as we get closer to the tip. This may not matter, since for a truly huge history, running bisect number of times could be quite time consuming, and we might be better off running "git rev-list --all" once into a temporary file, and manually pick cut-off points from the resulting list of commits. After all we are talking about "approximately half" for such an usage, and older history does not matter much. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-10blame and friends: adjust to multiple pathspec change.Libravatar Junio C Hamano1-0/+1
This makes things that include revision.h build again. Blame is also built, but I am not sure how well it works (or how well it worked to begin with) -- it was relying on tree-diff to be using whatever pathspec was used the last time, which smells a bit suspicious. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-08Make "--parents" logs also be incrementalLibravatar Linus Torvalds1-2/+2
The parent rewriting feature caused us to create the whole history in one go, and then simplify it later, because of how rewrite_parents() had been written. However, with a little tweaking, it's perfectly possible to do even that one incrementally. Right now, this doesn't really much matter, because every user of "--parents" will probably generally _also_ use "--topo-order", which will cause the old non-incremental behaviour anyway. However, I'm hopeful that we could make even the topological sort incremental, or at least _partially_ so (for example, make it incremental up to the first merge). In the meantime, this at least moves things in the right direction, and removes a strange special case. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-07rev-list --abbrev-commitLibravatar Junio C Hamano1-1/+14
This should make --pretty=oneline a whole lot more readable for people using 80-column terminals. Originally from Eric Wong. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-31Move "--parent" parsing into generic revision.c library codeLibravatar Linus Torvalds1-6/+1
Not only do we do it in both rev-list.c and git.c, the revision walking code will soon want to know whether we should rewrite parenthood information or not. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-29tree/diff header cleanup.Libravatar Junio C Hamano1-1/+1
Introduce tree-walk.[ch] and move "struct tree_desc" and associated functions from various places. Rename DIFF_FILE_CANON_MODE(mode) macro to canon_mode(mode) and move it to cache.h. This macro returns the canonicalized st_mode value in the host byte order for files, symlinks and directories -- to be compared with a tree_desc entry. create_ce_mode(mode) in cache.h is similar but is intended to be used for index entries (so it does not work for directories) and returns the value in the network byte order. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-28rev-list --boundaryLibravatar Junio C Hamano1-2/+4
With the new --boundary flag, the output from rev-list includes the UNINTERESING commits at the boundary, which are usually not shown. Their object names are prefixed with '-'. For example, with this graph: C side / A---B---D master You would get something like this: $ git rev-list --boundary --header --parents side..master D B tree D^{tree} parent B ... log message for commit D here ... \0-B A tree B^{tree} parent A ... log message for commit B here ... \0 Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-28rev-list: memory usage reduction.Libravatar Junio C Hamano1-3/+3
We do not need to track object refs, neither we need to save commit unless we are doing verbose header. A lot of traversal happens inside prepare_revision_walk() these days so setting things up before calling that function is necessary. Signed-off-by: Junio C Hamano <junkio@cox.net> Acked-by: Linus Torvalds <torvalds@osdl.org>
2006-03-22rev-list --timestampLibravatar Junio C Hamano1-1/+10
This prefixes the raw commit timestamp to the output. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-10rev-lib: Make it easy to do rename tracking (take 2)Libravatar Fredrik Kuivinen1-3/+3
prune_fn in the rev_info structure is called in place of try_to_simplify_commit. This makes it possible to do rename tracking with a custom try_to_simplify_commit-like function. This commit also introduces init_revisions which initialises the rev_info structure with default values. Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-01git-log (internal): more options.Libravatar Junio C Hamano1-3/+2
This ports the following options from rev-list based git-log implementation: * -<n>, -n<n>, and -n <n>. I am still wondering if we want this natively supported by setup_revisions(), which already takes --max-count. We may want to move them in the next round. Also I am not sure if we can get away with not setting revs->limited when we set max-count. The latest rev-list.c and revision.c in this series do not, so I left them as they are. * --pretty and --pretty=<fmt>. * --abbrev=<n> and --no-abbrev. The previous commit already handles time-based limiters (--since, --until and friends). The remaining things that rev-list based git-log happens to do are not useful in a pure log-viewing purposes, and not ported: * --bisect (obviously). * --header. I am actually in favor of doing the NUL terminated record format, but rev-list based one always passed --pretty, which defeated this option. Maybe next round. * --parents. I do not think of a reason a log viewer wants this. The flag is primarily for feeding squashed history via pipe to downstream tools. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-03-01Rip out merge-order and make "git log <paths>..." work again.Libravatar Linus Torvalds1-110/+4
Well, assuming breaking --merge-order is fine, here's a patch (on top of the other ones) that makes git log <filename> actually work, as far as I can tell. I didn't add the logic for --before/--after flags, but that should be pretty trivial, and is independent of this anyway. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-28git-rev-list libification: rev-list walkingLibravatar Linus Torvalds1-248/+16
This actually moves the "meat" of the revision walking from rev-list.c to the new library code in revision.h. It introduces the new functions void prepare_revision_walk(struct rev_info *revs); struct commit *get_revision(struct rev_info *revs); to prepare and then walk the revisions that we have. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27Splitting rev-list into revisions lib, end of beginning.Libravatar Linus Torvalds1-20/+5
This makes the rewrite easier to validate in that revision flag parsing and warlking part are now all in rev_info structure. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26rev-list split: minimum fixup.Libravatar Junio C Hamano1-5/+3
This fixes "the other end has commit X but since then we tagged that commit with tag T, and he says he wants T -- what is the list of objects we need to send him?" question: git-rev-list --objects ^X T We ended up sending everything since the beginning of time X-<. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26First cut at libifying revlist generationLibravatar Linus Torvalds1-354/+43
This really just splits things up partially, and creates the interface to set things up by parsing the command line. No real code changes so far, although the parsing of filenames is a bit stricter. In particular, if there is a "--", then we do not accept any filenames before it, and if there isn't any "--", then we check that _all_ paths listed are valid, not just the first one. The new argument parsing automatically also gives us "--default" and "--not" handling as in git-rev-parse. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-24Merge branches 'jc/rev-list' and 'jc/pack-thin'Libravatar Junio C Hamano1-19/+86
* jc/rev-list: rev-list --objects: use full pathname to help hashing. rev-list --objects-edge: remove duplicated edge commit output. rev-list --objects-edge * jc/pack-thin: pack-objects: hash basename and direname a bit differently. pack-objects: allow "thin" packs to exceed depth limits pack-objects: use full pathname to help hashing with "thin" pack. pack-objects: thin pack micro-optimization. Use thin pack transfer in "git fetch". Add git-push --thin. send-pack --thin: use "thin pack" delta transfer. Thin pack - create packfile with missing delta base. Conflicts: pack-objects.c (taking "next") send-pack.c (taking "next")
2006-02-23rev-list --objects: use full pathname to help hashing.Libravatar Junio C Hamano1-13/+56
This helps to group the same files from different revs together, while spreading files with the same basename in different directories, to help pack-object. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-23rev-list --objects-edge: remove duplicated edge commit output.Libravatar Junio C Hamano1-1/+3
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-22rev-list.c: fix non-grammatical comments.Libravatar Junio C Hamano1-2/+2
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-19rev-list --objects-edgeLibravatar Junio C Hamano1-6/+28
This new flag is similar to --objects, but causes rev-list to show list of "uninteresting" commits that appear on the edge commit prefixed with '-'. Downstream pack-objects will be changed to take these as hints to use the trees and blobs contained with them as base objects of resulting pack, producing an incomplete (not self-contained) pack. Such a pack cannot be used in .git/objects/pack (it is prevented by git-index-pack erroring out if it is fed to git-fetch-pack -k or git-clone-pack), but would be useful when transferring only small changes to huge blobs. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-15topo-order: make --date-order optional.Libravatar Junio C Hamano1-1/+10
This adds --date-order to rev-list; it is similar to topo order in the sense that no parent comes before all of its children, but otherwise things are still ordered in the commit timestamp order. The same flag is also added to show-branch. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-10rev-list: default to abbreviate merge parent names under --pretty.Libravatar Junio C Hamano1-1/+15
When we prettyprint commit log messages, merge parent names were often very long and there was no way to abbreviate it. This changes them to be abbreviated by default, and non-default abbreviations can be specified with --no-abbrev or --abbrev=<n> options. Note that this affects only the prettyprinted parent names. The output from --show-parents is meant for machine consumption and is not affected by this flag.
2006-02-01rev-list: omit duplicated parents.Libravatar Junio C Hamano1-1/+14
Showing the same parent more than once for a commit does not make much sense downstream, so stop it. This can happen with an incorrectly made merge commit that merges the same parent twice, but can happen in an otherwise sane development history while squishing the history by taking into account only commits that touch specified paths. For example, $ git rev-list --max-count=1 --parents addafaf -- rev-list.c would have to show this commit ancestry graph: .---o---. / \ .---*---o---. / 93b74bc \ ---*---o---o-----o---o-----o addafaf d8f6b34 \ / .---o---o---. \ / .---*---. 3815f42 where 5 independent development tracks, only two of which have changes in the specified paths since they forked. The last change for the other three development tracks was done by the same commit before they forked, and we were showing that three times. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-01-31rev-list: allow -<n> as shorthand for --max-count=<n>Libravatar Eric Wong1-0/+5
This builds on top of the previous one. Traditionally, head(1) and tail(1) allow their line limits to be parsed this way. Signed-off-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-01-31rev-list: allow -n<n> as shorthand for --max-count=<n>Libravatar Eric Wong1-0/+10
Both -n<n> and -n <n> are supported. POSIX versions of head(1) and tail(1) allow their line limits to be parsed this way. I find --max-count to be a commonly used option, and also similar in spirit to head/tail, so I decided to make life easier on my worn out (and lazy :) fingers with this patch. Signed-off-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-01-28Merge lt/revlist,jc/diff,jc/revparse,jc/abbrevLibravatar Junio C Hamano1-59/+80
2006-01-28pretty_print_commit(): pass commit object instead of commit->buffer.Libravatar Junio C Hamano1-1/+1
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-01-28diff-tree: abbreviate merge parent object names with --abbrev --pretty.Libravatar Junio C Hamano1-1/+1
When --abbrev is in effect, abbreviate the merge parent names in prettyprinted output. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-01-28rev-list --remove-empty: add minimum help and doc entry.Libravatar Junio C Hamano1-0/+1
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-01-28rev-list: stop when the file disappearsLibravatar Linus Torvalds1-58/+78
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). 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: 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
2006-01-25Make git-rev-list and git-rev-parse argument parsing stricterLibravatar Linus Torvalds1-1/+5
If you pass it a filename without the "--" marker to separate it from revision information and flags, we now require that the file in question actually exists. This makes mis-typed revision information not be silently just considered a strange filename. With the "--" marker, you can continue to pass in filenames that do not actually exists - useful for querying what happened to a file that you no longer have in the repository. [ All scripts should use the "--" format regardless, to make things unambiguous. So this change should not affect any existing tools ] Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-19rev-list --objects: fix object list without commit.Libravatar Junio C Hamano1-1/+2
Earlier, "rev-list --objects <sha1>" for an object chain that does not have any commit failed with a usage message. This fixes "send-pack remote $tag" where tag points at a non-commit (e.g. a blob). Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-28bisect: limit the searchspace by pathspecsLibravatar Linus Torvalds1-6/+12
It was surprisingly easy to do. git bisect start <pathspec> followed by all the normal "git bisect good/bad" stuff. Almost totally untested, and I guarantee that if your pathnames have spaces in them (or your GIT_DIR has spaces in it) this won't work. I don't know how to fix that, my shell programming isn't good enough. This involves small changes to make "git-rev-list --bisect" work in the presense of a pathspec limiter, and then truly trivial (and that's the broken part) changes to make "git bisect" save away and use the pathspec. I tried one bisection, and a "git bisect visualize", and it all looked correct. But hey, don't be surprised if it has problems. Linus Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-21max-count in terms of intersectionLibravatar Luben Tuikov1-2/+3
When a path designation is given, max-count counts the number of commits therein (intersection), not globally. This avoids the case where in case path has been inactive for the last N commits, --max-count=N and path designation at git-rev-list is given, would give no commits. Signed-off-by: Luben Tuikov <ltuikov@yahoo.com> Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-10-30Update usage string and documentation for git-rev-list.Libravatar Junio C Hamano1-13/+19
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-10-26git-rev-list: do not forget non-commit refsLibravatar Linus Torvalds1-12/+14
What happens is that the new logic decides that if it can't look up a commit reference (ie "get_commit_reference()" returns NULL), the thing must be a pathname. Fair enough. But wrong. The thing is, it may be a perfectly fine ref that _isn't_ a commit. In git, you have a tag that points to your PGP key, and in the kernel, I have a tag that points to a tree (and a direct ref that points to that tree too, for that matter). So the rule is (as for all the other programs that mix revs and pathnames) not that we only accept commit references, but _any_ valid object ref. If the object then isn't a commit ref, git-rev-list will either ignore it, or add it to the list of non-commit objects (if using "--objects"). The solution is to move the "get_sha1()" out of get_commit_reference(), and into the callers. In fact, we already _have_ the SHA1 in the case of the handle_all() loop, since for_each_ref() will have done it for us, so this is the correct thing to do anyway. This patch (on top of the original one) does exactly that. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-10-26git-rev-list: make --dense the default (and introduce "--sparse")Libravatar Linus Torvalds1-7/+18
This actually does three things: - make "--dense" the default for git-rev-list. Since dense is a no-op if no filenames are given, this doesn't actually change any historical behaviour, but it's logically the right default (if we want to prune on filenames, do it fully. The sparse "merge-only" thing may be useful, but it's not what you'd normally expect) - make "git-rev-parse" show the default revision control before it shows any pathnames. This was a real bug, but nobody would ever have noticed, because the default thing tends to only make sense for git-rev-list, and git-rev-list didn't use to take pathnames. - it changes "git-rev-list" to match the other commands that take a mix of revisions and filenames - it no longer requires the "--" before filenames (although you still need to do it if a filename could be confused with a revision name, eg "gitk" in the git archive) This all just makes for much more pleasant and obvous usage. Just doing a gitk t/ does the obvious thing: it will show the history as it concerns the "t/" subdirectory. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-10-25git-rev-list: fix "--dense" flagLibravatar Linus Torvalds1-8/+43
Right now --dense will _always_ show the root commit. I didn't do the logic that does the diff against an empty tree. I was lazy. This patch does that. The first round was incorrect but this patch is even slightly tested, and might do a better job. Signed-off-by: Junio C Hamano <junkio@cox.net>