summaryrefslogtreecommitdiff
path: root/wt-status.c
AgeCommit message (Collapse)AuthorFilesLines
2009-08-22git stat: the beginning of "status that is not a dry-run of commit"Libravatar Junio C Hamano1-4/+6
Tentatively add "git stat" as a new command. This is not "preview of commit with the same arguments"; the path parameters are not paths to be added to the pristine index (aka "--only" option), but are taken as pathspecs to limit the output. Later in 1.7.0 release, it will take over "git status". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-10wt-status: collect untracked files in a separate "collect" phaseLibravatar Junio C Hamano1-22/+36
In a way similar to updated and locally modified files are collected. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-10Make git_status_config() file scope static to builtin-commit.cLibravatar Junio C Hamano1-60/+0
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-10wt-status: move wt_status_colors[] into wt_status structureLibravatar Junio C Hamano1-4/+5
The benefit of this one alone is somewhat iffy, but for completeness this moves the wt_status_colors[] color palette to the wt_status structure to complete the libification started by the previous commit. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-10wt-status: move many global settings to wt_status structureLibravatar Junio C Hamano1-41/+40
Turn four global variables (wt_status_use_color, show_tracked_files, wt_status_relative_paths, and wt_status_submodule_summary) into fields of wt_status structure. They can also lose "wt_status_" prefix. Get rid of "untracked" field that was used only to keep track of otherwise available information redundantly. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-06status: show worktree status of conflicted paths separatelyLibravatar Junio C Hamano1-3/+92
When a path is unmerged in the index, we used to always say "unmerged" in the "Changed but not updated" section, even when the path was deleted in the work tree. Remove unmerged entries from the "Updated" section, and create a new section "Unmerged paths". Describe how the different stages conflict in more detail in this new section. Note that with the current 3-way merge policy (with or without recursive), certain combinations of index stages should never happen. For example, having only stage #2 means that a path that did not exist in the common ancestor was added by us while the other branch did not do anything to it, which would have autoresolved to take our addition. The code nevertheless prepares for the possibility that future merge policies may leave a path in such a state. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-06wt-status.c: rework the way changes to the index and work tree are summarizedLibravatar Junio C Hamano1-45/+181
Introduce a new infrastructure to find and summarize changes in a single string list, and rewrite wt_status_print_{updated,changed} functions using it. The goal of this change is to give more information on conflicted paths in the status output. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-07-09Add 'fill_directory()' helper function for directory traversalLibravatar Linus Torvalds1-1/+1
Most of the users of "read_directory()" actually want a much simpler interface than the whole complex (but rather powerful) one. In fact 'git add' had already largely abstracted out the core interface issues into a private "fill_directory()" function that was largely applicable almost as-is to a number of callers. Yes, 'git add' wants to do some extra work of its own, specific to the add semantics, but we can easily split that out, and use the core as a generic function. This function does exactly that, and now that much simplified 'fill_directory()' function can be shared with a number of callers, while also ensuring that the rather more complex calling conventions of read_directory() are used by fewer call-sites. This also makes the 'common_prefix()' helper function private to dir.c, since all callers are now in that file. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-06-20Fix various sparse warnings in the git source codeLibravatar Linus Torvalds1-1/+1
There are a few remaining ones, but this fixes the trivial ones. It boils down to two main issues that sparse complains about: - warning: Using plain integer as NULL pointer Sparse doesn't like you using '0' instead of 'NULL'. For various good reasons, not the least of which is just the visual confusion. A NULL pointer is not an integer, and that whole "0 works as NULL" is a historical accident and not very pretty. A few of these remain: zlib is a total mess, and Z_NULL is just a 0. I didn't touch those. - warning: symbol 'xyz' was not declared. Should it be static? Sparse wants to see declarations for any functions you export. A lack of a declaration tends to mean that you should either add one, or you should mark the function 'static' to show that it's in file scope. A few of these remain: I only did the ones that should obviously just be made static. That 'wt_status_submodule_summary' one is debatable. It has a few related flags (like 'wt_status_use_color') which _are_ declared, and are used by builtin-commit.c. So maybe we'd like to export it at some point, but it's not declared now, and not used outside of that file, so 'static' it is in this patch. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-05-01Fix a bunch of pointer declarations (codestyle)Libravatar Felipe Contreras1-1/+1
Essentially; s/type* /type */ as per the coding guidelines. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-03-20Merge branch 'mv/parseopt-ls-files'Libravatar Junio C Hamano1-4/+3
* mv/parseopt-ls-files: ls-files: fix broken --no-empty-directory t3000: use test_cmp instead of diff parse-opt: migrate builtin-ls-files. Turn the flags in struct dir_struct into a single variable Conflicts: builtin-ls-files.c t/t3000-ls-files-others.sh
2009-02-18Turn the flags in struct dir_struct into a single variableLibravatar Johannes Schindelin1-4/+3
By having flags represented as bits in the new member variable 'flags', it will be easier to use parse_options when dir_struct is involved. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-02-13Clean up use of ANSI color sequencesLibravatar Arjen Laarhoven1-5/+5
Remove the literal ANSI escape sequences and replace them by readable constants. Signed-off-by: Arjen Laarhoven <arjen@yaph.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-12-07reorder ALLOW_TEXTCONV option settingLibravatar Jeff King1-1/+1
Right now for the diff porcelain and the log family, we call: init_revisions(); setup_revisions(); DIFF_OPT_SET(ALLOW_TEXTCONV); However, that means textconv will _always_ be on, instead of being a default that can be manipulated with setup_revisions. Instead, we want: init_revisions(); DIFF_OPT_SET(ALLOW_TEXTCONV); setup_revisions(); which is what this patch does. We'll go ahead and move the callsite in wt-status, also; even though the user can't pass any options here, it is a cleanup that will help avoid any surprise later if the setup_revisions line is changed. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-11-16Merge branch 'jk/commit-v-strip'Libravatar Junio C Hamano1-27/+6
* jk/commit-v-strip: status: show "-v" diff even for initial commit wt-status: refactor initial commit printing define empty tree sha1 as a macro
2008-11-12status: show "-v" diff even for initial commitLibravatar Jeff King1-2/+3
Since we can use the same "diff against empty tree" trick as we do for the non-initial case, it is trivial to make this work. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-11-12wt-status: refactor initial commit printingLibravatar Jeff King1-25/+3
When we showed the initial commit, we had no reference to diff against, so we went through the cache manually. Nowadays, however, we have a virtual empty tree commit, so we can simply diff against that to get the same results. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-10-26enable textconv for diff in verbose status/commitLibravatar Jeff King1-0/+1
This diff is meant for human consumption, so it makes sense to apply text conversion here, as we would for the regular diff porcelain. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-10-26wt-status: load diff ui configLibravatar Jeff King1-1/+9
When "git status -v" shows a diff, we did not respect the user's usual diff preferences at all. Loading just git_diff_basic_config would give us things like rename limits and diff drivers. But it makes even more sense to load git_diff_ui_config, which gives us colorization if the user has requested it. Note that we need to take special care to cancel colorization when writing to the commit template file, as described in the code comments. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-10-17Merge branch 'jk/maint-ls-files-other' into jk/fix-ls-files-otherLibravatar Junio C Hamano1-13/+2
* jk/maint-ls-files-other: refactor handling of "other" files in ls-files and status Conflicts: read-cache.c
2008-10-17refactor handling of "other" files in ls-files and statusLibravatar Jeff King1-13/+2
When the "git status" display code was originally converted to C, we copied the code from ls-files to discover whether a pathname returned by read_directory was an "other", or untracked, file. Much later, 5698454e updated the code in ls-files to handle some new cases caused by gitlinks. This left the code in wt-status.c broken: it would display submodule directories as untracked directories. Nobody noticed until now, however, because unless status.showUntrackedFiles was set to "all", submodule directories were not actually reported by read_directory. So the bug was only triggered in the presence of a submodule _and_ this config option. This patch pulls the ls-files code into a new function, cache_name_is_other, and uses it in both places. This should leave the ls-files functionality the same and fix the bug in status. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-10-12Replace calls to strbuf_init(&foo, 0) with STRBUF_INIT initializerLibravatar Brandon Casey1-7/+3
Many call sites use strbuf_init(&foo, 0) to initialize local strbuf variable "foo" which has not been accessed since its declaration. These can be replaced with a static initialization using the STRBUF_INIT macro which is just as readable, saves a function call, and takes up fewer lines. Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2008-09-07wt-status: Teach how to discard changes in the working directoryLibravatar Anders Melchiorsen1-0/+1
This is a question that comes up a lot in #git. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-07wt-status: Split header generation into three functionsLibravatar Anders Melchiorsen1-15/+19
Reorganize header generation so that all header text related to each block is in one place. This adds a function, but makes it easier to see what is generated in each case. It also allows for easy tweaking of individual headers. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-13Merge branch 'jc/report-tracking'Libravatar Junio C Hamano1-0/+22
* jc/report-tracking: branch -r -v: do not spit out garbage stat_tracking_info(): clear object flags used during counting git-branch -v: show the remote tracking statistics git-status: show the remote tracking statistics Refactor "tracking statistics" code used by "git checkout"
2008-07-05Fix "config_error_nonbool" used with value instead of keyLibravatar Christian Couder1-1/+1
The function "config_error_nonbool", that is defined in "config.c", is used to report an error when a config key in the config file should have a corresponding value but it hasn't. So the parameter to this function should be the key and not the value, because the value is undefined. And it could crash if the value is used. This patches fixes two occurences where the value was passed instead of the key. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-02git-status: show the remote tracking statisticsLibravatar Junio C Hamano1-0/+22
This teaches "git status" to show the same remote tracking statistics "git checkout" gives at the beginning of the output. Now the necessary low-level machinery is properly factored out, we can do this quite cleanly. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-09Add configuration option for default untracked files modeLibravatar Marius Storm-Olsen1-0/+13
By default, the untracked files mode for commit/status is 'normal' Signed-off-by: Marius Storm-Olsen <marius@trolltech.com>
2008-06-09Add argument 'no' commit/status option -u|--untracked-filesLibravatar Marius Storm-Olsen1-1/+6
This new argument teaches Git to not look for any untracked files, saving cycles on slow file systems, or large repos. Signed-off-by: Marius Storm-Olsen <marius@trolltech.com>
2008-06-09Add an optional <mode> argument to commit/status -u|--untracked-files optionLibravatar Marius Storm-Olsen1-0/+1
This lets you specify how you want untracked files to be listed. The possible options are: normal - Show untracked files and directories all - Show all untracked files The 'all' mode is used, if the mode is not specified. Signed-off-by: Marius Storm-Olsen <marius@trolltech.com>
2008-05-25Merge branch 'js/config-cb'Libravatar Junio C Hamano1-2/+2
* js/config-cb: Provide git_config with a callback-data parameter Conflicts: builtin-add.c builtin-cat-file.c
2008-05-22Updated status to show 'Not currently on any branch' in redLibravatar Chris Parsons1-3/+8
This provides additional warning to users when attempting to commit to a detached HEAD. It is configurable in color.status.nobranch. Signed-off-by: Chris Parsons <chris@edendevelopment.co.uk> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-05-14Provide git_config with a callback-data parameterLibravatar Johannes Schindelin1-2/+2
git_config() only had a function parameter, but no callback data parameter. This assumes that all callback functions only modify global variables. With this patch, every callback gets a void * parameter, and it is hoped that this will help the libification effort. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-05-03bump rename limit defaultsLibravatar Jeff King1-1/+1
The current rename limit default of 100 was arbitrarily chosen. Testing[1] has shown that on modern hardware, a limit of 200 adds about a second of computation time, and a limit of 500 adds about 5 seconds of computation time. This patch bumps the default limit to 200 for viewing diffs, and to 500 for performing a merge. The limit for generating git-status templates is set independently; we bump it up to 200 here, as well, to match the diff limit. [1]: See <20080211113516.GB6344@coredump.intra.peff.net> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-04-12builtin-status: submodule summary supportLibravatar Ping Yin1-0/+41
This commit teaches 'git commit/status' show a new 'Modified submodules' section, which is an output from: git submodule summary --cached --for-status --summary-limit <limit> just before the 'Untracked files' section. The <limit> is given by the config variable status.submodulesummary to limit the submodule summary size. status.submodulesummary is a bool/int variable with value: - false or 0 by default to disable the summary, or - positive number to limit the summary size, or - true or negative number to unlimit the summary size. Also mention status.submodulesummary in the documentation. Signed-off-by: Ping Yin <pkufranky@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-03-14wt-status.c: no need for dup() dance anymoreLibravatar Kristian Høgsberg1-15/+2
Now we can generate diff to a file descriptor, we do not have to dup() the stdout around when writing the status output. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-03-07Make private quote_path() in wt-status.c available as quote_path_relative()Libravatar Dmitry Potapov1-45/+2
Move quote_path() from wt-status.c to quote.c and rename it as quote_path_relative(), because it is a better name for a public function. Also, instead of handcrafted quoting, quote_c_style_counted() is now used, to make its quoting more consistent with the rest of the system, also honoring core.quotepath specified in configuration. Signed-off-by: Dmitry Potapov <dpotapov@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-18Add color.ui variable which globally enables colorization if setLibravatar Matthias Kestenholz1-3/+3
Signed-off-by: Matthias Kestenholz <mk@spinlock.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-13Merge branch 'maint'Libravatar Junio C Hamano1-1/+1
* maint: config: add test cases for empty value and no value config variables. cvsimport: have default merge regex also match beginning of commit message git clone -s documentation: force a new paragraph for the NOTE status: suggest "git rm --cached" to unstage for initial commit Protect get_author_ident_from_commit() from filenames in work tree upload-pack: Initialize the exec-path. bisect: use verbatim commit subject in the bisect log git-cvsimport.txt: fix '-M' description. Revert "pack-objects: only throw away data during memory pressure"
2008-02-13status: suggest "git rm --cached" to unstage for initial commitLibravatar Jeff King1-1/+1
It makes no sense to suggest "git reset HEAD" since we have no HEAD commit. This actually used to work but regressed in f26a0012. wt_status_print_cached_header was updated to take the whole wt_status struct rather than just the reference field. Previously the various code paths were sometimes sending in s->reference and sometimes sending in NULL, making the decision on whether this was an initial commit before we even got to this function. Now we must check the initial flag here. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-11Merge branch 'lt/in-core-index'Libravatar Junio C Hamano1-10/+0
* lt/in-core-index: lazy index hashing Create pathname-based hash-table lookup into index read-cache.c: introduce is_racy_timestamp() helper read-cache.c: fix a couple more CE_REMOVE conversion Also use unpack_trees() in do_diff_cache() Make run_diff_index() use unpack_trees(), not read_tree() Avoid running lstat(2) on the same cache entry. index: be careful when handling long names Make on-disk index representation separate from in-core one
2008-02-11wt-status.c: guard config parser from value=NULLLibravatar Junio C Hamano1-0/+2
status.color.* and color.status.* expect a string value Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-01-21Make run_diff_index() use unpack_trees(), not read_tree()Libravatar Linus Torvalds1-10/+0
A plain "git commit" would still run lstat() a lot more than necessary, because wt_status_print() would cause the index to be repeatedly flushed and re-read by wt_read_cache(), and that would cause the CE_UPTODATE bit to be lost, resulting in the files in the index being lstat'ed three times each. The reason why wt-status.c ended up invalidating and re-reading the cache multiple times was that it uses "run_diff_index()", which in turn uses "read_tree()" to populate the index with *both* the old index and the tree we want to compare against. So this patch re-writes run_diff_index() to not use read_tree(), but instead use "unpack_trees()" to diff the index to a tree. That, in turn, means that we don't need to modify the index itself, which then means that we don't need to invalidate it and re-read it! This, together with the lstat() optimizations, means that "git commit" on the kernel tree really only needs to lstat() the index entries once. That noticeably cuts down on the cached timings. Best time before: [torvalds@woody linux]$ time git commit > /dev/null real 0m0.399s user 0m0.232s sys 0m0.164s Best time after: [torvalds@woody linux]$ time git commit > /dev/null real 0m0.254s user 0m0.140s sys 0m0.112s so it's a noticeable improvement in addition to being a nice conceptual cleanup (it's really not that pretty that "run_diff_index()" dirties the index!) Doing an "strace -c" on it also shows that as it cuts the number of lstat() calls by two thirds, it goes from being lstat()-limited to being limited by getdents() (which is the readdir system call): Before: % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 60.69 0.000704 0 69230 31 lstat 23.62 0.000274 0 5522 getdents 8.36 0.000097 0 5508 2638 open 2.59 0.000030 0 2869 close 2.50 0.000029 0 274 write 1.47 0.000017 0 2844 fstat After: % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 45.17 0.000276 0 5522 getdents 26.51 0.000162 0 23112 31 lstat 19.80 0.000121 0 5503 2638 open 4.91 0.000030 0 2864 close 1.48 0.000020 0 274 write 1.34 0.000018 0 2844 fstat ... It passes the test-suite for me, but this is another of one of those really core functions, and certainly pretty subtle, so.. NOTE! The Linux lstat() system call is really quite cheap when everything is cached, so the fact that this is quite noticeable on Linux is likely to mean that it is *much* more noticeable on other operating systems. I bet you'll see a much bigger performance improvement from this on Windows in particular. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-12-12git-commit: squelch needless message during an empty mergeLibravatar Junio C Hamano1-0/+2
When recording a merge that conflicted and ends up in no changes after manual resolution, commit callchain looked like this: cmd_commit() -> prepare_log_message() -> run_status() -> wt_status_print() This invocation of run_status() is asked to find out if there is a committable change, but it unconditionally gave instructions such as "use git-add" at the same time. When in merge, we do allow an empty change to be recorded, so after showing this message the code still went ahead and made a commit. This introduces "nowarn" parameter to run_status() to avoid these useless messages. If we are not allowed to create an empty commit, we already call run_status() again in the original codepath, and the message will be shown from that call anyway. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-12-08add status.relativePaths config variableLibravatar Jeff King1-0/+6
The output of git-status was recently changed to output relative paths. Setting this variable to false restores the old behavior for any old-timers that prefer it. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-12-08wt-status.c:quote_path(): convert empty path to "./"Libravatar Jeff King1-0/+3
Now that we are correctly removing leading prefixes from files in git status, there is a degenerate case: the directory matching the prefix. Because we show only the directory name for a directory that contains only untracked files, it gets collapsed to an empty string. Example: $ git init $ mkdir subdir $ touch subdir/file $ git status ... # Untracked files: # (use "git add <file>..." to include in what will be committed) # # subdir/ So far, so good. $ cd subdir $ git status .... # Untracked files: # (use "git add <file>..." to include in what will be committed) # # Oops, that's a bit confusing. This patch prints './' to show that there is some output. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-12-05git config --get-colorboolLibravatar Junio C Hamano1-1/+1
This adds an option to help scripts find out color settings from the configuration file. git config --get-colorbool color.diff inspects color.diff variable, and exits with status 0 (i.e. success) if color is to be used. It exits with status 1 otherwise. If a script wants "true"/"false" answer to the standard output of the command, it can pass an additional boolean parameter to its command line, telling if its standard output is a terminal, like this: git config --get-colorbool color.diff true When called like this, the command outputs "true" to its standard output if color is to be used (i.e. "color.diff" says "always", "auto", or "true"), and "false" otherwise. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-12-04Merge branch 'kh/commit'Libravatar Junio C Hamano1-23/+63
* kh/commit: (33 commits) git-commit --allow-empty git-commit: Allow to amend a merge commit that does not change the tree quote_path: fix collapsing of relative paths Make git status usage say git status instead of git commit Fix --signoff in builtin-commit differently. git-commit: clean up die messages Do not generate full commit log message if it is not going to be used Remove git-status from list of scripts as it is builtin Fix off-by-one error when truncating the diff out of the commit message. builtin-commit.c: export GIT_INDEX_FILE for launch_editor as well. Add a few more tests for git-commit builtin-commit: Include the diff in the commit message when verbose. builtin-commit: fix partial-commit support Fix add_files_to_cache() to take pathspec, not user specified list of files Export three helper functions from ls-files builtin-commit: run commit-msg hook with correct message file builtin-commit: do not color status output shown in the message template file_exists(): dangling symlinks do exist Replace "runstatus" with "status" in the tests t7501-commit: Add test for git commit <file> with dirty index. ...
2007-12-02quote_path: fix collapsing of relative pathsLibravatar Jeff King1-5/+6
The code tries to collapse identical leading components between the prefix and the path. So if we're in "dir1", the path "dir1/file" should become just "file". However, we were ending up with "../dir1/file". The included test expected the wrong output. The "len" parameter to quote_path can be negative to mean "this is a NUL terminated string". Simply count it so that the loop can rely on it being the length of the path. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-12-02Enable rewrite as well as rename detection in git-statusLibravatar Jeff King1-0/+1
Signed-off-by: Junio C Hamano <gitster@pobox.com>