diff options
136 files changed, 2652 insertions, 743 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index 62269e39c4..ded0e40b97 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -44,6 +44,7 @@ MANPAGE_XSL = callouts.xsl INSTALL?=install RM ?= rm -f DOC_REF = origin/man +HTML_REF = origin/html infodir?=$(prefix)/share/info MAKEINFO=makeinfo @@ -222,4 +223,7 @@ install-webdoc : html quick-install: sh ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) +quick-install-html: + sh ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) + .PHONY: .FORCE-GIT-VERSION-FILE diff --git a/Documentation/RelNotes-1.6.0.2.txt b/Documentation/RelNotes-1.6.0.2.txt index 6c5446bc07..7a9646fc4f 100644 --- a/Documentation/RelNotes-1.6.0.2.txt +++ b/Documentation/RelNotes-1.6.0.2.txt @@ -17,6 +17,10 @@ Fixes since v1.6.0.1 * Many commands did not use the correct working tree location when used with GIT_WORK_TREE environment settings. +* Some systems needs to use compatibility fnmach and regex libraries + independent from each other; the compat/ area has been reorganized to + allow this. + * "git apply --unidiff-zero" incorrectly applied a -U0 patch that inserts a new line before the second line. @@ -24,9 +28,15 @@ Fixes since v1.6.0.1 * "git blame -c" did not exactly work like "git annotate" when range boundaries are involved. +* "git checkout file" when file is still unmerged checked out contents from + a random high order stage, which was confusing. + * "git clone $there $here/" with extra trailing slashes after explicit local directory name $here did not work as expected. +* "git diff" on tracked contents with CRLF line endings did not drive "less" + intelligently when showing added or removed lines. + * "git diff --dirstat -M" did not add changes in subdirectories up correctly for renamed paths. @@ -42,18 +52,29 @@ Fixes since v1.6.0.1 * "git gui" translation updates and i18n fixes. +* "git index-pack" is more careful against disk corruption while completing + a thin pack. + * "git log -i --grep=pattern" did not ignore case; neither "git log -E --grep=pattern" triggered extended regexp. * "git log --pretty="%ad" --date=short" did not use short format when showing the timestamp. +* "git log --author=author" match incorrectly matched with the + timestamp part of "author " line in commit objects. + +* "git log -F --author=author" did not work at all. + * Build procedure for "git shell" that used stub versions of some functions and globals was not understood by linkers on some platforms. * "git stash" was fooled by a stat-dirty but otherwise unmodified paths and refused to work until the user refreshed the index. +* "git svn" was broken on Perl before 5.8 with recent fixes to reduce + use of temporary files. + * "git verify-pack -v" did not work correctly when given more than one packfile. @@ -61,7 +82,6 @@ Also contains many documentation updates. -- exec >/var/tmp/1 -O=v1.6.0.1-61-g1eff26c +O=v1.6.0.1-78-g3632cfc echo O=$(git describe maint) git shortlog --no-merges $O..maint - diff --git a/Documentation/RelNotes-1.6.0.3.txt b/Documentation/RelNotes-1.6.0.3.txt new file mode 100644 index 0000000000..46e13a450a --- /dev/null +++ b/Documentation/RelNotes-1.6.0.3.txt @@ -0,0 +1,45 @@ +GIT v1.6.0.3 Release Notes +========================== + +Fixes since v1.6.0.2 +-------------------- + +* "git archive --format=zip" did not honor core.autocrlf while + --format=tar did. + +* Continuing "git rebase -i" was very confused when the user left modified + files in the working tree while resolving conflicts. + +* Continuing "git rebase -i" was also very confused when the user left + some staged changes in the index after "edit". + +* Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code" + with the output redirected to /dev/null. + +* "git stash apply sash@{1}" was fixed to error out. Prior versions + would have applied stash@{0} incorrectly. + +* "git for-each-ref --format=%(subject)" fixed for commits with no + no newline in the message body. + +* "git remote" fixed to protect printf from user input. + +* "git checkout -q" once again suppresses the locally modified file list. + +* Cross-directory renames are no longer used when creating packs. This + allows more graceful behavior on filesystems like sshfs. + +* Stale temporary files under $GIT_DIR/objects/pack are now cleaned up + automatically by "git prune". + +* "Git.pm" tests relied on unnecessarily more recent version of Perl. + +* "gitweb" triggered undef warning on commits without log messages. + +Many other documentation updates. + +-- +exec >/var/tmp/1 +O=v1.6.0.2-41-g7fe4a72 +echo O=$(git describe maint) +git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt index 609d4ca562..421e569ea0 100644 --- a/Documentation/RelNotes-1.6.1.txt +++ b/Documentation/RelNotes-1.6.1.txt @@ -32,8 +32,19 @@ on. * Most of the test scripts (but not the ones that try to run servers) can be run in parallel. +* Bash completion of refnames in a repository with massive number of + refs has been optimized. + (usability, bells and whistles) +* When you mistype a command name, git helpfully suggests what it guesses + you might have meant to say. help.autocorrect configuration can be set + to a non-zero value to accept the suggestion when git can uniquely + guess. + +* "git bisect" is careful about a user mistake and suggests testing of + merge base first when good is not a strict ancestor of bad. + * "git checkout --track origin/hack" used to be a syntax error. It now DWIMs to create a corresponding local branch "hack", i.e. acts as if you said "git checkout --track -b hack origin/hack". @@ -54,6 +65,12 @@ on. * "git diff" learned to put more sensible hunk headers for Python and HTML contents. +* "git diff" learned to vary the a/ vs b/ prefix depending on what are + being compared, controlled by diff.mnemonicprefix configuration. + +* "git for-each-ref" learned "refname:short" token that gives an + unambiguously abbreviated refname. + * "git help" learned to use GIT_MAN_VIEWER environment variable before using "man" program. @@ -68,6 +85,9 @@ on. * "git log" learned --simplify-merges, a milder variant of --full-history; "gitk --simplify-merges" is easier to view than with --full-history. +* "git log --pretty=format:" learned "%d" format element that inserts + names of tags that point at the commit. + * "git merge --squash" and "git merge --no-ff" into an unborn branch are noticed as user errors. @@ -115,6 +135,6 @@ release, unless otherwise noted. -- exec >/var/tmp/1 -O=v1.6.0.1-266-gaf9552f +O=v1.6.0.2-295-g34a5d35 echo O=$(git describe master) git shortlog --no-merges $O..master ^maint diff --git a/Documentation/config.txt b/Documentation/config.txt index 922ac7b44d..bea867df60 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -585,6 +585,22 @@ diff.external:: you want to use an external diff program only on a subset of your files, you might want to use linkgit:gitattributes[5] instead. +diff.mnemonicprefix:: + If set, 'git-diff' uses a prefix pair that is different from the + standard "a/" and "b/" depending on what is being compared. When + this configuration is in effect, reverse diff output also swaps + the order of the prefixes: +'git-diff';; + compares the (i)ndex and the (w)ork tree; +'git-diff HEAD';; + compares a (c)ommit and the (w)ork tree; +'git diff --cached';; + compares a (c)ommit and the (i)ndex; +'git-diff HEAD:file1 file2';; + compares an (o)bject and a (w)ork tree entity; +'git diff --no-index a b';; + compares two non-git things (1) and (2). + diff.renameLimit:: The number of files to consider when performing the copy/rename detection; equivalent to the 'git-diff' option '-l'. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 6e268326da..7788d4fa4a 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -65,6 +65,9 @@ endif::git-format-patch[] can be set with "--dirstat=limit". Changes in a child directory is not counted for the parent directory, unless "--cumulative" is used. +--dirstat-by-file[=limit]:: + Same as --dirstat, but counts changed files instead of lines. + --summary:: Output a condensed summary of extended header information such as creations, renames and mode changes. diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index feb51f124a..e726510ab1 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -14,7 +14,8 @@ SYNOPSIS [--allow-binary-replacement | --binary] [--reject] [-z] [-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached] [--whitespace=<nowarn|warn|fix|error|error-all>] - [--exclude=PATH] [--directory=<root>] [--verbose] [<patch>...] + [--exclude=PATH] [--include=PATH] [--directory=<root>] + [--verbose] [<patch>...] DESCRIPTION ----------- @@ -137,6 +138,17 @@ discouraged. be useful when importing patchsets, where you want to exclude certain files or directories. +--include=<path-pattern>:: + Apply changes to files matching the given path pattern. This can + be useful when importing patchsets, where you want to include certain + files or directories. ++ +When --exclude and --include patterns are used, they are examined in the +order they appear on the command line, and the first match determines if a +patch to each path is used. A patch to a path that does not match any +include/exclude pattern is used by default if there is no include pattern +on the command line, and ignored if there is any include pattern. + --whitespace=<action>:: When applying a patch, detect a new or modified line that has whitespace errors. What are considered whitespace errors is diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index ebd7c5fbb3..5061d3e4e7 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -74,6 +74,7 @@ For all objects, the following names can be used: refname:: The name of the ref (the part after $GIT_DIR/). + For a non-ambiguous short name of the ref append `:short`. objecttype:: The type of the object (`blob`, `tree`, `commit`, `tag`). diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index 6f4b9b017f..309deac23b 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -160,7 +160,10 @@ Here are the "carry forward" rules: 0 nothing nothing nothing (does not happen) 1 nothing nothing exists use M 2 nothing exists nothing remove path from index - 3 nothing exists exists use M + 3 nothing exists exists, use M if "initial checkout" + H == M keep index otherwise + exists fail + H != M clean I==H I==M ------------------ @@ -207,6 +210,12 @@ you picked it up via e-mail in a patch form), `git diff-index merge, but it would not show in `git diff-index --cached $M` output after two-tree merge. +Case #3 is slightly tricky and needs explanation. The result from this +rule logically should be to remove the path if the user staged the removal +of the path and then swiching to a new branch. That however will prevent +the initial checkout from happening, so the rule is modified to use M (new +tree) only when the contents of the index is empty. Otherwise the removal +of the path is kept as long as $H and $M are the same. 3-Way Merge ~~~~~~~~~~~ diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 59c1b021a6..32f0f122e9 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -92,7 +92,7 @@ branch to another, to pretend that you forked the topic branch from the latter branch, using `rebase --onto`. First let's assume your 'topic' is based on branch 'next'. -For example feature developed in 'topic' depends on some +For example, a feature developed in 'topic' depends on some functionality which is found in 'next'. ------------ @@ -103,9 +103,9 @@ functionality which is found in 'next'. o---o---o topic ------------ -We would want to make 'topic' forked from branch 'master', -for example because the functionality 'topic' branch depend on -got merged into more stable 'master' branch, like this: +We want to make 'topic' forked from branch 'master'; for example, +because the functionality on which 'topic' depends was merged into the +more stable 'master' branch. We want our tree to look like this: ------------ o---o---o---o---o master diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt index 38ac60947b..bbe1485a97 100644 --- a/Documentation/git-repack.txt +++ b/Documentation/git-repack.txt @@ -60,7 +60,7 @@ OPTIONS linkgit:git-pack-objects[1]. -f:: - Pass the `--no-reuse-delta` option to 'git-pack-objects'. See + Pass the `--no-reuse-object` option to `git-pack-objects`, see linkgit:git-pack-objects[1]. -q:: diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt index 36afad8d4e..278cf73527 100644 --- a/Documentation/git-web--browse.txt +++ b/Documentation/git-web--browse.txt @@ -26,6 +26,7 @@ The following browsers (or commands) are currently supported: * lynx * dillo * open (this is the default under Mac OS X GUI) +* start (this is the default under MinGW) Custom commands may also be specified. @@ -77,7 +78,7 @@ the URLs passed as arguments. Note about konqueror -------------------- -When 'konqueror' is specified by the a command line option or a +When 'konqueror' is specified by a command line option or a configuration variable, we launch 'kfmclient' to try to open the HTML man page on an already opened konqueror in a new tab if possible. diff --git a/Documentation/git.txt b/Documentation/git.txt index e178fb5813..df420aeb33 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,10 +43,11 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.1/git.html[documentation for release 1.6.1] +* link:v1.6.0.2/git.html[documentation for release 1.6.0.2] * release notes for - link:RelNotes-1.6.1.txt[1.6.1], + link:RelNotes-1.6.0.2.txt[1.6.0.2], + link:RelNotes-1.6.0.1.txt[1.6.0.1], link:RelNotes-1.6.0.txt[1.6.0]. * link:v1.5.6.5/git.html[documentation for release 1.5.6.5] diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 75124d2612..e848c94397 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -270,27 +270,27 @@ See linkgit:git[1] for details. Defining a custom hunk-header ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each group of changes (called "hunk") in the textual diff output +Each group of changes (called a "hunk") in the textual diff output is prefixed with a line of the form: @@ -k,l +n,m @@ TEXT -The text is called 'hunk header', and by default a line that -begins with an alphabet, an underscore or a dollar sign is used, -which matches what GNU 'diff -p' output uses. This default -selection however is not suited for some contents, and you can -use customized pattern to make a selection. +This is called a 'hunk header'. The "TEXT" portion is by default a line +that begins with an alphabet, an underscore or a dollar sign; this +matches what GNU 'diff -p' output uses. This default selection however +is not suited for some contents, and you can use a customized pattern +to make a selection. -First in .gitattributes, you would assign the `diff` attribute +First, in .gitattributes, you would assign the `diff` attribute for paths. ------------------------ *.tex diff=tex ------------------------ -Then, you would define "diff.tex.funcname" configuration to +Then, you would define a "diff.tex.funcname" configuration to specify a regular expression that matches a line that you would -want to appear as the hunk header, like this: +want to appear as the hunk header "TEXT", like this: ------------------------ [diff "tex"] @@ -313,7 +313,7 @@ patterns are available: - `html` suitable for HTML/XHTML documents. -- `java` suitable for source code in the Java lanugage. +- `java` suitable for source code in the Java language. - `pascal` suitable for source code in the Pascal/Delphi language. diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt index 2bdbc3d4f6..e8041bc08f 100644 --- a/Documentation/gitdiffcore.txt +++ b/Documentation/gitdiffcore.txt @@ -36,11 +36,25 @@ files: - 'git-diff-tree' compares contents of two "tree" objects; -In all of these cases, the commands themselves compare -corresponding paths in the two sets of files. The result of -comparison is passed from these commands to what is internally -called "diffcore", in a format similar to what is output when -the -p option is not used. E.g. +In all of these cases, the commands themselves first optionally limit +the two sets of files by any pathspecs given on their command-lines, +and compare corresponding paths in the two resulting sets of files. + +The pathspecs are used to limit the world diff operates in. They remove +the filepairs outside the specified sets of pathnames. E.g. If the +input set of filepairs included: + +------------------------------------------------ +:100644 100644 bcd1234... 0123456... M junkfile +------------------------------------------------ + +but the command invocation was `git diff-files myfile`, then the +junkfile entry would be removed from the list because only "myfile" +is under consideration. + +The result of comparison is passed from these commands to what is +internally called "diffcore", in a format similar to what is output +when the -p option is not used. E.g. ------------------------------------------------ in-place edit :100644 100644 bcd1234... 0123456... M file0 @@ -52,9 +66,8 @@ unmerged :000000 000000 0000000... 0000000... U file6 The diffcore mechanism is fed a list of such comparison results (each of which is called "filepair", although at this point each of them talks about a single file), and transforms such a list -into another list. There are currently 6 such transformations: +into another list. There are currently 5 such transformations: -- diffcore-pathspec - diffcore-break - diffcore-rename - diffcore-merge-broken @@ -62,38 +75,14 @@ into another list. There are currently 6 such transformations: - diffcore-order These are applied in sequence. The set of filepairs 'git-diff-{asterisk}' -commands find are used as the input to diffcore-pathspec, and -the output from diffcore-pathspec is used as the input to the +commands find are used as the input to diffcore-break, and +the output from diffcore-break is used as the input to the next transformation. The final result is then passed to the output routine and generates either diff-raw format (see Output format sections of the manual for 'git-diff-{asterisk}' commands) or diff-patch format. -diffcore-pathspec: For Ignoring Files Outside Our Consideration ---------------------------------------------------------------- - -The first transformation in the chain is diffcore-pathspec, and -is controlled by giving the pathname parameters to the -'git-diff-{asterisk}' commands on the command line. The pathspec is used -to limit the world diff operates in. It removes the filepairs -outside the specified set of pathnames. E.g. If the input set -of filepairs included: - ------------------------------------------------- -:100644 100644 bcd1234... 0123456... M junkfile ------------------------------------------------- - -but the command invocation was `git diff-files myfile`, then the -junkfile entry would be removed from the list because only "myfile" -is under consideration. - -Implementation note. For performance reasons, 'git-diff-tree' -uses the pathname parameters on the command line to cull set of -filepairs it feeds the diffcore mechanism itself, and does not -use diffcore-pathspec, but the end result is the same. - - diffcore-break: For Splitting Up "Complete Rewrites" ---------------------------------------------------- diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 00277e0613..c735788b0f 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -1,5 +1,5 @@ merge.stat:: - Whether to print the diffstat between ORIG_HEAD and merge result + Whether to print the diffstat between ORIG_HEAD and the merge result at the end of the merge. True by default. merge.log:: diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 388d4925e6..f18d33e00b 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -116,6 +116,7 @@ The placeholders are: - '%cr': committer date, relative - '%ct': committer date, UNIX timestamp - '%ci': committer date, ISO 8601 format +- '%d': ref names, like the --decorate option of linkgit:git-log[1] - '%e': encoding - '%s': subject - '%b': body diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 156dc13733..6c7465c758 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.0.GIT +DEF_VER=v1.6.0.2.GIT LF=' ' @@ -6,7 +6,7 @@ will install the git programs in your own ~/bin/ directory. If you want to do a global install, you can do $ make prefix=/usr all doc info ;# as yourself - # make prefix=/usr install install-doc install-info ;# as root + # make prefix=/usr install install-doc install-html install-info ;# as root (or prefix=/usr/local, of course). Just like any program suite that uses $prefix, the built results have some paths encoded, @@ -19,7 +19,7 @@ set up install paths (via config.mak.autogen), so you can write instead $ make configure ;# as yourself $ ./configure --prefix=/usr ;# as yourself $ make all doc ;# as yourself - # make install install-doc ;# as root + # make install install-doc install-html;# as root Issues of note: @@ -89,13 +89,22 @@ Issues of note: inclined to install the tools, the default build target ("make all") does _not_ build them. + "make doc" builds documentation in man and html formats; there are + also "make man", "make html" and "make info". Note that "make html" + requires asciidoc, but not xmlto. "make man" (and thus make doc) + requires both. + + "make install-doc" installs documentation in man format only; there + are also "make install-man", "make install-html" and "make + install-info". + Building and installing the info file additionally requires makeinfo and docbook2X. Version 0.8.3 is known to work. The documentation is written for AsciiDoc 7, but "make ASCIIDOC8=YesPlease doc" will let you format with AsciiDoc 8. - Alternatively, pre-formatted documentation are available in + Alternatively, pre-formatted documentation is available in "html" and "man" branches of the git repository itself. For example, you could: @@ -117,6 +126,12 @@ Issues of note: http://www.kernel.org/pub/software/scm/git/docs/ + There are also "make quick-install-doc" and "make quick-install-html" + which install preformatted man pages and html documentation. + This does not require asciidoc/xmlto, but it only works from within + a cloned checkout of git.git with these two extra branches, and will + not work for the maintainer for obvious chicken-and-egg reasons. + It has been reported that docbook-xsl version 1.72 and 1.73 are buggy; 1.72 misformats manual pages for callouts, and 1.73 needs the patch in contrib/patches/docbook-xsl-manpages-charmap.patch @@ -636,6 +636,8 @@ ifeq ($(uname_S),Darwin) endif NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@ -686,6 +688,8 @@ ifeq ($(uname_S),FreeBSD) BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease THREADED_DELTA_SEARCH = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease @@ -712,6 +716,8 @@ ifeq ($(uname_S),AIX) INTERNAL_QSORT = UnfortunatelyYes NEEDS_LIBICONV=YesPlease BASIC_CFLAGS += -D_LARGE_FILES + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),GNU) # GNU/Hurd @@ -763,10 +769,10 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease - COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe gitexecdir = ../libexec/git-core @@ -1265,6 +1271,12 @@ $(XDIFF_LIB): $(XDIFF_OBJS) doc: $(MAKE) -C Documentation all +man: + $(MAKE) -C Documentation man + +html: + $(MAKE) -C Documentation html + info: $(MAKE) -C Documentation info @@ -1368,7 +1380,7 @@ install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK @@ -1401,6 +1413,9 @@ install-info: quick-install-doc: $(MAKE) -C Documentation quick-install +quick-install-html: + $(MAKE) -C Documentation quick-install-html + ### Maintainer's dist rules diff --git a/builtin-apply.c b/builtin-apply.c index 20bef1f21d..2ab4aba5a0 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2994,29 +2994,45 @@ static int write_out_results(struct patch *list, int skipped_patch) static struct lock_file lock_file; -static struct excludes { - struct excludes *next; - const char *path; -} *excludes; +static struct string_list limit_by_name; +static int has_include; +static void add_name_limit(const char *name, int exclude) +{ + struct string_list_item *it; + + it = string_list_append(name, &limit_by_name); + it->util = exclude ? NULL : (void *) 1; +} static int use_patch(struct patch *p) { const char *pathname = p->new_name ? p->new_name : p->old_name; - struct excludes *x = excludes; - while (x) { - if (fnmatch(x->path, pathname, 0) == 0) - return 0; - x = x->next; - } + int i; + + /* Paths outside are not touched regardless of "--include" */ if (0 < prefix_length) { int pathlen = strlen(pathname); if (pathlen <= prefix_length || memcmp(prefix, pathname, prefix_length)) return 0; } - return 1; + + /* See if it matches any of exclude/include rule */ + for (i = 0; i < limit_by_name.nr; i++) { + struct string_list_item *it = &limit_by_name.items[i]; + if (!fnmatch(it->string, pathname, 0)) + return (it->util != NULL); + } + + /* + * If we had any include, a path that does not match any rule is + * not used. Otherwise, we saw bunch of exclude rules (or none) + * and such a path is used. + */ + return !has_include; } + static void prefix_one(char **name) { char *old_name = *name; @@ -3157,10 +3173,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) continue; } if (!prefixcmp(arg, "--exclude=")) { - struct excludes *x = xmalloc(sizeof(*x)); - x->path = arg + 10; - x->next = excludes; - excludes = x; + add_name_limit(arg + 10, 1); + continue; + } + if (!prefixcmp(arg, "--include=")) { + add_name_limit(arg + 10, 0); + has_include = 1; continue; } if (!prefixcmp(arg, "-p")) { diff --git a/builtin-archive.c b/builtin-archive.c index 5ceec433fd..432ce2acc6 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -111,6 +111,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix) { const char *remote = NULL; + git_config(git_default_config, NULL); + remote = extract_remote_arg(&argc, argv); if (remote) return run_remote_archiver(remote, argc, argv); diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 90f8523eb5..55b7aafe06 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -5,26 +5,26 @@ * * Careful: order of argument flags does matter. For example, * - * git-checkout-index -a -f file.c + * git checkout-index -a -f file.c * * Will first check out all files listed in the cache (but not * overwrite any old ones), and then force-checkout "file.c" a * second time (ie that one _will_ overwrite any old contents * with the same filename). * - * Also, just doing "git-checkout-index" does nothing. You probably - * meant "git-checkout-index -a". And if you want to force it, you - * want "git-checkout-index -f -a". + * Also, just doing "git checkout-index" does nothing. You probably + * meant "git checkout-index -a". And if you want to force it, you + * want "git checkout-index -f -a". * * Intuitiveness is not the goal here. Repeatability is. The * reason for the "no arguments means no work" thing is that * from scripts you are supposed to be able to do things like * - * find . -name '*.h' -print0 | xargs -0 git-checkout-index -f -- + * find . -name '*.h' -print0 | xargs -0 git checkout-index -f -- * * or: * - * find . -name '*.h' -print0 | git-checkout-index -f -z --stdin + * find . -name '*.h' -print0 | git checkout-index -f -z --stdin * * which will force all existing *.h files to be replaced with * their cached copies. If an empty command line implied "all", @@ -107,7 +107,7 @@ static int checkout_file(const char *name, int prefix_length) } if (!state.quiet) { - fprintf(stderr, "git-checkout-index: %s ", name); + fprintf(stderr, "git checkout-index: %s ", name); if (!has_same_name) fprintf(stderr, "is not in the cache"); else if (checkout_stage) diff --git a/builtin-checkout.c b/builtin-checkout.c index d986ac7abb..9a0c173c14 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -269,6 +269,8 @@ static int merge_working_tree(struct checkout_opts *opts, } /* 2-way merge to the new branch */ + topts.initial_checkout = (!active_nr && + (old->commit == new->commit)); topts.update = 1; topts.merge = 1; topts.gently = opts->merge; @@ -326,7 +328,7 @@ static int merge_working_tree(struct checkout_opts *opts, commit_locked_index(lock_file)) die("unable to write new index file"); - if (!opts->force) + if (!opts->force && !opts->quiet) show_local_changes(&new->commit->object); return 0; @@ -578,6 +580,18 @@ no_reference: return checkout_paths(source_tree, pathspec); } + if (opts.new_branch) { + struct strbuf buf; + strbuf_init(&buf, 0); + strbuf_addstr(&buf, "refs/heads/"); + strbuf_addstr(&buf, opts.new_branch); + if (!get_sha1(buf.buf, rev)) + die("git checkout: branch %s already exists", opts.new_branch); + if (check_ref_format(buf.buf)) + die("git checkout: we do not like '%s' as a branch name.", opts.new_branch); + strbuf_release(&buf); + } + if (new.name && !new.commit) { die("Cannot switch branch to a non-commit."); } diff --git a/builtin-clone.c b/builtin-clone.c index a4b87904fc..49d2eb9c2b 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -58,7 +58,7 @@ static struct option builtin_clone_options[] = { OPT_STRING(0, "reference", &option_reference, "repo", "reference repository"), OPT_STRING('o', "origin", &option_origin, "branch", - "use <branch> instead or 'origin' to track upstream"), + "use <branch> instead of 'origin' to track upstream"), OPT_STRING('u', "upload-pack", &option_upload_pack, "path", "path to git-upload-pack on the remote"), OPT_STRING(0, "depth", &option_depth, "depth", diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 8a5ba4c667..0453425c47 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -24,7 +24,7 @@ static void check_valid(unsigned char *sha1, enum object_type expect) typename(expect)); } -static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog"; +static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog"; static void new_parent(struct commit *parent, struct commit_list **parents_p) { @@ -46,7 +46,8 @@ static const char commit_utf8_warn[] = "variable i18n.commitencoding to the encoding your project uses.\n"; int commit_tree(const char *msg, unsigned char *tree, - struct commit_list *parents, unsigned char *ret) + struct commit_list *parents, unsigned char *ret, + const char *author) { int result; int encoding_is_utf8; @@ -74,7 +75,9 @@ int commit_tree(const char *msg, unsigned char *tree, } /* Person/date information */ - strbuf_addf(&buffer, "author %s\n", git_author_info(IDENT_ERROR_ON_NO_NAME)); + if (!author) + author = git_author_info(IDENT_ERROR_ON_NO_NAME); + strbuf_addf(&buffer, "author %s\n", author); strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); if (!encoding_is_utf8) strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding); @@ -123,7 +126,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) if (strbuf_read(&buffer, 0, 0) < 0) die("git commit-tree: read returned %s", strerror(errno)); - if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1)) { + if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) { printf("%s\n", sha1_to_hex(commit_sha1)); return 0; } diff --git a/builtin-commit.c b/builtin-commit.c index 8165bb3d31..55e1087d27 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -667,14 +667,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix) } /* - * Find out if the message starting at position 'start' in the strbuf - * contains only whitespace and Signed-off-by lines. + * Find out if the message in the strbuf contains only whitespace and + * Signed-off-by lines. */ -static int message_is_empty(struct strbuf *sb, int start) +static int message_is_empty(struct strbuf *sb) { struct strbuf tmpl; const char *nl; - int eol, i; + int eol, i, start = 0; if (cleanup_mode == CLEANUP_NONE && sb->len) return 0; @@ -929,34 +929,14 @@ static const char commit_utf8_warn[] = "You may want to amend it after fixing the message, or set the config\n" "variable i18n.commitencoding to the encoding your project uses.\n"; -static void add_parent(struct strbuf *sb, const unsigned char *sha1) -{ - struct object *obj = parse_object(sha1); - const char *parent = sha1_to_hex(sha1); - const char *cp; - - if (!obj) - die("Unable to find commit parent %s", parent); - if (obj->type != OBJ_COMMIT) - die("Parent %s isn't a proper commit", parent); - - for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) { - if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') { - error("duplicate parent %s ignored", parent); - return; - } - } - strbuf_addf(sb, "parent %s\n", parent); -} - int cmd_commit(int argc, const char **argv, const char *prefix) { - int header_len; struct strbuf sb; const char *index_file, *reflog_msg; char *nl, *p; unsigned char commit_sha1[20]; struct ref_lock *ref_lock; + struct commit_list *parents = NULL, **pptr = &parents; git_config(git_commit_config, NULL); @@ -971,13 +951,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix) return 1; } - /* - * The commit object - */ - strbuf_init(&sb, 0); - strbuf_addf(&sb, "tree %s\n", - sha1_to_hex(active_cache_tree->sha1)); - /* Determine parents */ if (initial_commit) { reflog_msg = "commit (initial)"; @@ -991,13 +964,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("could not parse HEAD commit"); for (c = commit->parents; c; c = c->next) - add_parent(&sb, c->item->object.sha1); + pptr = &commit_list_insert(c->item, pptr)->next; } else if (in_merge) { struct strbuf m; FILE *fp; reflog_msg = "commit (merge)"; - add_parent(&sb, head_sha1); + pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; strbuf_init(&m, 0); fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) @@ -1007,24 +980,18 @@ int cmd_commit(int argc, const char **argv, const char *prefix) unsigned char sha1[20]; if (get_sha1_hex(m.buf, sha1) < 0) die("Corrupt MERGE_HEAD file (%s)", m.buf); - add_parent(&sb, sha1); + pptr = &commit_list_insert(lookup_commit(sha1), pptr)->next; } fclose(fp); strbuf_release(&m); } else { reflog_msg = "commit"; - strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1)); + pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; } - - strbuf_addf(&sb, "author %s\n", - fmt_ident(author_name, author_email, author_date, IDENT_ERROR_ON_NO_NAME)); - strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); - if (!is_encoding_utf8(git_commit_encoding)) - strbuf_addf(&sb, "encoding %s\n", git_commit_encoding); - strbuf_addch(&sb, '\n'); + parents = reduce_heads(parents); /* Finally, get the commit message */ - header_len = sb.len; + strbuf_init(&sb, 0); if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { rollback_index_files(); die("could not read commit message"); @@ -1037,16 +1004,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, cleanup_mode == CLEANUP_ALL); - if (sb.len < header_len || message_is_empty(&sb, header_len)) { + if (message_is_empty(&sb)) { rollback_index_files(); fprintf(stderr, "Aborting commit due to empty commit message.\n"); exit(1); } - strbuf_addch(&sb, '\0'); - if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf)) - fprintf(stderr, commit_utf8_warn); - if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) { + if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1, + fmt_ident(author_name, author_email, author_date, + IDENT_ERROR_ON_NO_NAME))) { rollback_index_files(); die("failed to write commit object"); } @@ -1055,12 +1021,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix) initial_commit ? NULL : head_sha1, 0); - nl = strchr(sb.buf + header_len, '\n'); + nl = strchr(sb.buf, '\n'); if (nl) strbuf_setlen(&sb, nl + 1 - sb.buf); else strbuf_addch(&sb, '\n'); - strbuf_remove(&sb, 0, header_len); strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg)); strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 9bf10bb37e..2b578c714d 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -50,7 +50,12 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) 3 < rev.max_count) usage(diff_files_usage); - if (rev.max_count == -1 && + /* + * "diff-files --base -p" should not combine merges because it + * was not asked to. "diff-files -c -p" should not densify + * (the user should ask with "diff-files --cc" explicitly). + */ + if (rev.max_count == -1 && !rev.combine_merges && (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 1138c2da73..8ecefd4f0f 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -71,8 +71,9 @@ static int diff_tree_stdin(char *line) line[len-1] = 0; if (get_sha1_hex(line, sha1)) return -1; - obj = lookup_object(sha1); - obj = obj ? obj : parse_object(sha1); + obj = lookup_unknown_object(sha1); + if (!obj || !obj->parsed) + obj = parse_object(sha1); if (!obj) return -1; if (obj->type == OBJ_COMMIT) diff --git a/builtin-diff.c b/builtin-diff.c index 037c3039a4..35da366f46 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -74,6 +74,8 @@ static int builtin_diff_b_f(struct rev_info *revs, if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) die("'%s': not a regular file or symlink", path); + diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); + if (blob[0].mode == S_IFINVALID) blob[0].mode = canon_mode(st.st_mode); @@ -223,7 +225,13 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv argv++; argc--; } - if (revs->max_count == -1 && + /* + * "diff --base" should not combine merges because it was not + * asked to. "diff -c" should not densify (if the user wants + * dense one, --cc can be explicitly asked for, or just rely + * on the default). + */ + if (revs->max_count == -1 && !revs->combine_merges && (revs->diffopt.output_format & DIFF_FORMAT_PATCH)) revs->combine_merges = revs->dense_combined_merges = 1; diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index e0c25615ef..fa3c936493 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -750,7 +750,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) if (!ret && nr_heads) { /* If the heads to pull were given, we should have * consumed all of them by matching the remote. - * Otherwise, 'git-fetch remote no-such-ref' would + * Otherwise, 'git fetch remote no-such-ref' would * silently succeed without issuing an error. */ for (i = 0; i < nr_heads; i++) diff --git a/builtin-fetch.c b/builtin-fetch.c index 7eec4a0e43..ee93d3a93d 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -86,10 +86,10 @@ static void add_merge_config(struct ref **head, /* * Not fetched to a tracking branch? We need to fetch * it anyway to allow this branch's "branch.$name.merge" - * to be honored by git-pull, but we do not have to + * to be honored by 'git pull', but we do not have to * fail if branch.$name.merge is misconfigured to point * at a nonexisting branch. If we were indeed called by - * git-pull, it will notice the misconfiguration because + * 'git pull', it will notice the misconfiguration because * there is no entry in the resulting FETCH_HEAD marked * for merging. */ @@ -396,7 +396,7 @@ static int store_updated_refs(const char *url, const char *remote_name, * The refs we are going to fetch are in to_fetch (nr_heads in * total). If running * - * $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all + * $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all * * does not error out, that means everything reachable from the * refs we are going to fetch exists and is connected to some of diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 21e92bbcb5..e59bd8075e 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -321,8 +321,8 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un static const char *copy_line(const char *buf) { const char *eol = strchr(buf, '\n'); - if (!eol) - return ""; + if (!eol) // simulate strchrnul() + eol = buf + strlen(buf); return xmemdupz(buf, eol - buf); } @@ -546,6 +546,107 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v } /* + * generate a format suitable for scanf from a ref_rev_parse_rules + * rule, that is replace the "%.*s" spec with a "%s" spec + */ +static void gen_scanf_fmt(char *scanf_fmt, const char *rule) +{ + char *spec; + + spec = strstr(rule, "%.*s"); + if (!spec || strstr(spec + 4, "%.*s")) + die("invalid rule in ref_rev_parse_rules: %s", rule); + + /* copy all until spec */ + strncpy(scanf_fmt, rule, spec - rule); + scanf_fmt[spec - rule] = '\0'; + /* copy new spec */ + strcat(scanf_fmt, "%s"); + /* copy remaining rule */ + strcat(scanf_fmt, spec + 4); + + return; +} + +/* + * Shorten the refname to an non-ambiguous form + */ +static char *get_short_ref(struct refinfo *ref) +{ + int i; + static char **scanf_fmts; + static int nr_rules; + char *short_name; + + /* pre generate scanf formats from ref_rev_parse_rules[] */ + if (!nr_rules) { + size_t total_len = 0; + + /* the rule list is NULL terminated, count them first */ + for (; ref_rev_parse_rules[nr_rules]; nr_rules++) + /* no +1 because strlen("%s") < strlen("%.*s") */ + total_len += strlen(ref_rev_parse_rules[nr_rules]); + + scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); + + total_len = 0; + for (i = 0; i < nr_rules; i++) { + scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + + total_len; + gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]); + total_len += strlen(ref_rev_parse_rules[i]); + } + } + + /* bail out if there are no rules */ + if (!nr_rules) + return ref->refname; + + /* buffer for scanf result, at most ref->refname must fit */ + short_name = xstrdup(ref->refname); + + /* skip first rule, it will always match */ + for (i = nr_rules - 1; i > 0 ; --i) { + int j; + int short_name_len; + + if (1 != sscanf(ref->refname, scanf_fmts[i], short_name)) + continue; + + short_name_len = strlen(short_name); + + /* + * check if the short name resolves to a valid ref, + * but use only rules prior to the matched one + */ + for (j = 0; j < i; j++) { + const char *rule = ref_rev_parse_rules[j]; + unsigned char short_objectname[20]; + + /* + * the short name is ambiguous, if it resolves + * (with this previous rule) to a valid ref + * read_ref() returns 0 on success + */ + if (!read_ref(mkpath(rule, short_name_len, short_name), + short_objectname)) + break; + } + + /* + * short name is non-ambiguous if all previous rules + * haven't resolved to a valid ref + */ + if (j == i) + return short_name; + } + + free(short_name); + return ref->refname; +} + + +/* * Parse the object referred by ref, and grab needed value. */ static void populate_value(struct refinfo *ref) @@ -570,13 +671,33 @@ static void populate_value(struct refinfo *ref) for (i = 0; i < used_atom_cnt; i++) { const char *name = used_atom[i]; struct atom_value *v = &ref->value[i]; - if (!strcmp(name, "refname")) - v->s = ref->refname; - else if (!strcmp(name, "*refname")) { - int len = strlen(ref->refname); - char *s = xmalloc(len + 4); - sprintf(s, "%s^{}", ref->refname); - v->s = s; + int deref = 0; + if (*name == '*') { + deref = 1; + name++; + } + if (!prefixcmp(name, "refname")) { + const char *formatp = strchr(name, ':'); + const char *refname = ref->refname; + + /* look for "short" refname format */ + if (formatp) { + formatp++; + if (!strcmp(formatp, "short")) + refname = get_short_ref(ref); + else + die("unknown refname format %s", + formatp); + } + + if (!deref) + v->s = refname; + else { + int len = strlen(refname); + char *s = xmalloc(len + 4); + sprintf(s, "%s^{}", refname); + v->s = s; + } } } diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c index 3a062487a7..f3e63d7206 100644 --- a/builtin-http-fetch.c +++ b/builtin-http-fetch.c @@ -42,7 +42,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) arg++; } if (argc < arg + 2 - commits_on_stdin) { - usage("git-http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); + usage("git http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); return 1; } if (commits_on_stdin) { @@ -53,7 +53,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) } url = argv[arg]; if (url && url[strlen(url)-1] != '/') { - rewritten_url = malloc(strlen(url)+2); + rewritten_url = xmalloc(strlen(url)+2); strcpy(rewritten_url, url); strcat(rewritten_url, "/"); url = rewritten_url; @@ -75,7 +75,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) fprintf(stderr, "Some loose object were found to be corrupt, but they might be just\n" "a false '404 Not Found' error message sent with incorrect HTTP\n" -"status code. Suggest running git-fsck.\n"); +"status code. Suggest running 'git fsck'.\n"); } walker_free(walker); diff --git a/builtin-init-db.c b/builtin-init-db.c index baf0d09ac4..8140c1299a 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -37,7 +37,7 @@ static void copy_templates_1(char *path, int baselen, /* Note: if ".git/hooks" file exists in the repository being * re-initialized, /etc/core-git/templates/hooks/update would - * cause git-init to fail here. I think this is sane but + * cause "git init" to fail here. I think this is sane but * it means that the set of templates we ship by default, along * with the way the namespace under .git/ is organized, should * be really carefully chosen. diff --git a/builtin-log.c b/builtin-log.c index 1d3c5cbf58..fc5e4da822 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -14,7 +14,6 @@ #include "tag.h" #include "reflog-walk.h" #include "patch-ids.h" -#include "refs.h" #include "run-command.h" #include "shortlog.h" @@ -25,31 +24,6 @@ static int default_show_root = 1; static const char *fmt_patch_subject_prefix = "PATCH"; static const char *fmt_pretty; -static void add_name_decoration(const char *prefix, const char *name, struct object *obj) -{ - int plen = strlen(prefix); - int nlen = strlen(name); - struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen); - memcpy(res->name, prefix, plen); - memcpy(res->name + plen, name, nlen + 1); - res->next = add_decoration(&name_decoration, obj, res); -} - -static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data) -{ - struct object *obj = parse_object(sha1); - if (!obj) - return 0; - add_name_decoration("", refname, obj); - while (obj->type == OBJ_TAG) { - obj = ((struct tag *)obj)->tagged; - if (!obj) - break; - add_name_decoration("tag: ", refname, obj); - } - return 0; -} - static void cmd_log_init(int argc, const char **argv, const char *prefix, struct rev_info *rev) { @@ -80,8 +54,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--decorate")) { - if (!decorate) - for_each_ref(add_ref_decoration, NULL); + load_ref_decorations(); decorate = 1; } else die("unrecognized argument: %s", arg); @@ -844,7 +817,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); endpos = strchr(committer, '>'); if (!endpos) - die("bogos committer info %s\n", committer); + die("bogus committer info %s\n", committer); add_signoff = xmemdupz(committer, endpos - committer + 1); } else if (!strcmp(argv[i], "--attach")) { diff --git a/builtin-merge.c b/builtin-merge.c index 9ad9791068..1942e72aaf 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -476,6 +476,8 @@ static int git_merge_config(const char *k, const char *v, void *cb) buf = xstrdup(v); argc = split_cmdline(buf, &argv); + if (argc < 0) + die("Bad branch.%s.mergeoptions string", branch); argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); argc++; @@ -691,7 +693,7 @@ static int merge_trivial(void) parent->next = xmalloc(sizeof(struct commit_list *)); parent->next->item = remoteheads->item; parent->next->next = NULL; - commit_tree(merge_msg.buf, result_tree, parent, result_commit); + commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL); finish(result_commit, "In-index merge"); drop_save(); return 0; @@ -720,7 +722,7 @@ static int finish_automerge(struct commit_list *common, } free_commit_list(remoteheads); strbuf_addch(&merge_msg, '\n'); - commit_tree(merge_msg.buf, result_tree, parents, result_commit); + commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL); strbuf_addf(&buf, "Merge made by %s.", wt_strategy); finish(result_commit, buf.buf); strbuf_release(&buf); diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index ba2cf00f5e..1158e42cba 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -23,7 +23,7 @@ #endif static const char pack_usage[] = "\ -git-pack-objects [{ -q | --progress | --all-progress }] \n\ +git pack-objects [{ -q | --progress | --all-progress }] \n\ [--max-pack-size=N] [--local] [--incremental] \n\ [--window=N] [--window-memory=N] [--depth=N] \n\ [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\ @@ -465,7 +465,7 @@ static void write_pack_file(void) char tmpname[PATH_MAX]; int fd; snprintf(tmpname, sizeof(tmpname), - "%s/tmp_pack_XXXXXX", get_object_directory()); + "%s/pack/tmp_pack_XXXXXX", get_object_directory()); fd = xmkstemp(tmpname); pack_tmp_name = xstrdup(tmpname); f = sha1fd(fd, pack_tmp_name); @@ -1725,6 +1725,14 @@ static void prepare_pack(int window, int depth) if (entry->type < 0) die("unable to get type of object %s", sha1_to_hex(entry->idx.sha1)); + } else { + if (entry->type < 0) { + /* + * This object is not found, but we + * don't have to include it anyway. + */ + continue; + } } delta_list[n++] = entry; @@ -1872,7 +1880,7 @@ static void mark_in_pack_object(struct object *object, struct packed_git *p, str /* * Compare the objects in the offset order, in order to emulate the - * "git-rev-list --objects" output that produced the pack originally. + * "git rev-list --objects" output that produced the pack originally. */ static int ofscmp(const void *a_, const void *b_) { diff --git a/builtin-prune.c b/builtin-prune.c index c767a0ac89..1663f8bdb1 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -13,7 +13,7 @@ static const char * const prune_usage[] = { static int show_only; static unsigned long expire; -static int prune_tmp_object(char *path, const char *filename) +static int prune_tmp_object(const char *path, const char *filename) { const char *fullpath = mkpath("%s/%s", path, filename); if (expire) { @@ -110,24 +110,22 @@ static void prune_object_dir(const char *path) /* * Write errors (particularly out of space) can result in * failed temporary packs (and more rarely indexes and other - * files begining with "tmp_") accumulating in the - * object directory. + * files begining with "tmp_") accumulating in the object + * and the pack directories. */ -static void remove_temporary_files(void) +static void remove_temporary_files(const char *path) { DIR *dir; struct dirent *de; - char* dirname=get_object_directory(); - dir = opendir(dirname); + dir = opendir(path); if (!dir) { - fprintf(stderr, "Unable to open object directory %s\n", - dirname); + fprintf(stderr, "Unable to open directory %s\n", path); return; } while ((de = readdir(dir)) != NULL) if (!prefixcmp(de->d_name, "tmp_")) - prune_tmp_object(dirname, de->d_name); + prune_tmp_object(path, de->d_name); closedir(dir); } @@ -141,6 +139,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) "expire objects older than <time>"), OPT_END() }; + char *s; save_commit_buffer = 0; init_revisions(&revs, prefix); @@ -163,6 +162,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix) prune_object_dir(get_object_directory()); prune_packed_objects(show_only); - remove_temporary_files(); + remove_temporary_files(get_object_directory()); + s = xstrdup(mkpath("%s/pack", get_object_directory())); + remove_temporary_files(s); + free(s); return 0; } diff --git a/builtin-read-tree.c b/builtin-read-tree.c index dddc3044b8..0706c95818 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -64,7 +64,7 @@ static void prime_cache_tree(void) } -static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])"; +static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])"; static struct lock_file lock_file; @@ -206,6 +206,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) break; case 2: opts.fn = twoway_merge; + opts.initial_checkout = !active_nr; break; case 3: default: diff --git a/builtin-remote.c b/builtin-remote.c index 01945a8651..4cb763f989 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -407,14 +407,15 @@ static int rm(int argc, const char **argv) return i; } -static void show_list(const char *title, struct string_list *list) +static void show_list(const char *title, struct string_list *list, + const char *extra_arg) { int i; if (!list->nr) return; - printf(title, list->nr > 1 ? "es" : ""); + printf(title, list->nr > 1 ? "es" : "", extra_arg); printf("\n "); for (i = 0; i < list->nr; i++) printf("%s%s", i ? " " : "", list->items[i].string); @@ -477,7 +478,6 @@ static int show(int argc, const char **argv) memset(&states, 0, sizeof(states)); for (; argc; argc--, argv++) { - struct strbuf buf; int i; get_remote_ref_states(*argv, &states, !no_query); @@ -503,18 +503,16 @@ static int show(int argc, const char **argv) } if (!no_query) { - strbuf_init(&buf, 0); - strbuf_addf(&buf, " New remote branch%%s (next fetch " - "will store in remotes/%s)", states.remote->name); - show_list(buf.buf, &states.new); - strbuf_release(&buf); + show_list(" New remote branch%s (next fetch " + "will store in remotes/%s)", + &states.new, states.remote->name); show_list(" Stale tracking branch%s (use 'git remote " - "prune')", &states.stale); + "prune')", &states.stale, ""); } if (no_query) for_each_ref(append_ref_to_tracked_list, &states); - show_list(" Tracked remote branch%s", &states.tracked); + show_list(" Tracked remote branch%s", &states.tracked, ""); if (states.remote->push_refspec_nr) { printf(" Local branch%s pushed with 'git push'\n ", diff --git a/builtin-rev-list.c b/builtin-rev-list.c index c023003b2b..facaff288d 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -178,7 +178,7 @@ static void finish_object(struct object_array_entry *p) static void show_object(struct object_array_entry *p) { /* An object with name "foo\n0000000..." can be used to - * confuse downstream git-pack-objects very badly. + * confuse downstream "git pack-objects" very badly. */ const char *ep = strchr(p->name, '\n'); diff --git a/builtin-rm.c b/builtin-rm.c index 6bd82111d2..fdac34f242 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -104,7 +104,7 @@ static int check_local_mod(unsigned char *head, int index_only) "from both the file and the HEAD\n" "(use -f to force removal)", name); else if (!index_only) { - /* It's not dangerous to git-rm --cached a + /* It's not dangerous to "git rm --cached" a * file if the index matches the file or the * HEAD, since it means the deleted content is * still available somewhere. diff --git a/builtin-send-pack.c b/builtin-send-pack.c index b3c22f6a4a..910db92b62 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -45,7 +45,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext po.out = fd; po.git_cmd = 1; if (start_command(&po)) - die("git-pack-objects failed (%s)", strerror(errno)); + die("git pack-objects failed (%s)", strerror(errno)); /* * We feed the pack-objects we just spawned with revision diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index cb7007e25f..0713bca778 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -9,26 +9,26 @@ static const char tar_tree_usage[] = "git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n" -"*** Note that this command is now deprecated; use git-archive instead."; +"*** Note that this command is now deprecated; use \"git archive\" instead."; int cmd_tar_tree(int argc, const char **argv, const char *prefix) { /* - * git-tar-tree is now a wrapper around git-archive --format=tar + * "git tar-tree" is now a wrapper around "git archive --format=tar" * * $0 --remote=<repo> arg... ==> - * git-archive --format=tar --remote=<repo> arg... + * git archive --format=tar --remote=<repo> arg... * $0 tree-ish ==> - * git-archive --format=tar tree-ish + * git archive --format=tar tree-ish * $0 tree-ish basedir ==> - * git-archive --format-tar --prefix=basedir tree-ish + * git archive --format-tar --prefix=basedir tree-ish */ int i; const char **nargv = xcalloc(sizeof(*nargv), argc + 2); char *basedir_arg; int nargc = 0; - nargv[nargc++] = "git-archive"; + nargv[nargc++] = "archive"; nargv[nargc++] = "--format=tar"; if (2 <= argc && !prefixcmp(argv[1], "--remote=")) { @@ -53,8 +53,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) nargv[nargc] = NULL; fprintf(stderr, - "*** git-tar-tree is now deprecated.\n" - "*** Running git-archive instead.\n***"); + "*** \"git tar-tree\" is now deprecated.\n" + "*** Running \"git archive\" instead.\n***"); for (i = 0; i < nargc; i++) { fputc(' ', stderr); sq_quote_print(stderr, nargv[i]); diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index a891866665..40b20f26e8 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -13,7 +13,7 @@ #include "fsck.h" static int dry_run, quiet, recover, has_errors, strict; -static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file"; +static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file"; /* We always read in 4kB chunks. */ static unsigned char buffer[4096]; diff --git a/builtin-update-index.c b/builtin-update-index.c index ce83224756..417f9724ab 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -14,7 +14,7 @@ * Default to not allowing changes to the list of files. The * tool doesn't actually care, but this makes it harder to add * files to the revision control by mistake by doing something - * like "git-update-index *" and suddenly having all the object + * like "git update-index *" and suddenly having all the object * files be revision controlled. */ static int allow_add; @@ -313,18 +313,18 @@ static void read_index_info(int line_termination) /* This reads lines formatted in one of three formats: * * (1) mode SP sha1 TAB path - * The first format is what "git-apply --index-info" + * The first format is what "git apply --index-info" * reports, and used to reconstruct a partial tree * that is used for phony merge base tree when falling * back on 3-way merge. * * (2) mode SP type SP sha1 TAB path - * The second format is to stuff git-ls-tree output + * The second format is to stuff "git ls-tree" output * into the index file. * * (3) mode SP sha1 SP stage TAB path * This format is to put higher order stages into the - * index file and matches git-ls-files --stage output. + * index file and matches "git ls-files --stage" output. */ errno = 0; ul = strtoul(buf.buf, &ptr, 8); @@ -17,7 +17,8 @@ extern int read_line_with_nul(char *buf, int size, FILE *file); extern int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out); extern int commit_tree(const char *msg, unsigned char *tree, - struct commit_list *parents, unsigned char *ret); + struct commit_list *parents, unsigned char *ret, + const char *author); extern int check_pager_config(const char *cmd); extern int cmd_add(int argc, const char **argv, const char *prefix); diff --git a/combine-diff.c b/combine-diff.c index dcb90b1701..de83c6972e 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -683,9 +683,13 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, int i, show_hunks; int working_tree_file = is_null_sha1(elem->sha1); int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV; + const char *a_prefix, *b_prefix; mmfile_t result_file; context = opt->context; + a_prefix = opt->a_prefix ? opt->a_prefix : "a/"; + b_prefix = opt->b_prefix ? opt->b_prefix : "b/"; + /* Read the result of merge first */ if (!working_tree_file) result = grab_blob(elem->sha1, &result_size); @@ -861,13 +865,13 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, dump_quoted_path("--- ", "", "/dev/null", c_meta, c_reset); else - dump_quoted_path("--- ", opt->a_prefix, elem->path, + dump_quoted_path("--- ", a_prefix, elem->path, c_meta, c_reset); if (deleted) dump_quoted_path("+++ ", "", "/dev/null", c_meta, c_reset); else - dump_quoted_path("+++ ", opt->b_prefix, elem->path, + dump_quoted_path("+++ ", b_prefix, elem->path, c_meta, c_reset); dump_sline(sline, cnt, num_parent, DIFF_OPT_TST(opt, COLOR_DIFF)); diff --git a/compat/fnmatch.c b/compat/fnmatch/fnmatch.c index 1f4ead5f98..1f4ead5f98 100644 --- a/compat/fnmatch.c +++ b/compat/fnmatch/fnmatch.c diff --git a/compat/fnmatch.h b/compat/fnmatch/fnmatch.h index cc3ec37940..cc3ec37940 100644 --- a/compat/fnmatch.h +++ b/compat/fnmatch/fnmatch.h diff --git a/compat/regex.c b/compat/regex/regex.c index 87b33e4669..87b33e4669 100644 --- a/compat/regex.c +++ b/compat/regex/regex.c diff --git a/compat/regex.h b/compat/regex/regex.h index 6eb64f1402..6eb64f1402 100644 --- a/compat/regex.h +++ b/compat/regex/regex.h diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d3fb6ae507..93f088189e 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -154,11 +154,8 @@ __git_heads () { local cmd i is_hash=y dir="$(__gitdir "$1")" if [ -d "$dir" ]; then - for i in $(git --git-dir="$dir" \ - for-each-ref --format='%(refname)' \ - refs/heads ); do - echo "${i#refs/heads/}" - done + git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + refs/heads return fi for i in $(git ls-remote "$1" 2>/dev/null); do @@ -175,11 +172,8 @@ __git_tags () { local cmd i is_hash=y dir="$(__gitdir "$1")" if [ -d "$dir" ]; then - for i in $(git --git-dir="$dir" \ - for-each-ref --format='%(refname)' \ - refs/tags ); do - echo "${i#refs/tags/}" - done + git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + refs/tags return fi for i in $(git ls-remote "$1" 2>/dev/null); do @@ -197,16 +191,8 @@ __git_refs () local cmd i is_hash=y dir="$(__gitdir "$1")" if [ -d "$dir" ]; then if [ -e "$dir/HEAD" ]; then echo HEAD; fi - for i in $(git --git-dir="$dir" \ - for-each-ref --format='%(refname)' \ - refs/tags refs/heads refs/remotes); do - case "$i" in - refs/tags/*) echo "${i#refs/tags/}" ;; - refs/heads/*) echo "${i#refs/heads/}" ;; - refs/remotes/*) echo "${i#refs/remotes/}" ;; - *) echo "$i" ;; - esac - done + git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + refs/tags refs/heads refs/remotes return fi for i in $(git ls-remote "$dir" 2>/dev/null); do @@ -750,7 +736,7 @@ _git_commit () --*) __gitcomp " --all --author= --signoff --verify --no-verify - --edit --amend --include --only + --edit --amend --include --only --interactive " return esac diff --git a/contrib/hooks/setgitperms.perl b/contrib/hooks/setgitperms.perl index dab7c8e3a1..a577ad095f 100644 --- a/contrib/hooks/setgitperms.perl +++ b/contrib/hooks/setgitperms.perl @@ -50,7 +50,7 @@ if ((@ARGV < 0) || !GetOptions( )) { die $usage; } die $usage unless ($read_mode xor $write_mode); -my $topdir = `git-rev-parse --show-cdup` or die "\n"; chomp $topdir; +my $topdir = `git rev-parse --show-cdup` or die "\n"; chomp $topdir; my $gitdir = $topdir . '.git'; my $gitmeta = $topdir . '.gitmeta'; @@ -155,7 +155,7 @@ elsif ($read_mode) { open (OUT, ">$gitmeta.tmp") or die "Could not open $gitmeta.tmp for writing: $!\n"; } - my @files = `git-ls-files`; + my @files = `git ls-files`; my %dirs; foreach my $path (@files) { diff --git a/csum-file.c b/csum-file.c index 28389541a3..bb70c75ee1 100644 --- a/csum-file.c +++ b/csum-file.c @@ -11,10 +11,8 @@ #include "progress.h" #include "csum-file.h" -static void sha1flush(struct sha1file *f, unsigned int count) +static void sha1flush(struct sha1file *f, void *buf, unsigned int count) { - void *buf = f->buffer; - for (;;) { int ret = xwrite(f->fd, buf, count); if (ret > 0) { @@ -39,7 +37,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) if (offset) { SHA1_Update(&f->ctx, f->buffer, offset); - sha1flush(f, offset); + sha1flush(f, f->buffer, offset); f->offset = 0; } SHA1_Final(f->buffer, &f->ctx); @@ -47,7 +45,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) hashcpy(result, f->buffer); if (flags & (CSUM_CLOSE | CSUM_FSYNC)) { /* write checksum and close fd */ - sha1flush(f, 20); + sha1flush(f, f->buffer, 20); if (flags & CSUM_FSYNC) fsync_or_die(f->fd, f->name); if (close(f->fd)) @@ -62,21 +60,30 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) int sha1write(struct sha1file *f, void *buf, unsigned int count) { - if (f->do_crc) - f->crc32 = crc32(f->crc32, buf, count); while (count) { unsigned offset = f->offset; unsigned left = sizeof(f->buffer) - offset; unsigned nr = count > left ? left : count; + void *data; + + if (f->do_crc) + f->crc32 = crc32(f->crc32, buf, nr); + + if (nr == sizeof(f->buffer)) { + /* process full buffer directly without copy */ + data = buf; + } else { + memcpy(f->buffer + offset, buf, nr); + data = f->buffer; + } - memcpy(f->buffer + offset, buf, nr); count -= nr; offset += nr; buf = (char *) buf + nr; left -= nr; if (!left) { - SHA1_Update(&f->ctx, f->buffer, offset); - sha1flush(f, offset); + SHA1_Update(&f->ctx, data, offset); + sha1flush(f, data, offset); offset = 0; } f->offset = offset; @@ -1083,7 +1083,8 @@ int main(int argc, char **argv) openlog("git-daemon", LOG_PID, LOG_DAEMON); set_die_routine(daemon_die); } else - setlinebuf(stderr); /* avoid splitting a message in the middle */ + /* avoid splitting a message in the middle */ + setvbuf(stderr, NULL, _IOLBF, 0); if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); diff --git a/diff-lib.c b/diff-lib.c index e7eaff9a68..ae96c64ca2 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -63,6 +63,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option) ? CE_MATCH_RACY_IS_DIRTY : 0); char symcache[PATH_MAX]; + diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); + if (diff_unmerged_stage < 0) diff_unmerged_stage = 2; entries = active_nr; @@ -469,6 +471,7 @@ int run_diff_index(struct rev_info *revs, int cached) if (unpack_trees(1, &t, &opts)) exit(128); + diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; diff --git a/diff-no-index.c b/diff-no-index.c index 7d68b7f1be..b60d3455da 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -252,6 +252,7 @@ void diff_no_index(struct rev_info *revs, if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], revs->diffopt.paths[1])) exit(1); + diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); @@ -24,6 +24,7 @@ static int diff_suppress_blank_empty; int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; +static int diff_mnemonic_prefix; static char diff_colors[][COLOR_MAXLEN] = { "\033[m", /* reset */ @@ -150,6 +151,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_auto_refresh_index = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.mnemonicprefix")) { + diff_mnemonic_prefix = git_config_bool(var, value); + return 0; + } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); if (!prefixcmp(var, "diff.")) { @@ -312,6 +317,15 @@ static void emit_rewrite_diff(const char *name_a, const char *new = diff_get_color(color_diff, DIFF_FILE_NEW); const char *reset = diff_get_color(color_diff, DIFF_RESET); static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT; + const char *a_prefix, *b_prefix; + + if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) { + a_prefix = o->b_prefix; + b_prefix = o->a_prefix; + } else { + a_prefix = o->a_prefix; + b_prefix = o->b_prefix; + } name_a += (*name_a == '/'); name_b += (*name_b == '/'); @@ -320,8 +334,8 @@ static void emit_rewrite_diff(const char *name_a, strbuf_reset(&a_name); strbuf_reset(&b_name); - quote_two_c_style(&a_name, o->a_prefix, name_a, 0); - quote_two_c_style(&b_name, o->b_prefix, name_b, 0); + quote_two_c_style(&a_name, a_prefix, name_a, 0); + quote_two_c_style(&b_name, b_prefix, name_b, 0); diff_populate_filespec(one, 0); diff_populate_filespec(two, 0); @@ -1117,9 +1131,13 @@ static void show_dirstat(struct diff_options *options) /* * Original minus copied is the removed material, * added is the new material. They are both damages - * made to the preimage. + * made to the preimage. In --dirstat-by-file mode, count + * damaged files, not damaged lines. This is done by + * counting only a single damaged line per file. */ damage = (p->one->size - copied) + added; + if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0) + damage = 1; ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc); dir.files[dir.nr].name = name; @@ -1447,6 +1465,14 @@ static const char *diff_funcname_pattern(struct diff_filespec *one) return NULL; } +void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b) +{ + if (!options->a_prefix) + options->a_prefix = a; + if (!options->b_prefix) + options->b_prefix = b; +} + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -1460,9 +1486,19 @@ static void builtin_diff(const char *name_a, char *a_one, *b_two; const char *set = diff_get_color_opt(o, DIFF_METAINFO); const char *reset = diff_get_color_opt(o, DIFF_RESET); + const char *a_prefix, *b_prefix; + + diff_set_mnemonic_prefix(o, "a/", "b/"); + if (DIFF_OPT_TST(o, REVERSE_DIFF)) { + a_prefix = o->b_prefix; + b_prefix = o->a_prefix; + } else { + a_prefix = o->a_prefix; + b_prefix = o->b_prefix; + } - a_one = quote_two(o->a_prefix, name_a + (*name_a == '/')); - b_two = quote_two(o->b_prefix, name_b + (*name_b == '/')); + a_one = quote_two(a_prefix, name_a + (*name_a == '/')); + b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); @@ -2319,8 +2355,10 @@ void diff_setup(struct diff_options *options) DIFF_OPT_CLR(options, COLOR_DIFF); options->detect_rename = diff_detect_rename_default; - options->a_prefix = "a/"; - options->b_prefix = "b/"; + if (!diff_mnemonic_prefix) { + options->a_prefix = "a/"; + options->b_prefix = "b/"; + } } int diff_setup_done(struct diff_options *options) @@ -2403,13 +2441,6 @@ int diff_setup_done(struct diff_options *options) DIFF_OPT_SET(options, EXIT_WITH_STATUS); } - /* - * If we postprocess in diffcore, we cannot simply return - * upon the first hit. We need to run diff as usual. - */ - if (options->pickaxe || options->filter) - DIFF_OPT_CLR(options, QUIET); - return 0; } @@ -2484,6 +2515,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--cumulative")) { options->output_format |= DIFF_FORMAT_DIRSTAT; DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); + } else if (opt_arg(arg, 0, "dirstat-by-file", + &options->dirstat_percent)) { + options->output_format |= DIFF_FORMAT_DIRSTAT; + DIFF_OPT_SET(options, DIRSTAT_BY_FILE); } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; @@ -3397,10 +3432,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) void diffcore_std(struct diff_options *options) { - if (DIFF_OPT_TST(options, QUIET)) - return; - - if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER)) + if (options->skip_stat_unmatch) diffcore_skip_stat_unmatch(options); if (options->break_opt != -1) diffcore_break(options->break_opt); @@ -64,6 +64,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_RELATIVE_NAME (1 << 17) #define DIFF_OPT_IGNORE_SUBMODULES (1 << 18) #define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) +#define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) @@ -160,6 +161,8 @@ extern void diff_tree_combined(const unsigned char *sha1, const unsigned char pa extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *); +void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b); + extern void diff_addremove(struct diff_options *, int addremove, unsigned mode, diff --git a/diffcore.h b/diffcore.h index cc96c20734..8ae35785fd 100644 --- a/diffcore.h +++ b/diffcore.h @@ -92,7 +92,6 @@ extern struct diff_filepair *diff_queue(struct diff_queue_struct *, struct diff_filespec *); extern void diff_q(struct diff_queue_struct *, struct diff_filepair *); -extern void diffcore_pathspec(const char **pathspec); extern void diffcore_break(int); extern void diffcore_rename(struct diff_options *); extern void diffcore_merge_broken(void); diff --git a/fast-import.c b/fast-import.c index ccdf2e57b0..ab6689a64d 100644 --- a/fast-import.c +++ b/fast-import.c @@ -816,7 +816,7 @@ static void start_packfile(void) int pack_fd; snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_pack_XXXXXX", get_object_directory()); + "%s/pack/tmp_pack_XXXXXX", get_object_directory()); pack_fd = xmkstemp(tmpfile); p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2); strcpy(p->pack_name, tmpfile); @@ -878,7 +878,7 @@ static char *create_index(void) } snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_idx_XXXXXX", get_object_directory()); + "%s/pack/tmp_idx_XXXXXX", get_object_directory()); idx_fd = xmkstemp(tmpfile); f = sha1fd(idx_fd, tmpfile); sha1write(f, array, 256 * sizeof(int)); diff --git a/git-bisect.sh b/git-bisect.sh index 97ac600873..79de7017e8 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -172,6 +172,25 @@ bisect_write() { test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG" } +is_expected_rev() { + test -f "$GIT_DIR/BISECT_EXPECTED_REV" && + test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV") +} + +mark_expected_rev() { + echo "$1" > "$GIT_DIR/BISECT_EXPECTED_REV" +} + +check_expected_revs() { + for _rev in "$@"; do + if ! is_expected_rev "$_rev"; then + rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" + rm -f "$GIT_DIR/BISECT_EXPECTED_REV" + return + fi + done +} + bisect_state() { bisect_autostart state=$1 @@ -181,7 +200,8 @@ bisect_state() { 1,bad|1,good|1,skip) rev=$(git rev-parse --verify HEAD) || die "Bad rev input: HEAD" - bisect_write "$state" "$rev" ;; + bisect_write "$state" "$rev" + check_expected_revs "$rev" ;; 2,bad|*,good|*,skip) shift eval='' @@ -191,7 +211,8 @@ bisect_state() { die "Bad rev input: $rev" eval="$eval bisect_write '$state' '$sha'; " done - eval "$eval" ;; + eval "$eval" + check_expected_revs "$@" ;; *,bad) die "'git bisect bad' can take only one argument." ;; *) @@ -243,33 +264,18 @@ bisect_auto_next() { bisect_next_check && bisect_next || : } -eval_rev_list() { - _eval="$1" - - eval $_eval - res=$? - - if [ $res -ne 0 ]; then - echo >&2 "'git rev-list --bisect-vars' failed:" - echo >&2 "maybe you mistake good and bad revs?" - exit $res - fi - - return $res -} - filter_skipped() { _eval="$1" _skip="$2" if [ -z "$_skip" ]; then - eval_rev_list "$_eval" + eval "$_eval" return fi # Let's parse the output of: # "git rev-list --bisect-vars --bisect-all ..." - eval_rev_list "$_eval" | while read hash line + eval "$_eval" | while read hash line do case "$VARS,$FOUND,$TRIED,$hash" in # We display some vars. @@ -332,20 +338,133 @@ exit_if_skipped_commits () { fi } +bisect_checkout() { + _rev="$1" + _msg="$2" + echo "Bisecting: $_msg" + mark_expected_rev "$_rev" + git checkout -q "$_rev" || exit + git show-branch "$_rev" +} + +is_among() { + _rev="$1" + _list="$2" + case "$_list" in *$_rev*) return 0 ;; esac + return 1 +} + +handle_bad_merge_base() { + _badmb="$1" + _good="$2" + if is_expected_rev "$_badmb"; then + cat >&2 <<EOF +The merge base $_badmb is bad. +This means the bug has been fixed between $_badmb and [$_good]. +EOF + exit 3 + else + cat >&2 <<EOF +Some good revs are not ancestor of the bad rev. +git bisect cannot work properly in this case. +Maybe you mistake good and bad revs? +EOF + exit 1 + fi +} + +handle_skipped_merge_base() { + _mb="$1" + _bad="$2" + _good="$3" + cat >&2 <<EOF +Warning: the merge base between $_bad and [$_good] must be skipped. +So we cannot be sure the first bad commit is between $_mb and $_bad. +We continue anyway. +EOF +} + +# +# "check_merge_bases" checks that merge bases are not "bad". +# +# - If one is "good", that's good, we have nothing to do. +# - If one is "bad", it means the user assumed something wrong +# and we must exit. +# - If one is "skipped", we can't know but we should warn. +# - If we don't know, we should check it out and ask the user to test. +# +# In the last case we will return 1, and otherwise 0. +# +check_merge_bases() { + _bad="$1" + _good="$2" + _skip="$3" + for _mb in $(git merge-base --all $_bad $_good) + do + if is_among "$_mb" "$_good"; then + continue + elif test "$_mb" = "$_bad"; then + handle_bad_merge_base "$_bad" "$_good" + elif is_among "$_mb" "$_skip"; then + handle_skipped_merge_base "$_mb" "$_bad" "$_good" + else + bisect_checkout "$_mb" "a merge base must be tested" + return 1 + fi + done + return 0 +} + +# +# "check_good_are_ancestors_of_bad" checks that all "good" revs are +# ancestor of the "bad" rev. +# +# If that's not the case, we need to check the merge bases. +# If a merge base must be tested by the user we return 1 and +# otherwise 0. +# +check_good_are_ancestors_of_bad() { + test -f "$GIT_DIR/BISECT_ANCESTORS_OK" && + return + + _bad="$1" + _good=$(echo $2 | sed -e 's/\^//g') + _skip="$3" + + # Bisecting with no good rev is ok + test -z "$_good" && return + + _side=$(git rev-list $_good ^$_bad) + if test -n "$_side"; then + # Return if a checkout was done + check_merge_bases "$_bad" "$_good" "$_skip" || return + fi + + : > "$GIT_DIR/BISECT_ANCESTORS_OK" + + return 0 +} + bisect_next() { case "$#" in 0) ;; *) usage ;; esac bisect_autostart bisect_next_check good + # Get bad, good and skipped revs + bad=$(git rev-parse --verify refs/bisect/bad) && + good=$(git for-each-ref --format='^%(objectname)' \ + "refs/bisect/good-*" | tr '\012' ' ') && skip=$(git for-each-ref --format='%(objectname)' \ - "refs/bisect/skip-*" | tr '\012' ' ') || exit + "refs/bisect/skip-*" | tr '\012' ' ') && + + # Maybe some merge bases must be tested first + check_good_are_ancestors_of_bad "$bad" "$good" "$skip" + # Return now if a checkout has already been done + test "$?" -eq "1" && return + # Get bisection information BISECT_OPT='' test -n "$skip" && BISECT_OPT='--bisect-all' - - bad=$(git rev-parse --verify refs/bisect/bad) && - good=$(git for-each-ref --format='^%(objectname)' \ - "refs/bisect/good-*" | tr '\012' ' ') && eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" && eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" && eval=$(filter_skipped "$eval" "$skip") && @@ -366,9 +485,7 @@ bisect_next() { # commit is also a "skip" commit (see above). exit_if_skipped_commits "$bisect_rev" - echo "Bisecting: $bisect_nr revisions left to test after this" - git checkout -q "$bisect_rev" || exit - git show-branch "$bisect_rev" + bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this" } bisect_visualize() { @@ -415,6 +532,8 @@ bisect_clean_state() { do git update-ref -d $ref $hash || exit done + rm -f "$GIT_DIR/BISECT_EXPECTED_REV" && + rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" && rm -f "$GIT_DIR/BISECT_LOG" && rm -f "$GIT_DIR/BISECT_NAMES" && rm -f "$GIT_DIR/BISECT_RUN" && diff --git a/git-gui/.gitattributes b/git-gui/.gitattributes new file mode 100644 index 0000000000..f96112d47f --- /dev/null +++ b/git-gui/.gitattributes @@ -0,0 +1,3 @@ +* encoding=US-ASCII +git-gui.sh encoding=UTF-8 +/po/*.po encoding=UTF-8 diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 10d8a4422f..4085e8fea5 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -521,6 +521,19 @@ proc kill_file_process {fd} { } } +proc gitattr {path attr default} { + if {[catch {set r [git check-attr $attr -- $path]}]} { + set r unspecified + } else { + set r [join [lrange [split $r :] 2 end] :] + regsub {^ } $r {} r + } + if {$r eq {unspecified}} { + return $default + } + return $r +} + proc sq {value} { regsub -all ' $value "'\\''" value return "'$value'" @@ -665,6 +678,7 @@ set default_config(merge.verbosity) 2 set default_config(user.name) {} set default_config(user.email) {} +set default_config(gui.encoding) [encoding system] set default_config(gui.matchtrackingbranch) false set default_config(gui.pruneduringfetch) false set default_config(gui.trustmtime) false @@ -948,10 +962,32 @@ blame { } citool { enable_option singlecommit + enable_option retcode disable_option multicommit disable_option branch disable_option transport + + while {[llength $argv] > 0} { + set a [lindex $argv 0] + switch -- $a { + --amend { + enable_option initialamend + } + --nocommit { + enable_option nocommit + enable_option nocommitmsg + } + --commitmsg { + disable_option nocommitmsg + } + default { + break + } + } + + set argv [lrange $argv 1 end] + } } } @@ -1023,8 +1059,12 @@ set current_branch {} set is_detached 0 set current_diff_path {} set is_3way_diff 0 +set is_conflict_diff 0 set selected_commit_type new +set nullid "0000000000000000000000000000000000000000" +set nullid2 "0000000000000000000000000000000000000001" + ###################################################################### ## ## task management @@ -1105,6 +1145,20 @@ proc PARENT {} { return $empty_tree } +proc force_amend {} { + global selected_commit_type + global HEAD PARENT MERGE_HEAD commit_type + + repository_state newType newHEAD newMERGE_HEAD + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType + + set selected_commit_type amend + do_select_commit_type +} + proc rescan {after {honor_trustmtime 1}} { global HEAD PARENT MERGE_HEAD commit_type global ui_index ui_workdir ui_comm @@ -1131,6 +1185,7 @@ proc rescan {after {honor_trustmtime 1}} { || [string trim [$ui_comm get 0.0 end]] eq {})} { if {[string match amend* $commit_type]} { } elseif {[load_message GITGUI_MSG]} { + } elseif {[run_prepare_commit_msg_hook]} { } elseif {[load_message MERGE_MSG]} { } elseif {[load_message SQUASH_MSG]} { } @@ -1230,6 +1285,70 @@ proc load_message {file} { return 0 } +proc run_prepare_commit_msg_hook {} { + global pch_error + + # prepare-commit-msg requires PREPARE_COMMIT_MSG exist. From git-gui + # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an + # empty file but existant file. + + set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] + + if {[file isfile [gitdir MERGE_MSG]]} { + set pcm_source "merge" + set fd_mm [open [gitdir MERGE_MSG] r] + puts -nonewline $fd_pcm [read $fd_mm] + close $fd_mm + } elseif {[file isfile [gitdir SQUASH_MSG]]} { + set pcm_source "squash" + set fd_sm [open [gitdir SQUASH_MSG] r] + puts -nonewline $fd_pcm [read $fd_sm] + close $fd_sm + } else { + set pcm_source "" + } + + close $fd_pcm + + set fd_ph [githook_read prepare-commit-msg \ + [gitdir PREPARE_COMMIT_MSG] $pcm_source] + if {$fd_ph eq {}} { + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + return 0; + } + + ui_status [mc "Calling prepare-commit-msg hook..."] + set pch_error {} + + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable \ + [list prepare_commit_msg_hook_wait $fd_ph] + + return 1; +} + +proc prepare_commit_msg_hook_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + ui_status [mc "Commit declined by prepare-commit-msg hook."] + hook_failed_popup prepare-commit-msg $pch_error + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + exit 1 + } else { + load_message PREPARE_COMMIT_MSG + } + set pch_error {} + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + return + } + fconfigure $fd_ph -blocking 0 + catch {file delete [gitdir PREPARE_COMMIT_MSG]} +} + proc read_diff_index {fd after} { global buf_rdi @@ -1751,11 +1870,19 @@ proc do_gitk {revs} { } set is_quitting 0 +set ret_code 1 + +proc terminate_me {win} { + global ret_code + if {$win ne {.}} return + exit $ret_code +} -proc do_quit {} { +proc do_quit {{rc {1}}} { global ui_comm is_quitting repo_config commit_type global GITGUI_BCK_exists GITGUI_BCK_i global ui_comm_spell + global ret_code if {$is_quitting} return set is_quitting 1 @@ -1810,6 +1937,7 @@ proc do_quit {} { } } + set ret_code $rc destroy . } @@ -1951,19 +2079,21 @@ proc toggle_or_diff {w x y} { $ui_index tag remove in_sel 0.0 end $ui_workdir tag remove in_sel 0.0 end - # Do not stage files with conflicts + # Determine the state of the file if {[info exists file_states($path)]} { set state [lindex $file_states($path) 0] } else { set state {__} } - if {[string first {U} $state] >= 0} { - set col 1 - } - # Restage the file, or simply show the diff if {$col == 0 && $y > 1} { + # Conflicts need special handling + if {[string first {U} $state] >= 0} { + merge_stage_workdir $path $w $lno + return + } + if {[string index $state 1] eq {O}} { set mmask {} } else { @@ -2212,26 +2342,36 @@ if {[is_enabled branch]} { # -- Commit Menu # +proc commit_btn_caption {} { + if {[is_enabled nocommit]} { + return [mc "Done"] + } else { + return [mc Commit@@verb] + } +} + if {[is_enabled multicommit] || [is_enabled singlecommit]} { menu .mbar.commit - .mbar.commit add radiobutton \ - -label [mc "New Commit"] \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value new - lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] + if {![is_enabled nocommit]} { + .mbar.commit add radiobutton \ + -label [mc "New Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] - .mbar.commit add radiobutton \ - -label [mc "Amend Last Commit"] \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value amend - lappend disable_on_lock \ - [list .mbar.commit entryconf [.mbar.commit index last] -state] + .mbar.commit add radiobutton \ + -label [mc "Amend Last Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] - .mbar.commit add separator + .mbar.commit add separator + } .mbar.commit add command -label [mc Rescan] \ -command ui_do_rescan \ @@ -2273,11 +2413,13 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar.commit add separator - .mbar.commit add command -label [mc "Sign Off"] \ - -command do_signoff \ - -accelerator $M1T-S + if {![is_enabled nocommit]} { + .mbar.commit add command -label [mc "Sign Off"] \ + -command do_signoff \ + -accelerator $M1T-S + } - .mbar.commit add command -label [mc Commit@@verb] \ + .mbar.commit add command -label [commit_btn_caption] \ -command do_commit \ -accelerator $M1T-Return lappend disable_on_lock \ @@ -2601,19 +2743,23 @@ pack .vpane.lower.commarea.buttons.incall -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.incall conf -state} -button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ - -command do_signoff -pack .vpane.lower.commarea.buttons.signoff -side top -fill x +if {![is_enabled nocommit]} { + button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ + -command do_signoff + pack .vpane.lower.commarea.buttons.signoff -side top -fill x +} -button .vpane.lower.commarea.buttons.commit -text [mc Commit@@verb] \ +button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \ -command do_commit pack .vpane.lower.commarea.buttons.commit -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.commit conf -state} -button .vpane.lower.commarea.buttons.push -text [mc Push] \ - -command do_push_anywhere -pack .vpane.lower.commarea.buttons.push -side top -fill x +if {![is_enabled nocommit]} { + button .vpane.lower.commarea.buttons.push -text [mc Push] \ + -command do_push_anywhere + pack .vpane.lower.commarea.buttons.push -side top -fill x +} # -- Commit Message Buffer # @@ -2621,20 +2767,24 @@ frame .vpane.lower.commarea.buffer frame .vpane.lower.commarea.buffer.header set ui_comm .vpane.lower.commarea.buffer.t set ui_coml .vpane.lower.commarea.buffer.header.l -radiobutton .vpane.lower.commarea.buffer.header.new \ - -text [mc "New Commit"] \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value new -lappend disable_on_lock \ - [list .vpane.lower.commarea.buffer.header.new conf -state] -radiobutton .vpane.lower.commarea.buffer.header.amend \ - -text [mc "Amend Last Commit"] \ - -command do_select_commit_type \ - -variable selected_commit_type \ - -value amend -lappend disable_on_lock \ - [list .vpane.lower.commarea.buffer.header.amend conf -state] + +if {![is_enabled nocommit]} { + radiobutton .vpane.lower.commarea.buffer.header.new \ + -text [mc "New Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new + lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.new conf -state] + radiobutton .vpane.lower.commarea.buffer.header.amend \ + -text [mc "Amend Last Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend + lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.amend conf -state] +} + label $ui_coml \ -anchor w \ -justify left @@ -2652,8 +2802,11 @@ proc trace_commit_type {varname args} { } trace add variable commit_type write trace_commit_type pack $ui_coml -side left -fill x -pack .vpane.lower.commarea.buffer.header.amend -side right -pack .vpane.lower.commarea.buffer.header.new -side right + +if {![is_enabled nocommit]} { + pack .vpane.lower.commarea.buffer.header.amend -side right + pack .vpane.lower.commarea.buffer.header.new -side right +} text $ui_comm -background white -foreground black \ -borderwidth 1 \ @@ -2860,6 +3013,14 @@ proc create_common_diff_popup {ctxm} { -command {incr_font_size font_diff 1} lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add separator + set emenu $ctxm.enc + menu $emenu + build_encoding_menu $emenu [list force_diff_encoding] + $ctxm add cascade \ + -label [mc "Encoding"] \ + -menu $emenu + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator $ctxm add command -label [mc "Options..."] \ -command do_options } @@ -3191,7 +3352,20 @@ lock_index begin-read if {![winfo ismapped .]} { wm deiconify . } -after 1 do_rescan +after 1 { + if {[is_enabled initialamend]} { + force_amend + } else { + do_rescan + } + + if {[is_enabled nocommitmsg]} { + $ui_comm configure -state disabled -background gray + } +} if {[is_enabled multicommit]} { after 1000 hint_gc } +if {[is_enabled retcode]} { + bind . <Destroy> {+terminate_me %W} +} diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl index 827c85d67f..eb61374d2d 100644 --- a/git-gui/lib/blame.tcl +++ b/git-gui/lib/blame.tcl @@ -256,9 +256,16 @@ constructor new {i_commit i_path i_jump} { $w.ctxm add command \ -label [mc "Copy Commit"] \ -command [cb _copycommit] + $w.ctxm add separator + menu $w.ctxm.enc + build_encoding_menu $w.ctxm.enc [cb _setencoding] + $w.ctxm add cascade \ + -label [mc "Encoding"] \ + -menu $w.ctxm.enc $w.ctxm add command \ -label [mc "Do Full Copy Detection"] \ -command [cb _fullcopyblame] + $w.ctxm add separator $w.ctxm add command \ -label [mc "Show History Context"] \ -command [cb _gitkcommit] @@ -399,7 +406,10 @@ method _load {jump} { } else { set fd [git_read cat-file blob "$commit:$path"] } - fconfigure $fd -blocking 0 -translation lf -encoding binary + fconfigure $fd \ + -blocking 0 \ + -translation lf \ + -encoding [get_path_encoding $path] fileevent $fd readable [cb _read_file $fd $jump] set current_fd $fd } @@ -508,7 +518,7 @@ method _exec_blame {cur_w cur_d options cur_s} { } lappend options -- $path set fd [eval git_read --nice blame $options] - fconfigure $fd -blocking 0 -translation lf -encoding binary + fconfigure $fd -blocking 0 -translation lf -encoding utf-8 fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] set current_fd $fd set blame_lines 0 @@ -788,6 +798,16 @@ method _click {cur_w pos} { _showcommit $this $cur_w $lno } +method _setencoding {enc} { + force_path_encoding $path $enc + _load $this [list \ + $highlight_column \ + $highlight_line \ + [lindex [$w_file xview] 0] \ + [lindex [$w_file yview] 0] \ + ] +} + method _load_commit {cur_w cur_d pos} { upvar #0 $cur_d line_data set lno [lindex [split [$cur_w index $pos] .] 0] @@ -881,12 +901,6 @@ method _showcommit {cur_w lno} { set enc [tcl_encoding $enc] if {$enc ne {}} { set msg [encoding convertfrom $enc $msg] - set author_name [encoding convertfrom $enc $author_name] - set committer_name [encoding convertfrom $enc $committer_name] - set header($cmit,author) $author_name - set header($cmit,committer) $committer_name - set header($cmit,summary) \ - [encoding convertfrom $enc $header($cmit,summary)] } set msg [string trim $msg] } @@ -942,9 +956,20 @@ method _format_offset_date {base offset} { } method _gitkcommit {} { + global nullid + set dat [_get_click_amov_info $this] if {$dat ne {}} { set cmit [lindex $dat 0] + + # If the line belongs to the working copy, use HEAD instead + if {$cmit eq $nullid} { + if {[catch {set cmit [git rev-parse --verify HEAD]} err]} { + error_popup [strcat [mc "Cannot find HEAD commit:"] "\n\n$err"] + return; + } + } + set radius [get_config gui.blamehistoryctx] set cmdline [list --select-commit=$cmit] @@ -981,12 +1006,20 @@ method _gitkcommit {} { } method _blameparent {} { + global nullid + set dat [_get_click_amov_info $this] if {$dat ne {}} { set cmit [lindex $dat 0] set new_path [lindex $dat 1] - if {[catch {set cparent [git rev-parse --verify "$cmit^"]}]} { + # Allow using Blame Parent on lines modified in the working copy + if {$cmit eq $nullid} { + set parent_ref "HEAD" + } else { + set parent_ref "$cmit^" + } + if {[catch {set cparent [git rev-parse --verify $parent_ref]} err]} { error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"] return; } @@ -996,8 +1029,12 @@ method _blameparent {} { # Generate a diff between the commit and its parent, # and use the hunks to update the line number. # Request zero context to simplify calculations. - if {[catch {set fd [eval git_read diff-tree \ - --unified=0 $cparent $cmit $new_path]} err]} { + if {$cmit eq $nullid} { + set diffcmd [list diff-index --unified=0 $cparent -- $new_path] + } else { + set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path] + } + if {[catch {set fd [eval git_read $diffcmd]} err]} { $status stop [mc "Unable to display parent"] error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] return diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 2977315624..334514996a 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -168,7 +168,7 @@ File %s cannot be committed by this program. } } } - if {!$files_ready && ![string match *merge $curType]} { + if {!$files_ready && ![string match *merge $curType] && ![is_enabled nocommit]} { info_popup [mc "No changes to commit. You must stage at least 1 file before you can commit. @@ -177,6 +177,8 @@ You must stage at least 1 file before you can commit. return } + if {[is_enabled nocommitmsg]} { do_quit 0 } + # -- A message is required. # set msg [string trim [$ui_comm get 1.0 end]] @@ -212,6 +214,8 @@ A good commit message has the following format: puts $msg_wt $msg close $msg_wt + if {[is_enabled nocommit]} { do_quit 0 } + # -- Run the pre-commit hook. # set fd_ph [githook_read pre-commit] @@ -410,7 +414,7 @@ A rescan will be automatically started now. set ::GITGUI_BCK_exists 0 } - if {[is_enabled singlecommit]} do_quit + if {[is_enabled singlecommit]} { do_quit 0 } # -- Update in memory status # diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index a30c80a935..abe502d971 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -40,6 +40,15 @@ proc reshow_diff {} { } } +proc force_diff_encoding {enc} { + global current_diff_path + + if {$current_diff_path ne {}} { + force_path_encoding $current_diff_path $enc + reshow_diff + } +} + proc handle_empty_diff {} { global current_diff_path file_states file_lists @@ -60,9 +69,9 @@ A rescan will be automatically started to find other files which may have the sa rescan ui_ready 0 } -proc show_diff {path w {lno {}} {scroll_pos {}}} { +proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { global file_states file_lists - global is_3way_diff diff_active repo_config + global is_3way_diff is_conflict_diff diff_active repo_config global ui_diff ui_index ui_workdir global current_diff_path current_diff_side current_diff_header global current_diff_queue @@ -83,36 +92,42 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { set s $file_states($path) set m [lindex $s 0] + set is_conflict_diff 0 set current_diff_path $path set current_diff_side $w set current_diff_queue {} ui_status [mc "Loading diff of %s..." [escape_path $path]] + set cont_info [list $scroll_pos $callback] + if {[string first {U} $m] >= 0} { - merge_load_stages $path [list show_unmerged_diff $scroll_pos] + merge_load_stages $path [list show_unmerged_diff $cont_info] } elseif {$m eq {_O}} { - show_other_diff $path $w $m $scroll_pos + show_other_diff $path $w $m $cont_info } else { - start_show_diff $scroll_pos + start_show_diff $cont_info } } -proc show_unmerged_diff {scroll_pos} { +proc show_unmerged_diff {cont_info} { global current_diff_path current_diff_side - global merge_stages ui_diff + global merge_stages ui_diff is_conflict_diff global current_diff_queue if {$merge_stages(2) eq {}} { + set is_conflict_diff 1 lappend current_diff_queue \ [list "LOCAL: deleted\nREMOTE:\n" d======= \ [list ":1:$current_diff_path" ":3:$current_diff_path"]] } elseif {$merge_stages(3) eq {}} { + set is_conflict_diff 1 lappend current_diff_queue \ [list "REMOTE: deleted\nLOCAL:\n" d======= \ [list ":1:$current_diff_path" ":2:$current_diff_path"]] } elseif {[lindex $merge_stages(1) 0] eq {120000} || [lindex $merge_stages(2) 0] eq {120000} || [lindex $merge_stages(3) 0] eq {120000}} { + set is_conflict_diff 1 lappend current_diff_queue \ [list "LOCAL:\n" d======= \ [list ":1:$current_diff_path" ":2:$current_diff_path"]] @@ -120,14 +135,14 @@ proc show_unmerged_diff {scroll_pos} { [list "REMOTE:\n" d======= \ [list ":1:$current_diff_path" ":3:$current_diff_path"]] } else { - start_show_diff $scroll_pos + start_show_diff $cont_info return } - advance_diff_queue $scroll_pos + advance_diff_queue $cont_info } -proc advance_diff_queue {scroll_pos} { +proc advance_diff_queue {cont_info} { global current_diff_queue ui_diff set item [lindex $current_diff_queue 0] @@ -137,10 +152,10 @@ proc advance_diff_queue {scroll_pos} { $ui_diff insert end [lindex $item 0] [lindex $item 1] $ui_diff conf -state disabled - start_show_diff $scroll_pos [lindex $item 2] + start_show_diff $cont_info [lindex $item 2] } -proc show_other_diff {path w m scroll_pos} { +proc show_other_diff {path w m cont_info} { global file_states file_lists global is_3way_diff diff_active repo_config global ui_diff ui_index ui_workdir @@ -165,7 +180,9 @@ proc show_other_diff {path w m scroll_pos} { } file { set fd [open $path r] - fconfigure $fd -eofchar {} + fconfigure $fd \ + -eofchar {} \ + -encoding [get_path_encoding $path] set content [read $fd $max_sz] close $fd set sz [file size $path] @@ -217,16 +234,21 @@ proc show_other_diff {path w m scroll_pos} { $ui_diff conf -state disabled set diff_active 0 unlock_index + set scroll_pos [lindex $cont_info 0] if {$scroll_pos ne {}} { update $ui_diff yview moveto $scroll_pos } ui_ready + set callback [lindex $cont_info 1] + if {$callback ne {}} { + eval $callback + } return } } -proc start_show_diff {scroll_pos {add_opts {}}} { +proc start_show_diff {cont_info {add_opts {}}} { global file_states file_lists global is_3way_diff diff_active repo_config global ui_diff ui_index ui_workdir @@ -279,14 +301,14 @@ proc start_show_diff {scroll_pos {add_opts {}}} { set ::current_diff_inheader 1 fconfigure $fd \ -blocking 0 \ - -encoding binary \ - -translation binary - fileevent $fd readable [list read_diff $fd $scroll_pos] + -encoding [get_path_encoding $path] \ + -translation lf + fileevent $fd readable [list read_diff $fd $cont_info] } -proc read_diff {fd scroll_pos} { +proc read_diff {fd cont_info} { global ui_diff diff_active - global is_3way_diff current_diff_header + global is_3way_diff is_conflict_diff current_diff_header global current_diff_queue $ui_diff conf -state normal @@ -334,6 +356,7 @@ proc read_diff {fd scroll_pos} { {--} {set tags d_--} {++} { if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} { + set is_conflict_diff 1 set line [string replace $line 0 1 { }] set tags d$op } else { @@ -353,6 +376,7 @@ proc read_diff {fd scroll_pos} { {-} {set tags d_-} {+} { if {[regexp {^\+([<>]{7} |={7})} $line _g op]} { + set is_conflict_diff 1 set line [string replace $line 0 0 { }] set tags d$op } else { @@ -377,12 +401,13 @@ proc read_diff {fd scroll_pos} { close $fd if {$current_diff_queue ne {}} { - advance_diff_queue $scroll_pos + advance_diff_queue $cont_info return } set diff_active 0 unlock_index + set scroll_pos [lindex $cont_info 0] if {$scroll_pos ne {}} { update $ui_diff yview moveto $scroll_pos @@ -392,6 +417,10 @@ proc read_diff {fd scroll_pos} { if {[$ui_diff index end] eq {2.0}} { handle_empty_diff } + set callback [lindex $cont_info 1] + if {$callback ne {}} { + eval $callback + } } } @@ -432,8 +461,9 @@ proc apply_hunk {x y} { } if {[catch { + set enc [get_path_encoding $current_diff_path] set p [eval git_write $apply_cmd] - fconfigure $p -translation binary -encoding binary + fconfigure $p -translation binary -encoding $enc puts -nonewline $p $current_diff_header puts -nonewline $p [$ui_diff get $s_lno $e_lno] close $p} err]} { @@ -601,8 +631,9 @@ proc apply_line {x y} { set patch "@@ -$hln,$n +$hln,[eval expr $n $sign 1] @@\n$patch" if {[catch { + set enc [get_path_encoding $current_diff_path] set p [eval git_write $apply_cmd] - fconfigure $p -translation binary -encoding binary + fconfigure $p -translation binary -encoding $enc puts -nonewline $p $current_diff_header puts -nonewline $p $patch close $p} err]} { diff --git a/git-gui/lib/encoding.tcl b/git-gui/lib/encoding.tcl index 7f06b0d47f..32668fc9c6 100644 --- a/git-gui/lib/encoding.tcl +++ b/git-gui/lib/encoding.tcl @@ -206,7 +206,7 @@ set encoding_aliases { { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 } { GBK CP936 MS936 windows-936 } { JIS_Encoding csJISEncoding } - { Shift_JIS MS_Kanji csShiftJIS } + { Shift_JIS MS_Kanji csShiftJIS ShiftJIS Shift-JIS } { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese EUC-JP } { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese } @@ -240,37 +240,227 @@ set encoding_aliases { { Big5 csBig5 } } +set encoding_groups { + {"" "" + {"Unicode" UTF-8} + {"Western" ISO-8859-1}} + {we "West European" + {"Western" ISO-8859-15 CP-437 CP-850 MacRoman CP-1252 Windows-1252} + {"Celtic" ISO-8859-14} + {"Greek" ISO-8859-14 ISO-8859-7 CP-737 CP-869 MacGreek CP-1253 Windows-1253} + {"Icelandic" MacIceland MacIcelandic CP-861} + {"Nordic" ISO-8859-10 CP-865} + {"Portuguese" CP-860} + {"South European" ISO-8859-3}} + {ee "East European" + {"Baltic" CP-775 ISO-8859-4 ISO-8859-13 CP-1257 Windows-1257} + {"Central European" CP-852 ISO-8859-2 MacCE CP-1250 Windows-1250} + {"Croatian" MacCroatian} + {"Cyrillic" CP-855 ISO-8859-5 ISO-IR-111 KOI8-R MacCyrillic CP-1251 Windows-1251} + {"Russian" CP-866} + {"Ukrainian" KOI8-U MacUkraine MacUkrainian} + {"Romanian" ISO-8859-16 MacRomania MacRomanian}} + {ea "East Asian" + {"Generic" ISO-2022} + {"Chinese Simplified" GB2312 GB1988 GB12345 GB2312-RAW GBK EUC-CN GB18030 HZ ISO-2022-CN} + {"Chinese Traditional" Big5 Big5-HKSCS EUC-TW CP-950} + {"Japanese" EUC-JP ISO-2022-JP Shift-JIS JIS-0212 JIS-0208 JIS-0201 CP-932 MacJapan} + {"Korean" EUC-KR UHC JOHAB ISO-2022-KR CP-949 KSC5601}} + {sa "SE & SW Asian" + {"Armenian" ARMSCII-8} + {"Georgian" GEOSTD8} + {"Thai" TIS-620 ISO-8859-11 CP-874 Windows-874 MacThai} + {"Turkish" CP-857 CP857 ISO-8859-9 MacTurkish CP-1254 Windows-1254} + {"Vietnamese" TCVN VISCII VPS CP-1258 Windows-1258} + {"Hindi" MacDevanagari} + {"Gujarati" MacGujarati} + {"Gurmukhi" MacGurmukhi}} + {me "Middle Eastern" + {"Arabic" ISO-8859-6 Windows-1256 CP-1256 CP-864 MacArabic} + {"Farsi" MacFarsi} + {"Hebrew" ISO-8859-8-I Windows-1255 CP-1255 ISO-8859-8 CP-862 MacHebrew}} + {mi "Misc" + {"7-bit" ASCII} + {"16-bit" Unicode} + {"Legacy" CP-863 EBCDIC} + {"Symbol" Symbol Dingbats MacDingbats MacCentEuro}} +} + +proc build_encoding_table {} { + global encoding_aliases encoding_lookup_table + + # Prepare the lookup list; cannot use lsort -nocase because + # of compatibility issues with older Tcl (e.g. in msysgit) + set names [list] + foreach item [encoding names] { + lappend names [list [string tolower $item] $item] + } + set names [lsort -ascii -index 0 $names] + # neither can we use lsearch -index + set lnames [list] + foreach item $names { + lappend lnames [lindex $item 0] + } + + foreach grp $encoding_aliases { + set target {} + foreach item $grp { + set i [lsearch -sorted -ascii $lnames \ + [string tolower $item]] + if {$i >= 0} { + set target [lindex $names $i 1] + break + } + } + if {$target eq {}} continue + foreach item $grp { + set encoding_lookup_table([string tolower $item]) $target + } + } + + foreach item $names { + set encoding_lookup_table([lindex $item 0]) [lindex $item 1] + } +} + proc tcl_encoding {enc} { - global encoding_aliases - set names [encoding names] - set lcnames [string tolower $names] - set enc [string tolower $enc] - set i [lsearch -exact $lcnames $enc] - if {$i < 0} { - # look for "isonnn" instead of "iso-nnn" or "iso_nnn" - if {[regsub {^iso[-_]} $enc iso encx]} { - set i [lsearch -exact $lcnames $encx] + global encoding_lookup_table + if {$enc eq {}} { + return {} + } + if {![info exists encoding_lookup_table]} { + build_encoding_table + } + set enc [string tolower $enc] + if {![info exists encoding_lookup_table($enc)]} { + # look for "isonnn" instead of "iso-nnn" or "iso_nnn" + if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} { + set enc $encx + } + } + if {[info exists encoding_lookup_table($enc)]} { + return $encoding_lookup_table($enc) + } else { + return {} + } +} + +proc force_path_encoding {path enc} { + global path_encoding_overrides last_encoding_override + + set enc [tcl_encoding $enc] + if {$enc eq {}} { + catch { unset last_encoding_override } + catch { unset path_encoding_overrides($path) } + } else { + set last_encoding_override $enc + if {$path ne {}} { + set path_encoding_overrides($path) $enc + } + } +} + +proc get_path_encoding {path} { + global path_encoding_overrides last_encoding_override + + if {[info exists last_encoding_override]} { + set tcl_enc $last_encoding_override + } else { + set tcl_enc [tcl_encoding [get_config gui.encoding]] } - } - if {$i < 0} { - foreach l $encoding_aliases { - set ll [string tolower $l] - if {[lsearch -exact $ll $enc] < 0} continue - # look through the aliases for one that tcl knows about - foreach e $ll { - set i [lsearch -exact $lcnames $e] - if {$i < 0} { - if {[regsub {^iso[-_]} $e iso ex]} { - set i [lsearch -exact $lcnames $ex] - } + if {$tcl_enc eq {}} { + set tcl_enc [encoding system] + } + if {$path ne {}} { + if {[info exists path_encoding_overrides($path)]} { + set enc2 $path_encoding_overrides($path) + } else { + set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]] + } + if {$enc2 ne {}} { + set tcl_enc $enc2 + } + } + return $tcl_enc +} + +proc build_encoding_submenu {parent grp cmd} { + global used_encodings + + set mid [lindex $grp 0] + set gname [mc [lindex $grp 1]] + + set smenu {} + foreach subset [lrange $grp 2 end] { + set name [mc [lindex $subset 0]] + + foreach enc [lrange $subset 1 end] { + set tcl_enc [tcl_encoding $enc] + if {$tcl_enc eq {}} continue + + if {$smenu eq {}} { + if {$mid eq {}} { + set smenu $parent + } else { + set smenu "$parent.$mid" + menu $smenu + $parent add cascade \ + -label $gname \ + -menu $smenu + } + } + + if {$name ne {}} { + set lbl "$name ($enc)" + } else { + set lbl $enc + } + $smenu add command \ + -label $lbl \ + -command [concat $cmd [list $tcl_enc]] + + lappend used_encodings $tcl_enc + } + } +} + +proc popup_btn_menu {m b} { + tk_popup $m [winfo pointerx $b] [winfo pointery $b] +} + +proc build_encoding_menu {emenu cmd {nodef 0}} { + $emenu configure -postcommand \ + [list do_build_encoding_menu $emenu $cmd $nodef] +} + +proc do_build_encoding_menu {emenu cmd {nodef 0}} { + global used_encodings encoding_groups + + $emenu configure -postcommand {} + + if {!$nodef} { + $emenu add command \ + -label [mc "Default"] \ + -command [concat $cmd [list {}]] + } + set sysenc [encoding system] + $emenu add command \ + -label [mc "System (%s)" $sysenc] \ + -command [concat $cmd [list $sysenc]] + + # Main encoding tree + set used_encodings [list identity] + $emenu add separator + foreach grp $encoding_groups { + build_encoding_submenu $emenu $grp $cmd + } + + # Add unclassified encodings + set unused_grp [list [mc Other]] + foreach enc [encoding names] { + if {[lsearch -exact $used_encodings $enc] < 0} { + lappend unused_grp $enc } - if {$i >= 0} break - } - break } - } - if {$i >= 0} { - return [lindex $names $i] - } - return {} + build_encoding_submenu $emenu [list other [mc Other] $unused_grp] $cmd } diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl index 79c58bc7bc..6ab5701d93 100644 --- a/git-gui/lib/mergetool.tcl +++ b/git-gui/lib/mergetool.tcl @@ -5,24 +5,51 @@ proc merge_resolve_one {stage} { global current_diff_path switch -- $stage { - 1 { set target [mc "the base version"] } - 2 { set target [mc "this branch"] } - 3 { set target [mc "the other branch"] } + 1 { set targetquestion [mc "Force resolution to the base version?"] } + 2 { set targetquestion [mc "Force resolution to this branch?"] } + 3 { set targetquestion [mc "Force resolution to the other branch?"] } } - set op_question [mc "Force resolution to %s? -Note that the diff shows only conflicting changes. + set op_question [strcat $targetquestion "\n" \ +[mc "Note that the diff shows only conflicting changes. %s will be overwritten. This operation can be undone only by restarting the merge." \ - $target [short_path $current_diff_path]] + [short_path $current_diff_path]]] if {[ask_popup $op_question] eq {yes}} { merge_load_stages $current_diff_path [list merge_force_stage $stage] } } +proc merge_stage_workdir {path w lno} { + global current_diff_path diff_active + + if {$diff_active} return + + if {$path ne $current_diff_path} { + show_diff $path $w $lno {} [list do_merge_stage_workdir $path] + } else { + do_merge_stage_workdir $path + } +} + +proc do_merge_stage_workdir {path} { + global current_diff_path is_conflict_diff + + if {$path ne $current_diff_path} return; + + if {$is_conflict_diff} { + if {[ask_popup [mc "File %s seems to have unresolved conflicts, still stage?" \ + [short_path $path]]] ne {yes}} { + return + } + } + + merge_add_resolution $path +} + proc merge_add_resolution {path} { global current_diff_path ui_workdir diff --git a/git-gui/lib/option.tcl b/git-gui/lib/option.tcl index 9b865f6a75..c80c939878 100644 --- a/git-gui/lib/option.tcl +++ b/git-gui/lib/option.tcl @@ -1,6 +1,28 @@ # git-gui options editor # Copyright (C) 2006, 2007 Shawn Pearce +proc config_check_encodings {} { + global repo_config_new global_config_new + + set enc $global_config_new(gui.encoding) + if {$enc eq {}} { + set global_config_new(gui.encoding) [encoding system] + } elseif {[tcl_encoding $enc] eq {}} { + error_popup [mc "Invalid global encoding '%s'" $enc] + return 0 + } + + set enc $repo_config_new(gui.encoding) + if {$enc eq {}} { + set repo_config_new(gui.encoding) [encoding system] + } elseif {[tcl_encoding $enc] eq {}} { + error_popup [mc "Invalid repo encoding '%s'" $enc] + return 0 + } + + return 1 +} + proc save_config {} { global default_config font_descs global repo_config global_config @@ -130,6 +152,7 @@ proc do_options {} { {i-1..99 gui.diffcontext {mc "Number of Diff Context Lines"}} {i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}} {t gui.newbranchtemplate {mc "New Branch Name Template"}} + {c gui.encoding {mc "Default File Contents Encoding"}} } { set type [lindex $option 0] set name [lindex $option 1] @@ -159,6 +182,7 @@ proc do_options {} { pack $w.$f.$optid.v -side right -anchor e -padx 5 pack $w.$f.$optid -side top -anchor w -fill x } + c - t { frame $w.$f.$optid label $w.$f.$optid.l -text "$text:" @@ -171,6 +195,16 @@ proc do_options {} { pack $w.$f.$optid.v -side left -anchor w \ -fill x -expand 1 \ -padx 5 + if {$type eq {c}} { + menu $w.$f.$optid.m + build_encoding_menu $w.$f.$optid.m \ + [list set ${f}_config_new($name)] 1 + button $w.$f.$optid.b \ + -text [mc "Change"] \ + -command [list popup_btn_menu \ + $w.$f.$optid.m $w.$f.$optid.b] + pack $w.$f.$optid.b -side left -anchor w + } pack $w.$f.$optid -side top -anchor w -fill x } } @@ -275,6 +309,7 @@ proc do_restore_defaults {} { } proc do_save_config {w} { + if {![config_check_encodings]} return if {[catch {save_config} err]} { error_popup [strcat [mc "Failed to completely save options:"] "\n\n$err"] } diff --git a/git-gui/po/de.po b/git-gui/po/de.po index fa43947ad0..793cca1e79 100644 --- a/git-gui/po/de.po +++ b/git-gui/po/de.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: git-gui\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-08-02 08:58+0200\n" -"PO-Revision-Date: 2008-08-02 09:09+0200\n" +"POT-Creation-Date: 2008-09-13 10:20+0200\n" +"PO-Revision-Date: 2008-09-13 10:24+0200\n" "Last-Translator: Christian Stimming <stimming@tuhh.de>\n" "Language-Team: German\n" "MIME-Version: 1.0\n" @@ -110,7 +110,15 @@ msgstr "Teilweise bereitgestellt zum Eintragen" msgid "Staged for commit, missing" msgstr "Bereitgestellt zum Eintragen, fehlend" -#: git-gui.sh:1597 +#: git-gui.sh:1658 +msgid "File type changed, not staged" +msgstr "Dateityp geändert, nicht bereitgestellt" + +#: git-gui.sh:1659 +msgid "File type changed, staged" +msgstr "Dateityp geändert, bereitgestellt" + +#: git-gui.sh:1661 msgid "Untracked, not staged" msgstr "Nicht unter Versionskontrolle, nicht bereitgestellt" @@ -396,15 +404,7 @@ msgstr "Alle kopieren" msgid "File:" msgstr "Datei:" -#: git-gui.sh:2589 -msgid "Apply/Reverse Hunk" -msgstr "Kontext anwenden/umkehren" - -#: git-gui.sh:2696 -msgid "Apply/Reverse Line" -msgstr "Zeile anwenden/umkehren" - -#: git-gui.sh:2711 +#: git-gui.sh:2834 msgid "Refresh" msgstr "Aktualisieren" @@ -416,7 +416,35 @@ msgstr "Schriftgröße verkleinern" msgid "Increase Font Size" msgstr "Schriftgröße vergrößern" -#: git-gui.sh:2646 +#: git-gui.sh:2870 +msgid "Apply/Reverse Hunk" +msgstr "Kontext anwenden/umkehren" + +#: git-gui.sh:2875 +msgid "Apply/Reverse Line" +msgstr "Zeile anwenden/umkehren" + +#: git-gui.sh:2885 +msgid "Run Merge Tool" +msgstr "Zusammenführungswerkzeug" + +#: git-gui.sh:2890 +msgid "Use Remote Version" +msgstr "Entfernte Version benutzen" + +#: git-gui.sh:2894 +msgid "Use Local Version" +msgstr "Lokale Version benutzen" + +#: git-gui.sh:2898 +msgid "Revert To Base" +msgstr "Ursprüngliche Version benutzen" + +#: git-gui.sh:2906 +msgid "Stage Working Copy" +msgstr "Arbeitskopie bereitstellen" + +#: git-gui.sh:2925 msgid "Unstage Hunk From Commit" msgstr "Kontext aus Bereitstellung herausnehmen" @@ -498,7 +526,15 @@ msgstr "Version kopieren" msgid "Do Full Copy Detection" msgstr "Volle Kopie-Erkennung" -#: lib/blame.tcl:388 +#: lib/blame.tcl:263 +msgid "Show History Context" +msgstr "Historien-Kontext anzeigen" + +#: lib/blame.tcl:266 +msgid "Blame Parent Commit" +msgstr "Elternversion annotieren" + +#: lib/blame.tcl:394 #, tcl-format msgid "Reading %s..." msgstr "%s lesen..." @@ -547,7 +583,19 @@ msgstr "Eintragender:" msgid "Original File:" msgstr "Ursprüngliche Datei:" -#: lib/blame.tcl:925 +#: lib/blame.tcl:990 +msgid "Cannot find parent commit:" +msgstr "Elternversion kann nicht gefunden werden:" + +#: lib/blame.tcl:1001 +msgid "Unable to display parent" +msgstr "Elternversion kann nicht angezeigt werden" + +#: lib/blame.tcl:1002 lib/diff.tcl:191 +msgid "Error loading diff:" +msgstr "Fehler beim Laden des Vergleichs:" + +#: lib/blame.tcl:1142 msgid "Originally By:" msgstr "Ursprünglich von:" @@ -1494,11 +1542,7 @@ msgstr "Git-Projektarchiv (Unterprojekt)" msgid "* Binary file (not showing content)." msgstr "* Binärdatei (Inhalt wird nicht angezeigt)" -#: lib/diff.tcl:185 -msgid "Error loading diff:" -msgstr "Fehler beim Laden des Vergleichs:" - -#: lib/diff.tcl:303 +#: lib/diff.tcl:313 msgid "Failed to unstage selected hunk." msgstr "" "Fehler beim Herausnehmen des gewählten Kontexts aus der Bereitstellung." @@ -1586,6 +1630,15 @@ msgstr "" msgid "Do Nothing" msgstr "Nichts tun" +#: lib/index.tcl:419 +msgid "Reverting selected files" +msgstr "Änderungen in gewählten Dateien verwerfen" + +#: lib/index.tcl:423 +#, tcl-format +msgid "Reverting %s" +msgstr "Änderungen in %s verwerfen" + #: lib/merge.tcl:13 msgid "" "Cannot merge while amending.\n" @@ -1730,6 +1783,96 @@ msgstr "Abbruch fehlgeschlagen." msgid "Abort completed. Ready." msgstr "Abbruch durchgeführt. Bereit." +#: lib/mergetool.tcl:14 +msgid "Force resolution to the base version?" +msgstr "Konflikt durch Basisversion ersetzen?" + +#: lib/mergetool.tcl:15 +msgid "Force resolution to this branch?" +msgstr "Konflikt durch diesen Zweig ersetzen?" + +#: lib/mergetool.tcl:16 +msgid "Force resolution to the other branch?" +msgstr "Konflikt durch anderen Zweig ersetzen?" + +#: lib/mergetool.tcl:20 +#, tcl-format +msgid "" +"Note that the diff shows only conflicting changes.\n" +"\n" +"%s will be overwritten.\n" +"\n" +"This operation can be undone only by restarting the merge." +msgstr "" +"Hinweis: Der Vergleich zeigt nur konfliktverursachende Änderungen an.\n" +"\n" +"»%s« wird überschrieben.\n" +"\n" +"Diese Operation kann nur rückgängig gemacht werden, wenn die\n" +"Zusammenführung erneut gestartet wird." + +#: lib/mergetool.tcl:32 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Auflösung hinzugefügt für %s" + +#: lib/mergetool.tcl:119 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Konflikte durch gelöschte Dateien oder symbolische Links können nicht durch " +"das Zusamenführungswerkzeug gelöst werden." + +#: lib/mergetool.tcl:124 +msgid "Conflict file does not exist" +msgstr "Konflikt-Datei existiert nicht" + +#: lib/mergetool.tcl:236 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Kein GUI Zusammenführungswerkzeug: »%s«" + +#: lib/mergetool.tcl:240 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Unbekanntes Zusammenführungswerkzeug: »%s«" + +#: lib/mergetool.tcl:275 +msgid "Merge tool is already running, terminate it?" +msgstr "Zusammenführungswerkzeug läuft bereits. Soll es abgebrochen werden?" + +#: lib/mergetool.tcl:295 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Fehler beim Abrufen der Dateiversionen:\n" +"%s" + +#: lib/mergetool.tcl:315 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Zusammenführungswerkzeug konnte nicht gestartet werden:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:319 +msgid "Running merge tool..." +msgstr "Zusammenführungswerkzeug starten..." + +#: lib/mergetool.tcl:347 lib/mergetool.tcl:363 +msgid "Merge tool failed." +msgstr "Zusammenführungswerkzeug fehlgeschlagen." + +#: lib/mergetool.tcl:353 +#, tcl-format +msgid "File %s unchanged, still accept as resolved?" +msgstr "Datei »%s« unverändert. Trotzdem Konflikt als gelöst akzeptieren?" + #: lib/option.tcl:95 msgid "Restore Defaults" msgstr "Voreinstellungen wiederherstellen" @@ -1767,7 +1910,11 @@ msgstr "Ausführlichkeit der Zusammenführen-Meldungen" msgid "Show Diffstat After Merge" msgstr "Vergleichsstatistik nach Zusammenführen anzeigen" -#: lib/option.tcl:123 +#: lib/option.tcl:122 +msgid "Use Merge Tool" +msgstr "Zusammenführungswerkzeug" + +#: lib/option.tcl:124 msgid "Trust File Modification Timestamps" msgstr "Auf Dateiänderungsdatum verlassen" @@ -1788,6 +1935,10 @@ msgid "Minimum Letters To Blame Copy On" msgstr "Mindestzahl Zeichen für Kopie-Annotieren" #: lib/option.tcl:128 +msgid "Blame History Context Radius (days)" +msgstr "Anzahl Tage für Historien-Kontext" + +#: lib/option.tcl:129 msgid "Number of Diff Context Lines" msgstr "Anzahl der Kontextzeilen beim Vergleich" diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 929d681c47..edb6ec6ed0 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -284,7 +284,7 @@ do_next () { pick_one $sha1 || die_with_patch $sha1 "Could not apply $sha1... $rest" make_patch $sha1 - : > "$DOTEST"/amend + git rev-parse --verify HEAD > "$DOTEST"/amend warn "Stopped at $sha1... $rest" warn "You can amend the commit now, with" warn @@ -427,14 +427,22 @@ do else . "$DOTEST"/author-script || die "Cannot find the author identity" + amend= if test -f "$DOTEST"/amend then + amend=$(git rev-parse --verify HEAD) + test "$amend" = $(cat "$DOTEST"/amend) || + die "\ +You have uncommitted changes in your working tree. Please, commit them +first and then run 'git rebase --continue' again." git reset --soft HEAD^ || die "Cannot rewind the HEAD" fi export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE && - git commit --no-verify -F "$DOTEST"/message -e || - die "Could not commit staged changes." + git commit --no-verify -F "$DOTEST"/message -e || { + test -n "$amend" && git reset --soft $amend + die "Could not commit staged changes." + } fi require_clean_work_tree diff --git a/git-repack.sh b/git-repack.sh index 683960b04d..d39eb6cea6 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -10,7 +10,7 @@ git repack [options] a pack everything in a single pack A same as -a, and turn unreachable objects loose d remove redundant packs, and run git-prune-packed -f pass --no-reuse-delta to git-pack-objects +f pass --no-reuse-object to git-pack-objects n do not run git-update-server-info q,quiet be quiet l pass --local to git-pack-objects diff --git a/git-stash.sh b/git-stash.sh index d799c76378..6bd2572f77 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -144,7 +144,14 @@ show_stash () { then flags=--stat fi - s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") + + if test $# = 0 + then + set x "$ref_stash@{0}" + shift + fi + + s=$(git rev-parse --revs-only --no-flags "$@") w_commit=$(git rev-parse --verify "$s") && b_commit=$(git rev-parse --verify "$s^") && @@ -163,13 +170,19 @@ apply_stash () { shift esac + if test $# = 0 + then + set x "$ref_stash@{0}" + shift + fi + # current index state c_tree=$(git write-tree) || die 'Cannot apply a stash in the middle of a merge' # stash records the work tree, and is a merge between the # base commit (first parent) and the index tree (second parent). - s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") && + s=$(git rev-parse --revs-only --no-flags "$@") && w_tree=$(git rev-parse --verify "$s:") && b_tree=$(git rev-parse --verify "$s^1:") && i_tree=$(git rev-parse --verify "$s^2:") || diff --git a/git-submodule.sh b/git-submodule.sh index 1c39b593a6..92be0feb58 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -634,6 +634,14 @@ cmd_sync() do name=$(module_name "$path") url=$(git config -f .gitmodules --get submodule."$name".url) + + # Possibly a url relative to parent + case "$url" in + ./*|../*) + url=$(resolve_relative_url "$url") || exit + ;; + esac + if test -e "$path"/.git then ( diff --git a/git-svn.perl b/git-svn.perl index ecacf74c22..80a5728371 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2626,9 +2626,9 @@ sub rebuild_from_rev_db { sub rebuild { my ($self) = @_; my $map_path = $self->map_path; - return if (-e $map_path && ! -z $map_path); + my $partial = (-e $map_path && ! -z $map_path); return unless ::verify_ref($self->refname.'^0'); - if ($self->use_svm_props || $self->no_metadata) { + if (!$partial && ($self->use_svm_props || $self->no_metadata)) { my $rev_db = $self->rev_db_path; $self->rebuild_from_rev_db($rev_db); if ($self->use_svm_props) { @@ -2638,10 +2638,13 @@ sub rebuild { $self->unlink_rev_db_symlink; return; } - print "Rebuilding $map_path ...\n"; + print "Rebuilding $map_path ...\n" if (!$partial); + my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) : + (undef, undef)); my ($log, $ctx) = command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/, - $self->refname, '--'); + ($head ? "$head.." : "") . $self->refname, + '--'); my $metadata_url = $self->metadata_url; remove_username($metadata_url); my $svn_uuid = $self->ra_uuid; @@ -2664,12 +2667,17 @@ sub rebuild { ($metadata_url && $url && ($url ne $metadata_url))) { next; } + if ($partial && $head) { + print "Partial-rebuilding $map_path ...\n"; + print "Currently at $base_rev = $head\n"; + $head = undef; + } $self->rev_map_set($rev, $c); print "r$rev = $c\n"; } command_close_pipe($log, $ctx); - print "Done rebuilding $map_path\n"; + print "Done rebuilding $map_path\n" if (!$partial || !$head); my $rev_db_path = $self->rev_db_path; if (-f $self->rev_db_path) { unlink $self->rev_db_path or croak "unlink: $!"; @@ -2809,6 +2817,12 @@ sub rev_map_set { sub rev_map_max { my ($self, $want_commit) = @_; $self->rebuild; + my ($r, $c) = $self->rev_map_max_norebuild($want_commit); + $want_commit ? ($r, $c) : $r; +} + +sub rev_map_max_norebuild { + my ($self, $want_commit) = @_; my $map_path = $self->map_path; stat $map_path or return $want_commit ? (0, undef) : 0; sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; @@ -3304,7 +3318,7 @@ sub close_file { my $out = syswrite($tmp_fh, $str, $res); defined($out) && $out == $res or croak("write ", - $tmp_fh->filename, + Git::temp_path($tmp_fh), ": $!\n"); } defined $res or croak $!; @@ -3315,7 +3329,7 @@ sub close_file { } $hash = $::_repository->hash_and_insert_object( - $fh->filename); + Git::temp_path($fh)); $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n"; Git::temp_release($fb->{base}, 1); @@ -4010,20 +4024,19 @@ sub gs_do_switch { my $old_url = $full_url; $full_url .= '/' . escape_uri_only($path) if length $path; my ($ra, $reparented); - if ($old_url ne $full_url) { - if ($old_url !~ m#^svn(\+ssh)?://#) { - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, - $pool); - $self->{url} = $full_url; - $reparented = 1; - } else { - $_[0] = undef; - $self = undef; - $RA = undef; - $ra = Git::SVN::Ra->new($full_url); - $ra_invalid = 1; - } + + if ($old_url =~ m#^svn(\+ssh)?://#) { + $_[0] = undef; + $self = undef; + $RA = undef; + $ra = Git::SVN::Ra->new($full_url); + $ra_invalid = 1; + } elsif ($old_url ne $full_url) { + SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); + $self->{url} = $full_url; + $reparented = 1; } + $ra ||= $self; $url_b = escape_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); @@ -4425,7 +4438,7 @@ sub config_pager { sub run_pager { return unless -t *STDOUT && defined $pager; - pipe my $rfd, my $wfd or return; + pipe my ($rfd, $wfd) or return; defined(my $pid = fork) or ::fatal "Can't fork: $!"; if (!$pid) { open STDOUT, '>&', $wfd or diff --git a/git-web--browse.sh b/git-web--browse.sh index 384148a59f..78d236b77f 100755 --- a/git-web--browse.sh +++ b/git-web--browse.sh @@ -31,7 +31,7 @@ valid_custom_tool() valid_tool() { case "$1" in - firefox | iceweasel | konqueror | w3m | links | lynx | dillo | open) + firefox | iceweasel | konqueror | w3m | links | lynx | dillo | open | start) ;; # happy *) valid_custom_tool "$1" || return 1 @@ -114,6 +114,10 @@ if test -z "$browser" ; then if test -n "$SECURITYSESSIONID"; then browser_candidates="open $browser_candidates" fi + # /bin/start indicates MinGW + if test -n /bin/start; then + browser_candidates="start $browser_candidates" + fi for i in $browser_candidates; do init_browser_path $i @@ -157,7 +161,7 @@ case "$browser" in ;; esac ;; - w3m|links|lynx|open) + w3m|links|lynx|open|start) eval "$browser_path" "$@" ;; dillo) @@ -162,6 +162,8 @@ static int handle_alias(int *argcp, const char ***argv) alias_string + 1, alias_command); } count = split_cmdline(alias_string, &new_argv); + if (count < 0) + die("Bad alias.%s string", alias_command); option_count = handle_options(&new_argv, &count, &envchanged); if (envchanged) die("alias '%s' changes environment variables\n" @@ -365,7 +367,7 @@ static void handle_internal_command(int argc, const char **argv) if (sizeof(ext) > 1) { i = strlen(argv[0]) - strlen(ext); if (i > 0 && !strcmp(argv[0] + i, ext)) { - char *argv0 = strdup(argv[0]); + char *argv0 = xstrdup(argv[0]); argv[0] = cmd = argv0; argv0[i] = '\0'; } diff --git a/git.spec.in b/git.spec.in index c6492e5be2..6733b6f555 100644 --- a/git.spec.in +++ b/git.spec.in @@ -145,6 +145,7 @@ rm -rf $RPM_BUILD_ROOT %files cvs %defattr(-,root,root) %doc Documentation/*git-cvs*.txt +%{_bindir}/git-cvsserver %{_libexecdir}/git-core/*cvs* %{!?_without_docs: %{_mandir}/man1/*cvs*.1*} %{!?_without_docs: %doc Documentation/*git-cvs*.html } @@ -188,6 +189,9 @@ rm -rf $RPM_BUILD_ROOT # No files for you! %changelog +* Fri Sep 12 2008 Quy Tonthat <qtonthat@gmail.com> +- move git-cvsserver to bindir. + * Sun Jun 15 2008 Junio C Hamano <gitster@pobox.com> - Remove curl from Requires list. diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 29e21564c8..18e70a3663 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2123,7 +2123,7 @@ sub parse_commit_text { last; } } - if ($co{'title'} eq "") { + if (! defined $co{'title'} || $co{'title'} eq "") { $co{'title'} = $co{'title_short'} = '(no commit message)'; } # remove added spaces @@ -5498,7 +5498,11 @@ sub git_shortlog { } my $refs = git_get_references(); - my @commitlist = parse_commits($hash, 101, (100 * $page)); + my $commit_hash = $hash; + if (defined $hash_parent) { + $commit_hash = "$hash_parent..$hash"; + } + my @commitlist = parse_commits($commit_hash, 101, (100 * $page)); my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $#commitlist >= 100); my $next_link = ''; @@ -4,6 +4,43 @@ #include "diff.h" #include "revision.h" +/* Internal API */ + +/* + * Output the next line for a graph. + * This formats the next graph line into the specified strbuf. It is not + * terminated with a newline. + * + * Returns 1 if the line includes the current commit, and 0 otherwise. + * graph_next_line() will return 1 exactly once for each time + * graph_update() is called. + */ +static int graph_next_line(struct git_graph *graph, struct strbuf *sb); + +/* + * Output a padding line in the graph. + * This is similar to graph_next_line(). However, it is guaranteed to + * never print the current commit line. Instead, if the commit line is + * next, it will simply output a line of vertical padding, extending the + * branch lines downwards, but leaving them otherwise unchanged. + */ +static void graph_padding_line(struct git_graph *graph, struct strbuf *sb); + +/* + * Print a strbuf to stdout. If the graph is non-NULL, all lines but the + * first will be prefixed with the graph output. + * + * If the strbuf ends with a newline, the output will end after this + * newline. A new graph line will not be printed after the final newline. + * If the strbuf is empty, no output will be printed. + * + * Since the first line will not include the graph ouput, the caller is + * responsible for printing this line's graph (perhaps via + * graph_show_commit() or graph_show_oneline()) before calling + * graph_show_strbuf(). + */ +static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb); + /* * TODO: * - Add colors to the graph. @@ -180,14 +217,6 @@ struct git_graph *graph_init(struct rev_info *opt) return graph; } -void graph_release(struct git_graph *graph) -{ - free(graph->columns); - free(graph->new_columns); - free(graph->mapping); - free(graph); -} - static void graph_update_state(struct git_graph *graph, enum graph_state s) { graph->prev_state = graph->state; @@ -685,7 +714,7 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) strbuf_addch(sb, '*'); } -void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) +static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) { int seen_this = 0; int i, j; @@ -760,7 +789,7 @@ void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) graph_update_state(graph, GRAPH_COLLAPSING); } -void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb) +static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb) { int seen_this = 0; int i, j; @@ -801,7 +830,7 @@ void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb) graph_update_state(graph, GRAPH_COLLAPSING); } -void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb) +static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb) { int i; int *tmp_mapping; @@ -906,7 +935,7 @@ void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb) graph_update_state(graph, GRAPH_PADDING); } -int graph_next_line(struct git_graph *graph, struct strbuf *sb) +static int graph_next_line(struct git_graph *graph, struct strbuf *sb) { switch (graph->state) { case GRAPH_PADDING: @@ -933,7 +962,7 @@ int graph_next_line(struct git_graph *graph, struct strbuf *sb) return 0; } -void graph_padding_line(struct git_graph *graph, struct strbuf *sb) +static void graph_padding_line(struct git_graph *graph, struct strbuf *sb) { int i, j; @@ -1055,7 +1084,7 @@ int graph_show_remainder(struct git_graph *graph) } -void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb) +static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb) { char *p; @@ -11,11 +11,6 @@ struct git_graph; struct git_graph *graph_init(struct rev_info *opt); /* - * Destroy a struct git_graph and free associated memory. - */ -void graph_release(struct git_graph *graph); - -/* * Update a git_graph with a new commit. * This will cause the graph to begin outputting lines for the new commit * the next time graph_next_line() is called. @@ -27,26 +22,6 @@ void graph_release(struct git_graph *graph); void graph_update(struct git_graph *graph, struct commit *commit); /* - * Output the next line for a graph. - * This formats the next graph line into the specified strbuf. It is not - * terminated with a newline. - * - * Returns 1 if the line includes the current commit, and 0 otherwise. - * graph_next_line() will return 1 exactly once for each time - * graph_update() is called. - */ -int graph_next_line(struct git_graph *graph, struct strbuf *sb); - -/* - * Output a padding line in the graph. - * This is similar to graph_next_line(). However, it is guaranteed to - * never print the current commit line. Instead, if the commit line is - * next, it will simply output a line of vertical padding, extending the - * branch lines downwards, but leaving them otherwise unchanged. - */ -void graph_padding_line(struct git_graph *graph, struct strbuf *sb); - -/* * Determine if a graph has finished outputting lines for the current * commit. * @@ -90,21 +65,6 @@ void graph_show_padding(struct git_graph *graph); int graph_show_remainder(struct git_graph *graph); /* - * Print a strbuf to stdout. If the graph is non-NULL, all lines but the - * first will be prefixed with the graph output. - * - * If the strbuf ends with a newline, the output will end after this - * newline. A new graph line will not be printed after the final newline. - * If the strbuf is empty, no output will be printed. - * - * Since the first line will not include the graph ouput, the caller is - * responsible for printing this line's graph (perhaps via - * graph_show_commit() or graph_show_oneline()) before calling - * graph_show_strbuf(). - */ -void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb); - -/* * Print a commit message strbuf and the remainder of the graph to stdout. * * This is similar to graph_show_strbuf(), but it always prints the @@ -204,8 +204,8 @@ void load_command_list(const char *prefix, while (1) { if ((colon = strchr(path, PATH_SEP))) *colon = 0; - - list_commands_in_dir(other_cmds, path, prefix); + if (!exec_path || strcmp(path, exec_path)) + list_commands_in_dir(other_cmds, path, prefix); if (!colon) break; @@ -262,11 +262,15 @@ int is_in_cmdlist(struct cmdnames *c, const char *s) } static int autocorrect; +static struct cmdnames aliases; static int git_unknown_cmd_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "help.autocorrect")) autocorrect = git_config_int(var,value); + /* Also use aliases for command lookup */ + if (!prefixcmp(var, "alias.")) + add_cmdname(&aliases, var + 6, strlen(var + 6)); return git_default_config(var, value, cb); } @@ -280,6 +284,18 @@ static int levenshtein_compare(const void *p1, const void *p2) return l1 != l2 ? l1 - l2 : strcmp(s1, s2); } +static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) +{ + int i; + ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); + + for (i = 0; i < old->cnt; i++) + cmds->names[cmds->cnt++] = old->names[i]; + free(old->names); + old->cnt = 0; + old->names = NULL; +} + const char *help_unknown_cmd(const char *cmd) { int i, n, best_similarity = 0; @@ -287,17 +303,17 @@ const char *help_unknown_cmd(const char *cmd) memset(&main_cmds, 0, sizeof(main_cmds)); memset(&other_cmds, 0, sizeof(main_cmds)); + memset(&aliases, 0, sizeof(aliases)); git_config(git_unknown_cmd_config, NULL); load_command_list("git-", &main_cmds, &other_cmds); - ALLOC_GROW(main_cmds.names, main_cmds.cnt + other_cmds.cnt, - main_cmds.alloc); - memcpy(main_cmds.names + main_cmds.cnt, other_cmds.names, - other_cmds.cnt * sizeof(other_cmds.names[0])); - main_cmds.cnt += other_cmds.cnt; - free(other_cmds.names); + add_cmd_list(&main_cmds, &aliases); + add_cmd_list(&main_cmds, &other_cmds); + qsort(main_cmds.names, main_cmds.cnt, + sizeof(main_cmds.names), cmdname_compare); + uniq(&main_cmds); /* This reuses cmdname->len for similarity index */ for (i = 0; i < main_cmds.cnt; ++i) diff --git a/http-push.c b/http-push.c index 6805288857..c9dd9a1f64 100644 --- a/http-push.c +++ b/http-push.c @@ -2237,7 +2237,7 @@ int main(int argc, char **argv) no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); if (remote->url && remote->url[strlen(remote->url)-1] != '/') { - rewritten_url = malloc(strlen(remote->url)+2); + rewritten_url = xmalloc(strlen(remote->url)+2); strcpy(rewritten_url, remote->url); strcat(rewritten_url, "/"); remote->url = rewritten_url; @@ -165,7 +165,16 @@ static CURL* get_curl_handle(void) { CURL* result = curl_easy_init(); - curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify); + if (!curl_ssl_verify) { + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0); + } else { + /* Verify authenticity of the peer's certificate */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1); + /* The name in the cert must match whom we tried to connect */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2); + } + #if LIBCURL_VERSION_NUM >= 0x070907 curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif @@ -402,7 +411,7 @@ static struct fill_chain *fill_cfg = NULL; void add_fill_function(void *data, int (*fill)(void *)) { - struct fill_chain *new = malloc(sizeof(*new)); + struct fill_chain *new = xmalloc(sizeof(*new)); struct fill_chain **linkp = &fill_cfg; new->data = data; new->fill = fill; diff --git a/index-pack.c b/index-pack.c index a6e91fe3ba..530d820370 100644 --- a/index-pack.c +++ b/index-pack.c @@ -172,7 +172,7 @@ static char *open_pack_file(char *pack_name) if (!pack_name) { static char tmpfile[PATH_MAX]; snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_pack_XXXXXX", get_object_directory()); + "%s/pack/tmp_pack_XXXXXX", get_object_directory()); output_fd = xmkstemp(tmpfile); pack_name = xstrdup(tmpfile); } else diff --git a/log-tree.c b/log-tree.c index 30cd5bb228..2c1f3e673a 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,12 +1,48 @@ #include "cache.h" #include "diff.h" #include "commit.h" +#include "tag.h" #include "graph.h" #include "log-tree.h" #include "reflog-walk.h" +#include "refs.h" struct decoration name_decoration = { "object names" }; +static void add_name_decoration(const char *prefix, const char *name, struct object *obj) +{ + int plen = strlen(prefix); + int nlen = strlen(name); + struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen); + memcpy(res->name, prefix, plen); + memcpy(res->name + plen, name, nlen + 1); + res->next = add_decoration(&name_decoration, obj, res); +} + +static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data) +{ + struct object *obj = parse_object(sha1); + if (!obj) + return 0; + add_name_decoration("", refname, obj); + while (obj->type == OBJ_TAG) { + obj = ((struct tag *)obj)->tagged; + if (!obj) + break; + add_name_decoration("tag: ", refname, obj); + } + return 0; +} + +void load_ref_decorations(void) +{ + static int loaded; + if (!loaded) { + loaded = 1; + for_each_ref(add_ref_decoration, NULL); + } +} + static void show_parents(struct commit *commit, int abbrev) { struct commit_list *p; diff --git a/log-tree.h b/log-tree.h index 59ba4c48b7..3c8127bb7c 100644 --- a/log-tree.h +++ b/log-tree.h @@ -17,5 +17,6 @@ void log_write_email_headers(struct rev_info *opt, const char *name, const char **subject_p, const char **extra_headers_p, int *need_8bit_cte_p); +void load_ref_decorations(void); #endif @@ -41,7 +41,18 @@ extern int type_from_string(const char *str); extern unsigned int get_max_object_index(void); extern struct object *get_indexed_object(unsigned int); -/** Internal only **/ +/* + * This can be used to see if we have heard of the object before, but + * it can return "yes we have, and here is a half-initialised object" + * for an object that we haven't loaded/parsed yet. + * + * When parsing a commit to create an in-core commit object, its + * parents list holds commit objects that represent its parents, but + * they are expected to be lazily initialized and do not know what + * their trees or parents are yet. When this function returns such a + * half-initialised objects, the caller is expected to initialize them + * by calling parse_object() on them. + */ struct object *lookup_object(const unsigned char *sha1); extern void *create_object(const unsigned char *sha1, int type, void *obj); diff --git a/pack-write.c b/pack-write.c index 939ed56362..3621f1dd32 100644 --- a/pack-write.c +++ b/pack-write.c @@ -45,7 +45,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, if (!index_name) { static char tmpfile[PATH_MAX]; snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_idx_XXXXXX", get_object_directory()); + "%s/pack/tmp_idx_XXXXXX", get_object_directory()); fd = xmkstemp(tmpfile); index_name = xstrdup(tmpfile); } else { diff --git a/perl/Git.pm b/perl/Git.pm index 102e6a4ce3..6aab712e6a 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -58,7 +58,7 @@ require Exporter; command_bidi_pipe command_close_bidi_pipe version exec_path hash_object git_cmd_try remote_refs - temp_acquire temp_release temp_reset); + temp_acquire temp_release temp_reset temp_path); =head1 DESCRIPTION @@ -937,7 +937,7 @@ sub _close_cat_blob { { # %TEMP_* Lexical Context -my (%TEMP_LOCKS, %TEMP_FILES); +my (%TEMP_FILEMAP, %TEMP_FILES); =item temp_acquire ( NAME ) @@ -965,7 +965,7 @@ sub temp_acquire { my $temp_fd = _temp_cache($name); - $TEMP_LOCKS{$temp_fd} = 1; + $TEMP_FILES{$temp_fd}{locked} = 1; $temp_fd; } @@ -991,16 +991,16 @@ the same string. sub temp_release { my ($self, $temp_fd, $trunc) = _maybe_self(@_); - if (ref($temp_fd) ne 'File::Temp') { + if (exists $TEMP_FILEMAP{$temp_fd}) { $temp_fd = $TEMP_FILES{$temp_fd}; } - unless ($TEMP_LOCKS{$temp_fd}) { + unless ($TEMP_FILES{$temp_fd}{locked}) { carp "Attempt to release temp file '", $temp_fd, "' that has not been locked"; } temp_reset($temp_fd) if $trunc and $temp_fd->opened; - $TEMP_LOCKS{$temp_fd} = 0; + $TEMP_FILES{$temp_fd}{locked} = 0; undef; } @@ -1009,9 +1009,9 @@ sub _temp_cache { _verify_require(); - my $temp_fd = \$TEMP_FILES{$name}; + my $temp_fd = \$TEMP_FILEMAP{$name}; if (defined $$temp_fd and $$temp_fd->opened) { - if ($TEMP_LOCKS{$$temp_fd}) { + if ($TEMP_FILES{$$temp_fd}{locked}) { throw Error::Simple("Temp file with moniker '", $name, "' already in use"); } @@ -1021,12 +1021,13 @@ sub _temp_cache { carp "Temp file '", $name, "' was closed. Opening replacement."; } - $$temp_fd = File::Temp->new( - TEMPLATE => 'Git_XXXXXX', - DIR => File::Spec->tmpdir + my $fname; + ($$temp_fd, $fname) = File::Temp->tempfile( + 'Git_XXXXXX', UNLINK => 1 ) or throw Error::Simple("couldn't open new temp file"); $$temp_fd->autoflush; binmode $$temp_fd; + $TEMP_FILES{$$temp_fd}{fname} = $fname; } $$temp_fd; } @@ -1053,8 +1054,25 @@ sub temp_reset { or throw Error::Simple("expected file position to be reset"); } +=item temp_path ( NAME ) + +=item temp_path ( FILEHANDLE ) + +Returns the filename associated with the given tempfile. + +=cut + +sub temp_path { + my ($self, $temp_fd) = _maybe_self(@_); + + if (exists $TEMP_FILEMAP{$temp_fd}) { + $temp_fd = $TEMP_FILEMAP{$temp_fd}; + } + $TEMP_FILES{$temp_fd}{fname}; +} + sub END { - unlink values %TEMP_FILES if %TEMP_FILES; + unlink values %TEMP_FILEMAP if %TEMP_FILEMAP; } } # %TEMP_* Lexical Context @@ -5,6 +5,7 @@ #include "revision.h" #include "string-list.h" #include "mailmap.h" +#include "log-tree.h" static char *user_format; @@ -481,6 +482,23 @@ static void parse_commit_header(struct format_commit_context *context) context->commit_header_parsed = 1; } +static void format_decoration(struct strbuf *sb, const struct commit *commit) +{ + struct name_decoration *d; + const char *prefix = " ("; + + load_ref_decorations(); + d = lookup_decoration(&name_decoration, &commit->object); + while (d) { + strbuf_addstr(sb, prefix); + prefix = ", "; + strbuf_addstr(sb, d->name); + d = d->next; + } + if (prefix[0] == ',') + strbuf_addch(sb, ')'); +} + static size_t format_commit_item(struct strbuf *sb, const char *placeholder, void *context) { @@ -573,6 +591,9 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, ? '<' : '>'); return 1; + case 'd': + format_decoration(sb, commit); + return 1; } /* For the rest we have to parse the commit header. */ diff --git a/read-cache.c b/read-cache.c index 5150c1e14b..5b1b3ad03b 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1253,6 +1253,7 @@ int discard_index(struct index_state *istate) istate->cache_nr = 0; istate->cache_changed = 0; istate->timestamp = 0; + istate->name_hash_initialized = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); free(istate->alloc); @@ -390,6 +390,18 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re return retval; } +/* + * If the "reading" argument is set, this function finds out what _object_ + * the ref points at by "reading" the ref. The ref, if it is not symbolic, + * has to exist, and if it is symbolic, it has to point at an existing ref, + * because the "read" goes through the symref to the ref it points at. + * + * The access that is not "reading" may often be "writing", but does not + * have to; it can be merely checking _where it leads to_. If it is a + * prelude to "writing" to the ref, a write to a symref that points at + * yet-to-be-born ref will create the real ref pointed by the symref. + * reading=0 allows the caller to check where such a symref leads to. + */ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag) { int depth = MAXDEPTH; @@ -409,13 +421,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int * if (--depth < 0) return NULL; - /* Special case: non-existing file. - * Not having the refs/heads/new-branch is OK - * if we are writing into it, so is .git/HEAD - * that points at refs/heads/master still to be - * born. It is NOT OK if we are resolving for - * reading. - */ + /* Special case: non-existing file. */ if (lstat(path, &st) < 0) { struct ref_list *list = get_packed_refs(); while (list) { @@ -69,7 +69,7 @@ static const char *alias_url(const char *url) if (!longest) return url; - ret = malloc(rewrite[longest_i]->baselen + + ret = xmalloc(rewrite[longest_i]->baselen + (strlen(url) - longest->len) + 1); strcpy(ret, rewrite[longest_i]->base); strcpy(ret + rewrite[longest_i]->baselen, url + longest->len); @@ -152,7 +152,7 @@ static struct branch *make_branch(const char *name, int len) ret->name = xstrndup(name, len); else ret->name = xstrdup(name); - refname = malloc(strlen(name) + strlen("refs/heads/") + 1); + refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1); strcpy(refname, "refs/heads/"); strcpy(refname + strlen("refs/heads/"), ret->name); ret->refname = refname; @@ -455,7 +455,7 @@ static int verify_refname(char *name, int is_glob) * and dst pointers are always freeable pointers as well * as the refspec pointer itself. */ -void free_refspecs(struct refspec *refspec, int nr_refspec) +static void free_refspecs(struct refspec *refspec, int nr_refspec) { int i; @@ -613,7 +613,7 @@ struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) return parse_refspec_internal(nr_refspec, refspec, 1, 0); } -struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) +static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) { return parse_refspec_internal(nr_refspec, refspec, 0, 0); } @@ -783,7 +783,7 @@ struct ref *copy_ref_list(const struct ref *ref) return ret; } -void free_ref(struct ref *ref) +static void free_ref(struct ref *ref) { if (!ref) return; @@ -77,8 +77,6 @@ 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); -void free_refspecs(struct refspec *refspec, int nr_refspec); int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, const char **refspec, int all); diff --git a/revision.c b/revision.c index 499f0e0225..2f646deab0 100644 --- a/revision.c +++ b/revision.c @@ -1793,26 +1793,6 @@ static struct commit *get_revision_internal(struct rev_info *revs) return c; } - if (revs->reverse) { - int limit = -1; - - if (0 <= revs->max_count) { - limit = revs->max_count; - if (0 < revs->skip_count) - limit += revs->skip_count; - } - l = NULL; - while ((c = get_revision_1(revs))) { - commit_list_insert(c, &l); - if ((0 < limit) && !--limit) - break; - } - revs->commits = l; - revs->reverse = 0; - revs->max_count = -1; - c = NULL; - } - /* * Now pick up what they want to give us */ @@ -1885,7 +1865,23 @@ static struct commit *get_revision_internal(struct rev_info *revs) struct commit *get_revision(struct rev_info *revs) { - struct commit *c = get_revision_internal(revs); + struct commit *c; + struct commit_list *reversed; + + if (revs->reverse) { + reversed = NULL; + while ((c = get_revision_internal(revs))) { + commit_list_insert(c, &reversed); + } + revs->commits = reversed; + revs->reverse = 0; + revs->reverse_output_stage = 1; + } + + if (revs->reverse_output_stage) + return pop_commit(&revs->commits); + + c = get_revision_internal(revs); if (c && revs->graph) graph_update(revs->graph, c); return c; diff --git a/revision.h b/revision.h index fc23522b38..2fdb2dd0ff 100644 --- a/revision.h +++ b/revision.h @@ -54,6 +54,7 @@ struct rev_info { rewrite_parents:1, print_parents:1, reverse:1, + reverse_output_stage:1, cherry_pick:1, first_parent_only:1; diff --git a/sha1_file.c b/sha1_file.c index 12be17b5da..70ff904717 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -99,7 +99,11 @@ int safe_create_leading_directories(char *path) pos = strchr(pos, '/'); if (!pos) break; - *pos = 0; + while (*++pos == '/') + ; + if (!*pos) + break; + *--pos = '\0'; if (!stat(path, &st)) { /* path exists */ if (!S_ISDIR(st.st_mode)) { @@ -2145,7 +2149,9 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len, */ int move_temp_to_file(const char *tmpfile, const char *filename) { - int ret = link(tmpfile, filename); + int ret = 0; + if (link(tmpfile, filename)) + ret = errno; /* * Coda hack - coda doesn't like cross-directory links, diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index c526eedd62..67c431d4eb 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -138,3 +138,20 @@ close $wr or die $!; close $rd or die $!; EOF } + +require_svnserve () { + if test -z "$SVNSERVE_PORT" + then + say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' + test_done + exit + fi +} + +start_svnserve () { + svnserve --listen-port $SVNSERVE_PORT \ + --root "$rawsvnrepo" \ + --listen-once \ + --listen-host 127.0.0.1 & +} + diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh new file mode 100644 index 0000000000..e5330395fc --- /dev/null +++ b/t/t0024-crlf-archive.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +test_description='respect crlf in git archive' + +. ./test-lib.sh +UNZIP=${UNZIP:-unzip} + +test_expect_success setup ' + + git config core.autocrlf true + + printf "CRLF line ending\r\nAnd another\r\n" > sample && + git add sample && + + test_tick && + git commit -m Initial + +' + +test_expect_success 'tar archive' ' + + git archive --format=tar HEAD | + ( mkdir untarred && cd untarred && "$TAR" -xf - ) + + test_cmp sample untarred/sample + +' + +"$UNZIP" -v >/dev/null 2>&1 +if [ $? -eq 127 ]; then + echo "Skipping ZIP test, because unzip was not found" + test_done + exit +fi + +test_expect_success 'zip archive' ' + + git archive --format=zip HEAD >test.zip && + + ( mkdir unzipped && cd unzipped && unzip ../test.zip ) && + + test_cmp sample unzipped/sample + +' + +test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64567fb94d..11b82f43dd 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -741,4 +741,14 @@ test_expect_success 'symlinked configuration' ' ' +test_expect_success 'check split_cmdline return' " + git config alias.split-cmdline-fix 'echo \"' && + test_must_fail git split-cmdline-fix && + echo foo > foo && + git add foo && + git commit -m 'initial commit' && + git config branch.master.mergeoptions 'echo \"' && + test_must_fail git merge master + " + test_done diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 833d6cbcfc..18bcd9713d 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -57,4 +57,10 @@ test_expect_success 'last regexp must not be negated' ' test_must_fail git diff --no-index Beer.java Beer-correct.java ' +test_expect_success 'alternation in pattern' ' + git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$" + git diff --no-index Beer.java Beer-correct.java | + grep "^@@.*@@ public static void main(" +' + test_done diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 3a0ef8759c..b335c6b42d 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -272,7 +272,8 @@ test_expect_success \ test_expect_success \ 'make sure index-pack detects the SHA1 collision' \ - 'test_must_fail git index-pack -o bad.idx test-3.pack' + 'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg && + grep "SHA1 COLLISION FOUND" msg' test_expect_success \ 'honor pack.packSizeLimit' \ diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index de26c20327..9aae4965da 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -303,4 +303,24 @@ test_expect_success 'pushing nonexistent branch by mistake should not segv' ' ' +test_expect_success 'auto tag following fetches minimum' ' + + cd "$D" && + git clone .git follow && + git checkout HEAD^0 && + ( + for i in 1 2 3 4 5 6 7 + do + echo $i >>file && + git commit -m $i -a && + git tag -a -m $i excess-$i || exit 1 + done + ) && + git checkout master && + ( + cd follow && + git fetch + ) +' + test_done diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh new file mode 100755 index 0000000000..59fc2f06e0 --- /dev/null +++ b/t/t6013-rev-list-reverse-parents.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description='--reverse combines with --parents' + +. ./test-lib.sh + + +commit () { + test_tick && + echo $1 > foo && + git add foo && + git commit -m "$1" +} + +test_expect_success 'set up --reverse example' ' + commit one && + git tag root && + commit two && + git checkout -b side HEAD^ && + commit three && + git checkout master && + git merge -s ours side && + commit five + ' + +test_expect_success '--reverse --parents --full-history combines correctly' ' + git rev-list --parents --full-history master -- foo | + perl -e "print reverse <>" > expected && + git rev-list --reverse --parents --full-history master -- foo \ + > actual && + test_cmp actual expected + ' + +test_expect_success '--boundary does too' ' + git rev-list --boundary --parents --full-history master ^root -- foo | + perl -e "print reverse <>" > expected && + git rev-list --boundary --reverse --parents --full-history \ + master ^root -- foo > actual && + test_cmp actual expected + ' + +test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 36c9a6965f..85fa39cf0b 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -350,6 +350,120 @@ test_expect_success 'bisect does not create a "bisect" branch' ' git branch -D bisect ' +# This creates a "side" branch to test "siblings" cases. +# +# H1-H2-H3-H4-H5-H6-H7 <--other +# \ +# S5-S6-S7 <--side +# +test_expect_success 'side branch creation' ' + git bisect reset && + git checkout -b side $HASH4 && + add_line_into_file "5(side): first line on a side branch" hello2 && + SIDE_HASH5=$(git rev-parse --verify HEAD) && + add_line_into_file "6(side): second line on a side branch" hello2 && + SIDE_HASH6=$(git rev-parse --verify HEAD) && + add_line_into_file "7(side): third line on a side branch" hello2 && + SIDE_HASH7=$(git rev-parse --verify HEAD) +' + +test_expect_success 'good merge base when good and bad are siblings' ' + git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt && + grep "merge base must be tested" my_bisect_log.txt && + grep $HASH4 my_bisect_log.txt && + git bisect good > my_bisect_log.txt && + test_must_fail grep "merge base must be tested" my_bisect_log.txt && + grep $HASH6 my_bisect_log.txt && + git bisect reset +' +test_expect_success 'skipped merge base when good and bad are siblings' ' + git bisect start "$SIDE_HASH7" "$HASH7" > my_bisect_log.txt && + grep "merge base must be tested" my_bisect_log.txt && + grep $HASH4 my_bisect_log.txt && + git bisect skip > my_bisect_log.txt 2>&1 && + grep "Warning" my_bisect_log.txt && + grep $SIDE_HASH6 my_bisect_log.txt && + git bisect reset +' + +test_expect_success 'bad merge base when good and bad are siblings' ' + git bisect start "$HASH7" HEAD > my_bisect_log.txt && + grep "merge base must be tested" my_bisect_log.txt && + grep $HASH4 my_bisect_log.txt && + test_must_fail git bisect bad > my_bisect_log.txt 2>&1 && + grep "merge base $HASH4 is bad" my_bisect_log.txt && + grep "fixed between $HASH4 and \[$SIDE_HASH7\]" my_bisect_log.txt && + git bisect reset +' + +# This creates a few more commits (A and B) to test "siblings" cases +# when a good and a bad rev have many merge bases. +# +# We should have the following: +# +# H1-H2-H3-H4-H5-H6-H7 +# \ \ \ +# S5-A \ +# \ \ +# S6-S7----B +# +# And there A and B have 2 merge bases (S5 and H5) that should be +# reported by "git merge-base --all A B". +# +test_expect_success 'many merge bases creation' ' + git checkout "$SIDE_HASH5" && + git merge -m "merge HASH5 and SIDE_HASH5" "$HASH5" && + A_HASH=$(git rev-parse --verify HEAD) && + git checkout side && + git merge -m "merge HASH7 and SIDE_HASH7" "$HASH7" && + B_HASH=$(git rev-parse --verify HEAD) && + git merge-base --all "$A_HASH" "$B_HASH" > merge_bases.txt && + test $(wc -l < merge_bases.txt) = "2" && + grep "$HASH5" merge_bases.txt && + grep "$SIDE_HASH5" merge_bases.txt +' + +test_expect_success 'good merge bases when good and bad are siblings' ' + git bisect start "$B_HASH" "$A_HASH" > my_bisect_log.txt && + grep "merge base must be tested" my_bisect_log.txt && + git bisect good > my_bisect_log2.txt && + grep "merge base must be tested" my_bisect_log2.txt && + { + { + grep "$SIDE_HASH5" my_bisect_log.txt && + grep "$HASH5" my_bisect_log2.txt + } || { + grep "$SIDE_HASH5" my_bisect_log2.txt && + grep "$HASH5" my_bisect_log.txt + } + } && + git bisect reset +' + +check_trace() { + grep "$1" "$GIT_TRACE" | grep "\^$2" | grep "$3" >/dev/null +} + +test_expect_success 'optimized merge base checks' ' + GIT_TRACE="$(pwd)/trace.log" && + export GIT_TRACE && + git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt && + grep "merge base must be tested" my_bisect_log.txt && + grep "$HASH4" my_bisect_log.txt && + check_trace "rev-list" "$HASH7" "$SIDE_HASH7" && + git bisect good > my_bisect_log2.txt && + test -f ".git/BISECT_ANCESTORS_OK" && + test "$HASH6" = $(git rev-parse --verify HEAD) && + : > "$GIT_TRACE" && + git bisect bad > my_bisect_log3.txt && + test_must_fail check_trace "rev-list" "$HASH6" "$SIDE_HASH7" && + git bisect good "$A_HASH" > my_bisect_log4.txt && + grep "merge base must be tested" my_bisect_log4.txt && + test_must_fail test -f ".git/BISECT_ANCESTORS_OK" && + check_trace "rev-list" "$HASH6" "$A_HASH" && + unset GIT_TRACE +' + # # test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 26995b3cdd..8bfae44a83 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -262,6 +262,50 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do " done +cat >expected <<\EOF +master +testtag +EOF + +test_expect_success 'Check short refname format' ' + (git for-each-ref --format="%(refname:short)" refs/heads && + git for-each-ref --format="%(refname:short)" refs/tags) >actual && + test_cmp expected actual +' + +test_expect_success 'Check for invalid refname format' ' + test_must_fail git for-each-ref --format="%(refname:INVALID)" +' + +cat >expected <<\EOF +heads/master +master +EOF + +test_expect_success 'Check ambiguous head and tag refs' ' + git checkout -b newtag && + echo "Using $datestamp" > one && + git add one && + git commit -m "Branch" && + setdate_and_increment && + git tag -m "Tagging at $datestamp" master && + git for-each-ref --format "%(refname:short)" refs/heads/master refs/tags/master >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +heads/ambiguous +ambiguous +EOF + +test_expect_success 'Check ambiguous head and tag refs II' ' + git checkout master && + git tag ambiguous testtag^0 && + git branch ambiguous testtag^0 && + git for-each-ref --format "%(refname:short)" refs/heads/ambiguous refs/tags/ambiguous >actual && + test_cmp expected actual +' + test_expect_success 'an unusual tag with an incomplete line' ' git tag -m "bogo" bogo && diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 25181388f8..62d73f934a 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -391,4 +391,14 @@ test_expect_success 'checkout an unmerged path should fail' ' test_cmp sample file ' +test_expect_success 'failing checkout -b should not break working tree' ' + git reset --hard master && + git symbolic-ref HEAD refs/heads/master && + test_must_fail git checkout -b renamer side^ && + test $(git symbolic-ref HEAD) = refs/heads/master && + git diff --exit-code && + git diff --cached --exit-code + +' + test_done diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 469bff8873..63bfc6d8b3 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -141,7 +141,7 @@ EOF test_expect_success \ 'validate git rev-list output.' \ - 'diff current expected' + 'test_cmp expected current' test_expect_success 'partial commit that involves removal (1)' ' @@ -151,7 +151,7 @@ test_expect_success 'partial commit that involves removal (1)' ' git commit -m "Partial: add elif" elif && git diff-tree --name-status HEAD^ HEAD >current && echo "A elif" >expected && - diff expected current + test_cmp expected current ' @@ -160,7 +160,7 @@ test_expect_success 'partial commit that involves removal (2)' ' git commit -m "Partial: remove file" file && git diff-tree --name-status HEAD^ HEAD >current && echo "D file" >expected && - diff expected current + test_cmp expected current ' @@ -171,7 +171,7 @@ test_expect_success 'partial commit that involves removal (3)' ' git commit -m "Partial: modify elif" elif && git diff-tree --name-status HEAD^ HEAD >current && echo "M elif" >expected && - diff expected current + test_cmp expected current ' @@ -187,7 +187,7 @@ test_expect_success 'amend commit to fix author' ' expected && git commit --amend --author="$author" && git cat-file -p HEAD > current && - diff expected current + test_cmp expected current ' @@ -256,7 +256,7 @@ test_expect_success 'amend commit to fix author' ' expected && git commit --amend --author="$author" && git cat-file -p HEAD > current && - diff expected current + test_cmp expected current ' diff --git a/t/t7502-status.sh b/t/t7502-status.sh index c8e4c2e7b4..1905fb34cd 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -46,6 +46,7 @@ cat > expect << \EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -76,6 +77,7 @@ cat >expect <<EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -104,6 +106,7 @@ cat >expect <<EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -138,6 +141,7 @@ cat >expect <<EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -174,6 +178,7 @@ cat > expect << \EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: modified # @@ -204,6 +209,7 @@ cat > expect << \EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -267,6 +273,7 @@ cat >expect <<EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -297,6 +304,7 @@ cat >expect <<EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -326,6 +334,7 @@ cat >expect <<EOF # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # @@ -357,6 +366,7 @@ cat >expect <<EOF # # Changed but not updated: # (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) # # modified: dir1/modified # diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh index b47b7b9757..7e17eb490d 100755 --- a/t/t7603-merge-reduce-heads.sh +++ b/t/t7603-merge-reduce-heads.sh @@ -60,4 +60,57 @@ test_expect_success 'merge c1 with c2, c3, c4, c5' ' test -f c5.c ' +test_expect_success 'setup' ' + for i in A B C D E + do + echo $i > $i.c && + git add $i.c && + git commit -m $i && + git tag $i + done && + git reset --hard A && + for i in F G H I + do + echo $i > $i.c && + git add $i.c && + git commit -m $i && + git tag $i + done +' + +test_expect_success 'merge E and I' ' + git reset --hard A && + git merge E I +' + +test_expect_success 'verify merge result' ' + test $(git rev-parse HEAD^1) = $(git rev-parse E) && + test $(git rev-parse HEAD^2) = $(git rev-parse I) +' + +test_expect_success 'add conflicts' ' + git reset --hard E && + echo foo > file.c && + git add file.c && + git commit -m E2 && + git tag E2 && + git reset --hard I && + echo bar >file.c && + git add file.c && + git commit -m I2 && + git tag I2 +' + +test_expect_success 'merge E2 and I2, causing a conflict and resolve it' ' + git reset --hard A && + test_must_fail git merge E2 I2 && + echo baz > file.c && + git add file.c && + git commit -m "resolve conflict" +' + +test_expect_success 'verify merge result' ' + test $(git rev-parse HEAD^1) = $(git rev-parse E2) && + test $(git rev-parse HEAD^2) = $(git rev-parse I2) +' test_done diff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh index de9b6ed5ba..52a451dd57 100755 --- a/t/t7606-merge-custom.sh +++ b/t/t7606-merge-custom.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-merge +test_description='git merge Testing a custom strategy.' diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 5ade88d479..9b238c329b 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -20,7 +20,7 @@ esac say 'define NO_SVN_TESTS to skip git svn tests' test_expect_success \ - 'initialize git-svn' ' + 'initialize git svn' ' mkdir import && cd import && echo foo > foo && @@ -31,7 +31,7 @@ test_expect_success \ echo "zzz" > bar/zzz && echo "#!/bin/sh" > exec.sh && chmod +x exec.sh && - svn import -m "import for git-svn" . "$svnrepo" >/dev/null && + svn import -m "import for git svn" . "$svnrepo" >/dev/null && cd .. && rm -rf import && git svn init "$svnrepo"' diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh index 0d48b2619b..1e31d6ea72 100755 --- a/t/t9101-git-svn-props.sh +++ b/t/t9101-git-svn-props.sh @@ -26,29 +26,29 @@ cd import EOF printf "Hello\r\nWorld\r\n" > crlf - a_crlf=`git-hash-object -w crlf` + a_crlf=`git hash-object -w crlf` printf "Hello\rWorld\r" > cr - a_cr=`git-hash-object -w cr` + a_cr=`git hash-object -w cr` printf "Hello\nWorld\n" > lf - a_lf=`git-hash-object -w lf` + a_lf=`git hash-object -w lf` printf "Hello\r\nWorld" > ne_crlf - a_ne_crlf=`git-hash-object -w ne_crlf` + a_ne_crlf=`git hash-object -w ne_crlf` printf "Hello\nWorld" > ne_lf - a_ne_lf=`git-hash-object -w ne_lf` + a_ne_lf=`git hash-object -w ne_lf` printf "Hello\rWorld" > ne_cr - a_ne_cr=`git-hash-object -w ne_cr` + a_ne_cr=`git hash-object -w ne_cr` touch empty - a_empty=`git-hash-object -w empty` + a_empty=`git hash-object -w empty` printf "\n" > empty_lf - a_empty_lf=`git-hash-object -w empty_lf` + a_empty_lf=`git hash-object -w empty_lf` printf "\r" > empty_cr - a_empty_cr=`git-hash-object -w empty_cr` + a_empty_cr=`git hash-object -w empty_cr` printf "\r\n" > empty_crlf - a_empty_crlf=`git-hash-object -w empty_crlf` + a_empty_crlf=`git hash-object -w empty_crlf` - svn import --no-auto-props -m 'import for git-svn' . "$svnrepo" >/dev/null + svn import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null cd .. rm -rf import @@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \ svn commit -m "Propset Id" && cd ..' -test_expect_success 'initialize git-svn' 'git svn init "$svnrepo"' +test_expect_success 'initialize git svn' 'git svn init "$svnrepo"' test_expect_success 'fetch revisions from svn' 'git svn fetch' name='test svn:keywords ignoring' @@ -103,8 +103,8 @@ done cd test_wc printf '$Id$\rHello\rWorld\r' > cr printf '$Id$\rHello\rWorld' > ne_cr - a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git-hash-object --stdin` - a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git-hash-object --stdin` + a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin` + a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin` test_expect_success 'Set CRLF on cr files' \ 'svn propset svn:eol-style CRLF cr && svn propset svn:eol-style CRLF ne_cr && @@ -115,8 +115,8 @@ cd .. test_expect_success 'fetch and pull latest from svn' \ 'git svn fetch && git pull . ${remotes_git_svn}' -b_cr="`git-hash-object cr`" -b_ne_cr="`git-hash-object ne_cr`" +b_cr="`git hash-object cr`" +b_ne_cr="`git hash-object ne_cr`" test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'" test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'" diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh index ea5a385cad..e223218015 100755 --- a/t/t9102-git-svn-deep-rmdir.sh +++ b/t/t9102-git-svn-deep-rmdir.sh @@ -9,11 +9,11 @@ test_expect_success 'initialize repo' ' mkdir -p deeply/nested/directory/number/2 && echo foo > deeply/nested/directory/number/1/file && echo foo > deeply/nested/directory/number/2/another && - svn import -m "import for git-svn" . "$svnrepo" && + svn import -m "import for git svn" . "$svnrepo" && cd .. ' -test_expect_success 'mirror via git-svn' ' +test_expect_success 'mirror via git svn' ' git svn init "$svnrepo" && git svn fetch && git checkout -f -b test-rmdir ${remotes_git_svn} diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh index 91b88cf2e2..a61d6716d2 100755 --- a/t/t9112-git-svn-md5less-file.sh +++ b/t/t9112-git-svn-md5less-file.sh @@ -42,6 +42,6 @@ EOF test_expect_success 'load svn dumpfile' 'svnadmin load "$rawsvnrepo" < dumpfile.svn' -test_expect_success 'initialize git-svn' 'git svn init "$svnrepo"' +test_expect_success 'initialize git svn' 'git svn init "$svnrepo"' test_expect_success 'fetch revisions from svn' 'git svn fetch' test_done diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh index 250c53022b..e9b6128b3f 100755 --- a/t/t9113-git-svn-dcommit-new-file.sh +++ b/t/t9113-git-svn-dcommit-new-file.sh @@ -12,19 +12,7 @@ test_description='git svn dcommit new files over svn:// test' . ./lib-git-svn.sh -if test -z "$SVNSERVE_PORT" -then - say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' - test_done - exit -fi - -start_svnserve () { - svnserve --listen-port $SVNSERVE_PORT \ - --root "$rawsvnrepo" \ - --listen-once \ - --listen-host 127.0.0.1 & -} +require_svnserve test_expect_success 'start tracking an empty repo' ' svn mkdir -m "empty dir" "$svnrepo"/empty-dir && diff --git a/t/t9122-git-svn-author.sh b/t/t9122-git-svn-author.sh index 1190576a65..1b1cf47281 100755 --- a/t/t9122-git-svn-author.sh +++ b/t/t9122-git-svn-author.sh @@ -13,7 +13,7 @@ test_expect_success 'setup svn repository' ' ) ' -test_expect_success 'interact with it via git-svn' ' +test_expect_success 'interact with it via git svn' ' mkdir work.git && ( cd work.git && diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh index ddb1a481f7..cf0415274c 100755 --- a/t/t9123-git-svn-rebuild-with-rewriteroot.sh +++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh @@ -10,7 +10,7 @@ test_description='git svn respects rewriteRoot during rebuild' mkdir import cd import touch foo - svn import -m 'import for git-svn' . "$svnrepo" >/dev/null + svn import -m 'import for git svn' . "$svnrepo" >/dev/null cd .. rm -rf import diff --git a/t/t9124-git-svn-dcommit-auto-props.sh b/t/t9124-git-svn-dcommit-auto-props.sh index 0d7e7b2cf1..263dbf5fc2 100755 --- a/t/t9124-git-svn-dcommit-auto-props.sh +++ b/t/t9124-git-svn-dcommit-auto-props.sh @@ -16,12 +16,12 @@ enable-auto-props=$1 EOF } -test_expect_success 'initialize git-svn' ' +test_expect_success 'initialize git svn' ' mkdir import && ( cd import && echo foo >foo && - svn import -m "import for git-svn" . "$svnrepo" + svn import -m "import for git svn" . "$svnrepo" ) && rm -rf import && git svn init "$svnrepo" diff --git a/t/t9126-git-svn-follow-deleted-readded-directory.sh b/t/t9126-git-svn-follow-deleted-readded-directory.sh new file mode 100755 index 0000000000..edec640e97 --- /dev/null +++ b/t/t9126-git-svn-follow-deleted-readded-directory.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copyright (c) 2008 Alec Berryman + +test_description='git svn fetch repository with deleted and readded directory' + +. ./lib-git-svn.sh + +# Don't run this by default; it opens up a port. +require_svnserve + +test_expect_success 'load repository' ' + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9126/follow-deleted-readded.dump + ' + +test_expect_success 'fetch repository' ' + start_svnserve && + git svn init svn://127.0.0.1:$SVNSERVE_PORT && + git svn fetch + ' + +test_done diff --git a/t/t9126/follow-deleted-readded.dump b/t/t9126/follow-deleted-readded.dump new file mode 100644 index 0000000000..19da5d1ddc --- /dev/null +++ b/t/t9126/follow-deleted-readded.dump @@ -0,0 +1,201 @@ +SVN-fs-dump-format-version: 2 + +UUID: 1807dc6f-c693-4cda-9710-00e1be8c1f21 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2008-09-14T19:53:13.006748Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 111 +Content-length: 111 + +K 7 +svn:log +V 12 +Create trunk +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:13.239689Z +PROPS-END + +Node-path: trunk +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 2 +Prop-content-length: 119 +Content-length: 119 + +K 7 +svn:log +V 20 +Create trunk/project +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:13.548860Z +PROPS-END + +Node-path: trunk/project +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 3 +Prop-content-length: 111 +Content-length: 111 + +K 7 +svn:log +V 12 +add new file +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:15.433630Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: d3b07384d113edec49eaa6238ad5ff00 +Content-length: 14 + +PROPS-END +foo + + +Revision-number: 4 +Prop-content-length: 116 +Content-length: 116 + +K 7 +svn:log +V 17 +change foo to bar +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:17.339884Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: c157a79031e1c40f85931829bc5fc552 +Content-length: 4 + +bar + + +Revision-number: 5 +Prop-content-length: 114 +Content-length: 114 + +K 7 +svn:log +V 15 +don't like that +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:19.335001Z +PROPS-END + +Node-path: trunk/project +Node-action: delete + + +Revision-number: 6 +Prop-content-length: 110 +Content-length: 110 + +K 7 +svn:log +V 11 +reset trunk +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:19.845897Z +PROPS-END + +Node-path: trunk/project +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 4 +Node-copyfrom-path: trunk/project + + +Revision-number: 7 +Prop-content-length: 113 +Content-length: 113 + +K 7 +svn:log +V 14 +change to quux +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:21.367947Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: change +Text-content-length: 5 +Text-content-md5: d3b07a382ec010c01889250fce66fb13 +Content-length: 5 + +quux + + diff --git a/t/t9127-git-svn-partial-rebuild.sh b/t/t9127-git-svn-partial-rebuild.sh new file mode 100755 index 0000000000..87696a92dc --- /dev/null +++ b/t/t9127-git-svn-partial-rebuild.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# +# Copyright (c) 2008 Deskin Miller +# + +test_description='git svn partial-rebuild tests' +. ./lib-git-svn.sh + +test_expect_success 'initialize svnrepo' ' + mkdir import && + ( + cd import && + mkdir trunk branches tags && + cd trunk && + echo foo > foo && + cd .. && + svn import -m "import for git-svn" . "$svnrepo" >/dev/null && + svn copy "$svnrepo"/trunk "$svnrepo"/branches/a \ + -m "created branch a" && + cd .. && + rm -rf import && + svn co "$svnrepo"/trunk trunk && + cd trunk && + echo bar >> foo && + svn ci -m "updated trunk" && + cd .. && + svn co "$svnrepo"/branches/a a && + cd a && + echo baz >> a && + svn add a && + svn ci -m "updated a" && + cd .. && + git svn init --stdlayout "$svnrepo" + ) +' + +test_expect_success 'import an early SVN revision into git' ' + git svn fetch -r1:2 +' + +test_expect_success 'make full git mirror of SVN' ' + mkdir mirror && + ( + cd mirror && + git init && + git svn init --stdlayout "$svnrepo" && + git svn fetch && + cd .. + ) +' + +test_expect_success 'fetch from git mirror and partial-rebuild' ' + git config --add remote.origin.url "file://$PWD/mirror/.git" && + git config --add remote.origin.fetch refs/remotes/*:refs/remotes/* && + git fetch origin && + git svn fetch +' + +test_done diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 988c3ac754..245a7c3662 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -9,7 +9,7 @@ test_description='Test export of commits to CVS' cvs >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git-cvsexportcommit tests, cvs not found' : + test_expect_success 'skipping git cvsexportcommit tests, cvs not found' : test_done exit fi @@ -91,7 +91,7 @@ test_expect_success \ diff F/newfile6.png ../F/newfile6.png )' -# Should fail (but only on the git-cvsexportcommit stage) +# Should fail (but only on the git cvsexportcommit stage) test_expect_success \ 'Fail to change binary more than one generation old' \ 'cat F/newfile6.png >>D/newfile4.png && @@ -165,7 +165,7 @@ test_expect_success \ git commit -a -m "With spaces" && id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - git-cvsexportcommit -c $id && + git cvsexportcommit -c $id && check_entries "G g" "with spaces.png/1.1/-kb|with spaces.txt/1.1/" )' @@ -177,7 +177,7 @@ test_expect_success \ git commit -a -m "Update with spaces" && id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - git-cvsexportcommit -c $id + git cvsexportcommit -c $id check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/" )' @@ -202,7 +202,7 @@ test_expect_success \ git commit -a -m "Går det så går det" && \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - git-cvsexportcommit -v -c $id && + git cvsexportcommit -v -c $id && check_entries \ "Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" \ "gårdetsågårdet.png/1.1/-kb|gårdetsågårdet.txt/1.1/" @@ -222,7 +222,7 @@ test_expect_success \ git commit -a -m "Update two" && id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - test_must_fail git-cvsexportcommit -c $id + test_must_fail git cvsexportcommit -c $id )' case "$(git config --bool core.filemode)" in @@ -239,7 +239,7 @@ test_expect_success \ git add G/off && git commit -a -m "Execute test" && (cd "$CVSWORK" && - git-cvsexportcommit -c HEAD + git cvsexportcommit -c HEAD test -x G/on && ! test -x G/off )' diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index bd5d5af661..328444a306 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Shawn Pearce # -test_description='test git-fast-import utility' +test_description='test git fast-import utility' . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash @@ -59,7 +59,7 @@ M 755 :4 file4 INPUT_END test_expect_success \ 'A: create pack from stdin' \ - 'git-fast-import --export-marks=marks.out <input && + 'git fast-import --export-marks=marks.out <input && git whatchanged master' test_expect_success \ 'A: verify pack' \ @@ -113,7 +113,7 @@ test_expect_success \ test_expect_success \ 'A: verify marks import' \ - 'git-fast-import \ + 'git fast-import \ --import-marks=marks.out \ --export-marks=marks.new \ </dev/null && @@ -133,7 +133,7 @@ M 755 :2 copy-of-file2 INPUT_END test_expect_success \ 'A: verify marks import does not crash' \ - 'git-fast-import --import-marks=marks.out <input && + 'git fast-import --import-marks=marks.out <input && git whatchanged verify--import-marks' test_expect_success \ 'A: verify pack' \ @@ -166,7 +166,7 @@ M 755 0000000000000000000000000000000000000001 zero1 INPUT_END test_expect_success 'B: fail on invalid blob sha1' ' - test_must_fail git-fast-import <input + test_must_fail git fast-import <input ' rm -f .git/objects/pack_* .git/objects/index_* @@ -181,7 +181,7 @@ from refs/heads/master INPUT_END test_expect_success 'B: fail on invalid branch name ".badbranchname"' ' - test_must_fail git-fast-import <input + test_must_fail git fast-import <input ' rm -f .git/objects/pack_* .git/objects/index_* @@ -196,7 +196,7 @@ from refs/heads/master INPUT_END test_expect_success 'B: fail on invalid branch name "bad[branch]name"' ' - test_must_fail git-fast-import <input + test_must_fail git fast-import <input ' rm -f .git/objects/pack_* .git/objects/index_* @@ -212,7 +212,7 @@ from refs/heads/master INPUT_END test_expect_success \ 'B: accept branch name "TEMP_TAG"' \ - 'git-fast-import <input && + 'git fast-import <input && test -f .git/TEMP_TAG && test `git rev-parse master` = `git rev-parse TEMP_TAG^`' rm -f .git/TEMP_TAG @@ -221,7 +221,7 @@ rm -f .git/TEMP_TAG ### series C ### -newf=`echo hi newf | git-hash-object -w --stdin` +newf=`echo hi newf | git hash-object -w --stdin` oldf=`git rev-parse --verify master:file2` test_tick cat >input <<INPUT_END @@ -239,7 +239,7 @@ D file3 INPUT_END test_expect_success \ 'C: incremental import create pack from stdin' \ - 'git-fast-import <input && + 'git fast-import <input && git whatchanged branch' test_expect_success \ 'C: verify pack' \ @@ -297,7 +297,7 @@ EOF INPUT_END test_expect_success \ 'D: inline data in commit' \ - 'git-fast-import <input && + 'git fast-import <input && git whatchanged branch' test_expect_success \ 'D: verify pack' \ @@ -340,11 +340,11 @@ from refs/heads/branch^0 INPUT_END test_expect_success 'E: rfc2822 date, --date-format=raw' ' - test_must_fail git-fast-import --date-format=raw <input + test_must_fail git fast-import --date-format=raw <input ' test_expect_success \ 'E: rfc2822 date, --date-format=rfc2822' \ - 'git-fast-import --date-format=rfc2822 <input' + 'git fast-import --date-format=rfc2822 <input' test_expect_success \ 'E: verify pack' \ 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' @@ -381,7 +381,7 @@ from refs/heads/branch INPUT_END test_expect_success \ 'F: non-fast-forward update skips' \ - 'if git-fast-import <input + 'if git fast-import <input then echo BAD gfi did not fail return 1 @@ -431,7 +431,7 @@ from refs/heads/branch~1 INPUT_END test_expect_success \ 'G: non-fast-forward update forced' \ - 'git-fast-import --force <input' + 'git fast-import --force <input' test_expect_success \ 'G: verify pack' \ 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' @@ -467,7 +467,7 @@ EOF INPUT_END test_expect_success \ 'H: deletall, add 1' \ - 'git-fast-import <input && + 'git fast-import <input && git whatchanged H' test_expect_success \ 'H: verify pack' \ @@ -507,7 +507,7 @@ from refs/heads/branch INPUT_END test_expect_success \ 'I: export-pack-edges' \ - 'git-fast-import --export-pack-edges=edges.list <input' + 'git fast-import --export-pack-edges=edges.list <input' cat >expect <<EOF .git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` @@ -541,7 +541,7 @@ COMMIT INPUT_END test_expect_success \ 'J: reset existing branch creates empty commit' \ - 'git-fast-import <input' + 'git fast-import <input' test_expect_success \ 'J: branch has 1 commit, empty tree' \ 'test 1 = `git rev-list J | wc -l` && @@ -571,7 +571,7 @@ from refs/heads/branch^1 INPUT_END test_expect_success \ 'K: reinit branch with from' \ - 'git-fast-import <input' + 'git fast-import <input' test_expect_success \ 'K: verify K^1 = branch^1' \ 'test `git rev-parse --verify branch^1` \ @@ -623,7 +623,7 @@ EXPECT_END test_expect_success \ 'L: verify internal tree sorting' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree --abbrev --raw L^ L >output && test_cmp expect output' @@ -649,7 +649,7 @@ cat >expect <<EOF EOF test_expect_success \ 'M: rename file in same subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -M -r M1^ M1 >actual && compare_diff_raw expect actual' @@ -670,7 +670,7 @@ cat >expect <<EOF EOF test_expect_success \ 'M: rename file to new subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -M -r M2^ M2 >actual && compare_diff_raw expect actual' @@ -691,7 +691,7 @@ cat >expect <<EOF EOF test_expect_success \ 'M: rename subdirectory to new subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -M -r M3^ M3 >actual && compare_diff_raw expect actual' @@ -717,7 +717,7 @@ cat >expect <<EOF EOF test_expect_success \ 'N: copy file in same subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -C --find-copies-harder -r N1^ N1 >actual && compare_diff_raw expect actual' @@ -751,7 +751,7 @@ cat >expect <<EOF EOF test_expect_success \ 'N: copy then modify subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -C --find-copies-harder -r N2^^ N2 >actual && compare_diff_raw expect actual' @@ -775,8 +775,8 @@ INPUT_END test_expect_success \ 'N: copy dirty subdirectory' \ - 'git-fast-import <input && - test `git-rev-parse N2^{tree}` = `git-rev-parse N3^{tree}`' + 'git fast-import <input && + test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`' ### ### series O @@ -815,8 +815,8 @@ INPUT_END test_expect_success \ 'O: comments are all skipped' \ - 'git-fast-import <input && - test `git-rev-parse N3` = `git-rev-parse O1`' + 'git fast-import <input && + test `git rev-parse N3` = `git rev-parse O1`' cat >input <<INPUT_END commit refs/heads/O2 @@ -836,8 +836,8 @@ INPUT_END test_expect_success \ 'O: blank lines not necessary after data commands' \ - 'git-fast-import <input && - test `git-rev-parse N3` = `git-rev-parse O2`' + 'git fast-import <input && + test `git rev-parse N3` = `git rev-parse O2`' test_expect_success \ 'O: repack before next test' \ @@ -881,7 +881,7 @@ commits INPUT_END test_expect_success \ 'O: blank lines not necessary after other commands' \ - 'git-fast-import <input && + 'git fast-import <input && test 8 = `find .git/objects/pack -type f | wc -l` && test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && @@ -914,7 +914,7 @@ progress I'm done! INPUT_END test_expect_success \ 'O: progress outputs as requested by input' \ - 'git-fast-import <input >actual && + 'git fast-import <input >actual && grep "progress " <input >expect && test_cmp expect actual' @@ -979,7 +979,7 @@ INPUT_END test_expect_success \ 'P: supermodule & submodule mix' \ - 'git-fast-import <input && + 'git fast-import <input && git checkout subuse1 && rm -rf sub && mkdir sub && cd sub && git init && @@ -989,8 +989,8 @@ test_expect_success \ git submodule init && git submodule update' -SUBLAST=$(git-rev-parse --verify sub) -SUBPREV=$(git-rev-parse --verify sub^) +SUBLAST=$(git rev-parse --verify sub) +SUBPREV=$(git rev-parse --verify sub^) cat >input <<INPUT_END blob @@ -1024,8 +1024,8 @@ test_expect_success \ 'P: verbatim SHA gitlinks' \ 'git branch -D sub && git gc && git prune && - git-fast-import <input && - test $(git-rev-parse --verify subuse2) = $(git-rev-parse --verify subuse1)' + git fast-import <input && + test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)' test_tick cat >input <<INPUT_END @@ -1045,7 +1045,7 @@ DATA INPUT_END test_expect_success 'P: fail on inline gitlink' ' - test_must_fail git-fast-import <input' + test_must_fail git fast-import <input' test_tick cat >input <<INPUT_END @@ -1068,6 +1068,6 @@ M 160000 :1 sub INPUT_END test_expect_success 'P: fail on blob mark in gitlink' ' - test_must_fail git-fast-import <input' + test_must_fail git fast-import <input' test_done diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index 3cb9f80708..6ddd7c19fd 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Johannes E. Schindelin # -test_description='git-fast-export' +test_description='git fast-export' . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 0d7786a8c7..d2379e7f62 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-cvsimport basic tests' +test_description='git cvsimport basic tests' . ./test-lib.sh CVSROOT=$(pwd)/cvsroot diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index 0f04ba094b..b81d5dfc34 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -27,14 +27,14 @@ test_expect_success \ echo "changed file 1" > file1 && git commit -a -m "second commit" && - git-config --add color.test.slot1 green && - git-config --add test.string value && - git-config --add test.dupstring value1 && - git-config --add test.dupstring value2 && - git-config --add test.booltrue true && - git-config --add test.boolfalse no && - git-config --add test.boolother other && - git-config --add test.int 2k + git config --add color.test.slot1 green && + git config --add test.string value && + git config --add test.dupstring value1 && + git config --add test.dupstring value2 && + git config --add test.booltrue true && + git config --add test.boolfalse no && + git config --add test.boolother other && + git config --add test.int 2k ' test_external_without_stderr \ diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 851cea4a4b..697daf3ffd 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -9,7 +9,6 @@ use Test::More qw(no_plan); use Cwd; use File::Basename; -use File::Temp; BEGIN { use_ok('Git') } @@ -35,7 +34,7 @@ is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color"); # Failure cases for config: # Save and restore STDERR; we will probably extract this into a # "dies_ok" method and possibly move the STDERR handling to Git.pm. -open our $tmpstderr, ">&", STDERR or die "cannot save STDERR"; close STDERR; +open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR; eval { $r->config("test.dupstring") }; ok($@, "config: duplicate entry in scalar context fails"); eval { $r->config_bool("test.boolother") }; @@ -66,21 +65,25 @@ is($r->ident_person("Name", "email", "123 +0000"), "Name <email>", # objects and hashes ok(our $file1hash = $r->command_oneline('rev-parse', "HEAD:file1"), "(get file hash)"); -our $tmpfile = File::Temp->new; -is($r->cat_blob($file1hash, $tmpfile), 15, "cat_blob: size"); +my $tmpfile = "file.tmp"; +open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!"; +is($r->cat_blob($file1hash, \*TEMPFILE), 15, "cat_blob: size"); our $blobcontents; -{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; } +{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; } is($blobcontents, "changed file 1\n", "cat_blob: data"); -seek $tmpfile, 0, 0; +close TEMPFILE or die "Failed writing to $tmpfile: $!"; is(Git::hash_object("blob", $tmpfile), $file1hash, "hash_object: roundtrip"); -$tmpfile = File::Temp->new(); -print $tmpfile my $test_text = "test blob, to be inserted\n"; +open TEMPFILE, ">$tmpfile" or die "Can't open $tmpfile: $!"; +print TEMPFILE my $test_text = "test blob, to be inserted\n"; +close TEMPFILE or die "Failed writing to $tmpfile: $!"; like(our $newhash = $r->hash_and_insert_object($tmpfile), qr/[0-9a-fA-F]{40}/, "hash_and_insert_object: returns hash"); -$tmpfile = File::Temp->new; -is($r->cat_blob($newhash, $tmpfile), length $test_text, "cat_blob: roundtrip size"); -{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; } +open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!"; +is($r->cat_blob($newhash, \*TEMPFILE), length $test_text, "cat_blob: roundtrip size"); +{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; } is($blobcontents, $test_text, "cat_blob: roundtrip data"); +close TEMPFILE; +unlink $tmpfile; # paths is($r->repo_path, "./.git", "repo_path"); diff --git a/templates/Makefile b/templates/Makefile index 0722a926f7..a12c6e214e 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -31,9 +31,11 @@ boilerplates.made : $(bpsrc) dir=`expr "$$dst" : '\(.*\)/'` && \ mkdir -p blt/$$dir && \ case "$$boilerplate" in \ - *--) ;; \ - *) cp -p $$boilerplate blt/$$dst ;; \ - esac || exit; \ + *--) continue;; \ + esac && \ + cp $$boilerplate blt/$$dst && \ + if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \ + chmod a+$$rx "blt/$$dst" || exit; \ done && \ date >$@ diff --git a/unpack-trees.c b/unpack-trees.c index ef21c62195..e59d144d28 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -941,8 +941,17 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o) return -1; } } - else if (newtree) + else if (newtree) { + if (oldtree && !o->initial_checkout) { + /* + * deletion of the path was staged; + */ + if (same(oldtree, newtree)) + return 1; + return reject_merge(oldtree, o); + } return merged_entry(newtree, current, o); + } return deleted_entry(oldtree, current, o); } diff --git a/unpack-trees.h b/unpack-trees.h index 94e567265a..0d26f3d73e 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -26,6 +26,7 @@ struct unpack_trees_options { verbose_update:1, aggressive:1, skip_unmerged:1, + initial_checkout:1, gently:1; const char *prefix; int pos; diff --git a/wt-status.c b/wt-status.c index 889e50f89f..7cf890f243 100644 --- a/wt-status.c +++ b/wt-status.c @@ -22,12 +22,6 @@ static char wt_status_colors[][COLOR_MAXLEN] = { "\033[31m", /* WT_STATUS_NOBRANCH: red */ }; -static const char use_add_msg[] = -"use \"git add <file>...\" to update what will be committed"; -static const char use_add_rm_msg[] = -"use \"git add/rm <file>...\" to update what will be committed"; -static const char use_add_to_include_msg[] = -"use \"git add <file>...\" to include in what will be committed"; enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; static int parse_status_slot(const char *var, int offset) @@ -76,12 +70,24 @@ static void wt_status_print_cached_header(struct wt_status *s) color_fprintf_ln(s->fp, c, "#"); } -static void wt_status_print_header(struct wt_status *s, - const char *main, const char *sub) +static void wt_status_print_dirty_header(struct wt_status *s, + int has_deleted) { const char *c = color(WT_STATUS_HEADER); - color_fprintf_ln(s->fp, c, "# %s:", main); - color_fprintf_ln(s->fp, c, "# (%s)", sub); + color_fprintf_ln(s->fp, c, "# Changed but not updated:"); + if (!has_deleted) + color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to update what will be committed)"); + else + color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" to update what will be committed)"); + color_fprintf_ln(s->fp, c, "# (use \"git checkout -- <file>...\" to discard changes in working directory)"); + color_fprintf_ln(s->fp, c, "#"); +} + +static void wt_status_print_untracked_header(struct wt_status *s) +{ + const char *c = color(WT_STATUS_HEADER); + color_fprintf_ln(s->fp, c, "# Untracked files:"); + color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to include in what will be committed)"); color_fprintf_ln(s->fp, c, "#"); } @@ -166,14 +172,14 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q, struct wt_status *s = data; int i; if (q->nr) { - const char *msg = use_add_msg; + int has_deleted = 0; s->workdir_dirty = 1; for (i = 0; i < q->nr; i++) if (q->queue[i]->status == DIFF_STATUS_DELETED) { - msg = use_add_rm_msg; + has_deleted = 1; break; } - wt_status_print_header(s, "Changed but not updated", msg); + wt_status_print_dirty_header(s, has_deleted); } for (i = 0; i < q->nr; i++) wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]); @@ -291,8 +297,7 @@ static void wt_status_print_untracked(struct wt_status *s) } if (!shown_header) { s->workdir_untracked = 1; - wt_status_print_header(s, "Untracked files", - use_add_to_include_msg); + wt_status_print_untracked_header(s); shown_header = 1; } color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); |