diff options
37 files changed, 415 insertions, 125 deletions
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index 96585ae8d9..698ffde7ce 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -15,6 +15,7 @@ DESCRIPTION The command takes various subcommands, and different options depending on the subcommand: + git bisect help git bisect start [<bad> [<good>...]] [--] [<paths>...] git bisect bad [<rev>] git bisect good [<rev>...] @@ -29,6 +30,12 @@ This command uses 'git-rev-list --bisect' option to help drive the binary search process to find which change introduced a bug, given an old "good" commit object name and a later "bad" commit object name. +Getting help +~~~~~~~~~~~~ + +Use "git bisect" to get a short usage description, and "git bisect +help" or "git bisect -h" to get a long usage description. + Basic bisect commands: start, bad, good ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index b4ae61ff46..4bb51cc06e 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -139,6 +139,17 @@ but can be used to amend a merge commit. as well. This is usually not what you want unless you are concluding a conflicted merge. +-o|--only:: + Make a commit only from the paths specified on the + command line, disregarding any contents that have been + staged so far. This is the default mode of operation of + 'git commit' if any paths are given on the command line, + in which case this option can be omitted. + If this option is specified together with '--amend', then + no paths need be specified, which can be used to amend + the last commit without committing changes that have + already been staged. + -u|--untracked-files:: Show all untracked files, also those in uninteresting directories, in the "Untracked files:" section of commit diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index fa161718dd..5de5d051b7 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -144,6 +144,8 @@ See also <<FILES>>. "auto". If `stdout-is-tty` is missing, then checks the standard output of the command itself, and exits with status 0 if color is to be used, or exits with status 1 otherwise. + When the color setting for `name` is undefined, the command uses + `color.ui` as fallback. --get-color name default:: diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index 9cec8021b8..b1106714b2 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -110,7 +110,9 @@ cvs -d ":ext;CVS_SERVER=git-cvsserver:user@server/path/repo.git" co <HEAD_name> ------ This has the advantage that it will be saved in your 'CVS/Root' files and you don't need to worry about always setting the correct environment -variable. +variable. SSH users restricted to git-shell don't need to override the default +with CVS_SERVER (and shouldn't) as git-shell understands `cvs` to mean +git-cvsserver and pretends that the other end runs the real cvs better. -- 2. For each repo that you want accessible from CVS you need to edit config in the repo and add the following section. @@ -141,25 +143,29 @@ allowing access over SSH. enabled=1 ------ -- -3. On the client machine you need to set the following variables. - CVSROOT should be set as per normal, but the directory should point at the - appropriate git repo. For example: +3. If you didn't specify the CVSROOT/CVS_SERVER directly in the checkout command, + automatically saving it in your 'CVS/Root' files, then you need to set them + explicitly in your environment. CVSROOT should be set as per normal, but the + directory should point at the appropriate git repo. As above, for SSH clients + _not_ restricted to git-shell, CVS_SERVER should be set to git-cvsserver. + -- -For SSH access, CVS_SERVER should be set to git-cvsserver - -Example: - ------ export CVSROOT=:ext:user@server:/var/git/project.git export CVS_SERVER=git-cvsserver ------ -- -4. For SSH clients that will make commits, make sure their .bashrc file - sets the GIT_AUTHOR and GIT_COMMITTER variables. +4. For SSH clients that will make commits, make sure their server-side + .ssh/environment files (or .bashrc, etc., according to their specific shell) + export appropriate values for GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, + GIT_COMMITTER_NAME, and GIT_COMMITTER_EMAIL. For SSH clients whose login + shell is bash, .bashrc may be a reasonable alternative. 5. Clients should now be able to check out the project. Use the CVS 'module' - name to indicate what GIT 'head' you want to check out. Example: + name to indicate what GIT 'head' you want to check out. This also sets the + name of your newly checked-out directory, unless you tell it otherwise with + `-d <dir_name>`. For example, this checks out 'master' branch to the + `project-master` directory: + ------ cvs co -d project-master master diff --git a/Documentation/git-request-pull.txt b/Documentation/git-request-pull.txt index 270df9b185..9a14c04e39 100644 --- a/Documentation/git-request-pull.txt +++ b/Documentation/git-request-pull.txt @@ -24,7 +24,7 @@ OPTIONS URL to include in the summary. <end>:: - Commit to send at; defaults to HEAD. + Commit to end at; defaults to HEAD. Author ------ diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt index dc36c662ae..9c81b72dbe 100644 --- a/Documentation/git-rm.txt +++ b/Documentation/git-rm.txt @@ -11,28 +11,37 @@ SYNOPSIS DESCRIPTION ----------- -Remove files from the working tree and from the index. The -files have to be identical to the tip of the branch, and no -updates to its contents must have been placed in the staging -area (aka index). When --cached is given, the staged content has to -match either the tip of the branch *or* the file on disk. +Remove files from the index, or from the working tree and the index. +`git rm` will not remove a file from just your working directory. +(There is no option to remove a file only from the work tree +and yet keep it in the index; use `/bin/rm` if you want to do that.) +The files being removed have to be identical to the tip of the branch, +and no updates to their contents can be staged in the index, +though that default behavior can be overridden with the `-f` option. +When '--cached' is given, the staged content has to +match either the tip of the branch or the file on disk, +allowing the file to be removed from just the index. OPTIONS ------- <file>...:: Files to remove. Fileglobs (e.g. `*.c`) can be given to - remove all matching files. Also a leading directory name - (e.g. `dir` to add `dir/file1` and `dir/file2`) can be - given to remove all files in the directory, recursively, - but this requires `-r` option to be given for safety. + remove all matching files. If you want git to expand + file glob characters, you may need to shell-escape them. + A leading directory name + (e.g. `dir` to remove `dir/file1` and `dir/file2`) can be + given to remove all files in the directory, and recursively + all sub-directories, + but this requires the `-r` option to be explicitly given. -f:: Override the up-to-date check. -n, \--dry-run:: - Don't actually remove the file(s), just show if they exist in - the index. + Don't actually remove any file(s). Instead, just show + if they exist in the index and would otherwise be removed + by the command. -r:: Allow recursive removal when a leading directory name is @@ -44,9 +53,9 @@ OPTIONS for command-line options). \--cached:: - This option can be used to tell the command to remove - the paths only from the index, leaving working tree - files. + Use this option to unstage and remove paths only from the index. + Working tree files, whether modified or not, will be + left alone. \--ignore-unmatch:: Exit with a zero status even if no files matched. @@ -59,11 +68,15 @@ OPTIONS DISCUSSION ---------- -The list of <file> given to the command can be exact pathnames, -file glob patterns, or leading directory name. The command -removes only the paths that is known to git. Giving the name of +The <file> list given to the command can be exact pathnames, +file glob patterns, or leading directory names. The command +removes only the paths that are known to git. Giving the name of a file that you have not told git about does not remove that file. +File globbing matches across directory boundaries. Thus, given +two directories `d` and `d2`, there is a difference between +using `git rm \'d\*\'` and `git rm \'d/\*\'`, as the former will +also remove all of directory `d2`. EXAMPLES -------- @@ -72,11 +85,10 @@ git-rm Documentation/\\*.txt:: `Documentation` directory and any of its subdirectories. + Note that the asterisk `\*` is quoted from the shell in this -example; this lets the command include the files from -subdirectories of `Documentation/` directory. +example; this lets git, and not the shell, expand the pathnames +of files and subdirectories under the `Documentation/` directory. git-rm -f git-*.sh:: - Remove all git-*.sh scripts that are in the index. Because this example lets the shell expand the asterisk (i.e. you are listing the files explicitly), it does not remove `subdir/git-foo.sh`. diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index c7752575d8..d7cb4c0468 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output SYNOPSIS -------- [verse] -git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e] -git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [<committish>...] +git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e] [-w] +git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...] DESCRIPTION ----------- @@ -35,6 +35,12 @@ OPTIONS -e, \--email:: Show the email address of each author. +-w[<width>[,<indent1>[,<indent2>]]]:: + Linewrap the output by wrapping each line at `width`. The first + line of each entry is indented by `indent1` spaces, and the second + and subsequent lines are indented by `indent2` spaces. `width`, + `indent1`, and `indent2` default to 76, 6 and 9 respectively. + FILES ----- diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 41f9f63566..6ffd896fbc 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -70,7 +70,7 @@ OPTIONS -n, --summary-limit:: This option is only valid for the summary command. Limit the summary size (number of commits shown in total). - Giving 0 will disable the summary; a negative number means unlimted + Giving 0 will disable the summary; a negative number means unlimited (the default). This limit only applies to modified submodules. The size is always limited to 1 for added/deleted/typechanged submodules. diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 4b6fd90eaf..9712392f79 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -233,14 +233,14 @@ the tag object affects, for example, the ordering of tags in the gitweb interface. To set the date used in future tag objects, set the environment -variable GIT_AUTHOR_DATE to one or more of the date and time. The +variable GIT_COMMITTER_DATE to one or more of the date and time. The date and time can be specified in a number of ways; the most common is "YYYY-MM-DD HH:MM". An example follows. ------------ -$ GIT_AUTHOR_DATE="2006-10-02 10:31" git tag -s v1.0.1 +$ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1 ------------ diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt index 29edafceda..ed3ba83c53 100644 --- a/Documentation/gitk.txt +++ b/Documentation/gitk.txt @@ -74,6 +74,11 @@ gitk --max-count=100 --all \-- Makefile:: Show at most 100 changes made to the file 'Makefile'. Instead of only looking for changes in the current branch look in all branches. +Files +----- +Gitk creates the .gitk file in your $HOME directory to store preferences +such as display options, font, and colors. + See Also -------- 'qgit(1)':: diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt index 8eadc20494..b7d09c1ec6 100644 --- a/Documentation/howto/setup-git-server-over-http.txt +++ b/Documentation/howto/setup-git-server-over-http.txt @@ -1,5 +1,5 @@ From: Rutger Nijlunsing <rutger@nospam.com> -Subject: Setting up a git repository which can be pushed into and pulled from over HTTP. +Subject: Setting up a git repository which can be pushed into and pulled from over HTTP(S). Date: Thu, 10 Aug 2006 22:00:26 +0200 Since Apache is one of those packages people like to compile @@ -40,9 +40,13 @@ What's needed: - have permissions to chown a directory -- have git installed at the server _and_ client +- have git installed on the client, and -In effect, this probably means you're going to be root. +- either have git installed on the server or have a webdav client on + the client. + +In effect, this means you're going to be root, or that you're using a +preconfigured WebDAV server. Step 1: setup a bare GIT repository @@ -50,9 +54,9 @@ Step 1: setup a bare GIT repository At the time of writing, git-http-push cannot remotely create a GIT repository. So we have to do that at the server side with git. Another -option would be to generate an empty repository at the client and copy -it to the server with WebDAV. But then you're probably the first to -try that out :) +option is to generate an empty bare repository at the client and copy +it to the server with a WebDAV client (which is the only option if Git +is not installed on the server). Create the directory under the DocumentRoot of the directories served by Apache. As an example we take /usr/local/apache2, but try "grep @@ -169,7 +173,9 @@ On Debian: Most tests should pass. -A command line tool to test WebDAV is cadaver. +A command line tool to test WebDAV is cadaver. If you prefer GUIs, for +example, konqueror can open WebDAV URLs as "webdav://..." or +"webdavs://...". If you're into Windows, from XP onwards Internet Explorer supports WebDAV. For this, do Internet Explorer -> Open Location -> @@ -179,8 +185,9 @@ http://<servername>/my-new-repo.git [x] Open as webfolder -> login . Step 3: setup the client ------------------------ -Make sure that you have HTTP support, i.e. your git was built with curl. -The easiest way to check is to look for the executable 'git-http-push'. +Make sure that you have HTTP support, i.e. your git was built with +curl (version more recent than 7.10). The command 'git http-push' with +no argument should display a usage message. Then, add the following to your $HOME/.netrc (you can do without, but will be asked to input your password a _lot_ of times): @@ -197,10 +204,10 @@ instead of the server name. To check whether all is OK, do: - curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/ - -...this should give a directory listing in HTML of /var/www/my-new-repo.git . + curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD +...this should give something like 'ref: refs/heads/master', which is +the content of the file HEAD on the server. Now, add the remote in your existing repository which contains the project you want to export: @@ -225,6 +232,15 @@ want to export) to repository called 'upload', which we previously defined with git-config. +Using a proxy: +-------------- + +If you have to access the WebDAV server from behind an HTTP(S) proxy, +set the variable 'all_proxy' to 'http://proxy-host.com:port', or +'http://login-on-proxy:passwd-on-proxy@proxy-host.com:port'. See 'man +curl' for details. + + Troubleshooting: ---------------- @@ -248,9 +264,14 @@ Reading /usr/local/apache2/logs/error_log is often helpful. On Debian: Read /var/log/apache2/error.log instead. +If you access HTTPS locations, git may fail verifying the SSL +certificate (this is return code 60). Setting http.sslVerify=false can +help diagnosing the problem, but removes security checks. + Debian References: http://www.debian-administration.org/articles/285 Authors Johannes Schindelin <Johannes.Schindelin@gmx.de> Rutger Nijlunsing <git@wingding.demon.nl> + Matthieu Moy <Matthieu.Moy@imag.fr> diff --git a/builtin-apply.c b/builtin-apply.c index abe73a0f81..caa3f2aa0c 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2981,12 +2981,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) static int git_apply_config(const char *var, const char *value) { - if (!strcmp(var, "apply.whitespace")) { - if (!value) - return config_error_nonbool(var); - apply_default_whitespace = xstrdup(value); - return 0; - } + if (!strcmp(var, "apply.whitespace")) + return git_config_string(&apply_default_whitespace, var, value); return git_default_config(var, value); } @@ -3121,7 +3117,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) fd = open(arg, O_RDONLY); if (fd < 0) - usage(apply_usage); + die("can't open patch '%s': %s", arg, strerror(errno)); read_stdin = 0; set_default_whitespace_mode(whitespace_option); errs |= apply_patch(fd, arg, inaccurate_eof); diff --git a/builtin-clean.c b/builtin-clean.c index fefec3010c..6778a03ae4 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -95,7 +95,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix) for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; - int len, pos, matches; + int len, pos; + int matches = 0; struct cache_entry *ce; struct stat st; @@ -127,18 +128,18 @@ int cmd_clean(int argc, const char **argv, const char *prefix) if (pathspec) { memset(seen, 0, argc > 0 ? argc : 1); - matches = match_pathspec(pathspec, ent->name, ent->len, + matches = match_pathspec(pathspec, ent->name, len, baselen, seen); - } else { - matches = 0; } if (S_ISDIR(st.st_mode)) { strbuf_addstr(&directory, ent->name); qname = quote_path_relative(directory.buf, directory.len, &buf, prefix); - if (show_only && (remove_directories || matches)) { + if (show_only && (remove_directories || + (matches == MATCHED_EXACTLY))) { printf("Would remove %s\n", qname); - } else if (remove_directories || matches) { + } else if (remove_directories || + (matches == MATCHED_EXACTLY)) { if (!quiet) printf("Removing %s\n", qname); if (remove_dir_recursively(&directory, 0) != 0) { diff --git a/builtin-commit.c b/builtin-commit.c index 660a3458f7..bcb7aaaa93 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -98,7 +98,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('a', "all", &all, "commit all changed files"), OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"), OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), - OPT_BOOLEAN('o', "only", &only, ""), + OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"), @@ -745,10 +745,8 @@ static int parse_and_validate_options(int argc, const char *argv[], die("No paths with --include/--only does not make sense."); if (argc == 0 && only && amend) only_include_assumed = "Clever... amending the last one with dirty index."; - if (argc > 0 && !also && !only) { + if (argc > 0 && !also && !only) only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths..."; - also = 0; - } if (!cleanup_arg || !strcmp(cleanup_arg, "default")) cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE; else if (!strcmp(cleanup_arg, "verbatim")) diff --git a/builtin-config.c b/builtin-config.c index c34bc8b6a6..8ee01bdecd 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -3,7 +3,7 @@ #include "color.h" static const char git_config_set_usage[] = -"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]"; +"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]"; static char *key; static regex_t *key_regexp; @@ -16,7 +16,7 @@ static int seen; static char delim = '='; static char key_delim = ' '; static char term = '\n'; -static enum { T_RAW, T_INT, T_BOOL } type = T_RAW; +static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW; static int show_all_config(const char *key_, const char *value_) { @@ -53,6 +53,14 @@ static int show_config(const char* key_, const char* value_) sprintf(value, "%d", git_config_int(key_, value_?value_:"")); else if (type == T_BOOL) vptr = git_config_bool(key_, value_) ? "true" : "false"; + else if (type == T_BOOL_OR_INT) { + int is_bool, v; + v = git_config_bool_or_int(key_, value_, &is_bool); + if (is_bool) + vptr = v ? "true" : "false"; + else + sprintf(value, "%d", v); + } else vptr = value_?value_:""; seen++; @@ -157,6 +165,14 @@ char *normalize_value(const char *key, const char *value) else if (type == T_BOOL) sprintf(normalized, "%s", git_config_bool(key, value) ? "true" : "false"); + else if (type == T_BOOL_OR_INT) { + int is_bool, v; + v = git_config_bool_or_int(key, value, &is_bool); + if (!is_bool) + sprintf(normalized, "%d", v); + else + sprintf(normalized, "%s", v ? "true" : "false"); + } } return normalized; @@ -224,6 +240,10 @@ static int git_get_colorbool_config(const char *var, const char *value) get_diff_color_found = git_config_colorbool(var, value, stdout_is_tty); } + if (!strcmp(var, "color.ui")) { + git_use_color_default = git_config_colorbool(var, value, stdout_is_tty); + return 0; + } return 0; } @@ -251,7 +271,7 @@ static int get_colorbool(int argc, const char **argv) if (!strcmp(get_color_slot, "color.diff")) get_colorbool_found = get_diff_color_found; if (get_colorbool_found < 0) - get_colorbool_found = 0; + get_colorbool_found = git_use_color_default; } if (argc == 1) { @@ -273,6 +293,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) type = T_INT; else if (!strcmp(argv[1], "--bool")) type = T_BOOL; + else if (!strcmp(argv[1], "--bool-or-int")) + type = T_BOOL_OR_INT; else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { if (argc != 2) usage(git_config_set_usage); diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index ebb3f37cf1..7077d52477 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -201,6 +201,15 @@ static void shortlog(const char *name, unsigned char *sha1, continue; bol = strstr(commit->buffer, "\n\n"); + if (bol) { + unsigned char c; + do { + c = *++bol; + } while (isspace(c)); + if (!c) + bol = NULL; + } + if (!bol) { append_to_list(&subjects, xstrdup(sha1_to_hex( commit->object.sha1)), @@ -208,7 +217,6 @@ static void shortlog(const char *name, unsigned char *sha1, continue; } - bol += 2; eol = strchr(bol, '\n'); if (eol) { oneline = xmemdupz(bol, eol - bol); diff --git a/builtin-remote.c b/builtin-remote.c index 06d33e5c73..a3ee1ac393 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -90,18 +90,22 @@ static int add(int argc, const char **argv) strbuf_init(&buf, 0); strbuf_init(&buf2, 0); + strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name); + if (!valid_fetch_refspec(buf2.buf)) + die("'%s' is not a valid remote name", name); + strbuf_addf(&buf, "remote.%s.url", name); if (git_config_set(buf.buf, url)) return 1; + strbuf_reset(&buf); + strbuf_addf(&buf, "remote.%s.fetch", name); + if (track.nr == 0) path_list_append("*", &track); for (i = 0; i < track.nr; i++) { struct path_list_item *item = track.items + i; - strbuf_reset(&buf); - strbuf_addf(&buf, "remote.%s.fetch", name); - strbuf_reset(&buf2); if (mirror) strbuf_addf(&buf2, "refs/%s:refs/%s", diff --git a/builtin-shortlog.c b/builtin-shortlog.c index bd795b1db7..e6a2865019 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -9,7 +9,7 @@ #include "shortlog.h" static const char shortlog_usage[] = -"git-shortlog [-n] [-s] [-e] [<commit-id>... ]"; +"git-shortlog [-n] [-s] [-e] [-w] [<commit-id>... ]"; static int compare_by_number(const void *a1, const void *a2) { @@ -692,6 +692,7 @@ extern int git_parse_long(const char *, long *); extern int git_parse_ulong(const char *, unsigned long *); extern int git_config_int(const char *, const char *); extern unsigned long git_config_ulong(const char *, const char *); +extern int git_config_bool_or_int(const char *, const char *, int *); extern int git_config_bool(const char *, const char *); extern int git_config_string(const char **, const char *, const char *); extern int git_config_set(const char *, const char *); @@ -303,8 +303,9 @@ unsigned long git_config_ulong(const char *name, const char *value) return ret; } -int git_config_bool(const char *name, const char *value) +int git_config_bool_or_int(const char *name, const char *value, int *is_bool) { + *is_bool = 1; if (!value) return 1; if (!*value) @@ -313,7 +314,14 @@ int git_config_bool(const char *name, const char *value) return 1; if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) return 0; - return git_config_int(name, value) != 0; + *is_bool = 0; + return git_config_int(name, value); +} + +int git_config_bool(const char *name, const char *value) +{ + int discard; + return !!git_config_bool_or_int(name, value, &discard); } int git_config_string(const char **dest, const char *var, const char *value) @@ -80,7 +80,7 @@ static int match_one(const char *match, const char *name, int namelen) if (strncmp(match, name, matchlen)) return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0; - if (!name[matchlen]) + if (namelen == matchlen) return MATCHED_EXACTLY; if (match[matchlen-1] == '/' || name[matchlen] == '/') return MATCHED_RECURSIVELY; @@ -107,7 +107,7 @@ It does not apply to blobs recorded in its index." # patch did not touch, so recursive ends up canceling them, # saying that we reverted all those changes. - eval GITHEAD_$his_tree='"$SUBJECT"' + eval GITHEAD_$his_tree='"$FIRSTLINE"' export GITHEAD_$his_tree git-merge-recursive $orig_tree -- HEAD $his_tree || { git rerere @@ -117,10 +117,6 @@ It does not apply to blobs recorded in its index." unset GITHEAD_$his_tree } -reread_subject () { - git stripspace <"$1" | sed -e 1q -} - prec=4 dotest=".dotest" sign= utf8=t keep= skip= interactive= resolved= binary= rebasing= @@ -331,7 +327,20 @@ do echo "Patch is empty. Was it split wrong?" stop_here $this } - git stripspace < "$dotest/msg" > "$dotest/msg-clean" + if test -f "$dotest/rebasing" && + commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \ + -e q "$dotest/$msgnum") && + test "$(git cat-file -t "$commit")" = commit + then + git cat-file commit "$commit" | + sed -e '1,/^$/d' >"$dotest/msg-clean" + else + SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" + case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac + + (printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") | + git stripspace > "$dotest/msg-clean" + fi ;; esac @@ -347,9 +356,6 @@ do export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE - SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" - case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac - case "$resume" in '') if test '' != "$SIGNOFF" @@ -368,10 +374,8 @@ do ADD_SIGNOFF= fi { - printf '%s\n' "$SUBJECT" if test -s "$dotest/msg-clean" then - echo cat "$dotest/msg-clean" fi if test '' != "$ADD_SIGNOFF" @@ -408,7 +412,6 @@ do [aA]*) action=yes interactive= ;; [nN]*) action=skip ;; [eE]*) git_editor "$dotest/final-commit" - SUBJECT=$(reread_subject "$dotest/final-commit") action=again ;; [vV]*) action=again LESS=-S ${PAGER:-less} "$dotest/patch" ;; @@ -418,6 +421,7 @@ do else action=yes fi + FIRSTLINE=$(head -1 "$dotest/final-commit") if test $action = skip then @@ -431,7 +435,7 @@ do stop_here $this fi - printf 'Applying %s\n' "$SUBJECT" + printf 'Applying %s\n' "$FIRSTLINE" case "$resolved" in '') @@ -489,7 +493,7 @@ do tree=$(git write-tree) && parent=$(git rev-parse --verify HEAD) && commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit") && - git update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent || + git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || stop_here $this if test -x "$GIT_DIR"/hooks/post-applypatch diff --git a/git-bisect.sh b/git-bisect.sh index 48fb92d612..d8d9bfde4c 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -1,7 +1,9 @@ #!/bin/sh -USAGE='[start|bad|good|skip|next|reset|visualize|replay|log|run]' -LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...] +USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]' +LONG_USAGE='git bisect help + print this long help message. +git bisect start [<bad> [<good>...]] [--] [<pathspec>...] reset bisect state and start bisection. git bisect bad [<rev>] mark <rev> a known-bad revision. @@ -20,7 +22,9 @@ git bisect replay <logfile> git bisect log show bisect log. git bisect run <cmd>... - use <cmd>... to automatically bisect.' + use <cmd>... to automatically bisect. + +Please use "git help bisect" to get the full man page.' OPTIONS_SPEC= . git-sh-setup @@ -62,9 +66,10 @@ bisect_start() { # Verify HEAD. If we were bisecting before this, reset to the # top-of-line master first! # - head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) || + head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) || head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) || die "Bad HEAD - I need a HEAD" + start_head='' case "$head" in refs/heads/bisect) if [ -s "$GIT_DIR/BISECT_START" ]; then @@ -78,7 +83,7 @@ bisect_start() { # This error message should only be triggered by cogito usage, # and cogito users should understand it relates to cg-seek. [ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree" - echo "${head#refs/heads/}" >"$GIT_DIR/BISECT_START" + start_head="${head#refs/heads/}" ;; *) die "Bad HEAD - strange symbolic ref" @@ -99,6 +104,7 @@ bisect_start() { done orig_args=$(sq "$@") bad_seen=0 + eval='' while [ $# -gt 0 ]; do arg="$1" case "$arg" in @@ -116,13 +122,15 @@ bisect_start() { 0) state='bad' ; bad_seen=1 ;; *) state='good' ;; esac - bisect_write "$state" "$rev" 'nolog' + eval="$eval bisect_write '$state' '$rev' 'nolog'; " shift ;; esac done sq "$@" >"$GIT_DIR/BISECT_NAMES" + test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START" + eval "$eval" echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" bisect_auto_next } @@ -151,20 +159,18 @@ bisect_state() { rev=$(git rev-parse --verify HEAD) || die "Bad rev input: HEAD" bisect_write "$state" "$rev" ;; - 2,bad) - rev=$(git rev-parse --verify "$2^{commit}") || - die "Bad rev input: $2" - bisect_write "$state" "$rev" ;; - *,good|*,skip) + 2,bad|*,good|*,skip) shift - revs=$(git rev-parse --revs-only --no-flags "$@") && - test '' != "$revs" || die "Bad rev input: $@" - for rev in $revs + eval='' + for rev in "$@" do - rev=$(git rev-parse --verify "$rev^{commit}") || - die "Bad rev commit: $rev^{commit}" - bisect_write "$state" "$rev" - done ;; + sha=$(git rev-parse --verify "$rev^{commit}") || + die "Bad rev input: $rev" + eval="$eval bisect_write '$state' '$sha'; " + done + eval "$eval" ;; + *,bad) + die "'git bisect bad' can take only one argument." ;; *) usage ;; esac @@ -465,6 +471,8 @@ case "$#" in cmd="$1" shift case "$cmd" in + help) + git bisect -h ;; start) bisect_start "$@" ;; bad|good|skip) diff --git a/git-submodule.sh b/git-submodule.sh index 56ec3536e0..a745e42bf7 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -327,7 +327,8 @@ set_name_rev () { cd "$1" && { git describe "$2" 2>/dev/null || git describe --tags "$2" 2>/dev/null || - git describe --contains --tags "$2" + git describe --contains "$2" 2>/dev/null || + git describe --all --always "$2" } ) ) test -z "$revname" || revname=" ($revname)" diff --git a/git-svn.perl b/git-svn.perl index 81afb5cfcd..b864b54a44 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1120,7 +1120,7 @@ sub cmt_metadata { sub working_head_info { my ($head, $refs) = @_; - my @args = ('log', '--no-color', '--first-parent'); + my @args = ('log', '--no-color', '--first-parent', '--pretty=medium'); my ($fh, $ctx) = command_output_pipe(@args, $head); my $hash; my %max; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e69d7fd07b..a48bebb1bc 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5176,14 +5176,26 @@ sub git_history { my $refs = git_get_references(); my $limit = sprintf("--max-count=%i", (100 * ($page+1))); + my @commitlist = parse_commits($hash_base, 101, (100 * $page), + $file_name, "--full-history"); + if (!@commitlist) { + die_error('404 Not Found', "No such file or directory on given branch"); + } + if (!defined $hash && defined $file_name) { - $hash = git_get_hash_by_path($hash_base, $file_name); + # some commits could have deleted file in question, + # and not have it in tree, but one of them has to have it + for (my $i = 0; $i <= @commitlist; $i++) { + $hash = git_get_hash_by_path($commitlist[$i]{'id'}, $file_name); + last if defined $hash; + } } if (defined $hash) { $ftype = git_get_type($hash); } - - my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history"); + if (!defined $ftype) { + die_error(undef, "Unknown type of object"); + } my $paging_nav = ''; if ($page > 0) { @@ -315,7 +315,7 @@ static int handle_config(const char *key, const char *value) } if (!prefixcmp(key, "url.")) { struct rewrite *rewrite; - name = key + 5; + name = key + 4; subkey = strrchr(name, '.'); if (!subkey) return 0; @@ -409,7 +409,7 @@ static void read_config(void) alias_all_urls(); } -static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch) +static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) { int i; int st; @@ -519,17 +519,32 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp return rs; invalid: + if (verify) { + free(rs); + return NULL; + } die("Invalid refspec '%s'", refspec[i]); } +int valid_fetch_refspec(const char *fetch_refspec_str) +{ + const char *fetch_refspec[] = { fetch_refspec_str }; + struct refspec *refspec; + + refspec = parse_refspec_internal(1, fetch_refspec, 1, 1); + if (refspec) + free(refspec); + return !!refspec; +} + struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) { - return parse_refspec_internal(nr_refspec, refspec, 1); + return parse_refspec_internal(nr_refspec, refspec, 1, 0); } struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) { - return parse_refspec_internal(nr_refspec, refspec, 0); + return parse_refspec_internal(nr_refspec, refspec, 0, 0); } static int valid_remote_nick(const char *name) @@ -67,6 +67,7 @@ void free_refs(struct ref *ref); */ void ref_remove_duplicates(struct ref *ref_map); +int valid_fetch_refspec(const char *refspec); struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); diff --git a/revision.c b/revision.c index 196fedc9d1..ffbed3fbf2 100644 --- a/revision.c +++ b/revision.c @@ -1083,6 +1083,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch continue; } if (!strcmp(arg, "--topo-order")) { + revs->lifo = 1; revs->topo_order = 1; continue; } diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index b36a9012ec..a675cbb51b 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -595,6 +595,64 @@ test_expect_success 'set --int' ' rm .git/config +cat >expect <<\EOF +[bool] + true1 = true + true2 = true + false1 = false + false2 = false +[int] + int1 = 0 + int2 = 1 + int3 = -1 +EOF + +test_expect_success 'get --bool-or-int' ' + ( + echo "[bool]" + echo true1 + echo true2 = true + echo false = false + echo "[int]" + echo int1 = 0 + echo int2 = 1 + echo int3 = -1 + ) >>.git/config && + test $(git config --bool-or-int bool.true1) = true && + test $(git config --bool-or-int bool.true2) = true && + test $(git config --bool-or-int bool.false) = false && + test $(git config --bool-or-int int.int1) = 0 && + test $(git config --bool-or-int int.int2) = 1 && + test $(git config --bool-or-int int.int3) = -1 + +' + +rm .git/config +cat >expect <<\EOF +[bool] + true1 = true + false1 = false + true2 = true + false2 = false +[int] + int1 = 0 + int2 = 1 + int3 = -1 +EOF + +test_expect_success 'set --bool-or-int' ' + git config --bool-or-int bool.true1 true && + git config --bool-or-int bool.false1 false && + git config --bool-or-int bool.true2 yes && + git config --bool-or-int bool.false2 no && + git config --bool-or-int int.int1 0 && + git config --bool-or-int int.int2 1 && + git config --bool-or-int int.int3 -1 && + test_cmp expect .git/config +' + +rm .git/config + git config quote.leading " test" git config quote.ending "test " git config quote.semicolon "test;test" diff --git a/t/t3408-rebase-multi-line.sh b/t/t3408-rebase-multi-line.sh new file mode 100755 index 0000000000..e12cd578e8 --- /dev/null +++ b/t/t3408-rebase-multi-line.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +test_description='rebasing a commit with multi-line first paragraph.' + +. ./test-lib.sh + +test_expect_success setup ' + + >file && + git add file && + test_tick && + git commit -m initial && + + echo hello >file && + test_tick && + git commit -a -m "A sample commit log message that has a long +summary that spills over multiple lines. + +But otherwise with a sane description." + + git branch side && + + git reset --hard HEAD^ && + >elif && + git add elif && + test_tick && + git commit -m second + +' + +test_expect_success rebase ' + + git checkout side && + git rebase master && + git cat-file commit HEAD | sed -e "1,/^$/d" >actual && + git cat-file commit side@{1} | sed -e "1,/^$/d" >expect && + test_cmp expect actual + +' + +test_done diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0a7fea865d..af2d077792 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -253,4 +253,10 @@ test_expect_success '"remote show" does not show symbolic refs' ' ' +test_expect_success 'reject adding remote with an invalid name' ' + + ! git remote add some:url desired-name + +' + test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 793ffc6600..6d7e738548 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -103,9 +103,9 @@ test_expect_success 'fetch with wildcard' ' test_expect_success 'fetch with insteadOf' ' mk_empty && ( - TRASH=$(pwd) && + TRASH=$(pwd)/ && cd testrepo && - git config url./$TRASH/.insteadOf trash/ + git config url.$TRASH.insteadOf trash/ git config remote.up.url trash/. && git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" && git fetch up && @@ -145,8 +145,8 @@ test_expect_success 'push with wildcard' ' test_expect_success 'push with insteadOf' ' mk_empty && - TRASH=$(pwd) && - git config url./$TRASH/.insteadOf trash/ && + TRASH=$(pwd)/ && + git config url.$TRASH.insteadOf trash/ && git push trash/testrepo refs/heads/master:refs/remotes/origin/master && ( cd testrepo && diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index f471c1526f..5e3e5445c7 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -71,6 +71,24 @@ test_expect_success 'bisect start with one bad and good' ' git bisect next ' +test_expect_success 'bisect fails if given any junk instead of revs' ' + git bisect reset && + test_must_fail git bisect start foo $HASH1 -- && + test_must_fail git bisect start $HASH4 $HASH1 bar -- && + test -z "$(git for-each-ref "refs/bisect/*")" && + test_must_fail ls .git/BISECT_* && + git bisect start && + test_must_fail git bisect good foo $HASH1 && + test_must_fail git bisect good $HASH1 bar && + test_must_fail git bisect bad frotz && + test_must_fail git bisect bad $HASH3 $HASH4 && + test_must_fail git bisect skip bar $HASH3 && + test_must_fail git bisect skip $HASH1 foo && + test -z "$(git for-each-ref "refs/bisect/*")" && + git bisect good $HASH1 && + git bisect bad $HASH4 +' + test_expect_success 'bisect reset: back in the master branch' ' git bisect reset && echo "* master" > branch.expect && diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index afccfc9973..a50492f7c0 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -75,8 +75,8 @@ test_expect_success 'git-clean src/ src/' ' test_expect_success 'git-clean with prefix' ' - mkdir -p build docs && - touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && + mkdir -p build docs src/test && + touch a.out src/part3.c docs/manual.txt obj.o build/lib.so src/test/1.c && (cd src/ && git-clean) && test -f Makefile && test -f README && @@ -84,6 +84,7 @@ test_expect_success 'git-clean with prefix' ' test -f src/part2.c && test -f a.out && test ! -f src/part3.c && + test -f src/test/1.c && test -f docs/manual.txt && test -f obj.o && test -f build/lib.so diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 0f3c42ab35..b9a22190e8 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -30,7 +30,7 @@ commit_file () { } test_create_repo sm1 && -add_file . foo +add_file . foo >/dev/null head1=$(add_file sm1 foo1 foo2) diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 796cd7dba0..061a2596d3 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -483,6 +483,22 @@ test_expect_success \ 'gitweb_run "p=.git;a=history;f=file"' test_debug 'cat gitweb.log' +test_expect_success \ + 'logs: history (implicit HEAD, non-existent file)' \ + 'gitweb_run "p=.git;a=history;f=non-existent"' +test_debug 'cat gitweb.log' + +test_expect_success \ + 'logs: history (implicit HEAD, deleted file)' \ + 'git checkout master && + echo "to be deleted" > deleted_file && + git add deleted_file && + git commit -m "Add file to be deleted" && + git rm deleted_file && + git commit -m "Delete file" && + gitweb_run "p=.git;a=history;f=deleted_file"' +test_debug 'cat gitweb.log' + # ---------------------------------------------------------------------- # feed generation |