diff options
32 files changed, 504 insertions, 135 deletions
diff --git a/Documentation/RelNotes-1.6.0.txt b/Documentation/RelNotes-1.6.0.txt index 8afb5b253..9e2e417ef 100644 --- a/Documentation/RelNotes-1.6.0.txt +++ b/Documentation/RelNotes-1.6.0.txt @@ -28,6 +28,16 @@ introduced in v1.5.2 and v1.4.4.5. If you want to keep your repositories backwards compatible past these versions, set repack.useDeltaBaseOffset to false or pack.indexVersion to 1, respectively. +We used to prevent sample hook scripts shipped in templates/ from +triggering by default by relying on the fact that we install them as +unexecutable, but on some filesystems, this approach does not work. +They are now shipped with ".sample" suffix. If you want to activate +any of these samples as-is, rename them to drop the ".sample" suffix, +instead of running "chmod +x" on them. For example, you can rename +hooks/post-update.sample to hooks/post-update to enable the sample +hook that runs update-server-info, in order to make repositories +friendly to dumb protocols (i.e. HTTP). + GIT_CONFIG, which was only documented as affecting "git config", but actually affected all git commands, now only affects "git config". GIT_LOCAL_CONFIG, also only documented as affecting "git config" and @@ -56,11 +66,7 @@ Updates since v1.5.6 gangs. * Sample hook scripts shipped in templates/ are now suffixed with - *.sample. We used to prevent them from triggering by default by - relying on the fact that we install them as unexecutable, but on - some filesystems this approach does not work. Instead of running - "chmod +x" on them, the users who want to activate these samples - as-is can now rename them dropping *.sample suffix. + *.sample. * perl's in-place edit (-i) does not work well without backup files on Windows; some tests are rewritten to cope with this. @@ -172,7 +178,7 @@ Updates since v1.5.6 * git-diff --check now checks leftover merge conflict markers. * "git-diff -p" learned to grab a better hunk header lines in - Pascal/Delphi and Ruby source files, and also pays attention to + BibTex, Pascal/Delphi, and Ruby files and also pays attention to chapter and part boundary in TeX documents. * When remote side used to have branch 'foo' and git-fetch finds that now @@ -248,6 +254,6 @@ this release, unless otherwise noted. --- exec >/var/tmp/1 -O=v1.6.0-rc2-21-g0bb3a0b +O=v1.6.0-rc3 echo O=$(git describe refs/heads/master) git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint diff --git a/Documentation/config.txt b/Documentation/config.txt index b8ec01c92..676c39bb8 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -978,6 +978,11 @@ pack.packSizeLimit:: can be overridden by the `\--max-pack-size` option of linkgit:git-repack[1]. +pager.<cmd>:: + Allows to set your own pager preferences for each command, overriding + the default. If `\--pager` or `\--no-pager` is specified on the command + line, it takes precedence over this option. + pull.octopus:: The default merge strategy to use when pulling multiple branches at once. diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index c45c53ec2..b9c6fac74 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git am' [--signoff] [--keep] [--utf8 | --no-utf8] - [--3way] [--interactive] [--binary] + [--3way] [--interactive] [--whitespace=<option>] [-C<n>] [-p<n>] [<mbox> | <Maildir>...] 'git am' (--skip | --resolved | --abort) @@ -59,11 +59,6 @@ default. You could use `--no-utf8` to override this. it is supposed to apply to, and we have those blobs available locally. --b:: ---binary:: - Pass `--allow-binary-replacement` flag to 'git-apply' - (see linkgit:git-apply[1]). - --whitespace=<option>:: This flag is passed to the 'git-apply' (see linkgit:git-apply[1]) program that applies diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 010d9e432..adb4ea7b1 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -147,9 +147,9 @@ include::diff-options.txt[] to any configured headers, and may be used multiple times. --cover-letter:: - Generate a cover letter template. You still have to fill in - a description, but the shortlog and the diffstat will be - generated for you. + In addition to the patches, generate a cover letter file + containing the shortlog and the overall diffstat. You can + fill in a description in the file before sending it out. --suffix=.<sfx>:: Instead of using `.patch` as the suffix for generated diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 7d50d74cc..49e2296a2 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -8,11 +8,13 @@ git-stash - Stash the changes in a dirty working directory away SYNOPSIS -------- [verse] -'git stash' list -'git stash' (show | apply | drop | pop ) [<stash>] +'git stash' list [<options>] +'git stash' (show | drop | pop ) [<stash>] +'git stash' apply [--index] [<stash>] 'git stash' branch <branchname> [<stash>] -'git stash' [save [<message>]] +'git stash' [save [--keep-index] [<message>]] 'git stash' clear +'git stash' create DESCRIPTION ----------- @@ -116,6 +118,11 @@ pop [<stash>]:: of the current working tree state. When no `<stash>` is given, `stash@\{0}` is assumed. See also `apply`. +create:: + + Create a stash (which is a regular commit object) and return its + object name, without storing it anywhere in the ref namespace. + DISCUSSION ---------- diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index d7b41142d..db16b0ca5 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -307,9 +307,18 @@ backslash, and zero or more occurrences of `sub` followed by There are a few built-in patterns to make this easier, and `tex` is one of them, so you do not have to write the above in your configuration file (you still need to enable this with the -attribute mechanism, via `.gitattributes`). Another built-in -pattern is defined for `java` that defines a pattern suitable -for program text in Java language. +attribute mechanism, via `.gitattributes`). The following built in +patterns are available: + +- `bibtex` suitable for files with BibTeX coded references. + +- `java` suitable for source code in the Java lanugage. + +- `pascal` suitable for source code in the Pascal/Delphi language. + +- `ruby` suitable for source code in the Ruby language. + +- `tex` suitable for source code for LaTeX documents. Performing a three-way merge diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index 49179b0a0..a417e592a 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -1366,8 +1366,9 @@ your login shell is 'bash', only `.bashrc` is read and not [NOTE] If you plan to publish this repository to be accessed over http, -you should do `chmod +x my-git.git/hooks/post-update` at this -point. This makes sure that every time you push into this +you should do `mv my-git.git/hooks/post-update.sample +my-git.git/hooks/post-update` at this point. +This makes sure that every time you push into this repository, `git update-server-info` is run. Your "public repository" is now ready to accept your changes. @@ -1486,11 +1487,11 @@ A recommended workflow for a "project lead" goes like this: If other people are pulling from your repository over dumb transport protocols (HTTP), you need to keep this repository 'dumb transport friendly'. After `git init`, -`$GIT_DIR/hooks/post-update` copied from the standard templates -would contain a call to 'git-update-server-info' but the -`post-update` hook itself is disabled by default -- enable it -with `chmod +x post-update`. This makes sure 'git-update-server-info' -keeps the necessary files up-to-date. +`$GIT_DIR/hooks/post-update.sample` copied from the standard templates +would contain a call to 'git-update-server-info' +but you need to manually enable the hook with +`mv post-update.sample post-update`. This makes sure +'git-update-server-info' keeps the necessary files up-to-date. 3. Push into the public repository from your primary repository. diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index be8472178..735cf07b2 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -43,11 +43,13 @@ endif::git-rev-list[] --parents:: - Print the parents of the commit. + Print the parents of the commit. Also enables parent + rewriting, see 'History Simplification' below. --children:: - Print the children of the commit. + Print the children of the commit. Also enables parent + rewriting, see 'History Simplification' below. ifdef::git-rev-list[] --timestamp:: @@ -71,7 +73,7 @@ For example, if you have this topology: o---x---a---a branch A ----------------------------------------------------------------------- + -you would get an output line this: +you would get an output like this: + ----------------------------------------------------------------------- $ git rev-list --left-right --boundary --pretty=oneline A...B @@ -94,6 +96,7 @@ you would get an output line this: This implies the '--topo-order' option by default, but the '--date-order' option may also be specified. +ifndef::git-rev-list[] Diff Formatting ~~~~~~~~~~~~~~~ @@ -123,6 +126,7 @@ options may be given. See linkgit:git-diff-files[1] for more options. -t:: Show the tree objects in the diff output. This implies '-r'. +endif::git-rev-list[] Commit Limiting ~~~~~~~~~~~~~~~ @@ -191,14 +195,6 @@ endif::git-rev-list[] Stop when a given path disappears from the tree. ---full-history:: - - Show also parts of history irrelevant to current state of a given - path. This turns off history simplification, which removed merges - which didn't change anything at all at some child. It will still actually - simplify away merges that didn't change anything at all into either - child. - --no-merges:: Do not print commits with more than one parent. @@ -280,18 +276,144 @@ See also linkgit:git-reflog[1]. Output uninteresting commits at the boundary, which are usually not shown. +-- + +History Simplification +~~~~~~~~~~~~~~~~~~~~~~ + +When optional paths are given, 'git-rev-list' simplifies commits with +various strategies, according to the options you have selected. + +Suppose you specified `foo` as the <paths>. We shall call commits +that modify `foo` !TREESAME, and the rest TREESAME. (In a diff +filtered for `foo`, they look different and equal, respectively.) + +In the following, we will always refer to the same example history to +illustrate the differences between simplification settings. We assume +that you are filtering for a file `foo` in this commit graph: +----------------------------------------------------------------------- + .-A---M---N---O---P + / / / / / + I B C D E + \ / / / / + `-------------' +----------------------------------------------------------------------- +The horizontal line of history A--P is taken to be the first parent of +each merge. The commits are: + +* `I` is the initial commit, in which `foo` exists with contents + "asdf", and a file `quux` exists with contents "quux". Initial + commits are compared to an empty tree, so `I` is !TREESAME. + +* In `A`, `foo` contains just "foo". + +* `B` contains the same change as `A`. Its merge `M` is trivial and + hence TREESAME to all parents. + +* `C` does not change `foo`, but its merge `N` changes it to "foobar", + so it is not TREESAME to any parent. + +* `D` sets `foo` to "baz". Its merge `O` combines the strings from + `N` and `D` to "foobarbaz"; i.e., it is not TREESAME to any parent. + +* `E` changes `quux` to "xyzzy", and its merge `P` combines the + strings to "quux xyzzy". Despite appearing interesting, `P` is + TREESAME to all parents. + +'rev-list' walks backwards through history, including or excluding +commits based on whether '\--full-history' and/or parent rewriting +(via '\--parents' or '\--children') are used. The following settings +are available. + +Default mode:: + + Commits are included if they are not TREESAME to any parent + (though this can be changed, see '\--sparse' below). If the + commit was a merge, and it was TREESAME to one parent, follow + only that parent. (Even if there are several TREESAME + parents, follow only one of them.) Otherwise, follow all + parents. ++ +This results in: ++ +----------------------------------------------------------------------- + .-A---N---O + / / + I---------D +----------------------------------------------------------------------- ++ +Note how the rule to only follow the TREESAME parent, if one is +available, removed `B` from consideration entirely. `C` was +considered via `N`, but is TREESAME. Root commits are compared to an +empty tree, so `I` is !TREESAME. ++ +Parent/child relations are only visible with --parents, but that does +not affect the commits selected in default mode, so we have shown the +parent lines. + +--full-history without parent rewriting:: + + This mode differs from the default in one point: always follow + all parents of a merge, even if it is TREESAME to one of them. + Even if more than one side of the merge has commits that are + included, this does not imply that the merge itself is! In + the example, we get ++ +----------------------------------------------------------------------- + I A B N D O +----------------------------------------------------------------------- ++ +`P` and `M` were excluded because they are TREESAME to a parent. `E`, +`C` and `B` were all walked, but only `B` was !TREESAME, so the others +do not appear. ++ +Note that without parent rewriting, it is not really possible to talk +about the parent/child relationships between the commits, so we show +them disconnected. + +--full-history with parent rewriting:: + + Ordinary commits are only included if they are !TREESAME + (though this can be changed, see '\--sparse' below). ++ +Merges are always included. However, their parent list is rewritten: +Along each parent, prune away commits that are not included +themselves. This results in ++ +----------------------------------------------------------------------- + .-A---M---N---O---P + / / / / / + I B / D / + \ / / / / + `-------------' +----------------------------------------------------------------------- ++ +Compare to '\--full-history' without rewriting above. Note that `E` +was pruned away because it is TREESAME, but the parent list of P was +rewritten to contain `E`'s parent `I`. The same happened for `C` and +`N`. Note also that `P` was included despite being TREESAME. + +In addition to the above settings, you can change whether TREESAME +affects inclusion: + --dense:: + + Commits that are walked are included if they are not TREESAME + to any parent. + --sparse:: -When optional paths are given, the default behaviour ('--dense') is to -only output commits that changes at least one of them, and also ignore -merges that do not touch the given paths. + All commits that are walked are included. ++ +Note that without '\--full-history', this still simplifies merges: if +one of the parents is TREESAME, we follow only that one, so the other +sides of the merge are never walked. -Use the '--sparse' flag to makes the command output all eligible commits -(still subject to count and age limitation), but apply merge -simplification nevertheless. ifdef::git-rev-list[] +Bisection Helpers +~~~~~~~~~~~~~~~~~ + --bisect:: Limit output to the one commit object which is roughly halfway between @@ -341,7 +463,6 @@ after all the sorted commit objects, there will be the same text as if `--bisect-vars` had been used alone. endif::git-rev-list[] --- Commit Ordering ~~~~~~~~~~~~~~~ diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index e99921108..08d1310bf 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -1890,7 +1890,7 @@ adjustments to give web clients some extra information they need: $ mv proj.git /home/you/public_html/proj.git $ cd proj.git $ git --bare update-server-info -$ chmod a+x hooks/post-update +$ mv hooks/post-update.sample hooks/post-update ------------------------------------------------- (For an explanation of the last two lines, see @@ -1064,7 +1064,7 @@ SHELL = $(SHELL_PATH) all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) endif all:: diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 78189c1b7..158b91284 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -501,7 +501,7 @@ __git_has_doubledash () return 1 } -__git_whitespacelist="nowarn warn error error-all strip" +__git_whitespacelist="nowarn warn error error-all fix" _git_am () { @@ -885,7 +885,11 @@ _git_help () return ;; esac - __gitcomp "$(__git_all_commands)" + __gitcomp "$(__git_all_commands) + attributes cli core-tutorial cvs-migration + diffcore gitk glossary hooks ignore modules + repository-layout tutorial tutorial-2 + " } _git_init () @@ -972,6 +976,7 @@ _git_log () --decorate --diff-filter= --color-words --walk-reflogs --parents --children --full-history + --merge " return ;; @@ -1001,6 +1006,25 @@ _git_merge () __gitcomp "$(__git_refs)" } +_git_mergetool () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --tool=*) + __gitcomp " + kdiff3 tkdiff meld xxdiff emerge + vimdiff gvimdiff ecmerge opendiff + " "" "${cur##--tool=}" + return + ;; + --*) + __gitcomp "--tool=" + return + ;; + esac + COMPREPLY=() +} + _git_merge_base () { __gitcomp "$(__git_refs)" @@ -1650,6 +1674,7 @@ _git () ls-remote) _git_ls_remote ;; ls-tree) _git_ls_tree ;; merge) _git_merge;; + mergetool) _git_mergetool;; merge-base) _git_merge_base ;; mv) _git_mv ;; name-rev) _git_name_rev ;; diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 12fa9d3fd..f9865b444 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -51,6 +51,11 @@ def p4_build_cmd(cmd): print real_cmd return real_cmd +def chdir(dir): + if os.name == 'nt': + os.environ['PWD']=dir + os.chdir(dir) + def die(msg): if verbose: raise Exception(msg) @@ -764,7 +769,7 @@ class P4Submit(Command): print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath) self.oldWorkingDirectory = os.getcwd() - os.chdir(self.clientPath) + chdir(self.clientPath) print "Syncronizing p4 checkout..." p4_system("sync ...") @@ -784,7 +789,7 @@ class P4Submit(Command): if len(commits) == 0: print "All changes applied!" - os.chdir(self.oldWorkingDirectory) + chdir(self.oldWorkingDirectory) sync = P4Sync() sync.run([]) @@ -1722,7 +1727,7 @@ class P4Clone(P4Sync): print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination) if not os.path.exists(self.cloneDestination): os.makedirs(self.cloneDestination) - os.chdir(self.cloneDestination) + chdir(self.cloneDestination) system("git init") self.gitdir = os.getcwd() + "/.git" if not P4Sync.run(self, depotPaths): @@ -1834,7 +1839,7 @@ def main(): if os.path.exists(cmd.gitdir): cdup = read_pipe("git rev-parse --show-cdup").strip() if len(cdup) > 0: - os.chdir(cdup); + chdir(cdup); if not isValidGitDir(cmd.gitdir): if isValidGitDir(cmd.gitdir + "/.git"): @@ -794,6 +794,7 @@ static void child_handler(int signo) } break; } + signal(SIGCHLD, child_handler); } static int set_reuse_addr(int sockfd) @@ -1387,6 +1387,7 @@ static struct builtin_funcname_pattern { "\\|" "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" }, + { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, }; @@ -1631,7 +1632,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, ecb.priv = &data; xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); - if (data.trailing_blanks_start) { + if ((data.ws_rule & WS_TRAILING_SPACE) && + data.trailing_blanks_start) { fprintf(o->file, "%s:%d: ends with blank lines.\n", data.filename, data.trailing_blanks_start); data.status = 1; /* report errors */ @@ -54,7 +54,7 @@ int common_prefix(const char **pathspec) static inline int special_char(unsigned char c1) { - return !c1 || c1 == '*' || c1 == '[' || c1 == '?'; + return !c1 || c1 == '*' || c1 == '[' || c1 == '?' || c1 == '\\'; } /* @@ -10,7 +10,7 @@ git am [options] (--resolved | --skip | --abort) -- d,dotest= (removed -- do not use) i,interactive run interactively -b,binary pass --allow-binary-replacement to git-apply +b,binary (historical option -- no-op) 3,3way allow fall back on 3way merging if needed s,signoff add a Signed-off-by line to the commit message u,utf8 recode into utf8 (default) @@ -87,7 +87,7 @@ fall_back_3way () { echo Using index info to reconstruct a base tree... if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ - git apply $binary --cached <"$dotest/patch" + git apply --cached <"$dotest/patch" then mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" @@ -121,7 +121,7 @@ It does not apply to blobs recorded in its index." prec=4 dotest="$GIT_DIR/rebase-apply" -sign= utf8=t keep= skip= interactive= resolved= binary= rebasing= abort= +sign= utf8=t keep= skip= interactive= resolved= rebasing= abort= resolvemsg= resume= git_apply_opt= @@ -131,7 +131,7 @@ do -i|--interactive) interactive=t ;; -b|--binary) - binary=t ;; + : ;; -3|--3way) threeway=t ;; -s|--signoff) @@ -149,7 +149,7 @@ do --abort) abort=t ;; --rebasing) - rebasing=t threeway=t keep=t binary=t ;; + rebasing=t threeway=t keep=t ;; -d|--dotest) die "-d option is no longer supported. Do not use." ;; @@ -247,10 +247,9 @@ else exit 1 } - # -b, -s, -u, -k and --whitespace flags are kept for the + # -s, -u, -k and --whitespace flags are kept for the # resuming session after a patch failure. # -3 and -i can and must be given when resuming. - echo "$binary" >"$dotest/binary" echo " $ws" >"$dotest/whitespace" echo "$sign" >"$dotest/sign" echo "$utf8" >"$dotest/utf8" @@ -274,10 +273,6 @@ case "$resolved" in fi esac -if test "$(cat "$dotest/binary")" = t -then - binary=--allow-binary-replacement -fi if test "$(cat "$dotest/utf8")" = t then utf8=-u @@ -459,7 +454,7 @@ do case "$resolved" in '') - git apply $git_apply_opt $binary --index "$dotest/patch" + git apply $git_apply_opt --index "$dotest/patch" apply_status=$? ;; t) diff --git a/git-bisect.sh b/git-bisect.sh index 3cac20db7..97ac60087 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -220,7 +220,8 @@ bisect_next_check() { if test -t 0 then printf >&2 'Are you sure [Y/n]? ' - case "$(read yesno)" in [Nn]*) exit 1 ;; esac + read yesno + case "$yesno" in [Nn]*) exit 1 ;; esac fi : bisect without good... ;; diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 4e334ba41..929d681c4 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -145,7 +145,16 @@ pick_one () { } pick_one_preserving_merges () { - case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac + fast_forward=t + case "$1" in + -n) + fast_forward=f + sha1=$2 + ;; + *) + sha1=$1 + ;; + esac sha1=$(git rev-parse $sha1) if test -f "$DOTEST"/current-commit @@ -156,15 +165,14 @@ pick_one_preserving_merges () { die "Cannot write current commit's replacement sha1" fi + echo $sha1 > "$DOTEST"/current-commit + # rewrite parents; if none were rewritten, we can fast-forward. - fast_forward=t - preserve=t new_parents= for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-) do if test -f "$REWRITTEN"/$p then - preserve=f new_p=$(cat "$REWRITTEN"/$p) test $p != $new_p && fast_forward=f case "$new_parents" in @@ -181,7 +189,8 @@ pick_one_preserving_merges () { case $fast_forward in t) output warn "Fast forward to $sha1" - test $preserve = f || echo $sha1 > "$REWRITTEN"/$sha1 + output git reset --hard $sha1 || + die "Cannot fast forward to $sha1" ;; f) test "a$1" = a-n && die "Refusing to squash a merge: $sha1" @@ -191,7 +200,6 @@ pick_one_preserving_merges () { output git checkout $first_parent 2> /dev/null || die "Cannot move HEAD to $first_parent" - echo $sha1 > "$DOTEST"/current-commit case "$new_parents" in ' '*' '*) # redo merge diff --git a/git-rebase.sh b/git-rebase.sh index 412e135c3..528b604cd 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -144,8 +144,19 @@ is_interactive () { done && test -n "$1" } +test -f "$GIT_DIR"/rebase-apply/applying && + die 'It looks like git-am is in progress. Cannot rebase.' + is_interactive "$@" && exec git-rebase--interactive "$@" +if test $# -eq 0 +then + test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage + test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing && + die 'A rebase is in progress, try --continue, --skip or --abort.' + die "No arguments given and $GIT_DIR/rebase-apply already exists." +fi + while test $# != 0 do case "$1" in @@ -268,16 +279,16 @@ done # Make sure we do not have $GIT_DIR/rebase-apply if test -z "$do_merge" then - if mkdir "$GIT_DIR"/rebase-apply + if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null then rmdir "$GIT_DIR"/rebase-apply else echo >&2 ' -It seems that I cannot create a '"$GIT_DIR"'/rebase-apply directory, -and I wonder if you are in the middle of patch application or another +It seems that I cannot create a rebase-apply directory, and +I wonder if you are in the middle of patch application or another rebase. If that is not the case, please rm -fr '"$GIT_DIR"'/rebase-apply - and run me again. I am stopping in case you still have something +and run me again. I am stopping in case you still have something valuable there.' exit 1 fi @@ -285,7 +296,7 @@ else if test -d "$dotest" then die "previous rebase directory $dotest still exists." \ - 'try git-rebase < --continue | --abort >' + 'Try git rebase (--continue | --abort | --skip)' fi fi diff --git a/git-stash.sh b/git-stash.sh index 5ad2c4b7a..e15c12abc 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -1,7 +1,13 @@ #!/bin/sh # Copyright (c) 2007, Nanako Shiraishi -USAGE='[ | save | list | show | apply | clear | drop | pop | create | branch ]' +dashless=$(basename "$0" | sed -e 's/-/ /') +USAGE="list [<options>] + or: $dashless (show | drop | pop ) [<stash>] + or: $dashless apply [--index] [<stash>] + or: $dashless branch <branchname> [<stash>] + or: $dashless [save [--keep-index] [<message>]] + or: $dashless clear" SUBDIRECTORY_OK=Yes OPTIONS_SPEC= diff --git a/git-svn.perl b/git-svn.perl index 4dc33801a..099fd02b3 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1265,7 +1265,7 @@ sub md5sum { my $arg = shift; my $ref = ref $arg; my $md5 = Digest::MD5->new(); - if ($ref eq 'GLOB' || $ref eq 'IO::File') { + if ($ref eq 'GLOB' || $ref eq 'IO::File' || $ref eq 'File::Temp') { $md5->addfile($arg) or croak $!; } elsif ($ref eq 'SCALAR') { $md5->add($$arg) or croak $!; @@ -1328,6 +1328,7 @@ BEGIN { } } + my (%LOCKFILES, %INDEX_FILES); END { unlink keys %LOCKFILES if %LOCKFILES; @@ -3230,13 +3231,11 @@ sub change_file_prop { sub apply_textdelta { my ($self, $fb, $exp) = @_; - my $fh = IO::File->new_tmpfile; - $fh->autoflush(1); + my $fh = Git::temp_acquire('svn_delta'); # $fh gets auto-closed() by SVN::TxDelta::apply(), # (but $base does not,) so dup() it for reading in close_file open my $dup, '<&', $fh or croak $!; - my $base = IO::File->new_tmpfile; - $base->autoflush(1); + my $base = Git::temp_acquire('git_blob'); if ($fb->{blob}) { print $base 'link ' if ($fb->{mode_a} == 120000); my $size = $::_repository->cat_blob($fb->{blob}, $base); @@ -3251,9 +3250,9 @@ sub apply_textdelta { } } seek $base, 0, 0 or croak $!; - $fb->{fh} = $dup; + $fb->{fh} = $fh; $fb->{base} = $base; - [ SVN::TxDelta::apply($base, $fh, undef, $fb->{path}, $fb->{pool}) ]; + [ SVN::TxDelta::apply($base, $dup, undef, $fb->{path}, $fb->{pool}) ]; } sub close_file { @@ -3269,35 +3268,36 @@ sub close_file { "expected: $exp\n got: $got\n"; } } - sysseek($fh, 0, 0) or croak $!; if ($fb->{mode_b} == 120000) { - eval { - sysread($fh, my $buf, 5) == 5 or croak $!; - $buf eq 'link ' or die "$path has mode 120000", - " but is not a link"; - }; - if ($@) { - warn "$@\n"; - sysseek($fh, 0, 0) or croak $!; - } - } + sysseek($fh, 0, 0) or croak $!; + sysread($fh, my $buf, 5) == 5 or croak $!; - my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1); - my $result; - while ($result = sysread($fh, my $string, 1024)) { - my $wrote = syswrite($tmp_fh, $string, $result); - defined($wrote) && $wrote == $result - or croak("write $tmp_filename: $!\n"); - } - defined $result or croak $!; - close $tmp_fh or croak $!; + unless ($buf eq 'link ') { + warn "$path has mode 120000", + " but is not a link\n"; + } else { + my $tmp_fh = Git::temp_acquire('svn_hash'); + my $res; + while ($res = sysread($fh, my $str, 1024)) { + my $out = syswrite($tmp_fh, $str, $res); + defined($out) && $out == $res + or croak("write ", + $tmp_fh->filename, + ": $!\n"); + } + defined $res or croak $!; - close $fh or croak $!; + ($fh, $tmp_fh) = ($tmp_fh, $fh); + Git::temp_release($tmp_fh, 1); + } + } - $hash = $::_repository->hash_and_insert_object($tmp_filename); - unlink($tmp_filename); + $hash = $::_repository->hash_and_insert_object( + $fh->filename); $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n"; - close $fb->{base} or croak $!; + + Git::temp_release($fb->{base}, 1); + Git::temp_release($fh, 1); } else { $hash = $fb->{blob} or die "no blob information\n"; } @@ -3667,7 +3667,7 @@ sub chg_file { } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { $self->change_file_prop($fbat,'svn:executable',undef); } - my $fh = IO::File->new_tmpfile or croak $!; + my $fh = Git::temp_acquire('git_blob'); if ($m->{mode_b} =~ /^120/) { print $fh 'link ' or croak $!; $self->change_file_prop($fbat,'svn:special','*'); @@ -3686,9 +3686,8 @@ sub chg_file { my $atd = $self->apply_textdelta($fbat, undef, $pool); my $got = SVN::TxDelta::send_stream($fh, @$atd, $pool); die "Checksum mismatch\nexpected: $exp\ngot: $got\n" if ($got ne $exp); + Git::temp_release($fh, 1); $pool->clear; - - close $fh or croak $!; } sub D { diff --git a/gitk-git/gitk b/gitk-git/gitk index d093a3950..087c4ac73 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -22,11 +22,11 @@ proc gitdir {} { # run before X event handlers, so reading from a fast source can # make the GUI completely unresponsive. proc run args { - global isonrunq runq + global isonrunq runq currunq set script $args if {[info exists isonrunq($script)]} return - if {$runq eq {}} { + if {$runq eq {} && ![info exists currunq]} { after idle dorunq } lappend runq [list {} $script] @@ -38,10 +38,10 @@ proc filerun {fd script} { } proc filereadable {fd script} { - global runq + global runq currunq fileevent $fd readable {} - if {$runq eq {}} { + if {$runq eq {} && ![info exists currunq]} { after idle dorunq } lappend runq [list $fd $script] @@ -60,17 +60,19 @@ proc nukefile {fd} { } proc dorunq {} { - global isonrunq runq + global isonrunq runq currunq set tstart [clock clicks -milliseconds] set t0 $tstart while {[llength $runq] > 0} { set fd [lindex $runq 0 0] set script [lindex $runq 0 1] + set currunq [lindex $runq 0] + set runq [lrange $runq 1 end] set repeat [eval $script] + unset currunq set t1 [clock clicks -milliseconds] set t [expr {$t1 - $t0}] - set runq [lrange $runq 1 end] if {$repeat ne {} && $repeat} { if {$fd eq {} || $repeat == 2} { # script returns 1 if it wants to be readded @@ -365,7 +365,7 @@ int normalize_absolute_path(char *buf, const char *path) * path = Canonical absolute path * prefix_list = Colon-separated list of absolute paths * - * Determines, for each path in parent_list, whether the "prefix" really + * Determines, for each path in prefix_list, whether the "prefix" really * is an ancestor directory of path. Returns the length of the longest * ancestor directory, excluding any trailing slashes, or -1 if no prefix * is an ancestor. (Note that this means 0 is returned if prefix_list is diff --git a/perl/Git.pm b/perl/Git.pm index e1ca5b4a2..102e6a4ce 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -57,7 +57,8 @@ require Exporter; command_output_pipe command_input_pipe command_close_pipe command_bidi_pipe command_close_bidi_pipe version exec_path hash_object git_cmd_try - remote_refs); + remote_refs + temp_acquire temp_release temp_reset); =head1 DESCRIPTION @@ -99,7 +100,7 @@ use Carp qw(carp croak); # but croak is bad - throw instead use Error qw(:try); use Cwd qw(abs_path); use IPC::Open2 qw(open2); - +use Fcntl qw(SEEK_SET SEEK_CUR); } @@ -933,6 +934,131 @@ sub _close_cat_blob { delete @$self{@vars}; } + +{ # %TEMP_* Lexical Context + +my (%TEMP_LOCKS, %TEMP_FILES); + +=item temp_acquire ( NAME ) + +Attempts to retreive the temporary file mapped to the string C<NAME>. If an +associated temp file has not been created this session or was closed, it is +created, cached, and set for autoflush and binmode. + +Internally locks the file mapped to C<NAME>. This lock must be released with +C<temp_release()> when the temp file is no longer needed. Subsequent attempts +to retrieve temporary files mapped to the same C<NAME> while still locked will +cause an error. This locking mechanism provides a weak guarantee and is not +threadsafe. It does provide some error checking to help prevent temp file refs +writing over one another. + +In general, the L<File::Handle> returned should not be closed by consumers as +it defeats the purpose of this caching mechanism. If you need to close the temp +file handle, then you should use L<File::Temp> or another temp file faculty +directly. If a handle is closed and then requested again, then a warning will +issue. + +=cut + +sub temp_acquire { + my ($self, $name) = _maybe_self(@_); + + my $temp_fd = _temp_cache($name); + + $TEMP_LOCKS{$temp_fd} = 1; + $temp_fd; +} + +=item temp_release ( NAME ) + +=item temp_release ( FILEHANDLE ) + +Releases a lock acquired through C<temp_acquire()>. Can be called either with +the C<NAME> mapping used when acquiring the temp file or with the C<FILEHANDLE> +referencing a locked temp file. + +Warns if an attempt is made to release a file that is not locked. + +The temp file will be truncated before being released. This can help to reduce +disk I/O where the system is smart enough to detect the truncation while data +is in the output buffers. Beware that after the temp file is released and +truncated, any operations on that file may fail miserably until it is +re-acquired. All contents are lost between each release and acquire mapped to +the same string. + +=cut + +sub temp_release { + my ($self, $temp_fd, $trunc) = _maybe_self(@_); + + if (ref($temp_fd) ne 'File::Temp') { + $temp_fd = $TEMP_FILES{$temp_fd}; + } + unless ($TEMP_LOCKS{$temp_fd}) { + 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; + undef; +} + +sub _temp_cache { + my ($name) = @_; + + _verify_require(); + + my $temp_fd = \$TEMP_FILES{$name}; + if (defined $$temp_fd and $$temp_fd->opened) { + if ($TEMP_LOCKS{$$temp_fd}) { + throw Error::Simple("Temp file with moniker '", + $name, "' already in use"); + } + } else { + if (defined $$temp_fd) { + # then we're here because of a closed handle. + carp "Temp file '", $name, + "' was closed. Opening replacement."; + } + $$temp_fd = File::Temp->new( + TEMPLATE => 'Git_XXXXXX', + DIR => File::Spec->tmpdir + ) or throw Error::Simple("couldn't open new temp file"); + $$temp_fd->autoflush; + binmode $$temp_fd; + } + $$temp_fd; +} + +sub _verify_require { + eval { require File::Temp; require File::Spec; }; + $@ and throw Error::Simple($@); +} + +=item temp_reset ( FILEHANDLE ) + +Truncates and resets the position of the C<FILEHANDLE>. + +=cut + +sub temp_reset { + my ($self, $temp_fd) = _maybe_self(@_); + + truncate $temp_fd, 0 + or throw Error::Simple("couldn't truncate file"); + sysseek($temp_fd, 0, SEEK_SET) and seek($temp_fd, 0, SEEK_SET) + or throw Error::Simple("couldn't seek to beginning of file"); + sysseek($temp_fd, 0, SEEK_CUR) == 0 and tell($temp_fd) == 0 + or throw Error::Simple("expected file position to be reset"); +} + +sub END { + unlink values %TEMP_FILES if %TEMP_FILES; +} + +} # %TEMP_* Lexical Context + =back =head1 ERROR HANDLING diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh index 6f8a4347d..aaed72540 100755 --- a/t/t0023-crlf-am.sh +++ b/t/t0023-crlf-am.sh @@ -36,7 +36,7 @@ test_expect_success 'setup' ' test_expect_success 'am' ' - git am --binary -3 <patchfile && + git am -3 <patchfile && git diff-files --name-status --exit-code ' diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index ffe3dd97b..5aa487ac0 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -202,6 +202,9 @@ test_expect_success 'retain authorship when squashing' ' test_expect_success '-p handles "no changes" gracefully' ' HEAD=$(git rev-parse HEAD) && git rebase -i -p HEAD^ && + git update-index --refresh && + git diff-files --quiet && + git diff-index --quiet --cached HEAD -- && test $HEAD = $(git rev-parse HEAD) ' @@ -235,6 +238,9 @@ test_expect_success 'preserve merges with -p' ' git checkout -b to-be-rebased && test_tick && git rebase -i -p --onto branch1 master && + git update-index --refresh && + git diff-files --quiet && + git diff-index --quiet --cached HEAD -- && test $(git rev-parse HEAD~6) = $(git rev-parse branch1) && test $(git rev-parse HEAD~4^2) = $(git rev-parse to-be-preserved) && test $(git rev-parse HEAD^^2^) = $(git rev-parse HEAD^^^) && @@ -244,6 +250,18 @@ test_expect_success 'preserve merges with -p' ' test $(git show HEAD:unrelated-file) = 1 ' +test_expect_success 'edit ancestor with -p' ' + FAKE_LINES="1 edit 2 3 4" git rebase -i -p HEAD~3 && + echo 2 > unrelated-file && + test_tick && + git commit -m L2-modified --amend unrelated-file && + git rebase --continue && + git update-index --refresh && + git diff-files --quiet && + git diff-index --quiet --cached HEAD -- && + test $(git show HEAD:unrelated-file) = 2 +' + test_expect_success '--continue tries to commit' ' test_tick && test_must_fail git rebase -i --onto new-branch1 HEAD^ && diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 7d123d17f..2ac93a346 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -222,4 +222,12 @@ test_expect_success 'git add (add.ignore-errors = false)' ' ! ( git ls-files foo1 | grep foo1 ) ' +test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' ' + git reset --hard && + touch fo\[ou\]bar foobar && + git add '\''fo\[ou\]bar'\'' && + git ls-files fo\[ou\]bar | grep -F fo\[ou\]bar && + ! ( git ls-files foobar | grep foobar ) +' + test_done diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 0d9cbb626..7eae1f450 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -13,7 +13,8 @@ test_expect_success setup ' echo " HT and SP indent" >>F && echo "With trailing SP " >>F && echo "Carriage ReturnQ" | tr Q "\015" >>F && - echo "No problem" >>F + echo "No problem" >>F && + echo >>F ' @@ -160,4 +161,21 @@ test_expect_success 'with cr-at-eol (attribute)' ' ' +test_expect_success 'trailing empty lines (1)' ' + + rm -f .gitattributes && + test_must_fail git diff --check >output && + grep "ends with blank lines." output && + grep "trailing whitespace" output + +' + +test_expect_success 'trailing empty lines (2)' ' + + echo "F -whitespace" >.gitattributes && + git diff --check >output && + ! test -s output + +' + test_done diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 9fd9d0700..771c0a06a 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -21,7 +21,7 @@ test_expect_success 'prune stale packs' ' orig_pack=$(echo .git/objects/pack/*.pack) && : > .git/objects/tmp_1.pack && : > .git/objects/tmp_2.pack && - test-chmtime -86501 .git/objects/tmp_1.pack && + test-chmtime =-86501 .git/objects/tmp_1.pack && git prune --expire 1.day && test -f $orig_pack && test -f .git/objects/tmp_2.pack && @@ -39,7 +39,7 @@ test_expect_success 'prune --expire' ' git prune --expire=1.hour.ago && test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && test -f $BLOB_FILE && - test-chmtime -86500 $BLOB_FILE && + test-chmtime =-86500 $BLOB_FILE && git prune --expire 1.day && test $before = $(git count-objects | sed "s/ .*//") && ! test -f $BLOB_FILE @@ -53,11 +53,11 @@ test_expect_success 'gc: implicit prune --expire' ' BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") && test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && test -f $BLOB_FILE && - test-chmtime -$((86400*14-30)) $BLOB_FILE && + test-chmtime =-$((86400*14-30)) $BLOB_FILE && git gc && test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && test -f $BLOB_FILE && - test-chmtime -$((86400*14+1)) $BLOB_FILE && + test-chmtime =-$((86400*14+1)) $BLOB_FILE && git gc && test $before = $(git count-objects | sed "s/ .*//") && ! test -f $BLOB_FILE diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh index f8c17cd96..b0d242e3e 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push.sh @@ -41,7 +41,7 @@ test_expect_success 'setup remote repository' ' git clone --bare test_repo test_repo.git && cd test_repo.git && git --bare update-server-info && - chmod +x hooks/post-update && + mv hooks/post-update.sample hooks/post-update && cd - && mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH" ' diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 1fc06c5a2..c6bc0a607 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -1045,7 +1045,7 @@ DATA INPUT_END test_expect_success 'P: fail on inline gitlink' ' - ! 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' ' - ! git-fast-import <input' + test_must_fail git-fast-import <input' test_done diff --git a/test-parse-options.c b/test-parse-options.c index 6e18083a7..61d2c3981 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -15,7 +15,7 @@ int length_callback(const struct option *opt, const char *arg, int unset) if (unset) return 1; /* do not support unset */ - *(unsigned long *)opt->value = strlen(arg); + *(int *)opt->value = strlen(arg); return 0; } |