]> asedeno.scripts.mit.edu Git - git.git/commitdiff
Merge branch 'mw/send-email'
authorJunio C Hamano <gitster@pobox.com>
Sun, 31 May 2009 23:16:52 +0000 (16:16 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 31 May 2009 23:16:52 +0000 (16:16 -0700)
* mw/send-email:
  send-email: Remove superfluous `my $editor = ...'
  send-email: 'References:' should only reference what is sent
  send-email: Handle "GIT:" rather than "GIT: " during --compose
  Docs: send-email: --smtp-server-port can take symbolic ports
  Docs: send-email: Refer to CONFIGURATION section for sendemail.multiedit
  Docs: send-email: Put options back into alphabetical order

301 files changed:
.gitignore
Documentation/Makefile
Documentation/RelNotes-1.6.1.4.txt
Documentation/RelNotes-1.6.2.4.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.2.5.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.3.1.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.3.2.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.3.txt
Documentation/RelNotes-1.6.4.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-archive.txt
Documentation/git-branch.txt
Documentation/git-cat-file.txt
Documentation/git-check-ref-format.txt
Documentation/git-checkout.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-config.txt
Documentation/git-cvsimport.txt
Documentation/git-daemon.txt
Documentation/git-difftool.txt [moved from contrib/difftool/git-difftool.txt with 70% similarity]
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-imap-send.txt
Documentation/git-init.txt
Documentation/git-ls-tree.txt
Documentation/git-mergetool--lib.txt [new file with mode: 0644]
Documentation/git-mergetool.txt
Documentation/git-rebase.txt
Documentation/git-rev-parse.txt
Documentation/git-send-email.txt
Documentation/git-shell.txt
Documentation/git-show-branch.txt
Documentation/git-stash.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git-update-server-info.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcvs-migration.txt
Documentation/merge-config.txt
Documentation/merge-options.txt
Documentation/technical/api-builtin.txt
Documentation/technical/api-parse-options.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
alias.c
alloc.c
archive-tar.c
archive.c
archive.h
attr.c
attr.h
bisect.c
bisect.h
builtin-add.c
builtin-apply.c
builtin-bisect--helper.c
builtin-blame.c
builtin-branch.c
builtin-cat-file.c
builtin-checkout-index.c
builtin-checkout.c
builtin-clone.c
builtin-commit.c
builtin-config.c
builtin-describe.c
builtin-fetch-pack.c
builtin-fetch.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-grep.c
builtin-help.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-merge-recursive.c
builtin-merge.c
builtin-pack-objects.c
builtin-prune-packed.c
builtin-prune.c
builtin-read-tree.c
builtin-receive-pack.c
builtin-reflog.c
builtin-remote.c
builtin-rerere.c
builtin-reset.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-send-pack.c
builtin-show-branch.c
builtin-tag.c
builtin-tar-tree.c
builtin-update-index.c
builtin-verify-tag.c
bundle.c
cache-tree.c
cache-tree.h
cache.h
color.h
combine-diff.c
command-list.txt
commit.c
commit.h
compat/cygwin.c
compat/fnmatch/fnmatch.c
compat/mingw.c
compat/mingw.h
compat/regex/regex.c
config.c
connect.c
contrib/completion/git-completion.bash
contrib/convert-objects/convert-objects.c
contrib/difftool/git-difftool [deleted file]
contrib/difftool/git-difftool-helper [deleted file]
contrib/hooks/post-receive-email [changed mode: 0644->0755]
contrib/thunderbird-patch-inline/README
ctype.c
daemon.c
date.c
decorate.c
diff-lib.c
diff-no-index.c
diff.c
diffcore-rename.c
dir.c
entry.c
environment.c
fast-import.c
fsck.h
git-add--interactive.perl
git-am.sh
git-bisect.sh
git-compat-util.h
git-difftool--helper.sh [new file with mode: 0755]
git-difftool.perl [new file with mode: 0755]
git-filter-branch.sh
git-gui/Makefile
git-gui/git-gui.sh
git-gui/lib/branch_delete.tcl
git-gui/lib/checkout_op.tcl
git-gui/lib/choose_repository.tcl
git-gui/lib/commit.tcl
git-gui/lib/diff.tcl
git-gui/lib/mergetool.tcl
git-gui/lib/remote_branch_delete.tcl
git-gui/lib/shortcut.tcl
git-gui/lib/tools.tcl
git-gui/po/de.po
git-gui/po/fr.po
git-gui/po/git-gui.pot
git-gui/po/hu.po
git-gui/po/it.po
git-gui/po/ja.po
git-gui/po/nb.po
git-gui/po/ru.po
git-gui/po/sv.po
git-gui/po/zh_cn.po
git-gui/windows/git-gui.sh
git-merge-one-file.sh
git-merge-resolve.sh
git-mergetool--lib.sh [new file with mode: 0644]
git-mergetool.sh
git-parse-remote.sh
git-pull.sh
git-send-email.perl
git-submodule.sh
git-svn.perl
git.c
gitk-git/gitk
gitk-git/po/ru.po [new file with mode: 0644]
gitweb/README
gitweb/gitweb.perl
graph.c
grep.c
grep.h
http-push.c
http-walker.c
imap-send.c
levenshtein.c
list-objects.c
list-objects.h
ll-merge.c
lockfile.c
log-tree.c
merge-recursive.c
object.c
pack-refs.c
parse-options.c
parse-options.h
perl/Git.pm
progress.c
reflog-walk.c
refs.c
refs.h
remote.c
rerere.c
revision.c
revision.h
run-command.c
send-pack.h
server-info.c
sha1_file.c
shell.c
strbuf.h
t/annotate-tests.sh
t/lib-git-svn.sh
t/t0001-init.sh
t/t0040-parse-options.sh
t/t1301-shared-repo.sh
t/t1303-wacky-config.sh
t/t2014-switch.sh [new file with mode: 0755]
t/t3031-merge-criscross.sh [new file with mode: 0755]
t/t3400-rebase.sh
t/t3700-add.sh
t/t3701-add-interactive.sh
t/t3702-add-edit.sh [new file with mode: 0755]
t/t3900-i18n-commit.sh
t/t4013/diff.log_--decorate_--all
t/t4014-format-patch.sh
t/t4018-diff-funcname.sh
t/t4021-format-patch-numbered.sh
t/t4027-diff-submodule.sh
t/t4029-diff-trailing-space.sh
t/t4118-apply-empty-context.sh
t/t4130-apply-criss-cross-rename.sh [new file with mode: 0755]
t/t4131-apply-fake-ancestor.sh [new file with mode: 0755]
t/t4150-am.sh
t/t4200-rerere.sh
t/t4202-log.sh
t/t5000-tar-tree.sh
t/t5001-archive-attr.sh [new file with mode: 0755]
t/t5500-fetch-pack.sh
t/t5505-remote.sh
t/t5701-clone-local.sh
t/t6030-bisect-porcelain.sh
t/t6040-tracking-info.sh
t/t6200-fmt-merge-msg.sh
t/t6300-for-each-ref.sh
t/t7002-grep.sh
t/t7201-co.sh
t/t7400-submodule-basic.sh
t/t7405-submodule-merge.sh
t/t7406-submodule-reference.sh [new file with mode: 0755]
t/t7500-commit.sh
t/t7700-repack.sh
t/t7800-difftool.sh [new file with mode: 0755]
t/t8005-blame-i18n.sh
t/t9001-send-email.sh
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9102-git-svn-deep-rmdir.sh
t/t9103-git-svn-tracked-directory-removed.sh
t/t9104-git-svn-follow-parent.sh
t/t9105-git-svn-commit-diff.sh
t/t9106-git-svn-commit-diff-clobber.sh
t/t9107-git-svn-migrate.sh
t/t9108-git-svn-glob.sh
t/t9109-git-svn-multi-glob.sh
t/t9113-git-svn-dcommit-new-file.sh
t/t9114-git-svn-dcommit-merge.sh
t/t9116-git-svn-log.sh
t/t9117-git-svn-init-clone.sh
t/t9118-git-svn-funky-branch-names.sh
t/t9119-git-svn-info.sh
t/t9120-git-svn-clone-with-percent-escapes.sh
t/t9122-git-svn-author.sh
t/t9123-git-svn-rebuild-with-rewriteroot.sh
t/t9124-git-svn-dcommit-auto-props.sh
t/t9125-git-svn-multi-glob-branch-names.sh
t/t9127-git-svn-partial-rebuild.sh
t/t9128-git-svn-cmd-branch.sh
t/t9129-git-svn-i18n-commitencoding.sh
t/t9130-git-svn-authors-file.sh
t/t9133-git-svn-nested-git-repo.sh
t/t9134-git-svn-ignore-paths.sh
t/t9137-git-svn-dcommit-clobber-series.sh
t/t9138-git-svn-authors-prog.sh [new file with mode: 0755]
t/t9139-git-svn-non-utf8-commitencoding.sh [new file with mode: 0755]
t/t9700-perl-git.sh
t/t9700/test.pl
t/test-lib.sh
templates/hooks--pre-commit.sample
templates/hooks--update.sample
test-genrandom.c
test-parse-options.c
transport.c
transport.h
tree-diff.c
tree.c
unpack-trees.c
upload-pack.c
wrapper.c
wt-status.c
xdiff/xdiffi.c

index 16f7a97d9711acd9f9bd2397eccde191f00b3254..41c0b20a76ce0fd47c7cafc51777336ce99ce1b0 100644 (file)
@@ -36,6 +36,8 @@ git-diff
 git-diff-files
 git-diff-index
 git-diff-tree
+git-difftool
+git-difftool--helper
 git-describe
 git-fast-export
 git-fast-import
@@ -79,6 +81,7 @@ git-merge-recursive
 git-merge-resolve
 git-merge-subtree
 git-mergetool
+git-mergetool--lib
 git-mktag
 git-mktree
 git-name-rev
index e18242a6d40451f57dbb5cc8805228371a78e421..7a8037f586773c00004e34079b48bb514db2515f 100644 (file)
@@ -240,7 +240,7 @@ $(MAN_HTML): %.html : %.txt
        mv $@+ $@
 
 user-manual.xml: user-manual.txt user-manual.conf
-       $(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d book $<
+       $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book $<
 
 technical/api-index.txt: technical/api-index-skel.txt \
        technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
@@ -293,13 +293,13 @@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
        mv $@+ $@
 
 $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
-       $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt
+       $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 $*.txt
 
 WEBDOC_DEST = /pub/software/scm/git/docs
 
 $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
        $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
-       sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
+       sed -e '1,/^$$/d' $< | $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 - >$@+ && \
        mv $@+ $@
 
 install-webdoc : html
index a9f1a6b8b53c141917d6ba015a49908c956d1044..0ce6316d75356500faf7e830eca54f9618064701 100644 (file)
@@ -4,15 +4,40 @@ GIT v1.6.1.4 Release Notes
 Fixes since v1.6.1.3
 --------------------
 
+* .gitignore learned to handle backslash as a quoting mechanism for
+  comment introduction character "#".
+  This fix was first merged to 1.6.2.1.
+
 * "git fast-export" produced wrong output with some parents missing from
   commits, when the history is clock-skewed.
 
 * "git fast-import" sometimes failed to read back objects it just wrote
   out and aborted, because it failed to flush stale cached data.
 
+* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
+  deciding to descend into a subdirectory but they did not match the
+  individual paths correctly.  This caused pathspecs "abc/d ab" to match
+  "abc/0" ("abc/d" made them decide to descend into the directory "abc/",
+  and then "ab" incorrectly matched "abc/0" when it shouldn't).
+  This fix was first merged to 1.6.2.3.
+
+* import-zips script (in contrib) did not compute the common directory
+  prefix correctly.
+  This fix was first merged to 1.6.2.2.
+
+* "git init" segfaulted when given an overlong template location via
+  the --template= option.
+  This fix was first merged to 1.6.2.4.
+
 * "git repack" did not error out when necessary object was missing in the
   repository.
 
+* git-repack (invoked from git-gc) did not work as nicely as it should in
+  a repository that borrows objects from neighbours via alternates
+  mechanism especially when some packs are marked with the ".keep" flag
+  to prevent them from being repacked.
+  This fix was first merged to 1.6.2.3.
+
 Also includes minor documentation fixes and updates.
 
 --
diff --git a/Documentation/RelNotes-1.6.2.4.txt b/Documentation/RelNotes-1.6.2.4.txt
new file mode 100644 (file)
index 0000000..f4bf1d0
--- /dev/null
@@ -0,0 +1,39 @@
+GIT v1.6.2.4 Release Notes
+==========================
+
+Fixes since v1.6.2.3
+--------------------
+
+* The configuration parser had a buffer overflow while parsing an overlong
+  value.
+
+* pruning reflog entries that are unreachable from the tip of the ref
+  during "git reflog prune" (hence "git gc") was very inefficient.
+
+* "git-add -p" lacked a way to say "q"uit to refuse staging any hunks for
+  the remaining paths.  You had to say "d" and then ^C.
+
+* "git-checkout <tree-ish> <submodule>" did not update the index entry at
+  the named path; it now does.
+
+* "git-fast-export" choked when seeing a tag that does not point at commit.
+
+* "git init" segfaulted when given an overlong template location via
+  the --template= option.
+
+* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
+  deciding to descend into a subdirectory but they did not match the
+  individual paths correctly.  This caused pathspecs "abc/d ab" to match
+  "abc/0" ("abc/d" made them decide to descend into the directory "abc/",
+  and then "ab" incorrectly matched "abc/0" when it shouldn't).
+
+* "git-merge-recursive" was broken when a submodule entry was involved in
+  a criss-cross merge situation.
+
+Many small documentation updates are included as well.
+
+---
+exec >/var/tmp/1
+echo O=$(git describe maint)
+O=v1.6.2.3-38-g318b847
+git shortlog --no-merges $O..maint
diff --git a/Documentation/RelNotes-1.6.2.5.txt b/Documentation/RelNotes-1.6.2.5.txt
new file mode 100644 (file)
index 0000000..b23f9e9
--- /dev/null
@@ -0,0 +1,21 @@
+GIT v1.6.2.5 Release Notes
+==========================
+
+Fixes since v1.6.2.4
+--------------------
+
+* "git apply" mishandled if you fed a git generated patch that renames
+  file A to B and file B to A at the same time.
+
+* "git diff -c -p" (and "diff --cc") did not expect to see submodule
+  differences and instead refused to work.
+
+* "git grep -e '('" segfaulted, instead of diagnosing a mismatched
+  parentheses error.
+
+* "git fetch" generated packs with offset-delta encoding when both ends of
+  the connection are capable of producing one; this cannot be read by
+  ancient git and the user should be able to disable this by setting
+  repack.usedeltabaseoffset configuration to false.
+
+
diff --git a/Documentation/RelNotes-1.6.3.1.txt b/Documentation/RelNotes-1.6.3.1.txt
new file mode 100644 (file)
index 0000000..2400b72
--- /dev/null
@@ -0,0 +1,10 @@
+GIT v1.6.3.1 Release Notes
+==========================
+
+Fixes since v1.6.3
+------------------
+
+* "git checkout -b new-branch" with a staged change in the index
+  incorrectly primed the in-index cache-tree, resulting a wrong tree
+  object to be written out of the index.  This is a grave regression
+  since the last 1.6.2.X maintenance release.
diff --git a/Documentation/RelNotes-1.6.3.2.txt b/Documentation/RelNotes-1.6.3.2.txt
new file mode 100644 (file)
index 0000000..a3fceeb
--- /dev/null
@@ -0,0 +1,51 @@
+GIT v1.6.3.2 Release Notes
+==========================
+
+Fixes since v1.6.3.1
+--------------------
+
+ * A few codepaths picked up the first few bytes from an sha1[] by
+   casting the (char *) pointer to (int *); GCC 4.4 did not like this,
+   and aborted compilation.
+
+ * http-push had a small use-after-free bug.
+
+ * command completion code in bash did not reliably detect that we are
+   in a bare repository.
+
+ * "git for-each-ref" had a segfaulting bug when dealing with a tag object
+   created by an ancient git.
+
+ * Some unlink(2) failures went undiagnosed.
+
+ * The "recursive" merge strategy misbehaved when faced rename/delete
+   conflicts while coming up with an intermediate merge base.
+
+ * GIT_TRACE mechanism segfaulted when tracing a shell-quoted aliases.
+
+ * "git add ." in an empty directory complained that pathspec "." did not
+   match anything, which may be technically correct, but not useful.  We
+   silently make it a no-op now.
+
+ * "git format-patch -k" still added patch numbers if format.numbered
+   configuration was set.
+
+ * OpenBSD also uses st_ctimspec in "struct stat", instead of "st_ctim".
+
+ * With NO_CROSS_DIRECTORY_HARDLINKS, "make install" can be told not to
+   create hardlinks between $(gitexecdir)/git-$builtin_commands and
+   $(bindir)/git.
+
+ * "git push" was converting OFS_DELTA pack representation into less
+   efficient REF_DELTA representation unconditionally upon transfer,
+   making the transferred data unnecessarily larger.
+
+Many other general usability updates around help text, diagnostic messages
+and documentation are included as well.
+
+---
+exec >/var/tmp/1
+O=v1.6.3.1-51-g2a1feb9
+echo O=$(git describe maint)
+git shortlog --no-merges $O..maint
+
index 839498c38a11e72d793a9145f94cadb1456478a0..418c685cf8328a0dc128847a98c334b727a8d6f9 100644 (file)
@@ -37,16 +37,21 @@ Updates since v1.6.2
 
 * various git-svn updates.
 
+* git-gui updates, including an update to Russian translation, and a
+  fix to an infinite loop when showing an empty diff.
+
+* gitk updates, including an update to Russian translation and improved Windows
+  support.
+
 (performance)
 
 * many uses of lstat(2) in the codepath for "git checkout" have been
   optimized out.
 
-* pruning reflog entries that are unreachable from the tip of the ref
-  during "git reflog prune" (hence "git gc") was very inefficient.
-
 (usability, bells and whistles)
 
+* Boolean configuration variable yes/no can be written as on/off.
+
 * rsync:/path/to/repo can be used to run git over rsync for local
   repositories.  It may not be useful in practice; meant primarily for
   testing.
@@ -63,20 +68,25 @@ Updates since v1.6.2
 
 * "--oneline" is a synonym for "--pretty=oneline --abbrev-commit".
 
+* "--graph" to the "git log" family can draw the commit ancestry graph
+  in colors.
+
 * If you realize that you botched the patch when you are editing hunks
   with the 'edit' action in git-add -i/-p, you can abort the editor to
   tell git not to apply it.
 
-* The number of commits shown in "you are ahead/behind your upstream"
-  messages given by "git checkout" and "git status" used to count merge
-  commits; now it doesn't.
-
 * @{-1} is a new way to refer to the last branch you were on introduced in
   1.6.2, but the initial implementation did not teach this to a few
   commands.  Now the syntax works with "branch -m @{-1} newname".
 
 * git-archive learned --output=<file> option.
 
+* git-archive takes attributes from the tree being archived; strictly
+  speaking, this is an incompatible behaviour change, but is a good one.
+  Use --worktree-attributes option to allow it to read attributes from
+  the work tree as before (deprecated git-tar tree command always reads
+  attributes from the work tree).
+
 * git-bisect shows not just the number of remaining commits whose goodness
   is unknown, but also shows the estimated number of remaining rounds.
 
@@ -93,7 +103,8 @@ Updates since v1.6.2
 
 * git-clone runs post-checkout hook when run without --no-checkout.
 
-* git-fast-export choked when seeing a tag that does not point at commit.
+* git-difftool is now part of the officially supported command, primarily
+  maintained by David Aguilar.
 
 * git-for-each-ref learned a new "upstream" token.
 
@@ -147,6 +158,10 @@ Updates since v1.6.2
   knobs you can tweak to work around issues with various versions of the
   docbook-xsl package.  See comments in Documentation/Makefile for details.
 
+* Support for building and testing a subset of git on a system without a
+  working perl has been improved.
+
+
 Fixes since v1.6.2
 ------------------
 
@@ -156,26 +171,12 @@ release, unless otherwise noted.
 Here are fixes that this release has, but have not been backported to
 v1.6.2.X series.
 
+* "git-apply" rejected a patch that swaps two files (i.e. renames A to B
+  and B to A at the same time).  May need to be backported by cherry
+  picking d8c81df and then 7fac0ee).
+
 * The initial checkout did not read the attributes from the .gitattribute
   file that is being checked out.
 
-* "git-checkout <tree-ish> <submodule>" did not update the index entry at
-  the named path; it now does.
-
 * git-gc spent excessive amount of time to decide if an object appears
   in a locally existing pack (if needed, backport by merging 69e020a).
-
-* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
-  deciding to descend into a subdirectory but they did not match the
-  individual paths correctly.  This caused pathspecs "abc/d ab" to match
-  "abc/0" ("abc/d" made them decide to descend into the directory "abc/",
-  and then "ab" incorrectly matched "abc/0" when it shouldn't).
-
-* "git-merge-recursive" was broken when a submodule entry was involved in
-  a criss-cross merge situation.
-
----
-exec >/var/tmp/1
-O=v1.6.2.3-497-g54a4749
-echo O=$(git describe master)
-git shortlog --no-merges $O..master ^maint
diff --git a/Documentation/RelNotes-1.6.4.txt b/Documentation/RelNotes-1.6.4.txt
new file mode 100644 (file)
index 0000000..af68297
--- /dev/null
@@ -0,0 +1,93 @@
+GIT v1.6.4 Release Notes
+========================
+
+With the next major release, "git push" into a branch that is
+currently checked out will be refused by default.  You can choose
+what should happen upon such a push by setting the configuration
+variable receive.denyCurrentBranch in the receiving repository.
+
+To ease the transition plan, the receiving repository of such a
+push running this release will issue a big warning when the
+configuration variable is missing.  Please refer to:
+
+  http://git.or.cz/gitwiki/GitFaq#non-bare
+  http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+
+for more details on the reason why this change is needed and the
+transition plan.
+
+For a similar reason, "git push $there :$killed" to delete the branch
+$killed in a remote repository $there, if $killed branch is the current
+branch pointed at by its HEAD, gets a large warning.  You can choose what
+should happen upon such a push by setting the configuration variable
+receive.denyDeleteCurrent in the receiving repository.
+
+When the user does not tell "git push" what to push, it has always
+pushed matching refs.  For some people it is unexpected, and a new
+configuration variable push.default has been introduced to allow
+changing a different default behaviour.  To advertise the new feature,
+a big warning is issued if this is not configured and a git push without
+arguments is attempted.
+
+
+Updates since v1.6.3
+--------------------
+
+(subsystems)
+
+ * gitweb Perl style clean-up.
+
+ * git-svn updates, including a new --authors-prog option to map author
+   names by invoking an external program.
+
+(portability)
+
+ * We feed iconv with "UTF-8" instead of "utf8"; the former is
+   understood more widely.
+
+(performance)
+
+(usability, bells and whistles)
+
+ * "git add --edit" lets users edit the whole patch text to fine-tune what
+   is added to the index.
+
+ * "git log --graph" draws graphs more compactly by using horizonal lines
+   when able.
+
+ * "git log --decorate" shows shorter refnames by stripping well-known
+   refs/* prefix.
+
+ * "git send-email" understands quoted aliases in .mailrc files (might
+   have to be backported to 1.6.3.X).
+
+ * "git send-email" can fetch the sender address from the configuration
+   variable "sendmail.from" (and "sendmail.<identity>.from").
+
+ * "git show-branch" can color its output.
+
+ * "add" and "update" subcommands to "git submodule" learned --reference
+   option to use local clone with references.
+
+(developers)
+
+ * A major part of the "git bisect" wrapper has moved to C.
+
+Fixes since v1.6.3
+------------------
+
+All of the fixes in v1.6.3.X maintenance series are included in this
+release, unless otherwise noted.
+
+Here are fixes that this release has, but have not been backported to
+v1.6.3.X series.
+
+ * The way Git.pm sets up a Repository object was not friendly to callers
+   that chdir around.  It now internally records the repository location
+   as an absolute path when autodetected.
+
+---
+exec >/var/tmp/1
+echo O=$(git describe master)
+O=v1.6.3.1-168-g23807fa
+git shortlog --no-merges $O..master ^maint
index 8d818a21600f386abb02dee902d842a716767027..76fc84d8780762e083cd4ca584b9d783b8c0cd81 100644 (file)
@@ -6,9 +6,13 @@ Checklist (and a short version for the impatient):
        - check for unnecessary whitespace with "git diff --check"
          before committing
        - do not check in commented out code or unneeded files
-       - provide a meaningful commit message
        - the first line of the commit message should be a short
          description and should skip the full stop
+       - the body should provide a meaningful commit message, which:
+               - uses the imperative, present tense: "change",
+                 not "changed" or "changes".
+               - includes motivation for the change, and contrasts
+                 its implementation with previous behaviour
        - if you want your work included in git.git, add a
          "Signed-off-by: Your Name <you@example.com>" line to the
          commit message (or just use the option "-s" when
@@ -62,6 +66,14 @@ Describe the technical detail of the change(s).
 
 If your description starts to get too long, that's a sign that you
 probably need to split up your commit to finer grained pieces.
+That being said, patches which plainly describe the things that
+help reviewers check the patch, and future maintainers understand
+the code, are the most beautiful patches.  Descriptions that summarise
+the point in the subject well, and describe the motivation for the
+change, the approach taken by the change, and if relevant how this
+differs substantially from the prior version, can be found on Usenet
+archives back into the late 80's.  Consider it like good Netiquette,
+but for code.
 
 Oh, another thing.  I am picky about whitespaces.  Make sure your
 changes do not trigger errors with the sample pre-commit hook shipped
index f3ebd2f9a048371e7d519a93ea9c7eaf3bc75e2d..3a86d1f8f05317717d718a6db7c5e0f9acb47d6b 100644 (file)
@@ -2,15 +2,15 @@ CONFIGURATION FILE
 ------------------
 
 The git configuration file contains a number of variables that affect
-the git command's behavior. `.git/config` file for each repository
-is used to store the information for that repository, and
-`$HOME/.gitconfig` is used to store per user information to give
-fallback values for `.git/config` file. The file `/etc/gitconfig`
-can be used to store system-wide defaults.
-
-They can be used by both the git plumbing
-and the porcelains. The variables are divided into sections, where
-in the fully qualified variable name the variable itself is the last
+the git command's behavior. The `.git/config` file in each repository
+is used to store the configuration for that repository, and
+`$HOME/.gitconfig` is used to store a per-user configuration as
+fallback values for the `.git/config` file. The file `/etc/gitconfig`
+can be used to store a system-wide default configuration.
+
+The configuration variables are used by both the git plumbing
+and the porcelains. The variables are divided into sections, wherein
+the fully qualified variable name of the variable itself is the last
 dot-separated segment and the section name is everything before the last
 dot. The variable names are case-insensitive and only alphanumeric
 characters are allowed. Some variables may appear multiple times.
@@ -26,28 +26,28 @@ The file consists of sections and variables.  A section begins with
 the name of the section in square brackets and continues until the next
 section begins.  Section names are not case sensitive.  Only alphanumeric
 characters, `-` and `.` are allowed in section names.  Each variable
-must belong to some section, which means that there must be section
-header before first setting of a variable.
+must belong to some section, which means that there must be section
+header before the first setting of a variable.
 
 Sections can be further divided into subsections.  To begin a subsection
 put its name in double quotes, separated by space from the section name,
-in the section header, like in example below:
+in the section header, like in the example below:
 
 --------
        [section "subsection"]
 
 --------
 
-Subsection names can contain any characters except newline (doublequote
-`"` and backslash have to be escaped as `\"` and `\\`,
-respectively) and are case sensitive.  Section header cannot span multiple
+Subsection names are case sensitive and can contain any characters except
+newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`,
+respectively).  Section headers cannot span multiple
 lines.  Variables may belong directly to a section or to a given subsection.
 You can have `[section]` if you have `[section "subsection"]`, but you
 don't need to.
 
-There is also (case insensitive) alternative `[section.subsection]` syntax.
-In this syntax subsection names follow the same restrictions as for section
-name.
+There is also a case insensitive alternative `[section.subsection]` syntax.
+In this syntax, subsection names follow the same restrictions as for section
+names.
 
 All the other lines are recognized as setting variables, in the form
 'name = value'.  If there is no equal sign on the line, the entire line
@@ -61,15 +61,15 @@ Internal whitespace within a variable value is retained verbatim.
 
 The values following the equals sign in variable assign are all either
 a string, an integer, or a boolean.  Boolean values may be given as yes/no,
-0/1 or true/false.  Case is not significant in boolean values, when
+0/1, true/false or on/off.  Case is not significant in boolean values, when
 converting value to the canonical form using '--bool' type specifier;
 'git-config' will ensure that the output is "true" or "false".
 
 String values may be entirely or partially enclosed in double quotes.
-You need to enclose variable value in double quotes if you want to
-preserve leading or trailing whitespace, or if variable value contains
-beginning of comment characters (if it contains '#' or ';').
-Double quote `"` and backslash `\` characters in variable value must
+You need to enclose variable values in double quotes if you want to
+preserve leading or trailing whitespace, or if the variable value contains
+comment characters (i.e. it contains '#' or ';').
+Double quote `"` and backslash `\` characters in variable values must
 be escaped: use `\"` for `"` and `\\` for `\`.
 
 The following escape sequences (beside `\"` and `\\`) are recognized:
@@ -77,10 +77,10 @@ The following escape sequences (beside `\"` and `\\`) are recognized:
 and `\b` for backspace (BS).  No other char escape sequence, nor octal
 char sequences are valid.
 
-Variable value ending in a `\` is continued on the next line in the
+Variable values ending in a `\` are continued on the next line in the
 customary UNIX fashion.
 
-Some variables may require special value format.
+Some variables may require special value format.
 
 Example
 ~~~~~~~
@@ -295,8 +295,10 @@ core.sharedRepository::
        group-shareable. When 'umask' (or 'false'), git will use permissions
        reported by umask(2). When '0xxx', where '0xxx' is an octal number,
        files in the repository will have this mode value. '0xxx' will override
-       user's umask value, and thus, users with a safe umask (0077) can use
-       this option. Examples: '0660' is equivalent to 'group'. '0640' is a
+       user's umask value (whereas the other options will only override
+       requested parts of the user's umask value). Examples: '0660' will make
+       the repo read/write-able for the owner and group, but inaccessible to
+       others (equivalent to 'group' unless umask is e.g. '0022'). '0640' is a
        repository that is group-readable but not group-writable.
        See linkgit:git-init[1]. False by default.
 
@@ -427,6 +429,20 @@ relatively high IO latencies.  With this set to 'true', git will do the
 index comparison to the filesystem data in parallel, allowing
 overlapping IO's.
 
+core.createObject::
+       You can set this to 'link', in which case a hardlink followed by
+       a delete of the source are used to make sure that object creation
+       will not overwrite existing objects.
++
+On some file system/operating system combinations, this is unreliable.
+Set this config setting to 'rename' there; However, This will remove the
+check that makes sure that existing object files will not get overwritten.
+
+add.ignore-errors::
+       Tells 'git-add' to continue adding files when some files cannot be
+       added due to indexing errors. Equivalent to the '--ignore-errors'
+       option of linkgit:git-add[1].
+
 alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
        after defining "alias.last = cat-file commit HEAD", the invocation
@@ -593,6 +609,12 @@ color.pager::
        A boolean to enable/disable colored output when the pager is in
        use (default is true).
 
+color.showbranch::
+       A boolean to enable/disable color in the output of
+       linkgit:git-show-branch[1]. May be set to `always`,
+       `false` (or `never`) or `auto` (or `true`), in which case colors are used
+       only when the output is to a terminal. Defaults to false.
+
 color.status::
        A boolean to enable/disable color in the output of
        linkgit:git-status[1]. May be set to `always`,
@@ -667,6 +689,27 @@ diff.suppressBlankEmpty::
        A boolean to inhibit the standard behavior of printing a space
        before each empty output line. Defaults to false.
 
+diff.tool::
+       Controls which diff tool is used.  `diff.tool` overrides
+       `merge.tool` when used by linkgit:git-difftool[1] and has
+       the same valid values as `merge.tool` minus "tortoisemerge"
+       and plus "kompare".
+
+difftool.<tool>.path::
+       Override the path for the given tool.  This is useful in case
+       your tool is not in the PATH.
+
+difftool.<tool>.cmd::
+       Specify the command to invoke the specified diff tool.
+       The specified command is evaluated in shell with the following
+       variables available:  'LOCAL' is set to the name of the temporary
+       file containing the contents of the diff pre-image and 'REMOTE'
+       is set to the name of the temporary file containing the contents
+       of the diff post-image.
+
+difftool.prompt::
+       Prompt before each invocation of the diff tool.
+
 diff.wordRegex::
        A POSIX Extended Regular Expression used to determine what is a "word"
        when performing word-by-word difference calculations.  Character
@@ -684,6 +727,13 @@ fetch.unpackLimit::
        especially on slow filesystems.  If not set, the value of
        `transfer.unpackLimit` is used instead.
 
+format.attach::
+       Enable multipart/mixed attachments as the default for
+       'format-patch'.  The value can also be a double quoted string
+       which will enable attachments as the default and set the
+       value as the boundary.  See the --attach option in
+       linkgit:git-format-patch[1].
+
 format.numbered::
        A boolean which can enable or disable sequence numbers in patch
        subjects.  It defaults to "auto" which enables it only if there
@@ -695,6 +745,14 @@ format.headers::
        Additional email headers to include in a patch to be submitted
        by mail.  See linkgit:git-format-patch[1].
 
+format.cc::
+       Additional "Cc:" headers to include in a patch to be submitted
+       by mail.  See the --cc option in linkgit:git-format-patch[1].
+
+format.subjectprefix::
+       The default for format-patch is to output files with the '[PATCH]'
+       subject prefix. Use this variable to change that prefix.
+
 format.suffix::
        The default for format-patch is to output files with the suffix
        `.patch`. Use this variable to change that suffix (make sure to
@@ -707,11 +765,11 @@ format.pretty::
 
 format.thread::
        The default threading style for 'git-format-patch'.  Can be
-       either a boolean value, `shallow` or `deep`.  'Shallow'
+       either a boolean value, `shallow` or `deep`.  `shallow`
        threading makes every mail a reply to the head of the series,
        where the head is chosen from the cover letter, the
        `\--in-reply-to`, and the first patch mail, in this order.
-       'Deep' threading makes every mail a reply to the previous one.
+       `deep` threading makes every mail a reply to the previous one.
        A true boolean value is the same as `shallow`, and a false
        value disables threading.
 
index ce71838b9e17f3b68dcd19648da3a88dfe4f35bd..ab1943c71243df245f84ede7a69e4c666a8d8834 100644 (file)
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
-         [--all | [--update | -u]] [--intent-to-add | -N]
+         [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
          [--refresh] [--ignore-errors] [--] <filepattern>...
 
 DESCRIPTION
@@ -76,6 +76,15 @@ OPTIONS
        bypassed and the 'patch' subcommand is invoked using each of
        the specified filepatterns before exiting.
 
+-e, \--edit::
+       Open the diff vs. the index in an editor and let the user
+       edit it.  After the editor was closed, adjust the hunk headers
+       and apply the patch to the index.
++
+*NOTE*: Obviously, if you change anything else than the first character
+on lines beginning with a space or a minus, the patch will no longer
+apply.
+
 -u::
 --update::
        Update only files that git already knows about, staging modified
@@ -245,8 +254,11 @@ patch::
 
        y - stage this hunk
        n - do not stage this hunk
+       q - quit, do not stage this hunk nor any of the remaining ones
        a - stage this and all the remaining hunks in the file
        d - do not stage this hunk nor any of the remaining hunks in the file
+       g - select a hunk to go to
+       / - search for a hunk matching the given regex
        j - leave this hunk undecided, see next undecided hunk
        J - leave this hunk undecided, see next hunk
        k - leave this hunk undecided, see previous undecided hunk
index 1e71dd536b1881b61a007af09f1dedea37fe984e..6d92cbee6475e29660d91a97683bf5843aacab38 100644 (file)
@@ -32,7 +32,7 @@ OPTIONS
 
 -s::
 --signoff::
-       Add `Signed-off-by:` line to the commit message, using
+       Add `Signed-off-by:` line to the commit message, using
        the committer identity of yourself.
 
 -k::
@@ -79,14 +79,14 @@ default.   You can use `--no-utf8` to override this.
        message as the commit author date, and uses the time of
        commit creation as the committer date. This allows the
        user to lie about the committer date by using the same
-       timestamp as the author date.
+       value as the author date.
 
 --ignore-date::
        By default the command records the date from the e-mail
        message as the commit author date, and uses the time of
        commit creation as the committer date. This allows the
-       user to lie about author timestamp by using the same
-       timestamp as the committer date.
+       user to lie about the author date by using the same
+       value as the committer date.
 
 --skip::
        Skip the current patch.  This is only meaningful when
@@ -115,21 +115,21 @@ DISCUSSION
 ----------
 
 The commit author name is taken from the "From: " line of the
-message, and commit author time is taken from the "Date: " line
+message, and commit author date is taken from the "Date: " line
 of the message.  The "Subject: " line is used as the title of
 the commit, after stripping common prefix "[PATCH <anything>]".
-It is supposed to describe what the commit is about concisely as
-a one line text.
+The "Subject: " line is supposed to concisely describe what the
+commit is about in one line of text.
 
-The body of the message (the rest of the message after the blank line
-that terminates the RFC2822 headers) can begin with "Subject: " and
-"From: " lines that are different from those of the mail header,
-to override the values of these fields.
+"From: " and "Subject: " lines starting the body (the rest of the
+message after the blank line terminating the RFC2822 headers)
+override the respective commit author name and title values taken
+from the headers.
 
 The commit message is formed by the title taken from the
 "Subject: ", a blank line and the body of the message up to
-where the patch begins.  Excess whitespace characters at the end of the
-lines are automatically stripped.
+where the patch begins.  Excess whitespace at the end of each
+line is automatically stripped.
 
 The patch is expected to be inline, directly following the
 message.  Any line that is of the form:
@@ -141,7 +141,7 @@ message.  Any line that is of the form:
 is taken as the beginning of a patch, and the commit log message
 is terminated before the first occurrence of such a line.
 
-When initially invoking it, you give it the names of the mailboxes
+When initially invoking `git am`, you give it the names of the mailboxes
 to process.  Upon seeing the first patch that does not apply, it
 aborts in the middle.  You can recover from this in one of two ways:
 
index 9e5baa277731adf14e47fda8c6b13a076e0873db..735374d7df7e8d0e967dce7750f41aabff9a095f 100644 (file)
@@ -3,7 +3,7 @@ git-apply(1)
 
 NAME
 ----
-git-apply - Apply a patch on a git index file and a working tree
+git-apply - Apply a patch on a git index file and/or a working tree
 
 
 SYNOPSIS
index c1adf594972884b77c1f049b35a983688601a343..bc132c87e1a5b9f42ea1f2bbd4e3c46f67fc3852 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
-             [--output=<file>]
+             [--output=<file>] [--worktree-attributes]
              [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
              [path...]
 
@@ -51,6 +51,9 @@ OPTIONS
 --output=<file>::
        Write the archive to <file> instead of stdout.
 
+--worktree-attributes::
+       Look for attributes in .gitattributes in working directory too.
+
 <extra>::
        This can be any options that the archiver backend understands.
        See next section.
index ba3dea684096b601804058501f4631f09e6d4c38..ae201deb7af44c61e793ab408e916c5b6520800d 100644 (file)
@@ -111,20 +111,24 @@ OPTIONS
 --no-abbrev::
        Display the full sha1s in the output listing rather than abbreviating them.
 
+-t::
 --track::
-       When creating a new branch, set up the configuration so that 'git-pull'
-       will automatically retrieve data from the start point, which must be
-       a branch. Use this if you always pull from the same upstream branch
-       into the new branch, and if you do not want to use "git pull
-       <repository> <refspec>" explicitly. This behavior is the default
-       when the start point is a remote branch. Set the
-       branch.autosetupmerge configuration variable to `false` if you want
-       'git-checkout' and 'git-branch' to always behave as if '--no-track' were
-       given. Set it to `always` if you want this behavior when the
-       start-point is either a local or remote branch.
+       When creating a new branch, set up configuration to mark the
+       start-point branch as "upstream" from the new branch. This
+       configuration will tell git to show the relationship between the
+       two branches in `git status` and `git branch -v`. Furthermore,
+       it directs `git pull` without arguments to pull from the
+       upstream when the new branch is checked out.
++
+This behavior is the default when the start point is a remote branch.
+Set the branch.autosetupmerge configuration variable to `false` if you
+want `git checkout` and `git branch` to always behave as if '--no-track'
+were given. Set it to `always` if you want this behavior when the
+start-point is either a local or remote branch.
 
 --no-track::
-       Ignore the branch.autosetupmerge configuration variable.
+       Do not set up "upstream" configuration, even if the
+       branch.autosetupmerge configuration variable is true.
 
 --contains <commit>::
        Only list branches which contain the specified commit.
index b191276d7a44511bfce60febe6f5cb9a025ec9a3..58c8d65772af4ef20ad573af9dd28691f5357437 100644 (file)
@@ -9,8 +9,8 @@ git-cat-file - Provide content or type and size information for repository objec
 SYNOPSIS
 --------
 [verse]
-'git cat-file' [-t | -s | -e | -p | <type>] <object>
-'git cat-file' [--batch | --batch-check] < <list-of-objects>
+'git cat-file' (-t | -s | -e | -p | <type>) <object>
+'git cat-file' (--batch | --batch-check) < <list-of-objects>
 
 DESCRIPTION
 -----------
index c1ce26884e73f1599602472ba5032988486cc465..0b7982ea76633e45b8d3073cd275ea74a757c0eb 100644 (file)
@@ -25,6 +25,10 @@ imposes the following rules on how references are named:
   grouping, but no slash-separated component can begin with a
   dot `.`.
 
+. They must contain at least one `/`. This enforces the presence of a
+  category like `heads/`, `tags/` etc. but the actual names are not
+  restricted.
+
 . They cannot have two consecutive dots `..` anywhere.
 
 . They cannot have ASCII control characters (i.e. bytes whose
@@ -38,6 +42,8 @@ imposes the following rules on how references are named:
 
 . They cannot contain a sequence `@{`.
 
+- They cannot contain a `\\`.
+
 These rules make it easy for shell script based tools to parse
 reference names, pathname expansion by the shell when a reference name is used
 unquoted (by mistake), and also avoids ambiguities in certain
index 223ea9caef4d0ca875768db47e03f5c6cb71354f..ad4b31e89218e857001fce69f32acbe85fc7539c 100644 (file)
@@ -8,22 +8,22 @@ git-checkout - Checkout a branch or paths to the working tree
 SYNOPSIS
 --------
 [verse]
-'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
+'git checkout' [-q] [-f] [-m] [<branch>]
+'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]
 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
 
 DESCRIPTION
 -----------
 
 When <paths> are not given, this command switches branches by
-updating the index and working tree to reflect the specified
-branch, <branch>, and updating HEAD to be <branch> or, if
-specified, <new_branch>.  Using -b will cause <new_branch> to
-be created; in this case you can use the --track or --no-track
-options, which will be passed to `git branch`.
+updating the index, working tree, and HEAD to reflect the specified
+branch.
 
-As a convenience, --track will default to creating a branch whose
-name is constructed from the specified branch name by stripping
-the first namespace level.
+If `-b` is given, a new branch is created and checked out, as if
+linkgit:git-branch[1] were called; in this case you can
+use the --track or --no-track options, which will be passed to `git
+branch`.  As a convenience, --track without `-b` implies branch
+creation; see the description of --track below.
 
 When <paths> are given, this command does *not* switch
 branches.  It updates the named paths in the working tree from
@@ -62,22 +62,12 @@ entries; instead, unmerged entries are ignored.
 
 -b::
        Create a new branch named <new_branch> and start it at
-       <branch>.  The new branch name must pass all checks defined
-       by linkgit:git-check-ref-format[1].  Some of these checks
-       may restrict the characters allowed in a branch name.
+       <start_point>; see linkgit:git-branch[1] for details.
 
 -t::
 --track::
-       When creating a new branch, set up configuration so that 'git-pull'
-       will automatically retrieve data from the start point, which must be
-       a branch. Use this if you always pull from the same upstream branch
-       into the new branch, and if you don't want to use "git pull
-       <repository> <refspec>" explicitly. This behavior is the default
-       when the start point is a remote branch. Set the
-       branch.autosetupmerge configuration variable to `false` if you want
-       'git checkout' and 'git branch' to always behave as if '--no-track' were
-       given. Set it to `always` if you want this behavior when the
-       start point is either a local or remote branch.
+       When creating a new branch, set up "upstream" configuration. See
+       "--track" in linkgit:git-branch[1] for details.
 +
 If no '-b' option is given, the name of the new branch will be
 derived from the remote branch.  If "remotes/" or "refs/remotes/"
@@ -90,12 +80,12 @@ guessing results in an empty name, the guessing is aborted.  You can
 explicitly give a name with '-b' in such a case.
 
 --no-track::
-       Ignore the branch.autosetupmerge configuration variable.
+       Do not set up "upstream" configuration, even if the
+       branch.autosetupmerge configuration variable is true.
 
 -l::
-       Create the new branch's reflog.  This activates recording of
-       all changes made to the branch ref, enabling use of date
-       based sha1 expressions such as "<branchname>@\{yesterday}".
+       Create the new branch's reflog; see linkgit:git-branch[1] for
+       details.
 
 -m::
 --merge::
@@ -123,23 +113,28 @@ the conflicted merge in the specified paths.
        "merge" (default) and "diff3" (in addition to what is shown by
        "merge" style, shows the original contents).
 
+<branch>::
+       Branch to checkout; if it refers to a branch (i.e., a name that,
+       when prepended with "refs/heads/", is a valid ref), then that
+       branch is checked out. Otherwise, if it refers to a valid
+       commit, your HEAD becomes "detached" and you are no longer on
+       any branch (see below for details).
++
+As a special case, the `"@\{-N\}"` syntax for the N-th last branch
+checks out the branch (instead of detaching).  You may also specify
+`-` which is synonymous with `"@\{-1\}"`.
+
 <new_branch>::
        Name for the new branch.
 
+<start_point>::
+       The name of a commit at which to start the new branch; see
+       linkgit:git-branch[1] for details. Defaults to HEAD.
+
 <tree-ish>::
        Tree to checkout from (when paths are given). If not specified,
        the index will be used.
 
-<branch>::
-       Branch to checkout (when no paths are given); may be any object
-       ID that resolves to a commit.  Defaults to HEAD.
-+
-When this parameter names a non-branch (but still a valid commit object),
-your HEAD becomes 'detached'.
-+
-As a special case, the `"@\{-N\}"` syntax for the N-th last branch
-checks out the branch (instead of detaching).  You may also specify
-`-` which is synonymous with `"@\{-1\}"`.
 
 
 Detached HEAD
index 8a114509f4a19b4fa6c6d8de8afdc94938d24b82..be894af39ff6559affbf0617e4c5d8fe68c33fe8 100644 (file)
@@ -12,14 +12,17 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Removes files unknown to git.  This allows to clean the working tree
-from files that are not under version control.  If the '-x' option is
-specified, ignored files are also removed, allowing to remove all
-build products.
+
+Cleans the working tree by recursively removing files that are not
+under version control, starting from the current directory.
+
+Normally, only files unknown to git are removed, but if the '-x'
+option is specified, ignored files are also removed. This can, for
+example, be useful to remove all build products.
+
 If any optional `<path>...` arguments are given, only those paths
 are affected.
 
-
 OPTIONS
 -------
 -d::
index 4072f40d7ae5417c51d1cddcf587b674aa1dc0e5..b14de6c407b8bd0bc001c608ca4f26fc619abf3e 100644 (file)
@@ -149,7 +149,7 @@ then the cloned repository will become corrupt.
        part of the source repository is used if no directory is
        explicitly given ("repo" for "/path/to/repo.git" and "foo"
        for "host.xz:foo/.git").  Cloning into an existing directory
-       is not allowed.
+       is only allowed if the directory is empty.
 
 :git-clone: 1
 include::urls.txt[]
index 7131ee3c66951de5981a82e304f4619de88064c5..f68b198205d3a4d808ce58e6b0ac03e70bb160a4 100644 (file)
@@ -69,7 +69,8 @@ OPTIONS
 
 --add::
        Adds a new line to the option without altering any existing
-       values.  This is the same as providing '^$' as the value_regex.
+       values.  This is the same as providing '^$' as the value_regex
+       in `--replace-all`.
 
 --get::
        Get the value for a given key (optionally filtered by a regex
@@ -155,7 +156,7 @@ See also <<FILES>>.
        When the color setting for `name` is undefined, the command uses
        `color.ui` as fallback.
 
---get-color name default::
+--get-color name [default]::
 
        Find the color configured for `name` (e.g. `color.diff.new`) and
        output it as the ANSI color escape sequence to the standard
index d7bab13f6c35762cbb83c5b244a827790da4c816..614e769f4e5351d2820ebb9bf0dd1ae519c965ba 100644 (file)
@@ -196,7 +196,7 @@ Problems related to tags:
 
 If you suspect that any of these issues may apply to the repository you
 want to import consider using these alternative tools which proved to be
-more stable in practise:
+more stable in practice:
 
 * cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
 * parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
index 36f00aed6798d543b2ee8f7315e447726fa100e5..a85121c689e394e86f7c97025b92ffa03fca0df9 100644 (file)
@@ -48,7 +48,7 @@ OPTIONS
        'git-daemon' will refuse to start when this option is enabled and no
        whitelist is specified.
 
---base-path::
+--base-path=path::
        Remap all the path requests as relative to the given path.
        This is sort of "GIT root" - if you run 'git-daemon' with
        '--base-path=/srv/git' on example.com, then if you later try to pull
@@ -81,8 +81,8 @@ OPTIONS
        Incompatible with --port, --listen, --user and --group options.
 
 --listen=host_or_ipaddr::
-       Listen on an a specific IP address or hostname.  IP addresses can
-       be either an IPv4 address or an IPV6 address if supported.  If IPv6
+       Listen on a specific IP address or hostname.  IP addresses can
+       be either an IPv4 address or an IPv6 address if supported.  If IPv6
        is not supported, then --listen=hostname is also not supported and
        --listen must be given an IPv4 address.
        Incompatible with '--inetd' option.
@@ -90,17 +90,17 @@ OPTIONS
 --port=n::
        Listen on an alternative port.  Incompatible with '--inetd' option.
 
---init-timeout::
+--init-timeout=n::
        Timeout between the moment the connection is established and the
        client request is received (typically a rather low value, since
        that should be basically immediate).
 
---timeout::
+--timeout=n::
        Timeout for specific client sub-requests. This includes the time
-       it takes for the server to process the sub-request and time spent
-       waiting for next client's request.
+       it takes for the server to process the sub-request and the time spent
+       waiting for the next client's request.
 
---max-connections::
+--max-connections=n::
        Maximum number of concurrent clients, defaults to 32.  Set it to
        zero for no limit.
 
@@ -150,7 +150,7 @@ the facility of inet daemon to achieve the same before spawning
        Enable/disable the service site-wide per default.  Note
        that a service disabled site-wide can still be enabled
        per repository if it is marked overridable and the
-       repository enables the service with an configuration
+       repository enables the service with a configuration
        item.
 
 --allow-override=service::
similarity index 70%
rename from contrib/difftool/git-difftool.txt
rename to Documentation/git-difftool.txt
index 2b7bc03ec3f63ce8bfe4ba8c00af9ab807e6cedf..15b247bab4195286e55447388308473af4e2d001 100644 (file)
@@ -3,35 +3,37 @@ git-difftool(1)
 
 NAME
 ----
-git-difftool - compare changes using common merge tools
+git-difftool - Show changes using common diff tools
 
 SYNOPSIS
 --------
-'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options]
+'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>]
 
 DESCRIPTION
 -----------
 'git-difftool' is a git command that allows you to compare and edit files
-between revisions using common merge tools.  At its most basic level,
-'git-difftool' does what 'git-mergetool' does but its use is for non-merge
-situations such as when preparing commits or comparing changes against
-the index.
-
-'git difftool' is a frontend to 'git diff' and accepts the same
-arguments and options.
-
-See linkgit:git-diff[1] for the full list of supported options.
+between revisions using common diff tools.  'git difftool' is a frontend
+to 'git-diff' and accepts the same options and arguments.
 
 OPTIONS
 -------
+-y::
+--no-prompt::
+       Do not prompt before launching a diff tool.
+
+--prompt::
+       Prompt before each invocation of the diff tool.
+       This is the default behaviour; the option is provided to
+       override any configuration settings.
+
 -t <tool>::
 --tool=<tool>::
-       Use the merge resolution program specified by <tool>.
+       Use the diff tool specified by <tool>.
        Valid merge tools are:
-       kdiff3, kompare, tkdiff, meld, xxdiff, emerge,
-       vimdiff, gvimdiff, ecmerge, and opendiff
+       kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
+       ecmerge, diffuse and opendiff
 +
-If a merge resolution program is not specified, 'git-difftool'
+If a diff tool is not specified, 'git-difftool'
 will use the configuration variable `diff.tool`.  If the
 configuration variable `diff.tool` is not set, 'git-difftool'
 will pick a suitable default.
@@ -42,7 +44,7 @@ can configure the absolute path to kdiff3 by setting
 `difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
 tool is available in PATH.
 +
-Instead of running one of the known merge tool programs,
+Instead of running one of the known diff tools,
 'git-difftool' can be customized to run an alternative program
 by specifying the command line to invoke in a configuration
 variable `difftool.<tool>.cmd`.
@@ -56,8 +58,7 @@ is set to the name of the temporary file containing the contents
 of the diff post-image.  `$BASE` is provided for compatibility
 with custom merge tool commands and has the same value as `$LOCAL`.
 
---no-prompt::
-       Do not prompt before launching a diff tool.
+See linkgit:git-diff[1] for the full list of supported options.
 
 CONFIG VARIABLES
 ----------------
@@ -65,20 +66,19 @@ CONFIG VARIABLES
 difftool equivalents have not been defined.
 
 diff.tool::
-       The default merge tool to use.
+       The default diff tool to use.
 
 difftool.<tool>.path::
        Override the path for the given tool.  This is useful in case
        your tool is not in the PATH.
 
 difftool.<tool>.cmd::
-       Specify the command to invoke the specified merge tool.
+       Specify the command to invoke the specified diff tool.
 +
 See the `--tool=<tool>` option above for more details.
 
-merge.keepBackup::
-       The original, unedited file content can be saved to a file with
-       a `.orig` extension.  Defaults to `true` (i.e. keep the backup files).
+difftool.prompt::
+       Prompt before each invocation of the diff tool.
 
 SEE ALSO
 --------
index b362e9ed12fb8c45802d488eb5685f8842e0607d..8dc873fd4465879ec3224732c690f1173a6e2dc2 100644 (file)
@@ -75,6 +75,8 @@ 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`.
+       The option core.warnAmbiguousRefs is used to select the strict
+       abbreviation mode.
 
 objecttype::
        The type of the object (`blob`, `tree`, `commit`, `tag`).
index eb2fbcff1a103c2b973eccbb449a20d3b68f157f..6f1fc80119600c419d2e3b98bac0c44f9cb09026 100644 (file)
@@ -9,10 +9,10 @@ git-format-patch - Prepare patches for e-mail submission
 SYNOPSIS
 --------
 [verse]
-'git format-patch' [-k] [-o <dir> | --stdout] [--thread]
-                  [--attach[=<boundary>] | --inline[=<boundary>] |
-                    [--no-attach]]
-                  [-s | --signoff] [<common diff options>]
+'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout]
+                  [--thread[=<style>]]
+                  [(--attach|--inline)[=<boundary>] | --no-attach]
+                  [-s | --signoff]
                   [-n | --numbered | -N | --no-numbered]
                   [--start-number <n>] [--numbered-files]
                   [--in-reply-to=Message-Id] [--suffix=.<sfx>]
@@ -20,6 +20,7 @@ SYNOPSIS
                   [--subject-prefix=Subject-Prefix]
                   [--cc=<email>]
                   [--cover-letter]
+                  [<common diff options>]
                   [ <since> | <revision range> ]
 
 DESCRIPTION
@@ -128,9 +129,9 @@ include::diff-options.txt[]
        the Message-Id header to reference.
 +
 The optional <style> argument can be either `shallow` or `deep`.
-'Shallow' threading makes every mail a reply to the head of the
+'shallow' threading makes every mail a reply to the head of the
 series, where the head is chosen from the cover letter, the
-`\--in-reply-to`, and the first patch mail, in this order.  'Deep'
+`\--in-reply-to`, and the first patch mail, in this order.  'deep'
 threading makes every mail a reply to the previous one.  If not
 specified, defaults to the 'format.thread' configuration, or `shallow`
 if that is not set.
@@ -170,18 +171,17 @@ if that is not set.
 --suffix=.<sfx>::
        Instead of using `.patch` as the suffix for generated
        filenames, use specified suffix.  A common alternative is
-       `--suffix=.txt`.
+       `--suffix=.txt`.  Leaving this empty will remove the `.patch`
+       suffix.
 +
-Note that you would need to include the leading dot `.` if you
-want a filename like `0001-description-of-my-change.patch`, and
-the first letter does not have to be a dot.  Leaving it empty would
-not add any suffix.
+Note that the leading character does not have to be a dot; for example,
+you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
 
 --no-binary::
-       Don't output contents of changes in binary files, just take note
-       that they differ.  Note that this disable the patch to be properly
-       applied.  By default the contents of changes in those files are
-       encoded in the patch.
+       Do not output contents of changes in binary files, instead
+       display a notice that those files changed.  Patches generated
+       using this option cannot be applied properly, but they are
+       still useful for code review.
 
 --root::
        Treat the revision argument as a <revision range>, even if it
@@ -192,10 +192,10 @@ not add any suffix.
 
 CONFIGURATION
 -------------
-You can specify extra mail header lines to be added to each message
-in the repository configuration, new defaults for the subject prefix
-and file suffix, control attachements, and number patches when outputting
-more than one.
+You can specify extra mail header lines to be added to each message,
+defaults for the subject prefix and file suffix, number patches when
+outputting more than one patch, add "Cc:" headers, configure attachments,
+and sign off patches with configuration variables.
 
 ------------
 [format]
@@ -243,8 +243,8 @@ $ git format-patch -M -B origin
 +
 Additionally, it detects and handles renames and complete rewrites
 intelligently to produce a renaming patch.  A renaming patch reduces
-the amount of text output, and generally makes it easier to review it.
-Note that the "patch" program does not understand renaming patches, so
+the amount of text output, and generally makes it easier to review.
+Note that non-git "patch" programs won't understand renaming patches, so
 use it only when you know the recipient uses git to apply your patch.
 
 * Extract three topmost commits from the current branch and format them
index 024084b8b717d680c274737a14f609d299b6daa8..d016dafd491de5a4635e30b92607dadbaf7bf46f 100644 (file)
@@ -51,7 +51,7 @@ imap.host::
 imap.user::
        The username to use when logging in to the server.
 
-imap.password::
+imap.pass::
        The password to use when logging in to the server.
 
 imap.port::
index 71749c09d309f4cae2da9788969359d2620224a9..7151d12f349b7c6e265d5a4631029d71028a2c7d 100644 (file)
@@ -54,15 +54,21 @@ is given:
 
  - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
    the git group may be not the primary group of all users).
+   This is used to loosen the permissions of an otherwise safe umask(2) value.
+   Note that the umask still applies to the other permission bits (e.g. if
+   umask is '0022', using 'group' will not remove read privileges from other
+   (non-group) users). See '0xxx' for how to exactly specify the repository
+   permissions.
 
  - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
    readable by all users.
 
- - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'
-   Any option except 'umask' can be set using this option. '0xxx' will
-   override users umask(2) value, and thus, users with a safe umask (0077)
-   can use this option. '0640' will create a repository which is group-readable
-   but not writable. '0660' is equivalent to 'group'.
+ - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'.
+   '0xxx' will override users' umask(2) value (and not only loosen permissions
+   as 'group' and 'all' does). '0640' will create a repository which is
+   group-readable, but not group-writable or accessible to others. '0660' will
+   create a repo that is readable and writable to the current user and group,
+   but inaccessible to others.
 
 By default, the configuration flag receive.denyNonFastForwards is enabled
 in shared repositories, so that you cannot force a non fast-forwarding push
index f68e5c5c1abd15350e679eebf976f0ac8516123b..c3fdccb4c2f66b8b3a3c6b60b21feac881b06cb4 100644 (file)
@@ -82,8 +82,10 @@ Output Format
 -------------
         <mode> SP <type> SP <object> TAB <file>
 
-When the `-z` option is not used, TAB, LF, and backslash characters
+Unless the `-z` option is used, TAB, LF, and backslash characters
 in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
+This output format is compatible with what '--index-info --stdin' of
+'git update-index' expects.
 
 When the `-l` option is used, format changes to
 
diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt
new file mode 100644 (file)
index 0000000..78eb03f
--- /dev/null
@@ -0,0 +1,54 @@
+git-mergetool--lib(1)
+=====================
+
+NAME
+----
+git-mergetool--lib - Common git merge tool shell scriptlets
+
+SYNOPSIS
+--------
+'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"'
+
+DESCRIPTION
+-----------
+
+This is not a command the end user would want to run.  Ever.
+This documentation is meant for people who are studying the
+Porcelain-ish scripts and/or are writing new ones.
+
+The 'git-mergetool--lib' scriptlet is designed to be sourced (using
+`.`) by other shell scripts to set up functions for working
+with git merge tools.
+
+Before sourcing 'git-mergetool--lib', your script must set `TOOL_MODE`
+to define the operation mode for the functions listed below.
+'diff' and 'merge' are valid values.
+
+FUNCTIONS
+---------
+get_merge_tool::
+       returns a merge tool.
+
+get_merge_tool_cmd::
+       returns the custom command for a merge tool.
+
+get_merge_tool_path::
+       returns the custom path for a merge tool.
+
+run_merge_tool::
+       launches a merge tool given the tool name and a true/false
+       flag to indicate whether a merge base is present.
+       '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
+       for use by the merge tool.
+
+Author
+------
+Written by David Aguilar <davvid@gmail.com>
+
+Documentation
+--------------
+Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 5d3c6328726ba1af829026dd97840fc43335cfe0..ff9700d17a333f50d6509bc14a0bd81fad876d3b 100644 (file)
@@ -26,7 +26,8 @@ OPTIONS
 --tool=<tool>::
        Use the merge resolution program specified by <tool>.
        Valid merge tools are:
-       kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff
+       kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge,
+       diffuse, tortoisemerge and opendiff
 +
 If a merge resolution program is not specified, 'git-mergetool'
 will use the configuration variable `merge.tool`.  If the
index 3d5a066c31675e502eb027dde824d1966c9c0f09..26f3b7b2b0daad0affb36e6514156520a693b164 100644 (file)
@@ -231,8 +231,7 @@ OPTIONS
 
 -s <strategy>::
 --strategy=<strategy>::
-       Use the given merge strategy; can be supplied more than
-       once to specify them in the order they should be tried.
+       Use the given merge strategy.
        If there is no `-s` option, a built-in list of strategies
        is used instead ('git-merge-recursive' when merging a single
        head, 'git-merge-octopus' otherwise).  This implies --merge.
index 5ed2bc840f962cfe3af6bf4540edf46f47b9e148..4bbdd056da4ca5a3032b53afac820b86c74a54e4 100644 (file)
@@ -26,10 +26,15 @@ OPTIONS
 --parseopt::
        Use 'git-rev-parse' in option parsing mode (see PARSEOPT section below).
 
---keep-dash-dash::
+--keep-dashdash::
        Only meaningful in `--parseopt` mode. Tells the option parser to echo
        out the first `--` met instead of skipping it.
 
+--sq-quote::
+       Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE
+       section below). In contrast to the `--sq` option below, this
+       mode does only quoting. Nothing else is done to command input.
+
 --revs-only::
        Do not output flags and parameters not meant for
        'git-rev-list' command.
@@ -64,7 +69,8 @@ OPTIONS
        properly quoted for consumption by shell.  Useful when
        you expect your parameter to contain whitespaces and
        newlines (e.g. when using pickaxe `-S` with
-       'git-diff-\*').
+       'git-diff-\*'). In contrast to the `--sq-quote` option,
+       the command input is still interpreted as usual.
 
 --not::
        When showing object names, prefix them with '{caret}' and
@@ -84,6 +90,11 @@ OPTIONS
        unfortunately named tag "master"), and show them as full
        refnames (e.g. "refs/heads/master").
 
+--abbrev-ref[={strict|loose}]::
+       A non-ambiguous short name of the objects name.
+       The option core.warnAmbiguousRefs is used to select the strict
+       abbreviation mode.
+
 --all::
        Show all refs found in `$GIT_DIR/refs`.
 
@@ -401,6 +412,33 @@ C?        option C with an optional argument"
 eval `echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?`
 ------------
 
+SQ-QUOTE
+--------
+
+In `--sq-quote` mode, 'git-rev-parse' echoes on the standard output a
+single line suitable for `sh(1)` `eval`. This line is made by
+normalizing the arguments following `--sq-quote`. Nothing other than
+quoting the arguments is done.
+
+If you want command input to still be interpreted as usual by
+'git-rev-parse' before the output is shell quoted, see the `--sq`
+option.
+
+Example
+~~~~~~~
+
+------------
+$ cat >your-git-script.sh <<\EOF
+#!/bin/sh
+args=$(git rev-parse --sq-quote "$@")   # quote user-supplied arguments
+command="git frotz -n24 $args"          # and use it inside a handcrafted
+                                       # command line
+eval "$command"
+EOF
+
+$ sh your-git-script.sh "a b'c"
+------------
+
 EXAMPLES
 --------
 
index f7e428eb50292e2a186cd903fa4610f446c3890f..7c5ce415c7f27b4fb9b90ba65abf16158d36af82 100644 (file)
@@ -70,9 +70,12 @@ Missing From or In-Reply-To headers will be prompted for.
 See the CONFIGURATION section for 'sendemail.multiedit'.
 
 --from=<address>::
-       Specify the sender of the emails.  This will default to
-       the value GIT_COMMITTER_IDENT, as returned by "git var -l".
-       The user will still be prompted to confirm this entry.
+       Specify the sender of the emails.  If not specified on the command line,
+       the value of the 'sendemail.from' configuration option is used.  If
+       neither the command line option nor 'sendemail.from' are set, then the
+       user will be prompted for the value.  The default for the prompt will be
+       the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not
+       set, as returned by "git var -l".
 
 --in-reply-to=<identifier>::
        Specify the contents of the first In-Reply-To header.
@@ -265,7 +268,7 @@ sendemail.aliasesfile::
 
 sendemail.aliasfiletype::
        Format of the file(s) specified in sendemail.aliasesfile. Must be
-       one of 'mutt', 'mailrc', 'pine', or 'gnus'.
+       one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus'.
 
 sendemail.multiedit::
        If true (default), a single editor instance will be spawned to edit
index 3f8d973af1c9b8aead3f831eb94a42b2e461ec8b..0f3ad811cfa41e65a3d807a5eb766ce2a66a7831 100644 (file)
@@ -18,9 +18,9 @@ of server-side GIT commands implementing the pull/push functionality.
 The commands can be executed only by the '-c' option; the shell is not
 interactive.
 
-Currently, only three commands are permitted to be called, 'git-receive-pack'
-'git-upload-pack' with a single required argument or 'cvs server' (to invoke
-'git-cvsserver').
+Currently, only four commands are permitted to be called, 'git-receive-pack'
+'git-upload-pack' and 'git-upload-archive' with a single required argument, or
+'cvs server' (to invoke 'git-cvsserver').
 
 Author
 ------
index 7e9ff3762b111d8740a99b676ea516435018f3a8..edd8f6463ebab38f950db634e28fe5f06cf3915a 100644 (file)
@@ -10,6 +10,7 @@ SYNOPSIS
 [verse]
 'git show-branch' [--all] [--remotes] [--topo-order] [--current]
                [--more=<n> | --list | --independent | --merge-base]
+               [--color | --no-color]
                [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
 'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
 
@@ -107,6 +108,14 @@ OPTIONS
        When no explicit <ref> parameter is given, it defaults to the
        current branch (or `HEAD` if it is detached).
 
+--color::
+       Color the status sign (one of these: `*` `!` `+` `-`) of each commit
+       corresponding to the branch it's in.
+
+--no-color::
+       Turn off colored output, even when the configuration file gives the
+       default to color output.
+
 Note that --more, --list, --independent and --merge-base options
 are mutually exclusive.
 
@@ -148,9 +157,10 @@ $ git show-branch master fixes mhf
 ------------------------------------------------
 
 These three branches all forked from a common commit, [master],
-whose commit message is "Add 'git show-branch'.  "fixes" branch
-adds one commit 'Introduce "reset type"'.  "mhf" branch has many
-other commits.  The current branch is "master".
+whose commit message is "Add \'git show-branch\'". The "fixes"
+branch adds one commit "Introduce "reset type" flag to "git reset"".
+The "mhf" branch adds many other commits. The current branch
+is "master".
 
 
 EXAMPLE
index 051f94d26f9f057cbd4db0d6886ca1a4d33c912c..1cc24cc47e3b9845c9d1006ee58faed1bc731c49 100644 (file)
@@ -75,14 +75,22 @@ show [<stash>]::
        it will accept any format known to 'git-diff' (e.g., `git stash show
        -p stash@\{1}` to view the second most recent stash in patch form).
 
-apply [--index] [<stash>]::
+pop [<stash>]::
 
-       Restore the changes recorded in the stash on top of the current
-       working tree state.  When no `<stash>` is given, applies the latest
-       one.  The working directory must match the index.
+       Remove a single stashed state from the stash list and apply it
+       on top of the current working tree state, i.e., do the inverse
+       operation of `git stash save`. The working directory must
+       match the index.
 +
-This operation can fail with conflicts; you need to resolve them
-by hand in the working tree.
+Applying the state can fail with conflicts; in this case, it is not
+removed from the stash list. You need to resolve the conflicts by hand
+and call `git stash drop` manually afterwards.
++
+When no `<stash>` is given, `stash@\{0}` is assumed. See also `apply`.
+
+apply [--index] [<stash>]::
+
+       Like `pop`, but do not remove the state from the stash list.
 +
 If the `--index` option is used, then tries to reinstate not only the working
 tree's changes, but also the index's ones. However, this can fail, when you
@@ -112,12 +120,6 @@ drop [<stash>]::
        Remove a single stashed state from the stash list. When no `<stash>`
        is given, it removes the latest one. i.e. `stash@\{0}`
 
-pop [<stash>]::
-
-       Remove a single stashed state from the stash list and apply on top
-       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
@@ -163,7 +165,7 @@ $ git pull
 file foobar not up to date, cannot merge.
 $ git stash
 $ git pull
-$ git stash apply
+$ git stash pop
 ----------------------------------------------------------------
 
 Interrupted workflow::
@@ -192,7 +194,7 @@ You can use 'git-stash' to simplify the above, like this:
 $ git stash
 $ edit emergency fix
 $ git commit -a -m "Fix in a hurry"
-$ git stash apply
+$ git stash pop
 # ... continue hacking ...
 ----------------------------------------------------------------
 
index 3b8df4467377d73d613f76875c725cbf8544ee77..14256c695b3817014be8ba4f45a62a2cd588939c 100644 (file)
@@ -9,10 +9,12 @@ git-submodule - Initialize, update or inspect submodules
 SYNOPSIS
 --------
 [verse]
-'git submodule' [--quiet] add [-b branch] [--] <repository> <path>
+'git submodule' [--quiet] add [-b branch]
+             [--reference <repository>] [--] <repository> <path>
 'git submodule' [--quiet] status [--cached] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
-'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...]
+'git submodule' [--quiet] update [--init] [-N|--no-fetch]
+             [--reference <repository>] [--] [<path>...]
 'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
 'git submodule' [--quiet] foreach <command>
 'git submodule' [--quiet] sync [--] [<path>...]
@@ -177,6 +179,14 @@ OPTIONS
        This option is only valid for the update command.
        Don't fetch new objects from the remote site.
 
+--reference <repository>::
+       This option is only valid for add and update commands.  These
+       commands sometimes need to clone a remote repository. In this case,
+       this option will be passed to the linkgit:git-clone[1] command.
++
+*NOTE*: Do *not* use this option unless you have read the note
+for linkgit:git-clone[1]'s --reference and --shared options carefully.
+
 <path>...::
        Paths to submodule(s). When specified this will restrict the command
        to only operate on the submodules found at the specified paths.
index 9229d45ad9a94047a7ce4f24543770ebc521ef61..ca3fc3de1fcfc3509a9d5d1ff268c9673bafc3c0 100644 (file)
@@ -398,6 +398,14 @@ after the authors-file is modified should continue operation.
 
 config key: svn.authorsfile
 
+--authors-prog=<filename>::
+
+If this option is specified, for each SVN committer name that does not
+exist in the authors file, the given file is executed with the committer
+name as the first argument.  The program is expected to return a single
+line of the form "Name <email>", which will be treated as if included in
+the authors file.
+
 -q::
 --quiet::
        Make 'git-svn' less verbose. Specify a second time to make it
@@ -693,9 +701,9 @@ listed below are allowed:
        tags = tags/*/project-a:refs/remotes/project-a/tags/*
 ------------------------------------------------------------------------
 
-Keep in mind that the '*' (asterisk) wildcard of the local ref
+Keep in mind that the '\*' (asterisk) wildcard of the local ref
 (right of the ':') *must* be the farthest right path component;
-however the remote wildcard may be anywhere as long as it's own
+however the remote wildcard may be anywhere as long as it's an
 independent path component (surrounded by '/' or EOL).   This
 type of configuration is not automatically created by 'init' and
 should be manually entered with a text-editor or using 'git-config'.
index 35d27b0c7f0e4b7a1d0851140958e71fabb0e6bc..035cc3018f22a9e2669c94f10475624d02f4098a 100644 (file)
@@ -39,12 +39,6 @@ what they are for:
 * info/refs
 
 
-BUGS
-----
-When you remove an existing ref, the command fails to update
-info/refs file unless `--force` flag is given.
-
-
 Author
 ------
 Written by Junio C Hamano <gitster@pobox.com>
index 470fdc5ecd5609dc4f05c54b8aea53f6de292e4a..9d8f236fe84cd02550b8cf08e835b2926e6c45f0 100644 (file)
@@ -43,9 +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.2.3/git.html[documentation for release 1.6.2.3]
+* link:v1.6.3/git.html[documentation for release 1.6.3]
 
 * release notes for
+  link:RelNotes-1.6.2.5.txt[1.6.2.5],
+  link:RelNotes-1.6.2.4.txt[1.6.2.4],
   link:RelNotes-1.6.2.3.txt[1.6.2.3],
   link:RelNotes-1.6.2.2.txt[1.6.2.2],
   link:RelNotes-1.6.2.1.txt[1.6.2.1],
index b762bba759c790eb27c5adc0f622a954c76ecb3a..aaa073efc80522a649f17d60127aae8cc85b0b3b 100644 (file)
@@ -297,7 +297,8 @@ for paths.
 
 Then, you would define a "diff.tex.xfuncname" configuration to
 specify a regular expression that matches a line that you would
-want to appear as the hunk header "TEXT", like this:
+want to appear as the hunk header "TEXT". Add a section to your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
 
 ------------------------
 [diff "tex"]
@@ -345,7 +346,8 @@ split words in a line, by specifying an appropriate regular expression
 in the "diff.*.wordRegex" configuration variable.  For example, in TeX
 a backslash followed by a sequence of letters forms a command, but
 several such commands can be run together without intervening
-whitespace.  To separate them, use a regular expression such as
+whitespace.  To separate them, use a regular expression in your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
 
 ------------------------
 [diff "tex"]
@@ -373,7 +375,8 @@ resulting text on stdout.
 
 For example, to show the diff of the exif information of a
 file instead of the binary information (assuming you have the
-exif tool installed):
+exif tool installed), add the following section to your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file):
 
 ------------------------
 [diff "jpg"]
index aaa7ef737a4c190c60e37e2849ce42f3bdb5dda7..0e49c1c03776af30f0509679f720273061aaa7b3 100644 (file)
@@ -118,7 +118,7 @@ Importing a CVS archive
 First, install version 2.1 or higher of cvsps from
 link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
 sure it is in your path.  Then cd to a checked out CVS working directory
-of the project you are interested in and run 'git-cvsimport':
+of the project you are interested in and run linkgit:git-cvsimport[1]:
 
 -------------------------------------------
 $ git cvsimport -C <destination> <module>
index 1ff08ff2ccc6e56542f49713867698b66dab673f..4832bc75e2604c997e004018023e3b93cb394b87 100644 (file)
@@ -22,7 +22,8 @@ merge.stat::
 merge.tool::
        Controls which merge resolution program is used by
        linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
-       "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
+       "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff",
+       "diffuse", "ecmerge", "tortoisemerge", and
        "opendiff".  Any other value is treated is custom merge tool
        and there must be a corresponding mergetool.<tool>.cmd option.
 
index 637b53f898829af98153d60953434fa30e3df179..adadf8e4bf309a2fd2ec8efbeff09b410ca7b041 100644 (file)
@@ -39,7 +39,8 @@
 
 --squash::
        Produce the working tree and index state as if a real
-       merge happened, but do not actually make a commit or
+       merge happened (except for the merge information),
+       but do not actually make a commit or
        move the `HEAD`, nor record `$GIT_DIR/MERGE_HEAD` to
        cause the next `git commit` command to create a merge
        commit.  This allows you to create a single commit on
index 7ede1e64e5d40ec8f742e900d7273d6f961605e2..5cb2b0590abb1fc4e4685097ba3cdd3d0683a95f 100644 (file)
@@ -37,7 +37,7 @@ where options is the bitwise-or of:
 
        Make sure there is a work tree, i.e. the command cannot act
        on bare repositories.
-       This makes only sense when `RUN_SETUP` is also set.
+       This only makes sense when `RUN_SETUP` is also set.
 
 . Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`.
 
index e66ca9f70c705841c864196a3a651e04d8156e01..b43458eae6787caab163fadab113dff61e577498 100644 (file)
@@ -137,6 +137,10 @@ There are some macros to easily define options:
        Introduce a boolean option.
        If used, `int_var` is bitwise-ored with `mask`.
 
+`OPT_NEGBIT(short, long, &int_var, description, mask)`::
+       Introduce a boolean option.
+       If used, `int_var` is bitwise-anded with the inverted `mask`.
+
 `OPT_SET_INT(short, long, &int_var, description, integer)`::
        Introduce a boolean option.
        If used, set `int_var` to `integer`.
@@ -166,6 +170,14 @@ There are some macros to easily define options:
 `OPT_ARGUMENT(long, description)`::
        Introduce a long-option argument that will be kept in `argv[]`.
 
+`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
+       Recognize numerical options like -123 and feed the integer as
+       if it was an argument to the function given by `func_ptr`.
+       The result will be put into `var`.  There can be only one such
+       option definition.  It cannot be negated and it takes no
+       arguments.  Short options that happen to be digits take
+       precedence over it.
+
 
 The last element of the array must be `OPT_END()`.
 
@@ -198,7 +210,7 @@ The function must be defined in this form:
 
 The callback mechanism is as follows:
 
-* Inside `funct`, the only interesting member of the structure
+* Inside `func`, the only interesting member of the structure
   given by `opt` is the void pointer `opt->value`.
   `\*opt->value` will be the value that is saved into `var`, if you
   use `OPT_CALLBACK()`.
index dbbeb7e7c7856776450bc64321ff5f1de26202bb..0b88a51d0b192a3dbc2ec0fe73a32860247377a1 100644 (file)
@@ -1520,10 +1520,10 @@ $ git commit -a -m "blorpl: typofix"
 ------------------------------------------------
 
 After that, you can go back to what you were working on with
-`git stash apply`:
+`git stash pop`:
 
 ------------------------------------------------
-$ git stash apply
+$ git stash pop
 ------------------------------------------------
 
 
index 97fc1e0519936111beb295cbb345aa206cdd8893..39cde784c947fae6a2f294caac1898b9199d769d 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.6.2.GIT
+DEF_VER=v1.6.3.GIT
 
 LF='
 '
index 7c8763710c12350589e9a39815c8ad34a5054c37..eaae45db7cded397eb109d81f6dbf6b8c8a2bc69 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -167,6 +167,17 @@ all::
 # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call
 # your external grep (e.g., if your system lacks grep, if its grep is
 # broken, or spawning external process is slower than built-in grep git has).
+#
+# Define UNRELIABLE_FSTAT if your system's fstat does not return the same
+# information on a not yet closed file that lstat would return for the same
+# file after it was closed.
+#
+# Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems
+# when hardlinking a file to another name and unlinking the original file right
+# away (some NTFS drivers seem to zero the contents in that scenario).
+#
+# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
+# programs as a tar, where bin/ and libexec/ might be on different file systems.
 
 GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -217,6 +228,7 @@ ETC_GITCONFIG = etc/gitconfig
 endif
 lib = lib
 # DESTDIR=
+pathsep = :
 
 # default configuration for gitweb
 GITWEB_CONFIG = gitweb_config.perl
@@ -279,12 +291,14 @@ TEST_PROGRAMS =
 
 SCRIPT_SH += git-am.sh
 SCRIPT_SH += git-bisect.sh
+SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-lost-found.sh
 SCRIPT_SH += git-merge-octopus.sh
 SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
+SCRIPT_SH += git-mergetool--lib.sh
 SCRIPT_SH += git-parse-remote.sh
 SCRIPT_SH += git-pull.sh
 SCRIPT_SH += git-quiltimport.sh
@@ -298,6 +312,7 @@ SCRIPT_SH += git-submodule.sh
 SCRIPT_SH += git-web--browse.sh
 
 SCRIPT_PERL += git-add--interactive.perl
+SCRIPT_PERL += git-difftool.perl
 SCRIPT_PERL += git-archimport.perl
 SCRIPT_PERL += git-cvsexportcommit.perl
 SCRIPT_PERL += git-cvsimport.perl
@@ -316,7 +331,6 @@ EXTRA_PROGRAMS =
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS += $(EXTRA_PROGRAMS)
 PROGRAMS += git-fast-import$X
-PROGRAMS += git-fetch-pack$X
 PROGRAMS += git-hash-object$X
 PROGRAMS += git-index-pack$X
 PROGRAMS += git-merge-index$X
@@ -325,7 +339,6 @@ PROGRAMS += git-mktag$X
 PROGRAMS += git-mktree$X
 PROGRAMS += git-pack-redundant$X
 PROGRAMS += git-patch-id$X
-PROGRAMS += git-send-pack$X
 PROGRAMS += git-shell$X
 PROGRAMS += git-show-index$X
 PROGRAMS += git-unpack-file$X
@@ -356,9 +369,6 @@ ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
 
 # what 'all' will build but not install in gitexecdir
 OTHER_PROGRAMS = git$X
-ifndef NO_PERL
-OTHER_PROGRAMS += gitweb/gitweb.cgi
-endif
 
 # Set paths to tools early so that they can be used for version tests.
 ifndef SHELL_PATH
@@ -743,6 +753,7 @@ endif
 ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
        NO_MEMMEM = YesPlease
+       USE_ST_TIMESPEC = YesPlease
        NEEDS_LIBICONV = YesPlease
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
@@ -755,6 +766,7 @@ ifeq ($(uname_S),NetBSD)
        BASIC_CFLAGS += -I/usr/pkg/include
        BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
        THREADED_DELTA_SEARCH = YesPlease
+       USE_ST_TIMESPEC = YesPlease
 endif
 ifeq ($(uname_S),AIX)
        NO_STRCASESTR=YesPlease
@@ -802,8 +814,10 @@ ifeq ($(uname_S),HP-UX)
 endif
 ifneq (,$(findstring CYGWIN,$(uname_S)))
        COMPAT_OBJS += compat/cygwin.o
+       UNRELIABLE_FSTAT = UnfortunatelyYes
 endif
 ifneq (,$(findstring MINGW,$(uname_S)))
+       pathsep = ;
        NO_PREAD = YesPlease
        NO_OPENSSL = YesPlease
        NO_CURL = YesPlease
@@ -828,6 +842,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
        NO_NSEC = YesPlease
        USE_WIN32_MMAP = YesPlease
+       UNRELIABLE_FSTAT = UnfortunatelyYes
+       OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
        COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -1011,6 +1027,9 @@ else
                COMPAT_OBJS += compat/win32mmap.o
        endif
 endif
+ifdef OBJECT_CREATION_USES_RENAMES
+       COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
+endif
 ifdef NO_PREAD
        COMPAT_CFLAGS += -DNO_PREAD
        COMPAT_OBJS += compat/pread.o
@@ -1106,6 +1125,9 @@ endif
 ifdef NO_EXTERNAL_GREP
        BASIC_CFLAGS += -DNO_EXTERNAL_GREP
 endif
+ifdef UNRELIABLE_FSTAT
+       BASIC_CFLAGS += -DUNRELIABLE_FSTAT
+endif
 
 ifeq ($(TCLTK_PATH),)
 NO_TCLTK=NoThanks
@@ -1232,7 +1254,6 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
            -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-           -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
            -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
            -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
            $@.sh >$@+ && \
@@ -1251,7 +1272,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
        sed -e '1{' \
            -e '        s|#!.*perl|#!$(PERL_PATH_SQ)|' \
            -e '        h' \
-           -e '        s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
+           -e '        s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
            -e '        H' \
            -e '        x' \
            -e '}' \
@@ -1261,6 +1282,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
        chmod +x $@+ && \
        mv $@+ $@
 
+OTHER_PROGRAMS += gitweb/gitweb.cgi
 gitweb/gitweb.cgi: gitweb/gitweb.perl
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
@@ -1519,17 +1541,20 @@ install: all
        $(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 git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)'
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
+ifndef NO_PERL
        $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
+endif
 ifndef NO_TCLTK
        $(MAKE) -C gitk-git install
        $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
 endif
 ifneq (,$X)
-       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
+       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
 endif
        bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
        execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
        { $(RM) "$$execdir/git-add$X" && \
+               test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
                ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
                cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
        { for p in $(filter-out git-add$X,$(BUILT_INS)); do \
@@ -1537,7 +1562,7 @@ endif
                ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \
                ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \
                cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \
-         done } && \
+         done; } && \
        ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
 
 install-doc:
index dd8bc4bb4ab75e1148cb9b7aaf8ff7384ebb19ec..f8e49a5070afc21fbd3db9320841300fe93c570f 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.6.3.txt
\ No newline at end of file
+Documentation/RelNotes-1.6.4.txt
\ No newline at end of file
diff --git a/alias.c b/alias.c
index ccb1108c94436035d0da8b1d6f08f859b68294a3..372b7d809301f9e3e936459e405cd6f2627bd4a9 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -27,7 +27,7 @@ int split_cmdline(char *cmdline, const char ***argv)
        int src, dst, count = 0, size = 16;
        char quoted = 0;
 
-       *argv = xmalloc(sizeof(char*) * size);
+       *argv = xmalloc(sizeof(char *) * size);
 
        /* split alias_string */
        (*argv)[count++] = cmdline;
@@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv)
                        while (cmdline[++src]
                                        && isspace(cmdline[src]))
                                ; /* skip */
-                       if (count >= size) {
-                               size += 16;
-                               *argv = xrealloc(*argv, sizeof(char*) * size);
-                       }
+                       ALLOC_GROW(*argv, count+1, size);
                        (*argv)[count++] = cmdline + dst;
                } else if (!quoted && (c == '\'' || c == '"')) {
                        quoted = c;
@@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv)
                return error("unclosed quote");
        }
 
+       ALLOC_GROW(*argv, count+1, size);
+       (*argv)[count] = NULL;
+
        return count;
 }
 
diff --git a/alloc.c b/alloc.c
index 216c23a6f854c614d38c743cd7687a37f304161b..6ef6753d180afad29bc335854150c824b9de8a18 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -57,7 +57,7 @@ DEFINE_ALLOCATOR(object, union any_object)
 #define SZ_FMT "%zu"
 #endif
 
-static void report(const charname, unsigned int count, size_t size)
+static void report(const char *name, unsigned int count, size_t size)
 {
     fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size);
 }
index ba890ebdecd8672aeb32757605c8a2976fa21161..cee06ce3cbc1819008337633ed0753638c423ac5 100644 (file)
@@ -180,7 +180,7 @@ static int write_tar_entry(struct archiver_args *args,
 
        sprintf(header.mode, "%07o", mode & 07777);
        sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
-       sprintf(header.mtime, "%011lo", args->time);
+       sprintf(header.mtime, "%011lo", (unsigned long) args->time);
 
        sprintf(header.uid, "%07o", 0);
        sprintf(header.gid, "%07o", 0);
index 96b62d4309a3bd4198bb035f266a1326fed61d10..b2b90d31700d3aa50a3ac0626c1a8561c37c49b7 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -4,6 +4,7 @@
 #include "attr.h"
 #include "archive.h"
 #include "parse-options.h"
+#include "unpack-trees.h"
 
 static char const * const archive_usage[] = {
        "git archive [options] <tree-ish> [path...]",
@@ -150,6 +151,8 @@ int write_archive_entries(struct archiver_args *args,
                write_archive_entry_fn_t write_entry)
 {
        struct archiver_context context;
+       struct unpack_trees_options opts;
+       struct tree_desc t;
        int err;
 
        if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
@@ -168,6 +171,22 @@ int write_archive_entries(struct archiver_args *args,
        context.args = args;
        context.write_entry = write_entry;
 
+       /*
+        * Setup index and instruct attr to read index only
+        */
+       if (!args->worktree_attributes) {
+               memset(&opts, 0, sizeof(opts));
+               opts.index_only = 1;
+               opts.head_idx = -1;
+               opts.src_index = &the_index;
+               opts.dst_index = &the_index;
+               opts.fn = oneway_merge;
+               init_tree_desc(&t, args->tree->buffer, args->tree->size);
+               if (unpack_trees(1, &t, &opts))
+                       return -1;
+               git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
+       }
+
        err =  read_tree_recursive(args->tree, args->base, args->baselen, 0,
                        args->pathspec, write_archive_entry, &context);
        if (err == READ_TREE_RECURSIVE)
@@ -258,6 +277,7 @@ static int parse_archive_args(int argc, const char **argv,
        int verbose = 0;
        int i;
        int list = 0;
+       int worktree_attributes = 0;
        struct option opts[] = {
                OPT_GROUP(""),
                OPT_STRING(0, "format", &format, "fmt", "archive format"),
@@ -265,6 +285,8 @@ static int parse_archive_args(int argc, const char **argv,
                        "prepend prefix to each pathname in the archive"),
                OPT_STRING(0, "output", &output, "file",
                        "write the archive to this file"),
+               OPT_BOOLEAN(0, "worktree-attributes", &worktree_attributes,
+                       "read .gitattributes in working directory"),
                OPT__VERBOSE(&verbose),
                OPT__COMPR('0', &compression_level, "store only", 0),
                OPT__COMPR('1', &compression_level, "compress faster", 1),
@@ -324,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv,
        args->verbose = verbose;
        args->base = base;
        args->baselen = strlen(base);
+       args->worktree_attributes = worktree_attributes;
 
        return argc;
 }
index 0b15b35143fffcc13764e4e668ee452b191cc609..038ac353d40567029403e3e7a2933af73a130720 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -10,6 +10,7 @@ struct archiver_args {
        time_t time;
        const char **pathspec;
        unsigned int verbose : 1;
+       unsigned int worktree_attributes : 1;
        int compression_level;
 };
 
diff --git a/attr.c b/attr.c
index 43259e5b01f7c8368e5b5d53d8ed4af9dba593ee..98eb636f13d314c20e18e646c074e2511b3c891c 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -224,7 +224,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
                if (is_macro)
                        res->u.attr = git_attr(name, namelen);
                else {
-                       res->u.pattern = (char*)&(res->state[num_attr]);
+                       res->u.pattern = (char *)&(res->state[num_attr]);
                        memcpy(res->u.pattern, name, namelen);
                        res->u.pattern[namelen] = 0;
                }
@@ -275,7 +275,7 @@ static void free_attr_elem(struct attr_stack *e)
                            setto == ATTR__UNKNOWN)
                                ;
                        else
-                               free((char*) setto);
+                               free((char *) setto);
                }
                free(a);
        }
@@ -405,7 +405,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
                if (!res)
                        res = read_attr_from_file(path, macro_ok);
        }
-       else {
+       else if (direction == GIT_ATTR_CHECKIN) {
                res = read_attr_from_file(path, macro_ok);
                if (!res)
                        /*
@@ -415,6 +415,8 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
                         */
                        res = read_attr_from_index(path, macro_ok);
        }
+       else
+               res = read_attr_from_index(path, macro_ok);
        if (!res)
                res = xcalloc(1, sizeof(*res));
        return res;
@@ -466,7 +468,7 @@ static void bootstrap_attr_stack(void)
                elem->prev = attr_stack;
                attr_stack = elem;
 
-               if (!is_bare_repository()) {
+               if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
                        elem = read_attr(GITATTRIBUTES_FILE, 1);
                        elem->origin = strdup("");
                        elem->prev = attr_stack;
@@ -533,7 +535,7 @@ static void prepare_attr_stack(const char *path, int dirlen)
        /*
         * Read from parent directories and push them down
         */
-       if (!is_bare_repository()) {
+       if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
                while (1) {
                        char *cp;
 
@@ -674,6 +676,10 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
 void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
 {
        enum git_attr_direction old = direction;
+
+       if (is_bare_repository() && new != GIT_ATTR_INDEX)
+               die("BUG: non-INDEX attr direction in a bare repo");
+
        direction = new;
        if (new != old)
                drop_attr_stack();
diff --git a/attr.h b/attr.h
index 3a2f4ec1a09cca06fadedeb32bd86c5e279ad75c..69b5767ebc2189a8bf9d98ff88c1885ec8fcdb7d 100644 (file)
--- a/attr.h
+++ b/attr.h
@@ -33,7 +33,8 @@ int git_checkattr(const char *path, int, struct git_attr_check *);
 
 enum git_attr_direction {
        GIT_ATTR_CHECKIN,
-       GIT_ATTR_CHECKOUT
+       GIT_ATTR_CHECKOUT,
+       GIT_ATTR_INDEX,
 };
 void git_attr_set_direction(enum git_attr_direction, struct index_state *);
 
index 58f7e6f7738def184072247f934cce06d349c91d..c43c120bdefe95bda60b913c5a52d0a942e9d3f6 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -6,15 +6,30 @@
 #include "list-objects.h"
 #include "quote.h"
 #include "sha1-lookup.h"
+#include "run-command.h"
 #include "bisect.h"
 
-static unsigned char (*skipped_sha1)[20];
-static int skipped_sha1_nr;
-static int skipped_sha1_alloc;
+struct sha1_array {
+       unsigned char (*sha1)[20];
+       int sha1_nr;
+       int sha1_alloc;
+       int sorted;
+};
+
+static struct sha1_array good_revs;
+static struct sha1_array skipped_revs;
+
+static const unsigned char *current_bad_sha1;
+
+struct argv_array {
+       const char **argv;
+       int argv_nr;
+       int argv_alloc;
+};
 
-static const char **rev_argv;
-static int rev_argv_nr;
-static int rev_argv_alloc;
+static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL};
+static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
+static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
 
 /* bits #0-15 in revision.h */
 
@@ -398,23 +413,37 @@ struct commit_list *find_bisection(struct commit_list *list,
        return best;
 }
 
+static void argv_array_push(struct argv_array *array, const char *string)
+{
+       ALLOC_GROW(array->argv, array->argv_nr + 1, array->argv_alloc);
+       array->argv[array->argv_nr++] = string;
+}
+
+static void argv_array_push_sha1(struct argv_array *array,
+                                const unsigned char *sha1,
+                                const char *format)
+{
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_addf(&buf, format, sha1_to_hex(sha1));
+       argv_array_push(array, strbuf_detach(&buf, NULL));
+}
+
+static void sha1_array_push(struct sha1_array *array,
+                           const unsigned char *sha1)
+{
+       ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc);
+       hashcpy(array->sha1[array->sha1_nr++], sha1);
+}
+
 static int register_ref(const char *refname, const unsigned char *sha1,
                        int flags, void *cb_data)
 {
        if (!strcmp(refname, "bad")) {
-               ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
-               rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1));
+               current_bad_sha1 = sha1;
        } else if (!prefixcmp(refname, "good-")) {
-               const char *hex = sha1_to_hex(sha1);
-               char *good = xmalloc(strlen(hex) + 2);
-               *good = '^';
-               memcpy(good + 1, hex, strlen(hex) + 1);
-               ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
-               rev_argv[rev_argv_nr++] = good;
+               sha1_array_push(&good_revs, sha1);
        } else if (!prefixcmp(refname, "skip-")) {
-               ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1,
-                          skipped_sha1_alloc);
-               hashcpy(skipped_sha1[skipped_sha1_nr++], sha1);
+               sha1_array_push(&skipped_revs, sha1);
        }
 
        return 0;
@@ -425,7 +454,7 @@ static int read_bisect_refs(void)
        return for_each_ref_in("refs/bisect/", register_ref, NULL);
 }
 
-void read_bisect_paths(void)
+void read_bisect_paths(struct argv_array *array)
 {
        struct strbuf str = STRBUF_INIT;
        const char *filename = git_path("BISECT_NAMES");
@@ -440,8 +469,8 @@ void read_bisect_paths(void)
 
                strbuf_trim(&str);
                quoted = strbuf_detach(&str, NULL);
-               res = sq_dequote_to_argv(quoted, &rev_argv,
-                                        &rev_argv_nr, &rev_argv_alloc);
+               res = sq_dequote_to_argv(quoted, &array->argv,
+                                        &array->argv_nr, &array->argv_alloc);
                if (res)
                        die("Badly quoted content in file '%s': %s",
                            filename, quoted);
@@ -451,26 +480,45 @@ void read_bisect_paths(void)
        fclose(fp);
 }
 
-static int skipcmp(const void *a, const void *b)
+static int array_cmp(const void *a, const void *b)
 {
        return hashcmp(a, b);
 }
 
-static void prepare_skipped(void)
+static void sort_sha1_array(struct sha1_array *array)
 {
-       qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp);
+       qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp);
+
+       array->sorted = 1;
 }
 
-static const unsigned char *skipped_sha1_access(size_t index, void *table)
+static const unsigned char *sha1_access(size_t index, void *table)
 {
-       unsigned char (*skipped)[20] = table;
-       return skipped[index];
+       unsigned char (*array)[20] = table;
+       return array[index];
 }
 
-static int lookup_skipped(unsigned char *sha1)
+static int lookup_sha1_array(struct sha1_array *array,
+                            const unsigned char *sha1)
 {
-       return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
-                       skipped_sha1_access);
+       if (!array->sorted)
+               sort_sha1_array(array);
+
+       return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access);
+}
+
+static char *join_sha1_array_hex(struct sha1_array *array, char delim)
+{
+       struct strbuf joined_hexs = STRBUF_INIT;
+       int i;
+
+       for (i = 0; i < array->sha1_nr; i++) {
+               strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i]));
+               if (i + 1 < array->sha1_nr)
+                       strbuf_addch(&joined_hexs, delim);
+       }
+
+       return strbuf_detach(&joined_hexs, NULL);
 }
 
 struct commit_list *filter_skipped(struct commit_list *list,
@@ -481,15 +529,14 @@ struct commit_list *filter_skipped(struct commit_list *list,
 
        *tried = NULL;
 
-       if (!skipped_sha1_nr)
+       if (!skipped_revs.sha1_nr)
                return list;
 
-       prepare_skipped();
-
        while (list) {
                struct commit_list *next = list->next;
                list->next = NULL;
-               if (0 <= lookup_skipped(list->item->object.sha1)) {
+               if (0 <= lookup_sha1_array(&skipped_revs,
+                                          list->item->object.sha1)) {
                        /* Move current to tried list */
                        *tried = list;
                        tried = &list->next;
@@ -506,51 +553,323 @@ struct commit_list *filter_skipped(struct commit_list *list,
        return filtered;
 }
 
-static void bisect_rev_setup(struct rev_info *revs, const char *prefix)
+static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
+                            const char *bad_format, const char *good_format,
+                            int read_paths)
 {
+       struct argv_array rev_argv = { NULL, 0, 0 };
+       int i;
+
        init_revisions(revs, prefix);
        revs->abbrev = 0;
        revs->commit_format = CMIT_FMT_UNSPECIFIED;
 
-       /* argv[0] will be ignored by setup_revisions */
-       ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
-       rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup");
+       /* rev_argv.argv[0] will be ignored by setup_revisions */
+       argv_array_push(&rev_argv, xstrdup("bisect_rev_setup"));
+       argv_array_push_sha1(&rev_argv, current_bad_sha1, bad_format);
+       for (i = 0; i < good_revs.sha1_nr; i++)
+               argv_array_push_sha1(&rev_argv, good_revs.sha1[i],
+                                    good_format);
+       argv_array_push(&rev_argv, xstrdup("--"));
+       if (read_paths)
+               read_bisect_paths(&rev_argv);
+       argv_array_push(&rev_argv, NULL);
+
+       setup_revisions(rev_argv.argv_nr, rev_argv.argv, revs, NULL);
+}
 
-       if (read_bisect_refs())
-               die("reading bisect refs failed");
+static void bisect_common(struct rev_info *revs)
+{
+       if (prepare_revision_walk(revs))
+               die("revision walk setup failed");
+       if (revs->tree_objects)
+               mark_edges_uninteresting(revs->commits, revs, NULL);
+}
+
+static void exit_if_skipped_commits(struct commit_list *tried,
+                                   const unsigned char *bad)
+{
+       if (!tried)
+               return;
+
+       printf("There are only 'skip'ped commits left to test.\n"
+              "The first bad commit could be any of:\n");
+       print_commit_list(tried, "%s\n", "%s\n");
+       if (bad)
+               printf("%s\n", sha1_to_hex(bad));
+       printf("We cannot bisect more!\n");
+       exit(2);
+}
+
+static int is_expected_rev(const unsigned char *sha1)
+{
+       const char *filename = git_path("BISECT_EXPECTED_REV");
+       struct stat st;
+       struct strbuf str = STRBUF_INIT;
+       FILE *fp;
+       int res = 0;
+
+       if (stat(filename, &st) || !S_ISREG(st.st_mode))
+               return 0;
+
+       fp = fopen(filename, "r");
+       if (!fp)
+               return 0;
+
+       if (strbuf_getline(&str, fp, '\n') != EOF)
+               res = !strcmp(str.buf, sha1_to_hex(sha1));
+
+       strbuf_release(&str);
+       fclose(fp);
+
+       return res;
+}
+
+static void mark_expected_rev(char *bisect_rev_hex)
+{
+       int len = strlen(bisect_rev_hex);
+       const char *filename = git_path("BISECT_EXPECTED_REV");
+       int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+
+       if (fd < 0)
+               die("could not create file '%s': %s",
+                   filename, strerror(errno));
 
-       ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
-       rev_argv[rev_argv_nr++] = xstrdup("--");
+       bisect_rev_hex[len] = '\n';
+       write_or_die(fd, bisect_rev_hex, len + 1);
+       bisect_rev_hex[len] = '\0';
 
-       read_bisect_paths();
+       if (close(fd) < 0)
+               die("closing file %s: %s", filename, strerror(errno));
+}
+
+static int bisect_checkout(char *bisect_rev_hex)
+{
+       int res;
 
-       ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
-       rev_argv[rev_argv_nr++] = NULL;
+       mark_expected_rev(bisect_rev_hex);
 
-       setup_revisions(rev_argv_nr, rev_argv, revs, NULL);
+       argv_checkout[2] = bisect_rev_hex;
+       res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
+       if (res)
+               exit(res);
 
-       revs->limited = 1;
+       argv_show_branch[1] = bisect_rev_hex;
+       return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
 }
 
-int bisect_next_vars(const char *prefix)
+static struct commit *get_commit_reference(const unsigned char *sha1)
+{
+       struct commit *r = lookup_commit_reference(sha1);
+       if (!r)
+               die("Not a valid commit name %s", sha1_to_hex(sha1));
+       return r;
+}
+
+static struct commit **get_bad_and_good_commits(int *rev_nr)
+{
+       int len = 1 + good_revs.sha1_nr;
+       struct commit **rev = xmalloc(len * sizeof(*rev));
+       int i, n = 0;
+
+       rev[n++] = get_commit_reference(current_bad_sha1);
+       for (i = 0; i < good_revs.sha1_nr; i++)
+               rev[n++] = get_commit_reference(good_revs.sha1[i]);
+       *rev_nr = n;
+
+       return rev;
+}
+
+static void handle_bad_merge_base(void)
+{
+       if (is_expected_rev(current_bad_sha1)) {
+               char *bad_hex = sha1_to_hex(current_bad_sha1);
+               char *good_hex = join_sha1_array_hex(&good_revs, ' ');
+
+               fprintf(stderr, "The merge base %s is bad.\n"
+                       "This means the bug has been fixed "
+                       "between %s and [%s].\n",
+                       bad_hex, bad_hex, good_hex);
+
+               exit(3);
+       }
+
+       fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n"
+               "git bisect cannot work properly in this case.\n"
+               "Maybe you mistake good and bad revs?\n");
+       exit(1);
+}
+
+void handle_skipped_merge_base(const unsigned char *mb)
+{
+       char *mb_hex = sha1_to_hex(mb);
+       char *bad_hex = sha1_to_hex(current_bad_sha1);
+       char *good_hex = join_sha1_array_hex(&good_revs, ' ');
+
+       fprintf(stderr, "Warning: the merge base between %s and [%s] "
+               "must be skipped.\n"
+               "So we cannot be sure the first bad commit is "
+               "between %s and %s.\n"
+               "We continue anyway.\n",
+               bad_hex, good_hex, mb_hex, bad_hex);
+       free(good_hex);
+}
+
+/*
+ * "check_merge_bases" checks that merge bases are not "bad".
+ *
+ * - If one is "bad", it means the user assumed something wrong
+ * and we must exit with a non 0 error code.
+ * - If one is "good", that's good, we have nothing to do.
+ * - 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.
+ */
+static void check_merge_bases(void)
+{
+       struct commit_list *result;
+       int rev_nr;
+       struct commit **rev = get_bad_and_good_commits(&rev_nr);
+
+       result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+
+       for (; result; result = result->next) {
+               const unsigned char *mb = result->item->object.sha1;
+               if (!hashcmp(mb, current_bad_sha1)) {
+                       handle_bad_merge_base();
+               } else if (0 <= lookup_sha1_array(&good_revs, mb)) {
+                       continue;
+               } else if (0 <= lookup_sha1_array(&skipped_revs, mb)) {
+                       handle_skipped_merge_base(mb);
+               } else {
+                       printf("Bisecting: a merge base must be tested\n");
+                       exit(bisect_checkout(sha1_to_hex(mb)));
+               }
+       }
+
+       free(rev);
+       free_commit_list(result);
+}
+
+static int check_ancestors(const char *prefix)
 {
        struct rev_info revs;
-       struct rev_list_info info;
-       int reaches = 0, all = 0;
+       struct object_array pending_copy;
+       int i, res;
 
-       memset(&info, 0, sizeof(info));
-       info.revs = &revs;
-       info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED;
+       bisect_rev_setup(&revs, prefix, "^%s", "%s", 0);
 
-       bisect_rev_setup(&revs, prefix);
+       /* Save pending objects, so they can be cleaned up later. */
+       memset(&pending_copy, 0, sizeof(pending_copy));
+       for (i = 0; i < revs.pending.nr; i++)
+               add_object_array(revs.pending.objects[i].item,
+                                revs.pending.objects[i].name,
+                                &pending_copy);
 
-       if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
-       if (revs.tree_objects)
-               mark_edges_uninteresting(revs.commits, &revs, NULL);
+       bisect_common(&revs);
+       res = (revs.commits != NULL);
+
+       /* Clean up objects used, as they will be reused. */
+       for (i = 0; i < pending_copy.nr; i++) {
+               struct object *o = pending_copy.objects[i].item;
+               unparse_commit((struct commit *)o);
+       }
+
+       return res;
+}
+
+/*
+ * "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, its source code will be
+ * checked out to be tested by the user and we will exit.
+ */
+static void check_good_are_ancestors_of_bad(const char *prefix)
+{
+       const char *filename = git_path("BISECT_ANCESTORS_OK");
+       struct stat st;
+       int fd;
+
+       if (!current_bad_sha1)
+               die("a bad revision is needed");
+
+       /* Check if file BISECT_ANCESTORS_OK exists. */
+       if (!stat(filename, &st) && S_ISREG(st.st_mode))
+               return;
+
+       /* Bisecting with no good rev is ok. */
+       if (good_revs.sha1_nr == 0)
+               return;
+
+       /* Check if all good revs are ancestor of the bad rev. */
+       if (check_ancestors(prefix))
+               check_merge_bases();
+
+       /* Create file BISECT_ANCESTORS_OK. */
+       fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+       if (fd < 0)
+               warning("could not create file '%s': %s",
+                       filename, strerror(errno));
+       else
+               close(fd);
+}
+
+/*
+ * We use the convention that exiting with an exit code 10 means that
+ * the bisection process finished successfully.
+ * In this case the calling shell script should exit 0.
+ */
+int bisect_next_all(const char *prefix)
+{
+       struct rev_info revs;
+       struct commit_list *tried;
+       int reaches = 0, all = 0, nr;
+       const unsigned char *bisect_rev;
+       char bisect_rev_hex[41];
+
+       if (read_bisect_refs())
+               die("reading bisect refs failed");
+
+       check_good_are_ancestors_of_bad(prefix);
+
+       bisect_rev_setup(&revs, prefix, "%s", "^%s", 1);
+       revs.limited = 1;
+
+       bisect_common(&revs);
 
        revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                     !!skipped_sha1_nr);
+                                      !!skipped_revs.sha1_nr);
+       revs.commits = filter_skipped(revs.commits, &tried, 0);
+
+       if (!revs.commits) {
+               /*
+                * We should exit here only if the "bad"
+                * commit is also a "skip" commit.
+                */
+               exit_if_skipped_commits(tried, NULL);
+
+               printf("%s was both good and bad\n",
+                      sha1_to_hex(current_bad_sha1));
+               exit(1);
+       }
 
-       return show_bisect_vars(&info, reaches, all);
+       bisect_rev = revs.commits->item->object.sha1;
+       memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41);
+
+       if (!hashcmp(bisect_rev, current_bad_sha1)) {
+               exit_if_skipped_commits(tried, current_bad_sha1);
+               printf("%s is first bad commit\n", bisect_rev_hex);
+               argv_diff_tree[2] = bisect_rev_hex;
+               run_command_v_opt(argv_diff_tree, RUN_GIT_CMD);
+               /* This means the bisection process succeeded. */
+               exit(10);
+       }
+
+       nr = all - reaches - 1;
+       printf("Bisecting: %d revisions left to test after this "
+              "(roughly %d steps)\n", nr, estimate_bisect_steps(all));
+
+       return bisect_checkout(bisect_rev_hex);
 }
+
index fdba9138773f6f6a4f36655f81965e955e79b3bc..fb744fdb79e1dd4a46cd3f2759b73747d8e79fbd 100644 (file)
--- a/bisect.h
+++ b/bisect.h
@@ -9,10 +9,13 @@ extern struct commit_list *filter_skipped(struct commit_list *list,
                                          struct commit_list **tried,
                                          int show_all);
 
+extern void print_commit_list(struct commit_list *list,
+                             const char *format_cur,
+                             const char *format_last);
+
 /* bisect_show_flags flags in struct rev_list_info */
 #define BISECT_SHOW_ALL                (1<<0)
 #define BISECT_SHOW_TRIED      (1<<1)
-#define BISECT_SHOW_STRINGED   (1<<2)
 
 struct rev_list_info {
        struct rev_info *revs;
@@ -24,6 +27,8 @@ struct rev_list_info {
 
 extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all);
 
-extern int bisect_next_vars(const char *prefix);
+extern int bisect_next_all(const char *prefix);
+
+extern int estimate_bisect_steps(int all);
 
 #endif
index cb67d2c17e4017e8deede61b30c0eb7c8c60ac1e..bee45f00de7d82e07b617716033f0d5605b2a368 100644 (file)
 #include "cache-tree.h"
 #include "run-command.h"
 #include "parse-options.h"
+#include "diff.h"
+#include "revision.h"
 
 static const char * const builtin_add_usage[] = {
        "git add [options] [--] <filepattern>...",
        NULL
 };
-static int patch_interactive, add_interactive;
+static int patch_interactive, add_interactive, edit_interactive;
 static int take_worktree_changes;
 
 static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
@@ -61,7 +63,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
        fill_pathspec_matches(pathspec, seen, specs);
 
        for (i = 0; i < specs; i++) {
-               if (!seen[i] && !file_exists(pathspec[i]))
+               if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
                        die("pathspec '%s' did not match any files",
                                        pathspec[i]);
        }
@@ -187,6 +189,51 @@ int interactive_add(int argc, const char **argv, const char *prefix)
        return status;
 }
 
+int edit_patch(int argc, const char **argv, const char *prefix)
+{
+       char *file = xstrdup(git_path("ADD_EDIT.patch"));
+       const char *apply_argv[] = { "apply", "--recount", "--cached",
+               file, NULL };
+       struct child_process child;
+       struct rev_info rev;
+       int out;
+       struct stat st;
+
+       git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+       if (read_cache() < 0)
+               die ("Could not read the index");
+
+       init_revisions(&rev, prefix);
+       rev.diffopt.context = 7;
+
+       argc = setup_revisions(argc, argv, &rev, NULL);
+       rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+       out = open(file, O_CREAT | O_WRONLY, 0644);
+       if (out < 0)
+               die ("Could not open '%s' for writing.", file);
+       rev.diffopt.file = fdopen(out, "w");
+       rev.diffopt.close_file = 1;
+       if (run_diff_files(&rev, 0))
+               die ("Could not write patch");
+
+       launch_editor(file, NULL, NULL);
+
+       if (stat(file, &st))
+               die("Could not stat '%s'", file);
+       if (!st.st_size)
+               die("Empty patch. Aborted.");
+
+       memset(&child, 0, sizeof(child));
+       child.git_cmd = 1;
+       child.argv = apply_argv;
+       if (run_command(&child))
+               die ("Could not apply '%s'", file);
+
+       unlink(file);
+       return 0;
+}
+
 static struct lock_file lock_file;
 
 static const char ignore_error[] =
@@ -201,6 +248,7 @@ static struct option builtin_add_options[] = {
        OPT_GROUP(""),
        OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
        OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
+       OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
        OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
        OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
        OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
@@ -251,14 +299,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        int require_pathspec;
 
        argc = parse_options(argc, argv, builtin_add_options,
-                         builtin_add_usage, 0);
+                         builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
        if (patch_interactive)
                add_interactive = 1;
        if (add_interactive)
-               exit(interactive_add(argc, argv, prefix));
+               exit(interactive_add(argc - 1, argv + 1, prefix));
 
        git_config(add_config, NULL);
 
+       if (edit_interactive)
+               return(edit_patch(argc, argv, prefix));
+       argc--;
+       argv++;
+
        if (addremove && take_worktree_changes)
                die("-A and -u are mutually incompatible");
        if ((addremove || take_worktree_changes) && !argc) {
index 1926cd80559d3e6d6e917d1ed37c308c3a06d987..a40b9822425e25272cadf6f4170ba967eacf11bf 100644 (file)
@@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name)
        return NULL;
 }
 
+/*
+ * item->util in the filename table records the status of the path.
+ * Usually it points at a patch (whose result records the contents
+ * of it after applying it), but it could be PATH_WAS_DELETED for a
+ * path that a previously applied patch has already removed.
+ */
+ #define PATH_TO_BE_DELETED ((struct patch *) -2)
+#define PATH_WAS_DELETED ((struct patch *) -1)
+
+static int to_be_deleted(struct patch *patch)
+{
+       return patch == PATH_TO_BE_DELETED;
+}
+
+static int was_deleted(struct patch *patch)
+{
+       return patch == PATH_WAS_DELETED;
+}
+
 static void add_to_fn_table(struct patch *patch)
 {
        struct string_list_item *item;
@@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch)
         */
        if ((patch->new_name == NULL) || (patch->is_rename)) {
                item = string_list_insert(patch->old_name, &fn_table);
-               item->util = (struct patch *) -1;
+               item->util = PATH_WAS_DELETED;
+       }
+}
+
+static void prepare_fn_table(struct patch *patch)
+{
+       /*
+        * store information about incoming file deletion
+        */
+       while (patch) {
+               if ((patch->new_name == NULL) || (patch->is_rename)) {
+                       struct string_list_item *item;
+                       item = string_list_insert(patch->old_name, &fn_table);
+                       item->util = PATH_TO_BE_DELETED;
+               }
+               patch = patch->next;
        }
 }
 
@@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
        struct patch *tpatch;
 
        if (!(patch->is_copy || patch->is_rename) &&
-           ((tpatch = in_fn_table(patch->old_name)) != NULL)) {
-               if (tpatch == (struct patch *) -1) {
+           (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
+               if (was_deleted(tpatch)) {
                        return error("patch %s has been renamed/deleted",
                                patch->old_name);
                }
@@ -2399,10 +2433,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
        assert(patch->is_new <= 0);
 
        if (!(patch->is_copy || patch->is_rename) &&
-           (tpatch = in_fn_table(old_name)) != NULL) {
-               if (tpatch == (struct patch *) -1) {
+           (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
+               if (was_deleted(tpatch))
                        return error("%s: has been deleted/renamed", old_name);
-               }
                st_mode = tpatch->new_mode;
        } else if (!cached) {
                stat_ret = lstat(old_name, st);
@@ -2410,6 +2443,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                        return error("%s: %s", old_name, strerror(errno));
        }
 
+       if (to_be_deleted(tpatch))
+               tpatch = NULL;
+
        if (check_index && !tpatch) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
@@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch)
        const char *new_name = patch->new_name;
        const char *name = old_name ? old_name : new_name;
        struct cache_entry *ce = NULL;
+       struct patch *tpatch;
        int ok_if_exists;
        int status;
 
@@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch)
                return status;
        old_name = patch->old_name;
 
-       if (in_fn_table(new_name) == (struct patch *) -1)
+       if ((tpatch = in_fn_table(new_name)) &&
+                       (was_deleted(tpatch) || to_be_deleted(tpatch)))
                /*
                 * A type-change diff is always split into a patch to
                 * delete old, immediately followed by a patch to
@@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch)
 {
        int err = 0;
 
+       prepare_fn_table(patch);
        while (patch) {
                if (apply_verbosely)
                        say_patch_name(stderr,
@@ -2742,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
                        if (rmdir(patch->old_name))
                                warning("unable to remove submodule %s",
                                        patch->old_name);
-               } else if (!unlink(patch->old_name) && rmdir_empty) {
+               } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
                        remove_path(patch->old_name);
                }
        }
@@ -2852,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
                        if (!try_create_file(newpath, mode, buf, size)) {
                                if (!rename(newpath, path))
                                        return;
-                               unlink(newpath);
+                               unlink_or_warn(newpath);
                                break;
                        }
                        if (errno != EEXIST)
@@ -3276,6 +3315,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 
        argc = parse_options(argc, argv, builtin_apply_options,
                        apply_usage, 0);
+       fake_ancestor = parse_options_fix_filename(prefix, fake_ancestor);
+       if (fake_ancestor)
+               fake_ancestor = xstrdup(fake_ancestor);
+
        if (apply_with_reject)
                apply = apply_verbosely = 1;
        if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
index 8fe778766a45f8f7bfceeeef9f67a2433a892ffb..cb3e15511611240cbc3ea53a1a591fdee19ba0b9 100644 (file)
@@ -4,24 +4,24 @@
 #include "bisect.h"
 
 static const char * const git_bisect_helper_usage[] = {
-       "git bisect--helper --next-vars",
+       "git bisect--helper --next-all",
        NULL
 };
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-       int next_vars = 0;
+       int next_all = 0;
        struct option options[] = {
-               OPT_BOOLEAN(0, "next-vars", &next_vars,
-                           "output next bisect step variables"),
+               OPT_BOOLEAN(0, "next-all", &next_all,
+                           "perform 'git bisect next'"),
                OPT_END()
        };
 
        argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0);
 
-       if (!next_vars)
+       if (!next_all)
                usage_with_options(git_bisect_helper_usage, options);
 
-       /* next-vars */
-       return bisect_next_vars(prefix);
+       /* next-all */
+       return bisect_next_all(prefix);
 }
index 83141fc84e22ad4852f255fa1ad453cc125a3255..cf74a926149668b7e67544aecd46a0e05d4f59d9 100644 (file)
@@ -873,7 +873,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
         * Prepare mmfile that contains only the lines in ent.
         */
        cp = nth_line(sb, ent->lno);
-       file_o.ptr = (char*) cp;
+       file_o.ptr = (char *) cp;
        cnt = ent->num_lines;
 
        while (cnt && cp < sb->final_buf + sb->final_buf_size) {
@@ -1704,7 +1704,7 @@ static int prepare_lines(struct scoreboard *sb)
        while (len--) {
                if (bol) {
                        sb->lineno = xrealloc(sb->lineno,
-                                             sizeof(int) * (num + 1));
+                                             sizeof(int *) * (num + 1));
                        sb->lineno[num] = buf - sb->final_buf;
                        bol = 0;
                }
@@ -1714,7 +1714,7 @@ static int prepare_lines(struct scoreboard *sb)
                }
        }
        sb->lineno = xrealloc(sb->lineno,
-                             sizeof(int) * (num + incomplete + 1));
+                             sizeof(int *) * (num + incomplete + 1));
        sb->lineno[num + incomplete] = buf - sb->final_buf;
        sb->num_lines = num + incomplete;
        return sb->num_lines;
@@ -1889,7 +1889,7 @@ static const char *parse_loc(const char *spec,
                return spec;
 
        /* it could be a regexp of form /.../ */
-       for (term = (char*) spec + 1; *term && *term != '/'; term++) {
+       for (term = (char *) spec + 1; *term && *term != '/'; term++) {
                if (*term == '\\')
                        term++;
        }
index 32758216961b9160b32315e9cb0ff9c68f9afdf9..6aaa708473231848db8cba061f6048d41a6782af 100644 (file)
@@ -311,14 +311,14 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
                if (branch && branch->merge && branch->merge[0]->dst &&
                    show_upstream_ref)
                        strbuf_addf(stat, "[%s] ",
-                           shorten_unambiguous_ref(branch->merge[0]->dst));
+                           shorten_unambiguous_ref(branch->merge[0]->dst, 0));
                return;
        }
 
        strbuf_addch(stat, '[');
        if (show_upstream_ref)
                strbuf_addf(stat, "%s: ",
-                       shorten_unambiguous_ref(branch->merge[0]->dst));
+                       shorten_unambiguous_ref(branch->merge[0]->dst, 0));
        if (!ours)
                strbuf_addf(stat, "behind %d] ", theirs);
        else if (!theirs)
@@ -547,7 +547,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_GROUP("Generic options"),
                OPT__VERBOSE(&verbose),
-               OPT_SET_INT( 0 , "track",  &track, "set up tracking mode (see git-pull(1))",
+               OPT_SET_INT('t', "track",  &track, "set up tracking mode (see git-pull(1))",
                        BRANCH_TRACK_EXPLICIT),
                OPT_BOOLEAN( 0 , "color",  &branch_use_color, "use colored output"),
                OPT_SET_INT('r', NULL,     &kinds, "act on remote-tracking branches",
index 8fad19daedef8a38674ee35cd543983bad610857..43ffe7ffae90322d757e110d8693a936209236f0 100644 (file)
@@ -201,8 +201,8 @@ static int batch_objects(int print_contents)
 }
 
 static const char * const cat_file_usage[] = {
-       "git cat-file [-t|-s|-e|-p|<type>] <sha1>",
-       "git cat-file [--batch|--batch-check] < <list_of_sha1s>",
+       "git cat-file (-t|-s|-e|-p|<type>) <object>",
+       "git cat-file (--batch|--batch-check) < <list_of_objects>",
        NULL
 };
 
index 0d534bc023a1a3367bdf19f6450ce17e627959f0..afe35e246c5ab2b262683308def787c6abce2a83 100644 (file)
@@ -124,7 +124,7 @@ static int checkout_file(const char *name, int prefix_length)
 static void checkout_all(const char *prefix, int prefix_length)
 {
        int i, errs = 0;
-       struct cache_entrylast_ce = NULL;
+       struct cache_entry *last_ce = NULL;
 
        for (i = 0; i < active_nr ; i++) {
                struct cache_entry *ce = active_cache[i];
@@ -278,7 +278,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                p = prefix_path(prefix, prefix_length, arg);
                checkout_file(p, prefix_length);
                if (p < arg || p > arg + strlen(arg))
-                       free((char*)p);
+                       free((char *)p);
        }
 
        if (read_from_stdin) {
index ee1edd406ffde4b31bf2685a634a6d318407724f..b8a4b0139b3b9c2f731315413a73db30edaf9231 100644 (file)
@@ -5,6 +5,7 @@
 #include "commit.h"
 #include "tree.h"
 #include "tree-walk.h"
+#include "cache-tree.h"
 #include "unpack-trees.h"
 #include "dir.h"
 #include "run-command.h"
@@ -178,7 +179,7 @@ static int checkout_merged(int pos, struct checkout *state)
        /*
         * NEEDSWORK:
         * There is absolutely no reason to write this as a blob object
-        * and create a phoney cache entry just to leak.  This hack is
+        * and create a phony cache entry just to leak.  This hack is
         * primarily to get to the write_entry() machinery that massages
         * the contents to work-tree format and writes out which only
         * allows it for a cache entry.  The code in write_entry() needs
@@ -215,7 +216,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 
        newfd = hold_locked_index(lock_file, 1);
-       if (read_cache() < 0)
+       if (read_cache_preload(pathspec) < 0)
                return error("corrupt index file");
 
        if (source_tree)
@@ -365,7 +366,7 @@ static int merge_working_tree(struct checkout_opts *opts,
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
        int newfd = hold_locked_index(lock_file, 1);
 
-       if (read_cache() < 0)
+       if (read_cache_preload(NULL) < 0)
                return error("corrupt index file");
 
        if (opts->force) {
@@ -540,14 +541,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
                parse_commit(new->commit);
        }
 
-       /*
-        * If we were on a detached HEAD, but we are now moving to
-        * a new commit, we want to mention the old commit once more
-        * to remind the user that it might be lost.
-        */
-       if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
-               describe_detached_head("Previous HEAD position was", old.commit);
-
        if (!old.commit && !opts->force) {
                if (!opts->quiet) {
                        warning("You appear to be on a branch yet to be born.");
@@ -560,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
        if (ret)
                return ret;
 
+       /*
+        * If we were on a detached HEAD, but have now moved to
+        * a new commit, we want to mention the old commit once more
+        * to remind the user that it might be lost.
+        */
+       if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
+               describe_detached_head("Previous HEAD position was", old.commit);
+
        update_refs_for_switch(opts, &old, new);
 
        ret = post_checkout_hook(old.commit, new->commit, 1);
index 880373f279dd073ea7f0ae8564daca1cc687e529..c935833c6ce176caf47a14b5ad1f2848f0d1ab22 100644 (file)
@@ -104,11 +104,12 @@ static char *get_repo_path(const char *repo, int *is_bundle)
 static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
 {
        const char *end = repo + strlen(repo), *start;
+       char *dir;
 
        /*
-        * Strip trailing slashes and /.git
+        * Strip trailing spaces, slashes and /.git
         */
-       while (repo < end && is_dir_sep(end[-1]))
+       while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
                end--;
        if (end - repo > 5 && is_dir_sep(end[-5]) &&
            !strncmp(end - 4, ".git", 4)) {
@@ -140,10 +141,33 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
        if (is_bare) {
                struct strbuf result = STRBUF_INIT;
                strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
-               return strbuf_detach(&result, 0);
+               dir = strbuf_detach(&result, 0);
+       } else
+               dir = xstrndup(start, end - start);
+       /*
+        * Replace sequences of 'control' characters and whitespace
+        * with one ascii space, remove leading and trailing spaces.
+        */
+       if (*dir) {
+               char *out = dir;
+               int prev_space = 1 /* strip leading whitespace */;
+               for (end = dir; *end; ++end) {
+                       char ch = *end;
+                       if ((unsigned char)ch < '\x20')
+                               ch = '\x20';
+                       if (isspace(ch)) {
+                               if (prev_space)
+                                       continue;
+                               prev_space = 1;
+                       } else
+                               prev_space = 0;
+                       *out++ = ch;
+               }
+               *out = '\0';
+               if (out > dir && prev_space)
+                       out[-1] = '\0';
        }
-
-       return xstrndup(start, end - start);
+       return dir;
 }
 
 static void strip_trailing_slashes(char *dir)
@@ -228,7 +252,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
                }
 
                if (unlink(dest->buf) && errno != ENOENT)
-                       die("failed to unlink %s", dest->buf);
+                       die("failed to unlink %s: %s",
+                           dest->buf, strerror(errno));
                if (!option_no_hardlinks) {
                        if (!link(src->buf, dest->buf))
                                continue;
index 81371b1d2698a48dba36046d7ff9d849f830a762..baaa75cf908d57e6d8540b6483684400c0b2494b 100644 (file)
@@ -699,7 +699,11 @@ static int parse_and_validate_options(int argc, const char *argv[],
 
        argc = parse_options(argc, argv, builtin_commit_options, usage, 0);
        logfile = parse_options_fix_filename(prefix, logfile);
+       if (logfile)
+               logfile = xstrdup(logfile);
        template_file = parse_options_fix_filename(prefix, template_file);
+       if (template_file)
+               template_file = xstrdup(template_file);
 
        if (force_author && !strchr(force_author, '>'))
                force_author = find_author_by_nickname(force_author);
index d8da72cf20fa01600b4ad9e6e7a78240b4b4c290..a81bc8bbf033fac83ad6deecbf4a67ba44e06a0b 100644 (file)
@@ -390,6 +390,8 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
        }
        else if (actions == ACTION_EDIT) {
                check_argc(argc, 0, 0);
+               if (!config_exclusive_filename && nongit)
+                       die("not in a git directory");
                git_config(git_default_config, NULL);
                launch_editor(config_exclusive_filename ?
                              config_exclusive_filename : git_path("config"),
index 3a007ed1cafcab82f466d355b63e416b06eb8864..63c6a19da5b38bc7c00c624c080ba0afbb10ff8a 100644 (file)
@@ -334,7 +334,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                die("--long is incompatible with --abbrev=0");
 
        if (contains) {
-               const char **args = xmalloc((7 + argc) * sizeof(char*));
+               const char **args = xmalloc((7 + argc) * sizeof(char *));
                int i = 0;
                args[i++] = "name-rev";
                args[i++] = "--name-only";
@@ -349,7 +349,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                                args[i++] = s;
                        }
                }
-               memcpy(args + i, argv, argc * sizeof(char*));
+               memcpy(args + i, argv, argc * sizeof(char *));
                args[i + argc] = NULL;
                return cmd_name_rev(i + argc, args, prefix);
        }
index 5d134be47c85019dd66aed742eb845f6245cbf4d..6202462216f3b8c3cbe924d4cc002616e69d75ab 100644 (file)
@@ -13,6 +13,7 @@
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
 static int unpack_limit = 100;
+static int prefer_ofs_delta = 1;
 static struct fetch_pack_args args = {
        /* .uploadpack = */ "git-upload-pack",
 };
@@ -111,7 +112,7 @@ static void mark_common(struct commit *commit,
   Get the next rev to send, ignoring the common.
 */
 
-static const unsigned charget_rev(void)
+static const unsigned char *get_rev(void)
 {
        struct commit *commit = NULL;
 
@@ -200,7 +201,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                                     (args.use_thin_pack ? " thin-pack" : ""),
                                     (args.no_progress ? " no-progress" : ""),
                                     (args.include_tag ? " include-tag" : ""),
-                                    " ofs-delta");
+                                    (prefer_ofs_delta ? " ofs-delta" : ""));
                else
                        packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
                fetching++;
@@ -596,6 +597,11 @@ static struct ref *do_fetch_pack(int fd[2],
                        fprintf(stderr, "Server supports side-band\n");
                use_sideband = 1;
        }
+       if (server_supports("ofs-delta")) {
+               if (args.verbose)
+                       fprintf(stderr, "Server supports ofs-delta\n");
+       } else
+               prefer_ofs_delta = 0;
        if (everything_local(&ref, nr_match, match)) {
                packet_flush(fd[1]);
                goto all_done;
@@ -648,6 +654,11 @@ static int fetch_pack_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
+               prefer_ofs_delta = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value, cb);
 }
 
@@ -814,7 +825,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                fd = hold_lock_file_for_update(&lock, shallow,
                                               LOCK_DIE_ON_ERROR);
                if (!write_shallow_commits(fd, 0)) {
-                       unlink(shallow);
+                       unlink_or_warn(shallow);
                        rollback_lock_file(&lock);
                } else {
                        commit_lock_file(&lock);
index 3c998ea740adf474ee980fc763bd7156b9ce81af..1eec64e9c4f624f035dc8c155316964c3b87470f 100644 (file)
@@ -167,6 +167,9 @@ static struct ref *get_ref_map(struct transport *transport,
        return ref_map;
 }
 
+#define STORE_REF_ERROR_OTHER 1
+#define STORE_REF_ERROR_DF_CONFLICT 2
+
 static int s_update_ref(const char *action,
                        struct ref *ref,
                        int check_old)
@@ -181,9 +184,11 @@ static int s_update_ref(const char *action,
        lock = lock_any_ref_for_update(ref->name,
                                       check_old ? ref->old_sha1 : NULL, 0);
        if (!lock)
-               return 2;
+               return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+                                         STORE_REF_ERROR_OTHER;
        if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
-               return 2;
+               return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+                                         STORE_REF_ERROR_OTHER;
        return 0;
 }
 
@@ -197,7 +202,7 @@ static int update_local_ref(struct ref *ref,
        struct commit *current = NULL, *updated;
        enum object_type type;
        struct branch *current_branch = branch_get(NULL);
-       const char *pretty_ref = prettify_ref(ref);
+       const char *pretty_ref = prettify_refname(ref->name);
 
        *display = 0;
        type = sha1_object_info(ref->new_sha1, NULL);
@@ -289,7 +294,7 @@ static int update_local_ref(struct ref *ref,
        }
 }
 
-static int store_updated_refs(const char *url, const char *remote_name,
+static int store_updated_refs(const char *raw_url, const char *remote_name,
                struct ref *ref_map)
 {
        FILE *fp;
@@ -298,11 +303,13 @@ static int store_updated_refs(const char *url, const char *remote_name,
        char note[1024];
        const char *what, *kind;
        struct ref *rm;
-       char *filename = git_path("FETCH_HEAD");
+       char *url, *filename = git_path("FETCH_HEAD");
 
        fp = fopen(filename, "a");
        if (!fp)
                return error("cannot open %s: %s\n", filename, strerror(errno));
+
+       url = transport_anonymize_url(raw_url);
        for (rm = ref_map; rm; rm = rm->next) {
                struct ref *ref = NULL;
 
@@ -353,12 +360,18 @@ static int store_updated_refs(const char *url, const char *remote_name,
                                                    kind);
                        note_len += sprintf(note + note_len, "'%s' of ", what);
                }
-               note_len += sprintf(note + note_len, "%.*s", url_len, url);
-               fprintf(fp, "%s\t%s\t%s\n",
+               note[note_len] = '\0';
+               fprintf(fp, "%s\t%s\t%s",
                        sha1_to_hex(commit ? commit->object.sha1 :
                                    rm->old_sha1),
                        rm->merge ? "" : "not-for-merge",
                        note);
+               for (i = 0; i < url_len; ++i)
+                       if ('\n' == url[i])
+                               fputs("\\n", fp);
+                       else
+                               fputc(url[i], fp);
+               fputc('\n', fp);
 
                if (ref)
                        rc |= update_local_ref(ref, what, note);
@@ -376,8 +389,9 @@ static int store_updated_refs(const char *url, const char *remote_name,
                                fprintf(stderr, " %s\n", note);
                }
        }
+       free(url);
        fclose(fp);
-       if (rc & 2)
+       if (rc & STORE_REF_ERROR_DF_CONFLICT)
                error("some local refs could not be updated; try running\n"
                      " 'git remote prune %s' to remove any old, conflicting "
                      "branches", remote_name);
index a7883690d74cb1bcef7b20f27ebbea6f6c5dcc53..fae1482ba91937232f427a3f5dd03c587c3fba57 100644 (file)
@@ -363,6 +363,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
        if (argc > 0)
                usage_with_options(fmt_merge_msg_usage, options);
+       inpath = parse_options_fix_filename(prefix, inpath);
 
        if (inpath && strcmp(inpath, "-")) {
                in = fopen(inpath, "r");
index c8114c8afdb5e5d8a5f0adac2302aa97c384d232..d091e04af9549b70a1e15a4b845383056e71932e 100644 (file)
@@ -339,8 +339,11 @@ static const char *copy_name(const char *buf)
 static const char *copy_email(const char *buf)
 {
        const char *email = strchr(buf, '<');
-       const char *eoemail = strchr(email, '>');
-       if (!email || !eoemail)
+       const char *eoemail;
+       if (!email)
+               return "";
+       eoemail = strchr(email, '>');
+       if (!eoemail)
                return "";
        return xmemdupz(email, eoemail + 1 - email);
 }
@@ -601,7 +604,8 @@ static void populate_value(struct refinfo *ref)
                if (formatp) {
                        formatp++;
                        if (!strcmp(formatp, "short"))
-                               refname = shorten_unambiguous_ref(refname);
+                               refname = shorten_unambiguous_ref(refname,
+                                                     warn_ambiguous_refs);
                        else
                                die("unknown %.*s format %s",
                                    (int)(formatp - name), name, formatp);
@@ -917,6 +921,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                sort = default_sort();
        sort_atom_limit = used_atom_cnt;
 
+       /* for warn_ambiguous_refs */
+       git_config(git_default_config, NULL);
+
        memset(&cbdata, 0, sizeof(cbdata));
        cbdata.grab_pattern = argv;
        for_each_ref(grab_single_ref, &cbdata);
index 89489ddcf8edb85160036b0336ab4ce80c3cb6bc..5308b346e69a50d7695b26f3b8e00bfdf71e1dd2 100644 (file)
@@ -10,6 +10,7 @@
 #include "tag.h"
 #include "tree-walk.h"
 #include "builtin.h"
+#include "parse-options.h"
 #include "grep.h"
 
 #ifndef NO_EXTERNAL_GREP
 #endif
 #endif
 
-static int builtin_grep;
+static char const * const grep_usage[] = {
+       "git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
+       NULL
+};
 
 static int grep_config(const char *var, const char *value, void *cb)
 {
        struct grep_opt *opt = cb;
 
-       if (!strcmp(var, "grep.color") || !strcmp(var, "color.grep")) {
+       if (!strcmp(var, "color.grep")) {
                opt->color = git_config_colorbool(var, value, -1);
                return 0;
        }
-       if (!strcmp(var, "grep.color.external") ||
-           !strcmp(var, "color.grep.external")) {
+       if (!strcmp(var, "color.grep.external"))
                return git_config_string(&(opt->color_external), var, value);
-       }
-       if (!strcmp(var, "grep.color.match") ||
-           !strcmp(var, "color.grep.match")) {
+       if (!strcmp(var, "color.grep.match")) {
                if (!value)
                        return config_error_nonbool(var);
                color_parse(value, var, opt->color_match);
@@ -435,7 +436,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 }
 #endif
 
-static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
+static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
+                     int external_grep_allowed)
 {
        int hit = 0;
        int nr;
@@ -447,7 +449,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
         * we grep through the checked-out files. It tends to
         * be a lot more optimized
         */
-       if (!cached && !builtin_grep) {
+       if (!cached && external_grep_allowed) {
                hit = external_grep(opt, paths, cached);
                if (hit >= 0)
                        return hit;
@@ -563,25 +565,182 @@ static int grep_object(struct grep_opt *opt, const char **paths,
        die("unable to grep from object of type %s", typename(obj->type));
 }
 
-static const char builtin_grep_usage[] =
-"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]";
+static int context_callback(const struct option *opt, const char *arg,
+                           int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       int value;
+       const char *endp;
+
+       if (unset) {
+               grep_opt->pre_context = grep_opt->post_context = 0;
+               return 0;
+       }
+       value = strtol(arg, (char **)&endp, 10);
+       if (*endp) {
+               return error("switch `%c' expects a numerical value",
+                            opt->short_name);
+       }
+       grep_opt->pre_context = grep_opt->post_context = value;
+       return 0;
+}
+
+static int file_callback(const struct option *opt, const char *arg, int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       FILE *patterns;
+       int lno = 0;
+       struct strbuf sb;
+
+       patterns = fopen(arg, "r");
+       if (!patterns)
+               die("'%s': %s", arg, strerror(errno));
+       while (strbuf_getline(&sb, patterns, '\n') == 0) {
+               /* ignore empty line like grep does */
+               if (sb.len == 0)
+                       continue;
+               append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg,
+                                   ++lno, GREP_PATTERN);
+       }
+       fclose(patterns);
+       strbuf_release(&sb);
+       return 0;
+}
 
-static const char emsg_invalid_context_len[] =
-"%s: invalid context length argument";
-static const char emsg_missing_context_len[] =
-"missing context length argument";
-static const char emsg_missing_argument[] =
-"option requires an argument -%s";
+static int not_callback(const struct option *opt, const char *arg, int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
+       return 0;
+}
+
+static int and_callback(const struct option *opt, const char *arg, int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
+       return 0;
+}
+
+static int open_callback(const struct option *opt, const char *arg, int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
+       return 0;
+}
+
+static int close_callback(const struct option *opt, const char *arg, int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
+       return 0;
+}
+
+static int pattern_callback(const struct option *opt, const char *arg,
+                           int unset)
+{
+       struct grep_opt *grep_opt = opt->value;
+       append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
+       return 0;
+}
+
+static int help_callback(const struct option *opt, const char *arg, int unset)
+{
+       return -1;
+}
 
 int cmd_grep(int argc, const char **argv, const char *prefix)
 {
        int hit = 0;
        int cached = 0;
+       int external_grep_allowed = 1;
        int seen_dashdash = 0;
        struct grep_opt opt;
        struct object_array list = { 0, 0, NULL };
        const char **paths = NULL;
        int i;
+       int dummy;
+       struct option options[] = {
+               OPT_BOOLEAN(0, "cached", &cached,
+                       "search in index instead of in the work tree"),
+               OPT_GROUP(""),
+               OPT_BOOLEAN('v', "invert-match", &opt.invert,
+                       "show non-matching lines"),
+               OPT_BIT('i', "ignore-case", &opt.regflags,
+                       "case insensitive matching", REG_ICASE),
+               OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
+                       "match patterns only at word boundaries"),
+               OPT_SET_INT('a', "text", &opt.binary,
+                       "process binary files as text", GREP_BINARY_TEXT),
+               OPT_SET_INT('I', NULL, &opt.binary,
+                       "don't match patterns in binary files",
+                       GREP_BINARY_NOMATCH),
+               OPT_GROUP(""),
+               OPT_BIT('E', "extended-regexp", &opt.regflags,
+                       "use extended POSIX regular expressions", REG_EXTENDED),
+               OPT_NEGBIT('G', "basic-regexp", &opt.regflags,
+                       "use basic POSIX regular expressions (default)",
+                       REG_EXTENDED),
+               OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
+                       "interpret patterns as fixed strings"),
+               OPT_GROUP(""),
+               OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
+               OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
+               OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
+               OPT_NEGBIT(0, "full-name", &opt.relative,
+                       "show filenames relative to top directory", 1),
+               OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
+                       "show only filenames instead of matching lines"),
+               OPT_BOOLEAN(0, "name-only", &opt.name_only,
+                       "synonym for --files-with-matches"),
+               OPT_BOOLEAN('L', "files-without-match",
+                       &opt.unmatch_name_only,
+                       "show only the names of files without match"),
+               OPT_BOOLEAN('z', "null", &opt.null_following_name,
+                       "print NUL after filenames"),
+               OPT_BOOLEAN('c', "count", &opt.count,
+                       "show the number of matches instead of matching lines"),
+               OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1),
+               OPT_GROUP(""),
+               OPT_CALLBACK('C', NULL, &opt, "n",
+                       "show <n> context lines before and after matches",
+                       context_callback),
+               OPT_INTEGER('B', NULL, &opt.pre_context,
+                       "show <n> context lines before matches"),
+               OPT_INTEGER('A', NULL, &opt.post_context,
+                       "show <n> context lines after matches"),
+               OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
+                       context_callback),
+               OPT_GROUP(""),
+               OPT_CALLBACK('f', NULL, &opt, "file",
+                       "read patterns from file", file_callback),
+               { OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
+                       "match <pattern>", PARSE_OPT_NONEG, pattern_callback },
+               { OPTION_CALLBACK, 0, "and", &opt, NULL,
+                 "combine patterns specified with -e",
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
+               OPT_BOOLEAN(0, "or", &dummy, ""),
+               { OPTION_CALLBACK, 0, "not", &opt, NULL, "",
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
+               { OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
+                 open_callback },
+               { OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
+                 close_callback },
+               OPT_BOOLEAN(0, "all-match", &opt.all_match,
+                       "show only matches from files that match all patterns"),
+               OPT_GROUP(""),
+#if NO_EXTERNAL_GREP
+               OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
+                       "allow calling of grep(1) (ignored by this build)"),
+#else
+               OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
+                       "allow calling of grep(1) (default)"),
+#endif
+               { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
+                 PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
+               OPT_END()
+       };
 
        memset(&opt, 0, sizeof(opt));
        opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
@@ -606,227 +765,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
         * unrecognized non option is the beginning of the refs list
         * that continues up to the -- (if exists), and then paths.
         */
+       argc = parse_options(argc, argv, options, grep_usage,
+                            PARSE_OPT_KEEP_DASHDASH |
+                            PARSE_OPT_STOP_AT_NON_OPTION |
+                            PARSE_OPT_NO_INTERNAL_HELP);
 
-       while (1 < argc) {
-               const char *arg = argv[1];
-               argc--; argv++;
-               if (!strcmp("--cached", arg)) {
-                       cached = 1;
-                       continue;
-               }
-               if (!strcmp("--no-ext-grep", arg)) {
-                       builtin_grep = 1;
-                       continue;
-               }
-               if (!strcmp("-a", arg) ||
-                   !strcmp("--text", arg)) {
-                       opt.binary = GREP_BINARY_TEXT;
-                       continue;
-               }
-               if (!strcmp("-i", arg) ||
-                   !strcmp("--ignore-case", arg)) {
-                       opt.regflags |= REG_ICASE;
-                       continue;
-               }
-               if (!strcmp("-I", arg)) {
-                       opt.binary = GREP_BINARY_NOMATCH;
-                       continue;
-               }
-               if (!strcmp("-v", arg) ||
-                   !strcmp("--invert-match", arg)) {
-                       opt.invert = 1;
-                       continue;
-               }
-               if (!strcmp("-E", arg) ||
-                   !strcmp("--extended-regexp", arg)) {
-                       opt.regflags |= REG_EXTENDED;
-                       continue;
-               }
-               if (!strcmp("-F", arg) ||
-                   !strcmp("--fixed-strings", arg)) {
-                       opt.fixed = 1;
-                       continue;
-               }
-               if (!strcmp("-G", arg) ||
-                   !strcmp("--basic-regexp", arg)) {
-                       opt.regflags &= ~REG_EXTENDED;
-                       continue;
-               }
-               if (!strcmp("-n", arg)) {
-                       opt.linenum = 1;
-                       continue;
-               }
-               if (!strcmp("-h", arg)) {
-                       opt.pathname = 0;
-                       continue;
-               }
-               if (!strcmp("-H", arg)) {
-                       opt.pathname = 1;
-                       continue;
-               }
-               if (!strcmp("-l", arg) ||
-                   !strcmp("--name-only", arg) ||
-                   !strcmp("--files-with-matches", arg)) {
-                       opt.name_only = 1;
-                       continue;
-               }
-               if (!strcmp("-L", arg) ||
-                   !strcmp("--files-without-match", arg)) {
-                       opt.unmatch_name_only = 1;
-                       continue;
-               }
-               if (!strcmp("-z", arg) ||
-                   !strcmp("--null", arg)) {
-                       opt.null_following_name = 1;
-                       continue;
-               }
-               if (!strcmp("-c", arg) ||
-                   !strcmp("--count", arg)) {
-                       opt.count = 1;
-                       continue;
-               }
-               if (!strcmp("-w", arg) ||
-                   !strcmp("--word-regexp", arg)) {
-                       opt.word_regexp = 1;
-                       continue;
-               }
-               if (!prefixcmp(arg, "-A") ||
-                   !prefixcmp(arg, "-B") ||
-                   !prefixcmp(arg, "-C") ||
-                   (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
-                       unsigned num;
-                       const char *scan;
-                       switch (arg[1]) {
-                       case 'A': case 'B': case 'C':
-                               if (!arg[2]) {
-                                       if (argc <= 1)
-                                               die(emsg_missing_context_len);
-                                       scan = *++argv;
-                                       argc--;
-                               }
-                               else
-                                       scan = arg + 2;
-                               break;
-                       default:
-                               scan = arg + 1;
-                               break;
-                       }
-                       if (strtoul_ui(scan, 10, &num))
-                               die(emsg_invalid_context_len, scan);
-                       switch (arg[1]) {
-                       case 'A':
-                               opt.post_context = num;
-                               break;
-                       default:
-                       case 'C':
-                               opt.post_context = num;
-                       case 'B':
-                               opt.pre_context = num;
-                               break;
-                       }
-                       continue;
-               }
-               if (!strcmp("-f", arg)) {
-                       FILE *patterns;
-                       int lno = 0;
-                       char buf[1024];
-                       if (argc <= 1)
-                               die(emsg_missing_argument, arg);
-                       patterns = fopen(argv[1], "r");
-                       if (!patterns)
-                               die("'%s': %s", argv[1], strerror(errno));
-                       while (fgets(buf, sizeof(buf), patterns)) {
-                               int len = strlen(buf);
-                               if (len && buf[len-1] == '\n')
-                                       buf[len-1] = 0;
-                               /* ignore empty line like grep does */
-                               if (!buf[0])
-                                       continue;
-                               append_grep_pattern(&opt, xstrdup(buf),
-                                                   argv[1], ++lno,
-                                                   GREP_PATTERN);
-                       }
-                       fclose(patterns);
-                       argv++;
-                       argc--;
-                       continue;
-               }
-               if (!strcmp("--not", arg)) {
-                       append_grep_pattern(&opt, arg, "command line", 0,
-                                           GREP_NOT);
-                       continue;
-               }
-               if (!strcmp("--and", arg)) {
-                       append_grep_pattern(&opt, arg, "command line", 0,
-                                           GREP_AND);
-                       continue;
-               }
-               if (!strcmp("--or", arg))
-                       continue; /* no-op */
-               if (!strcmp("(", arg)) {
-                       append_grep_pattern(&opt, arg, "command line", 0,
-                                           GREP_OPEN_PAREN);
-                       continue;
-               }
-               if (!strcmp(")", arg)) {
-                       append_grep_pattern(&opt, arg, "command line", 0,
-                                           GREP_CLOSE_PAREN);
-                       continue;
-               }
-               if (!strcmp("--all-match", arg)) {
-                       opt.all_match = 1;
-                       continue;
-               }
-               if (!strcmp("-e", arg)) {
-                       if (1 < argc) {
-                               append_grep_pattern(&opt, argv[1],
-                                                   "-e option", 0,
-                                                   GREP_PATTERN);
-                               argv++;
-                               argc--;
-                               continue;
-                       }
-                       die(emsg_missing_argument, arg);
-               }
-               if (!strcmp("--full-name", arg)) {
-                       opt.relative = 0;
-                       continue;
-               }
-               if (!strcmp("--color", arg)) {
-                       opt.color = 1;
-                       continue;
-               }
-               if (!strcmp("--no-color", arg)) {
-                       opt.color = 0;
-                       continue;
-               }
-               if (!strcmp("--", arg)) {
-                       /* later processing wants to have this at argv[1] */
-                       argv--;
-                       argc++;
-                       break;
-               }
-               if (*arg == '-')
-                       usage(builtin_grep_usage);
-
-               /* First unrecognized non-option token */
-               if (!opt.pattern_list) {
-                       append_grep_pattern(&opt, arg, "command line", 0,
-                                           GREP_PATTERN);
-                       break;
-               }
-               else {
-                       /* We are looking at the first path or rev;
-                        * it is found at argv[1] after leaving the
-                        * loop.
-                        */
-                       argc++; argv--;
-                       break;
-               }
+       /* First unrecognized non-option token */
+       if (argc > 0 && !opt.pattern_list) {
+               append_grep_pattern(&opt, argv[0], "command line", 0,
+                                   GREP_PATTERN);
+               argv++;
+               argc--;
        }
 
        if (opt.color && !opt.color_external)
-               builtin_grep = 1;
+               external_grep_allowed = 0;
        if (!opt.pattern_list)
                die("no pattern given.");
        if ((opt.regflags != REG_NEWLINE) && opt.fixed)
@@ -834,7 +787,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        compile_grep_patterns(&opt);
 
        /* Check revs and then paths */
-       for (i = 1; i < argc; i++) {
+       for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
                unsigned char sha1[20];
                /* Is it a rev? */
@@ -877,7 +830,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (!list.nr) {
                if (!cached)
                        setup_work_tree();
-               return !grep_cache(&opt, paths, cached);
+               return !grep_cache(&opt, paths, cached, external_grep_allowed);
        }
 
        if (cached)
index 9b57a746185719eb43c962c4adb96283657692e9..67dda3e6e63c9130a6f1e1c94cb35e519d765a95 100644 (file)
@@ -114,7 +114,7 @@ static int check_emacsclient_version(void)
        return 0;
 }
 
-static void exec_woman_emacs(const charpath, const char *page)
+static void exec_woman_emacs(const char *path, const char *page)
 {
        if (!check_emacsclient_version()) {
                /* This works only with emacsclient version >= 22. */
@@ -128,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page)
        }
 }
 
-static void exec_man_konqueror(const charpath, const char *page)
+static void exec_man_konqueror(const char *path, const char *page)
 {
        const char *display = getenv("DISPLAY");
        if (display && *display) {
@@ -156,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page)
        }
 }
 
-static void exec_man_man(const charpath, const char *page)
+static void exec_man_man(const char *path, const char *page)
 {
        if (!path)
                path = "man";
@@ -236,7 +236,7 @@ static int add_man_viewer_info(const char *var, const char *value)
        const char *subkey = strrchr(name, '.');
 
        if (!subkey)
-               return error("Config with no key for man viewer: %s", name);
+               return 0;
 
        if (!strcmp(subkey, ".path")) {
                if (!value)
@@ -249,7 +249,6 @@ static int add_man_viewer_info(const char *var, const char *value)
                return add_man_viewer_cmd(name, subkey - name, value);
        }
 
-       warning("'%s': unsupported man viewer sub key.", subkey);
        return 0;
 }
 
index 4e02b33bb77b8957940562f87bc0b6faaeb3a101..d1fa12a59efb34256b2cc80b03c637cc844d84ff 100644 (file)
@@ -122,8 +122,10 @@ static void copy_templates(const char *template_dir)
                template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
        if (!template_dir[0])
                return;
+       template_len = strlen(template_dir);
+       if (PATH_MAX <= (template_len+strlen("/config")))
+               die("insanely long template path %s", template_dir);
        strcpy(template_path, template_dir);
-       template_len = strlen(template_path);
        if (template_path[template_len-1] != '/') {
                template_path[template_len++] = '/';
                template_path[template_len] = 0;
index 5eaec5d24e6ca70af2879ce9439eb2ba831211b6..f10cfebdbbabac67dea41639289e7ad968d5bbe3 100644 (file)
@@ -755,6 +755,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int cover_letter = 0;
        int boundary_count = 0;
        int no_binary_diff = 0;
+       int numbered_cmdline_opt = 0;
        struct commit *origin = NULL, *head = NULL;
        const char *in_reply_to = NULL;
        struct patch_ids ids;
@@ -786,8 +787,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (!strcmp(argv[i], "--stdout"))
                        use_stdout = 1;
                else if (!strcmp(argv[i], "-n") ||
-                               !strcmp(argv[i], "--numbered"))
+                               !strcmp(argv[i], "--numbered")) {
                        numbered = 1;
+                       numbered_cmdline_opt = 1;
+               }
                else if (!strcmp(argv[i], "-N") ||
                                !strcmp(argv[i], "--no-numbered")) {
                        numbered = 0;
@@ -918,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
        if (start_number < 0)
                start_number = 1;
+
+       /*
+        * If numbered is set solely due to format.numbered in config,
+        * and it would conflict with --keep-subject (-k) from the
+        * command line, reset "numbered".
+        */
+       if (numbered && keep_subject && !numbered_cmdline_opt)
+               numbered = 0;
+
        if (numbered && keep_subject)
                die ("-n and -k are mutually exclusive.");
        if (keep_subject && subject_prefix)
index 88e2697aebf11399baf9f9c8b5a63b06a0f83c1d..3d59b0e140ca199997704ffcf59fbc2138345168 100644 (file)
@@ -454,7 +454,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                OPT_BIT(0, "directory", &dir.flags,
                        "show 'other' directories' name only",
                        DIR_SHOW_OTHER_DIRECTORIES),
-               OPT_BIT(0, "no-empty-directory", &dir.flags,
+               OPT_NEGBIT(0, "empty-directory", &dir.flags,
                        "don't show empty directories",
                        DIR_HIDE_EMPTY_DIRECTORIES),
                OPT_BOOLEAN('u', "unmerged", &show_unmerged,
@@ -512,7 +512,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 
        pathspec = get_pathspec(prefix, argv);
 
-       /* be nice with submodule patsh ending in a slash */
+       /* be nice with submodule paths ending in a slash */
        read_cache();
        if (pathspec)
                strip_trailing_slash_from_submodules();
index 703045bfc84a804f5cf58537117fb17859951f7e..d26a96e486f2a84fdfc54527d15b9acdf7ea34bb 100644 (file)
@@ -45,8 +45,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
                        bases[bases_count++] = sha;
                }
                else
-                       warning("Cannot handle more than %zu bases. "
-                               "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]);
+                       warning("Cannot handle more than %d bases. "
+                               "Ignoring %s.",
+                               (int)ARRAY_SIZE(bases)-1, argv[i]);
        }
        if (argc - i != 3) /* "--" "<head>" "<remote>" */
                die("Not handling anything other than two heads merge.");
index 6a51823a55502766bee74dfd0a3857a8330a0f75..0b58e5eda1f38c1560cc9dcf69be37fa5fc9886f 100644 (file)
@@ -764,7 +764,7 @@ static int suggest_conflicts(void)
 
        fp = fopen(git_path("MERGE_MSG"), "a");
        if (!fp)
-               die("Could open %s for writing", git_path("MERGE_MSG"));
+               die("Could not open %s for writing", git_path("MERGE_MSG"));
        fprintf(fp, "\nConflicts:\n");
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
index d3360ac1f8bf13a00f90d9f385d69b628471a95d..9742b45c4da7f9330491d0b4c6d3ed60aadb0f4c 100644 (file)
@@ -293,7 +293,7 @@ static unsigned long write_object(struct sha1file *f,
                                die("unable to read %s", sha1_to_hex(entry->idx.sha1));
                        /*
                         * make sure no cached delta data remains from a
-                        * previous attempt before a pack split occured.
+                        * previous attempt before a pack split occurred.
                         */
                        free(entry->delta_data);
                        entry->delta_data = NULL;
@@ -1907,13 +1907,19 @@ static void show_commit(struct commit *commit, void *data)
        commit->object.flags |= OBJECT_ADDED;
 }
 
-static void show_object(struct object_array_entry *p, void *data)
+static void show_object(struct object *obj, const struct name_path *path, const char *last)
 {
-       add_preferred_base_object(p->name);
-       add_object_entry(p->item->sha1, p->item->type, p->name, 0);
-       p->item->flags |= OBJECT_ADDED;
-       free((char *)p->name);
-       p->name = NULL;
+       char *name = path_name(path, last);
+
+       add_preferred_base_object(name);
+       add_object_entry(obj->sha1, obj->type, name, 0);
+       obj->flags |= OBJECT_ADDED;
+
+       /*
+        * We will have generated the hash from the name,
+        * but not saved a pointer to it - we can free it
+        */
+       free((char *)name);
 }
 
 static void show_edge(struct commit *commit)
index 2d5b2cd353a5e80a74e3828aae8e0c7dfa0e1997..00590b1c3c2cceda7a75537c8680a96cd2ef84d4 100644 (file)
@@ -28,8 +28,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
                memcpy(pathname + len, de->d_name, 38);
                if (opts & DRY_RUN)
                        printf("rm -f %s\n", pathname);
-               else if (unlink(pathname) < 0)
-                       error("unable to unlink %s", pathname);
+               else
+                       unlink_or_warn(pathname);
                display_progress(progress, i + 1);
        }
        pathname[len] = 0;
@@ -55,6 +55,7 @@ void prune_packed_objects(int opts)
        for (i = 0; i < 256; i++) {
                DIR *d;
 
+               display_progress(progress, i + 1);
                sprintf(pathname + len, "%02x/", i);
                d = opendir(pathname);
                if (!d)
index 545e9c1f9458ed936e2a99a208f75b70f368294c..145ba83651e9c8560e20d6ab449ce64783bc65f5 100644 (file)
@@ -27,7 +27,7 @@ static int prune_tmp_object(const char *path, const char *filename)
        }
        printf("Removing stale temporary file %s\n", fullpath);
        if (!show_only)
-               unlink(fullpath);
+               unlink_or_warn(fullpath);
        return 0;
 }
 
@@ -47,7 +47,7 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
                       (type > 0) ? typename(type) : "unknown");
        }
        if (!show_only)
-               unlink(fullpath);
+               unlink_or_warn(fullpath);
        return 0;
 }
 
index 8e0273864d6af8de2a31868dcfbeda29cd36c2fc..82e25eaa0758d8b9584592f4072f81eeccb0bf1d 100644 (file)
@@ -29,41 +29,6 @@ static int list_tree(unsigned char *sha1)
        return 0;
 }
 
-static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
-{
-       struct tree_desc desc;
-       struct name_entry entry;
-       int cnt;
-
-       hashcpy(it->sha1, tree->object.sha1);
-       init_tree_desc(&desc, tree->buffer, tree->size);
-       cnt = 0;
-       while (tree_entry(&desc, &entry)) {
-               if (!S_ISDIR(entry.mode))
-                       cnt++;
-               else {
-                       struct cache_tree_sub *sub;
-                       struct tree *subtree = lookup_tree(entry.sha1);
-                       if (!subtree->object.parsed)
-                               parse_tree(subtree);
-                       sub = cache_tree_sub(it, entry.path);
-                       sub->cache_tree = cache_tree();
-                       prime_cache_tree_rec(sub->cache_tree, subtree);
-                       cnt += sub->cache_tree->entry_count;
-               }
-       }
-       it->entry_count = cnt;
-}
-
-static void prime_cache_tree(void)
-{
-       if (!nr_trees)
-               return;
-       active_cache_tree = cache_tree();
-       prime_cache_tree_rec(active_cache_tree, trees[0]);
-
-}
-
 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;
@@ -211,7 +176,6 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                case 3:
                default:
                        opts.fn = threeway_merge;
-                       cache_tree_free(&active_cache_tree);
                        break;
                }
 
@@ -221,6 +185,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                        opts.head_idx = 1;
        }
 
+       cache_tree_free(&active_cache_tree);
        for (i = 0; i < nr_trees; i++) {
                struct tree *tree = trees[i];
                parse_tree(tree);
@@ -234,11 +199,14 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
         * "-m ent" or "--reset ent" form), we can obtain a fully
         * valid cache-tree because the index must match exactly
         * what came from the tree.
+        *
+        * The same holds true if we are switching between two trees
+        * using read-tree -m A B.  The index must match B after that.
         */
-       if (nr_trees && !opts.prefix && (!opts.merge || (stage == 2))) {
-               cache_tree_free(&active_cache_tree);
-               prime_cache_tree();
-       }
+       if (nr_trees == 1 && !opts.prefix)
+               prime_cache_tree(&active_cache_tree, trees[0]);
+       else if (nr_trees == 2 && opts.merge)
+               prime_cache_tree(&active_cache_tree, trees[1]);
 
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_locked_index(&lock_file))
index a970b39505b5dda0bfa32a1a9c14ad676d28ec92..0b08da9b595432efa231eb59d88ecd2b422eb56a 100644 (file)
@@ -27,10 +27,9 @@ static int receive_unpack_limit = -1;
 static int transfer_unpack_limit = -1;
 static int unpack_limit = 100;
 static int report_status;
+static int prefer_ofs_delta = 1;
 static const char *head_name;
-
-static char capabilities[] = " report-status delete-refs ";
-static int capabilities_sent;
+static char *capabilities_to_send;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -84,24 +83,29 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
+               prefer_ofs_delta = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value, cb);
 }
 
 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
-       if (capabilities_sent)
+       if (!capabilities_to_send)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
        else
                packet_write(1, "%s %s%c%s\n",
-                            sha1_to_hex(sha1), path, 0, capabilities);
-       capabilities_sent = 1;
+                            sha1_to_hex(sha1), path, 0, capabilities_to_send);
+       capabilities_to_send = NULL;
        return 0;
 }
 
 static void write_head_info(void)
 {
        for_each_ref(show_ref, NULL);
-       if (!capabilities_sent)
+       if (capabilities_to_send)
                show_ref("capabilities^{}", null_sha1, 0, NULL);
 
 }
@@ -687,6 +691,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        else if (0 <= receive_unpack_limit)
                unpack_limit = receive_unpack_limit;
 
+       capabilities_to_send = (prefer_ofs_delta) ?
+               " report-status delete-refs ofs-delta " :
+               " report-status delete-refs ";
+
        add_alternate_refs();
        write_head_info();
        clear_extra_refs();
@@ -702,7 +710,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                        unpack_status = unpack();
                execute_commands(unpack_status);
                if (pack_lockfile)
-                       unlink(pack_lockfile);
+                       unlink_or_warn(pack_lockfile);
                if (report_status)
                        report(unpack_status);
                run_receive_hook(post_receive_hook);
index 249ad2a311f2e9680618870aed3ac053c9fcf7a1..ddfdf5a3cbc79003dfbad14af8d1f047e3594aa6 100644 (file)
@@ -240,10 +240,10 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig
 static void mark_reachable(struct commit *commit, unsigned long expire_limit)
 {
        /*
-        * We need to compute if commit on either side of an reflog
+        * We need to compute whether the commit on either side of a reflog
         * entry is reachable from the tip of the ref for all entries.
         * Mark commits that are reachable from the tip down to the
-        * time threashold first; we know a commit marked thusly is
+        * time threshold first; we know a commit marked thusly is
         * reachable from the tip without running in_merge_bases()
         * at all.
         */
index ca7c639ad30fd5682014eb984ab18d3fb0546c67..fda9a54a0c2f31b1071e4c401a3707375fc7a10d 100644 (file)
@@ -299,11 +299,11 @@ static int get_push_ref_states(const struct ref *remote_refs,
                return 0;
 
        local_refs = get_local_heads();
-       ref = push_map = copy_ref_list(remote_refs);
-       while (ref->next)
-               ref = ref->next;
-       push_tail = &ref->next;
+       push_map = copy_ref_list(remote_refs);
 
+       push_tail = &push_map;
+       while (*push_tail)
+               push_tail = &((*push_tail)->next);
        match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,
                   remote->push_refspec, MATCH_REFS_NONE);
 
@@ -525,8 +525,8 @@ static int migrate_file(struct remote *remote)
                path = git_path("remotes/%s", remote->name);
        else if (remote->origin == REMOTE_BRANCHES)
                path = git_path("branches/%s", remote->name);
-       if (path && unlink(path))
-               warning("failed to remove '%s'", path);
+       if (path)
+               unlink_or_warn(path);
        return 0;
 }
 
@@ -1216,7 +1216,7 @@ static int update(int argc, const char **argv)
        struct option options[] = {
                OPT_GROUP("update specific options"),
                OPT_BOOLEAN('p', "prune", &prune,
-                           "prune remotes after fecthing"),
+                           "prune remotes after fetching"),
                OPT_END()
        };
 
index 020af7377bb9aa1bced7489d40169e3cb2ff7682..adfb7b5f48597c19c23235b74cf1a0c779985dc6 100644 (file)
@@ -116,7 +116,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
                        if (!has_rerere_resolution(name))
                                unlink_rr_item(name);
                }
-               unlink(git_path("rr-cache/MERGE_RR"));
+               unlink_or_warn(git_path("rr-cache/MERGE_RR"));
        } else if (!strcmp(argv[1], "gc"))
                garbage_collect(&merge_rr);
        else if (!strcmp(argv[1], "status"))
index c0cb915c26b56a905807cefa4e246d99d199b297..7e7ebabaa865ebd749502774638efe7b6d26bec1 100644 (file)
@@ -228,7 +228,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                }
                /*
                 * Otherwise, argv[i] could be either <rev> or <paths> and
-                * has to be unambigous.
+                * has to be unambiguous.
                 */
                else if (!get_sha1(argv[i], sha1)) {
                        /*
index 193993cf4494aca98d5e57ce80bc2c99b5cba948..31ea5f4aac4559a69ed5b0033696fff2333f5e5a 100644 (file)
@@ -156,27 +156,29 @@ static void finish_commit(struct commit *commit, void *data)
        commit->buffer = NULL;
 }
 
-static void finish_object(struct object_array_entry *p, void *data)
+static void finish_object(struct object *obj, const struct name_path *path, const char *name)
 {
-       if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
-               die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
+       if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1))
+               die("missing blob object '%s'", sha1_to_hex(obj->sha1));
 }
 
-static void show_object(struct object_array_entry *p, void *data)
+static void show_object(struct object *obj, const struct name_path *path, const char *component)
 {
+       char *name = path_name(path, component);
        /* An object with name "foo\n0000000..." can be used to
         * confuse downstream "git pack-objects" very badly.
         */
-       const char *ep = strchr(p->name, '\n');
+       const char *ep = strchr(name, '\n');
 
-       finish_object(p, data);
+       finish_object(obj, path, name);
        if (ep) {
-               printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
-                      (int) (ep - p->name),
-                      p->name);
+               printf("%s %.*s\n", sha1_to_hex(obj->sha1),
+                      (int) (ep - name),
+                      name);
        }
        else
-               printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
+               printf("%s %s\n", sha1_to_hex(obj->sha1), name);
+       free(name);
 }
 
 static void show_edge(struct commit *commit)
@@ -209,7 +211,7 @@ static inline int exp2i(int n)
  *
  * and P(2^n + x) < 0.5 means 2^n < 3x
  */
-static int estimate_bisect_steps(int all)
+int estimate_bisect_steps(int all)
 {
        int n, x, e;
 
@@ -223,20 +225,37 @@ static int estimate_bisect_steps(int all)
        return (e < 3 * x) ? n : n - 1;
 }
 
-static void show_tried_revs(struct commit_list *tried, int stringed)
+void print_commit_list(struct commit_list *list,
+                      const char *format_cur,
+                      const char *format_last)
 {
-       printf("bisect_tried='");
-       for (;tried; tried = tried->next) {
-               char *format = tried->next ? "%s|" : "%s";
-               printf(format, sha1_to_hex(tried->item->object.sha1));
+       for ( ; list; list = list->next) {
+               const char *format = list->next ? format_cur : format_last;
+               printf(format, sha1_to_hex(list->item->object.sha1));
        }
-       printf(stringed ? "' &&\n" : "'\n");
+}
+
+static void show_tried_revs(struct commit_list *tried)
+{
+       printf("bisect_tried='");
+       print_commit_list(tried, "%s|", "%s");
+       printf("'\n");
+}
+
+static void print_var_str(const char *var, const char *val)
+{
+       printf("%s='%s'\n", var, val);
+}
+
+static void print_var_int(const char *var, int val)
+{
+       printf("%s=%d\n", var, val);
 }
 
 int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
 {
        int cnt, flags = info->bisect_show_flags;
-       char hex[41] = "", *format;
+       char hex[41] = "";
        struct commit_list *tried;
        struct rev_info *revs = info->revs;
 
@@ -267,28 +286,14 @@ int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
        }
 
        if (flags & BISECT_SHOW_TRIED)
-               show_tried_revs(tried, flags & BISECT_SHOW_STRINGED);
-       format = (flags & BISECT_SHOW_STRINGED) ?
-               "bisect_rev=%s &&\n"
-               "bisect_nr=%d &&\n"
-               "bisect_good=%d &&\n"
-               "bisect_bad=%d &&\n"
-               "bisect_all=%d &&\n"
-               "bisect_steps=%d\n"
-               :
-               "bisect_rev=%s\n"
-               "bisect_nr=%d\n"
-               "bisect_good=%d\n"
-               "bisect_bad=%d\n"
-               "bisect_all=%d\n"
-               "bisect_steps=%d\n";
-       printf(format,
-              hex,
-              cnt - 1,
-              all - reaches - 1,
-              reaches - 1,
-              all,
-              estimate_bisect_steps(all));
+               show_tried_revs(tried);
+
+       print_var_str("bisect_rev", hex);
+       print_var_int("bisect_nr", cnt - 1);
+       print_var_int("bisect_good", all - reaches - 1);
+       print_var_int("bisect_bad", reaches - 1);
+       print_var_int("bisect_all", all);
+       print_var_int("bisect_steps", estimate_bisect_steps(all));
 
        return 0;
 }
index 81d5a6ffc9ff1c149bfb68f976a9e66c307cae1d..c5b3d6e31bc899fe511f760de33870f20dc9766f 100644 (file)
@@ -26,6 +26,8 @@ static int show_type = NORMAL;
 #define SHOW_SYMBOLIC_FULL 2
 static int symbolic;
 static int abbrev;
+static int abbrev_ref;
+static int abbrev_ref_strict;
 static int output_sq;
 
 /*
@@ -109,8 +111,8 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
                return;
        def = NULL;
 
-       if (symbolic && name) {
-               if (symbolic == SHOW_SYMBOLIC_FULL) {
+       if ((symbolic || abbrev_ref) && name) {
+               if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
                        unsigned char discard[20];
                        char *full;
 
@@ -125,6 +127,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
                                 */
                                break;
                        case 1: /* happy */
+                               if (abbrev_ref)
+                                       full = shorten_unambiguous_ref(full,
+                                               abbrev_ref_strict);
                                show_with_type(type, full);
                                break;
                        default: /* ambiguous */
@@ -397,6 +402,18 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
+static int cmd_sq_quote(int argc, const char **argv)
+{
+       struct strbuf buf = STRBUF_INIT;
+
+       if (argc)
+               sq_quote_argv(&buf, argv, 0);
+       printf("%s\n", buf.buf);
+       strbuf_release(&buf);
+
+       return 0;
+}
+
 static void die_no_single_rev(int quiet)
 {
        if (quiet)
@@ -414,6 +431,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
        if (argc > 1 && !strcmp("--parseopt", argv[1]))
                return cmd_parseopt(argc - 1, argv + 1, prefix);
 
+       if (argc > 1 && !strcmp("--sq-quote", argv[1]))
+               return cmd_sq_quote(argc - 2, argv + 2);
+
        prefix = setup_git_directory();
        git_config(git_default_config, NULL);
        for (i = 1; i < argc; i++) {
@@ -506,6 +526,20 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                symbolic = SHOW_SYMBOLIC_FULL;
                                continue;
                        }
+                       if (!prefixcmp(arg, "--abbrev-ref") &&
+                           (!arg[12] || arg[12] == '=')) {
+                               abbrev_ref = 1;
+                               abbrev_ref_strict = warn_ambiguous_refs;
+                               if (arg[12] == '=') {
+                                       if (!strcmp(arg + 13, "strict"))
+                                               abbrev_ref_strict = 1;
+                                       else if (!strcmp(arg + 13, "loose"))
+                                               abbrev_ref_strict = 0;
+                                       else
+                                               die("unknown mode for %s", arg);
+                               }
+                               continue;
+                       }
                        if (!strcmp(arg, "--all")) {
                                for_each_ref(show_reference, NULL);
                                continue;
index d5a1c48d0e2abab16c646ce86ac9670b95dddc07..be3b0926deeb38f34b75c08bedf29fd80bac9b3c 100644 (file)
@@ -43,12 +43,16 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
                "--stdout",
                NULL,
                NULL,
+               NULL,
        };
        struct child_process po;
        int i;
 
+       i = 4;
        if (args->use_thin_pack)
-               argv[4] = "--thin";
+               argv[i++] = "--thin";
+       if (args->use_ofs_delta)
+               argv[i++] = "--delta-base-offset";
        memset(&po, 0, sizeof(po));
        po.argv = argv;
        po.in = -1;
@@ -174,9 +178,9 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str
 {
        fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
        if (from)
-               fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
+               fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
        else
-               fputs(prettify_ref(to), stderr);
+               fputs(prettify_refname(to->name), stderr);
        if (msg) {
                fputs(" (", stderr);
                fputs(msg, stderr);
@@ -315,6 +319,8 @@ int send_pack(struct send_pack_args *args,
                ask_for_status_report = 1;
        if (server_supports("delete-refs"))
                allow_deleting_refs = 1;
+       if (server_supports("ofs-delta"))
+               args->use_ofs_delta = 1;
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
index 828e6f86de22f8def68a49b702a27521c248a012..c8e9b3c723cb733e1d6b4cd2036f165f0a088970 100644 (file)
@@ -2,12 +2,25 @@
 #include "commit.h"
 #include "refs.h"
 #include "builtin.h"
+#include "color.h"
 
 static const char show_branch_usage[] =
 "git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
 static const char show_branch_usage_reflog[] =
 "--reflog is incompatible with --all, --remotes, --independent or --merge-base";
 
+static int showbranch_use_color = -1;
+static char column_colors[][COLOR_MAXLEN] = {
+       GIT_COLOR_RED,
+       GIT_COLOR_GREEN,
+       GIT_COLOR_YELLOW,
+       GIT_COLOR_BLUE,
+       GIT_COLOR_MAGENTA,
+       GIT_COLOR_CYAN,
+};
+
+#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
+
 static int default_num;
 static int default_alloc;
 static const char **default_arg;
@@ -19,6 +32,20 @@ static const char **default_arg;
 
 #define DEFAULT_REFLOG 4
 
+static const char *get_color_code(int idx)
+{
+       if (showbranch_use_color)
+               return column_colors[idx];
+       return "";
+}
+
+static const char *get_color_reset_code(void)
+{
+       if (showbranch_use_color)
+               return GIT_COLOR_RESET;
+       return "";
+}
+
 static struct commit *interesting(struct commit_list *list)
 {
        while (list) {
@@ -545,7 +572,12 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       if (!strcmp(var, "color.showbranch")) {
+               showbranch_use_color = git_config_colorbool(var, value, -1);
+               return 0;
+       }
+
+       return git_color_default_config(var, value, cb);
 }
 
 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -576,7 +608,7 @@ static void parse_reflog_param(const char *arg, int *cnt, const char **base)
        if (*ep == ',')
                *base = ep + 1;
        else if (*ep)
-               die("unrecognized reflog param '%s'", arg + 9);
+               die("unrecognized reflog param '%s'", arg);
        else
                *base = NULL;
        if (*cnt <= 0)
@@ -611,6 +643,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 
        git_config(git_show_branch_config, NULL);
 
+       if (showbranch_use_color == -1)
+               showbranch_use_color = git_use_color_default;
+
        /* If nothing is specified, try the default first */
        if (ac == 1 && default_num) {
                ac = default_num + 1;
@@ -658,6 +693,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        parse_reflog_param(arg + 9, &reflog, &reflog_base);
                else if (!prefixcmp(arg, "-g="))
                        parse_reflog_param(arg + 3, &reflog, &reflog_base);
+               else if (!strcmp(arg, "--color"))
+                       showbranch_use_color = 1;
+               else if (!strcmp(arg, "--no-color"))
+                       showbranch_use_color = 0;
                else
                        usage(show_branch_usage);
                ac--; av++;
@@ -843,8 +882,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        else {
                                for (j = 0; j < i; j++)
                                        putchar(' ');
-                               printf("%c [%s] ",
-                                      is_head ? '*' : '!', ref_name[i]);
+                               printf("%s%c%s [%s] ",
+                                      get_color_code(i % COLUMN_COLORS_MAX),
+                                      is_head ? '*' : '!',
+                                      get_color_reset_code(), ref_name[i]);
                        }
 
                        if (!reflog) {
@@ -903,7 +944,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                                        mark = '*';
                                else
                                        mark = '+';
-                               putchar(mark);
+                               printf("%s%c%s",
+                                      get_color_code(i % COLUMN_COLORS_MAX),
+                                      mark, get_color_reset_code());
                        }
                        putchar(' ');
                }
index 01e73747d02f384c5e31b846340a4b586c84aab3..e54443009420d98dc281285e997b32f2a263b996 100644 (file)
@@ -338,7 +338,7 @@ static void create_tag(const unsigned char *object, const char *tag,
                exit(128);
        }
        if (path) {
-               unlink(path);
+               unlink_or_warn(path);
                free(path);
        }
 }
index 0713bca778e7be18b58ec5d207dc7c8cd7e982ed..f88e7219367c309dbc3d3e7ce2db32666703a91d 100644 (file)
@@ -24,7 +24,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
         *      git archive --format-tar --prefix=basedir tree-ish
         */
        int i;
-       const char **nargv = xcalloc(sizeof(*nargv), argc + 2);
+       const char **nargv = xcalloc(sizeof(*nargv), argc + 3);
        char *basedir_arg;
        int nargc = 0;
 
@@ -36,6 +36,13 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
                argv++;
                argc--;
        }
+
+       /*
+        * Because it's just a compatibility wrapper, tar-tree supports only
+        * the old behaviour of reading attributes from the work tree.
+        */
+       nargv[nargc++] = "--worktree-attributes";
+
        switch (argc) {
        default:
                usage(tar_tree_usage);
index 1fde893cfa9f6318ae1e9958b2f61159b01c7c6a..92beaaf4b3ca5520a9af27bde7f15dda46d80197 100644 (file)
@@ -292,7 +292,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
        report("add '%s'", path);
  free_return:
        if (p < path || p > path + strlen(path))
-               free((char*)p);
+               free((char *)p);
 }
 
 static void read_index_info(int line_termination)
@@ -509,7 +509,7 @@ static int do_unresolve(int ac, const char **av,
                const char *p = prefix_path(prefix, prefix_length, arg);
                err |= unresolve_one(p);
                if (p < arg || p > arg + strlen(arg))
-                       free((char*)p);
+                       free((char *)p);
        }
        return err;
 }
@@ -712,7 +712,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                if (set_executable_bit)
                        chmod_path(set_executable_bit, p);
                if (p < path || p > path + strlen(path))
-                       free((char*)p);
+                       free((char *)p);
        }
        if (read_from_stdin) {
                struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
index 729a1593e61d87ad4596f07e7faedac81de64e81..7f7fda42f9b7ab272ff2b3fa4ad1984a79f11ce0 100644 (file)
@@ -55,7 +55,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
        close(gpg.in);
        ret = finish_command(&gpg);
 
-       unlink(path);
+       unlink_or_warn(path);
 
        return ret;
 }
index d0dd818b31faa04caa4d418a39ad3020a919aa2d..e4b2aa9c4a2a7fb52121828343aa27ab47d17279 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -98,7 +98,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
         */
        struct ref_list *p = &header->prerequisites;
        struct rev_info revs;
-       const char *argv[] = {NULL, "--all"};
+       const char *argv[] = {NULL, "--all", NULL};
        struct object_array refs;
        struct commit *commit;
        int i, ret = 0, req_nr;
index 3d8f218a5f9e838b15e1d56113a4dd56904ee544..37bf35e636f0966662416f0693dbea5c1cc73311 100644 (file)
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "tree.h"
+#include "tree-walk.h"
 #include "cache-tree.h"
 
 #ifndef DEBUG
@@ -591,3 +592,36 @@ int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix)
 
        return 0;
 }
+
+static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
+{
+       struct tree_desc desc;
+       struct name_entry entry;
+       int cnt;
+
+       hashcpy(it->sha1, tree->object.sha1);
+       init_tree_desc(&desc, tree->buffer, tree->size);
+       cnt = 0;
+       while (tree_entry(&desc, &entry)) {
+               if (!S_ISDIR(entry.mode))
+                       cnt++;
+               else {
+                       struct cache_tree_sub *sub;
+                       struct tree *subtree = lookup_tree(entry.sha1);
+                       if (!subtree->object.parsed)
+                               parse_tree(subtree);
+                       sub = cache_tree_sub(it, entry.path);
+                       sub->cache_tree = cache_tree();
+                       prime_cache_tree_rec(sub->cache_tree, subtree);
+                       cnt += sub->cache_tree->entry_count;
+               }
+       }
+       it->entry_count = cnt;
+}
+
+void prime_cache_tree(struct cache_tree **it, struct tree *tree)
+{
+       cache_tree_free(it);
+       *it = cache_tree();
+       prime_cache_tree_rec(*it, tree);
+}
index cf8b790874c4a4f5890b360c237ccdd4a5a03de4..e95883523633a51f833683e96af1738da2868238 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef CACHE_TREE_H
 #define CACHE_TREE_H
 
+#include "tree.h"
+
 struct cache_tree;
 struct cache_tree_sub {
        struct cache_tree *cache_tree;
@@ -33,4 +35,6 @@ int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int)
 #define WRITE_TREE_PREFIX_ERROR (-3)
 
 int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix);
+void prime_cache_tree(struct cache_tree **, struct tree *);
+
 #endif
diff --git a/cache.h b/cache.h
index ab1294d6fbb7f699af160ac06674e54798f3db6c..b8503ad91c3b13ccaf87a6f596d13918f7ae114b 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -554,6 +554,13 @@ extern enum branch_track git_branch_track;
 extern enum rebase_setup_type autorebase;
 extern enum push_default_type push_default;
 
+enum object_creation_mode {
+       OBJECT_CREATION_USES_HARDLINKS = 0,
+       OBJECT_CREATION_USES_RENAMES = 1,
+};
+
+extern enum object_creation_mode object_creation_mode;
+
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
 extern int check_repository_format(void);
@@ -839,7 +846,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
 
 extern void pack_report(void);
 extern int open_pack_index(struct packed_git *);
-extern unsigned charuse_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
+extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
 extern void close_pack_windows(struct packed_git *);
 extern void unuse_pack(struct pack_window **);
 extern void free_pack_by_name(const char *);
diff --git a/color.h b/color.h
index 6846be1706c1842f5a53abafd4e03758a36695e9..18abeb7c7dd47794d4f5fea4049b5719f03383fe 100644 (file)
--- a/color.h
+++ b/color.h
@@ -11,6 +11,7 @@
 #define GIT_COLOR_GREEN                "\033[32m"
 #define GIT_COLOR_YELLOW       "\033[33m"
 #define GIT_COLOR_BLUE         "\033[34m"
+#define GIT_COLOR_MAGENTA      "\033[35m"
 #define GIT_COLOR_CYAN         "\033[36m"
 #define GIT_COLOR_BG_RED       "\033[41m"
 
index 066ce841ed76e03dd87e789f6688cc3f5411ba64..60d03676bbd0dba7be79c7098d7cae553962ca98 100644 (file)
@@ -6,6 +6,7 @@
 #include "quote.h"
 #include "xdiff-interface.h"
 #include "log-tree.h"
+#include "refs.h"
 
 static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
 {
@@ -23,7 +24,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
                        path = q->queue[i]->two->path;
                        len = strlen(path);
                        p = xmalloc(combine_diff_path_size(num_parent, len));
-                       p->path = (char*) &(p->parent[num_parent]);
+                       p->path = (char *) &(p->parent[num_parent]);
                        memcpy(p->path, path, len);
                        p->path[len] = 0;
                        p->len = len;
@@ -90,18 +91,24 @@ struct sline {
        unsigned long *p_lno;
 };
 
-static char *grab_blob(const unsigned char *sha1, unsigned long *size)
+static char *grab_blob(const unsigned char *sha1, unsigned int mode, unsigned long *size)
 {
        char *blob;
        enum object_type type;
-       if (is_null_sha1(sha1)) {
+
+       if (S_ISGITLINK(mode)) {
+               blob = xmalloc(100);
+               *size = snprintf(blob, 100,
+                                "Subproject commit %s\n", sha1_to_hex(sha1));
+       } else if (is_null_sha1(sha1)) {
                /* deleted blob */
                *size = 0;
                return xcalloc(1, 1);
+       } else {
+               blob = read_sha1_file(sha1, &type, size);
+               if (type != OBJ_BLOB)
+                       die("object '%s' is not a blob!", sha1_to_hex(sha1));
        }
-       blob = read_sha1_file(sha1, &type, size);
-       if (type != OBJ_BLOB)
-               die("object '%s' is not a blob!", sha1_to_hex(sha1));
        return blob;
 }
 
@@ -195,7 +202,8 @@ static void consume_line(void *state_, char *line, unsigned long len)
        }
 }
 
-static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
+static void combine_diff(const unsigned char *parent, unsigned int mode,
+                        mmfile_t *result_file,
                         struct sline *sline, unsigned int cnt, int n,
                         int num_parent)
 {
@@ -211,7 +219,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
        if (!cnt)
                return; /* result deleted */
 
-       parent_file.ptr = grab_blob(parent, &sz);
+       parent_file.ptr = grab_blob(parent, mode, &sz);
        parent_file.size = sz;
        memset(&xpp, 0, sizeof(xpp));
        xpp.flags = XDF_NEED_MINIMAL;
@@ -692,7 +700,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
 
        /* Read the result of merge first */
        if (!working_tree_file)
-               result = grab_blob(elem->sha1, &result_size);
+               result = grab_blob(elem->sha1, elem->mode, &result_size);
        else {
                /* Used by diff-tree to read from the working tree */
                struct stat st;
@@ -712,6 +720,12 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        result_size = buf.len;
                        result = strbuf_detach(&buf, NULL);
                        elem->mode = canon_mode(st.st_mode);
+               } else if (S_ISDIR(st.st_mode)) {
+                       unsigned char sha1[20];
+                       if (resolve_gitlink_ref(elem->path, "HEAD", sha1) < 0)
+                               result = grab_blob(elem->sha1, elem->mode, &result_size);
+                       else
+                               result = grab_blob(sha1, elem->mode, &result_size);
                } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
                        size_t len = xsize_t(st.st_size);
                        ssize_t done;
@@ -804,7 +818,9 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        }
                }
                if (i <= j)
-                       combine_diff(elem->parent[i].sha1, &result_file, sline,
+                       combine_diff(elem->parent[i].sha1,
+                                    elem->parent[i].mode,
+                                    &result_file, sline,
                                     cnt, i, num_parent);
                if (elem->parent[i].mode != elem->mode)
                        mode_differs = 1;
@@ -1047,7 +1063,7 @@ void diff_tree_combined_merge(const unsigned char *sha1,
        for (parents = commit->parents, num_parent = 0;
             parents;
             parents = parents->next, num_parent++)
-               hashcpy((unsigned char*)(parent + num_parent),
+               hashcpy((unsigned char *)(parent + num_parent),
                        parents->item->object.sha1);
        diff_tree_combined(sha1, parent, num_parent, dense, rev);
 }
index 3583a33ee90647d8e6ded02643eb75753760d94f..fb03a2ebb5d51f46d00fad3b3f6b1794d4fdad2b 100644 (file)
@@ -33,6 +33,7 @@ git-diff                                mainporcelain common
 git-diff-files                          plumbinginterrogators
 git-diff-index                          plumbinginterrogators
 git-diff-tree                           plumbinginterrogators
+git-difftool                            ancillaryinterrogators
 git-fast-export                                ancillarymanipulators
 git-fast-import                                ancillarymanipulators
 git-fetch                               mainporcelain common
index aa3b35b6a86891ac9d0628e20a6a46d506bf7700..8f6b703c557599921d890c3b50b66eaa397de548 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -316,6 +316,26 @@ int parse_commit(struct commit *item)
        return ret;
 }
 
+static void unparse_commit_list(struct commit_list *list)
+{
+       for (; list; list = list->next)
+               unparse_commit(list->item);
+}
+
+void unparse_commit(struct commit *item)
+{
+       item->object.flags = 0;
+       item->object.used = 0;
+       if (item->object.parsed) {
+               item->object.parsed = 0;
+               if (item->parents) {
+                       unparse_commit_list(item->parents);
+                       free_commit_list(item->parents);
+                       item->parents = NULL;
+               }
+       }
+}
+
 struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)
 {
        struct commit_list *new_list = xmalloc(sizeof(struct commit_list));
index ba9f63813eba004ae409eba8741266a074161239..f3eaf1d048a3e799eb571fbfe1302c08b3d394a6 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -40,6 +40,8 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
 
 int parse_commit(struct commit *item);
 
+void unparse_commit(struct commit *item);
+
 struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p);
 unsigned commit_list_count(const struct commit_list *l);
 struct commit_list * insert_by_date(struct commit *item, struct commit_list **list);
index ebac1483929c798905e6558e0013e3de3d6abeb2..b4a51b958c5651d3b509013aaef0c4e30b68a816 100644 (file)
@@ -89,10 +89,10 @@ static int cygwin_stat(const char *path, struct stat *buf)
 /*
  * At start up, we are trying to determine whether Win32 API or cygwin stat
  * functions should be used. The choice is determined by core.ignorecygwinfstricks.
- * Reading this option is not always possible immediately as git_dir may be
+ * Reading this option is not always possible immediately as git_dir may
  * not be set yet. So until it is set, use cygwin lstat/stat functions.
  * However, if core.filemode is set, we must use the Cygwin posix
- * stat/lstat as the Windows stat fuctions do not determine posix filemode.
+ * stat/lstat as the Windows stat functions do not determine posix filemode.
  *
  * Note that git_cygwin_config() does NOT call git_default_config() and this
  * is deliberate.  Many commands read from config to establish initial
index 1f4ead5f981688ee9e29ae2ee281e3904c9131f6..14feac7fe179069908df6dbc084b2adcc78c9242 100644 (file)
@@ -39,7 +39,7 @@
 # include <stdlib.h>
 #endif
 
-/* For platform which support the ISO C amendement 1 functionality we
+/* For platforms which support the ISO C amendment 1 functionality we
    support user defined character classes.  */
 #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
@@ -90,7 +90,7 @@
 
 # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 /* The GNU C library provides support for user-defined character classes
-   and the functions from ISO C amendement 1.  */
+   and the functions from ISO C amendment 1.  */
 #  ifdef CHARCLASS_NAME_MAX
 #   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
 #  else
index 2839d9df6ee8ed1e7227769877b04dd9b542f496..e190fddf41d6b15d9254859fca8b638ed7c0f428 100644 (file)
@@ -396,7 +396,7 @@ repeat:
                 * its own input data to become available. But since
                 * the process (pack-objects) is itself CPU intensive,
                 * it will happily pick up the time slice that we are
-                * relinguishing here.
+                * relinquishing here.
                 */
                Sleep(0);
                goto repeat;
@@ -525,8 +525,8 @@ static const char *parse_interpreter(const char *cmd)
        if (buf[0] != '#' || buf[1] != '!')
                return NULL;
        buf[n] = '\0';
-       p = strchr(buf, '\n');
-       if (!p)
+       p = buf + strcspn(buf, "\r\n");
+       if (!*p)
                return NULL;
 
        *p = '\0';
@@ -562,7 +562,7 @@ static char **get_path_split(void)
        if (!n)
                return NULL;
 
-       path = xmalloc((n+1)*sizeof(char*));
+       path = xmalloc((n+1)*sizeof(char *));
        p = envpath;
        i = 0;
        do {
@@ -934,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
 #undef rename
 int mingw_rename(const char *pold, const char *pnew)
 {
-       DWORD attrs;
+       DWORD attrs, gle;
+       int tries = 0;
+       static const int delay[] = { 0, 1, 10, 20, 40 };
 
        /*
         * Try native rename() first to get errno right.
@@ -944,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew)
                return 0;
        if (errno != EEXIST)
                return -1;
+repeat:
        if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
                return 0;
        /* TODO: translate more errors */
-       if (GetLastError() == ERROR_ACCESS_DENIED &&
+       gle = GetLastError();
+       if (gle == ERROR_ACCESS_DENIED &&
            (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
                if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
                        errno = EISDIR;
@@ -957,10 +961,23 @@ int mingw_rename(const char *pold, const char *pnew)
                    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
                        if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
                                return 0;
+                       gle = GetLastError();
                        /* revert file attributes on failure */
                        SetFileAttributes(pnew, attrs);
                }
        }
+       if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
+               /*
+                * We assume that some other process had the source or
+                * destination file open at the wrong moment and retry.
+                * In order to give the other process a higher chance to
+                * complete its operation, we give up our time slice now.
+                * If we have to retry again, we do sleep a bit.
+                */
+               Sleep(delay[tries]);
+               tries++;
+               goto repeat;
+       }
        errno = EACCES;
        return -1;
 }
@@ -1139,3 +1156,18 @@ int link(const char *oldpath, const char *newpath)
        }
        return 0;
 }
+
+char *getpass(const char *prompt)
+{
+       struct strbuf buf = STRBUF_INIT;
+
+       fputs(prompt, stderr);
+       for (;;) {
+               char c = _getch();
+               if (c == '\r' || c == '\n')
+                       break;
+               strbuf_addch(&buf, c);
+       }
+       fputs("\n", stderr);
+       return strbuf_detach(&buf, NULL);
+}
index 762eb143a7654480d8831a6258a0767c0f33900b..4c50f5b1bca1e161b7e6cf0635b57f5e8d741c13 100644 (file)
@@ -38,6 +38,8 @@ struct passwd {
        char *pw_dir;
 };
 
+extern char *getpass(const char *prompt);
+
 struct pollfd {
        int fd;           /* file descriptor */
        short events;     /* requested events */
@@ -109,7 +111,7 @@ static inline int mingw_unlink(const char *pathname)
 }
 #define unlink mingw_unlink
 
-static inline int waitpid(pid_t pid, unsigned *status, unsigned options)
+static inline int waitpid(pid_t pid, int *status, unsigned options)
 {
        if (options == 0)
                return _cwait(status, pid, 0);
index 87b33e46697b9a5dd9a9e8391ca3607f7e2ff569..5ea007567d15c229685f571628d4afcce6783e8d 100644 (file)
@@ -1043,7 +1043,7 @@ regex_compile (pattern, size, syntax, bufp)
      they can be reliably used as array indices.  */
   register unsigned char c, c1;
 
-  /* A random tempory spot in PATTERN.  */
+  /* A random temporary spot in PATTERN.  */
   const char *p1;
 
   /* Points to the end of the buffer, where we should append.  */
@@ -1796,7 +1796,7 @@ regex_compile (pattern, size, syntax, bufp)
                    we're all done, the pattern will look like:
                      set_number_at <jump count> <upper bound>
                      set_number_at <succeed_n count> <lower bound>
-                     succeed_n <after jump addr> <succed_n count>
+                     succeed_n <after jump addr> <succeed_n count>
                      <body of loop>
                      jump_n <succeed_n addr> <jump count>
                    (The upper bound and `jump_n' are omitted if
index b76fe4c6dcc966f8c7c15da44d15f7cf45740f5b..1682273c12ab042d73fa32caf30d18fb13ef85e3 100644 (file)
--- a/config.c
+++ b/config.c
@@ -51,7 +51,7 @@ static char *parse_value(void)
 
        for (;;) {
                int c = get_next_char();
-               if (len >= sizeof(value))
+               if (len >= sizeof(value) - 1)
                        return NULL;
                if (c == '\n') {
                        if (quote)
@@ -331,9 +331,9 @@ int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
                return 1;
        if (!*value)
                return 0;
-       if (!strcasecmp(value, "true") || !strcasecmp(value, "yes"))
+       if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
                return 1;
-       if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
+       if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
                return 0;
        *is_bool = 0;
        return git_config_int(name, value);
@@ -495,6 +495,16 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.createobject")) {
+               if (!strcmp(value, "rename"))
+                       object_creation_mode = OBJECT_CREATION_USES_RENAMES;
+               else if (!strcmp(value, "link"))
+                       object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
+               else
+                       die("Invalid mode for object creation: %s", value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
@@ -714,16 +724,16 @@ int git_config(config_fn_t fn, void *data)
 
 static struct {
        int baselen;
-       charkey;
+       char *key;
        int do_not_match;
-       regex_tvalue_regex;
+       regex_t *value_regex;
        int multi_replace;
        size_t offset[MAX_MATCHES];
        enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
        int seen;
 } store;
 
-static int matches(const char* key, const char* value)
+static int matches(const char *key, const char *value)
 {
        return !strcmp(key, store.key) &&
                (store.value_regex == NULL ||
@@ -731,7 +741,7 @@ static int matches(const char* key, const char* value)
                  !regexec(store.value_regex, value, 0, NULL, 0)));
 }
 
-static int store_aux(const char* key, const char* value, void *cb)
+static int store_aux(const char *key, const char *value, void *cb)
 {
        const char *ep;
        size_t section_len;
@@ -800,7 +810,7 @@ static int write_error(const char *filename)
        return 4;
 }
 
-static int store_write_section(int fd, const charkey)
+static int store_write_section(int fd, const char *key)
 {
        const char *dot;
        int i, success;
@@ -825,7 +835,7 @@ static int store_write_section(int fd, const char* key)
        return success;
 }
 
-static int store_write_pair(int fd, const char* key, const char* value)
+static int store_write_pair(int fd, const char *key, const char *value)
 {
        int i, success;
        int length = strlen(key + store.baselen + 1);
@@ -873,8 +883,8 @@ static int store_write_pair(int fd, const char* key, const char* value)
        return success;
 }
 
-static ssize_t find_beginning_of_line(const charcontents, size_t size,
-       size_t offset_, intfound_bracket)
+static ssize_t find_beginning_of_line(const char *contents, size_t size,
+       size_t offset_, int *found_bracket)
 {
        size_t equal_offset = size, bracket_offset = size;
        ssize_t offset;
@@ -899,7 +909,7 @@ contline:
        return offset;
 }
 
-int git_config_set(const char* key, const char* value)
+int git_config_set(const char *key, const char *value)
 {
        return git_config_set_multivar(key, value, NULL, 0);
 }
@@ -927,15 +937,15 @@ int git_config_set(const char* key, const char* value)
  * - the config file is removed and the lock file rename()d to it.
  *
  */
-int git_config_set_multivar(const char* key, const char* value,
-       const charvalue_regex, int multi_replace)
+int git_config_set_multivar(const char *key, const char *value,
+       const char *value_regex, int multi_replace)
 {
        int i, dot;
        int fd = -1, in_fd;
        int ret;
-       charconfig_filename;
+       char *config_filename;
        struct lock_file *lock = NULL;
-       const charlast_dot = strrchr(key, '.');
+       const char *last_dot = strrchr(key, '.');
 
        if (config_exclusive_filename)
                config_filename = xstrdup(config_exclusive_filename);
@@ -991,7 +1001,7 @@ int git_config_set_multivar(const char* key, const char* value,
        lock = xcalloc(sizeof(struct lock_file), 1);
        fd = hold_lock_file_for_update(lock, config_filename, 0);
        if (fd < 0) {
-               error("could not lock config file %s", config_filename);
+               error("could not lock config file %s: %s", config_filename, strerror(errno));
                free(store.key);
                ret = -1;
                goto out_free;
@@ -1016,13 +1026,13 @@ int git_config_set_multivar(const char* key, const char* value,
                        goto out_free;
                }
 
-               store.key = (char*)key;
+               store.key = (char *)key;
                if (!store_write_section(fd, key) ||
                    !store_write_pair(fd, key, value))
                        goto write_err_out;
        } else {
                struct stat st;
-               charcontents;
+               char *contents;
                size_t contents_sz, copy_begin, copy_end;
                int i, new_line = 0;
 
index 7636bf976e78a6622281501af2dcc0135781f60a..f6b8ba6fec16ed2ff2de4c66e2465e79d059a817 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -177,18 +177,11 @@ static enum protocol get_protocol(const char *name)
 
 static const char *ai_name(const struct addrinfo *ai)
 {
-       static char addr[INET_ADDRSTRLEN];
-       if ( AF_INET == ai->ai_family ) {
-               struct sockaddr_in *in;
-               in = (struct sockaddr_in *)ai->ai_addr;
-               inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr));
-       } else if ( AF_INET6 == ai->ai_family ) {
-               struct sockaddr_in6 *in;
-               in = (struct sockaddr_in6 *)ai->ai_addr;
-               inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr));
-       } else {
+       static char addr[NI_MAXHOST];
+       if (getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, sizeof(addr), NULL, 0,
+                       NI_NUMERICHOST) != 0)
                strcpy(addr, "(unknown)");
-       }
+
        return addr;
 }
 
index c1c879821dc5c6314346d8c55c79fafdf48b5ac1..98b9cbedc2bcae32491fc69641740b186a64ab26 100755 (executable)
@@ -84,35 +84,45 @@ __git_ps1 ()
        if [ -n "$g" ]; then
                local r
                local b
-               if [ -d "$g/rebase-apply" ]; then
-                       if [ -f "$g/rebase-apply/rebasing" ]; then
-                               r="|REBASE"
-               elif [ -f "$g/rebase-apply/applying" ]; then
-                               r="|AM"
-                       else
-                               r="|AM/REBASE"
-                       fi
-                       b="$(git symbolic-ref HEAD 2>/dev/null)"
-               elif [ -f "$g/rebase-merge/interactive" ]; then
+               if [ -f "$g/rebase-merge/interactive" ]; then
                        r="|REBASE-i"
                        b="$(cat "$g/rebase-merge/head-name")"
                elif [ -d "$g/rebase-merge" ]; then
                        r="|REBASE-m"
                        b="$(cat "$g/rebase-merge/head-name")"
-               elif [ -f "$g/MERGE_HEAD" ]; then
-                       r="|MERGING"
-                       b="$(git symbolic-ref HEAD 2>/dev/null)"
                else
-                       if [ -f "$g/BISECT_LOG" ]; then
-                               r="|BISECTING"
-                       fi
-                       if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then
-                               if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then
-                                       if [ -r "$g/HEAD" ]; then
-                                               b="$(cut -c1-7 "$g/HEAD")..."
-                                       fi
+                       if [ -d "$g/rebase-apply" ]; then
+                               if [ -f "$g/rebase-apply/rebasing" ]; then
+                                       r="|REBASE"
+                               elif [ -f "$g/rebase-apply/applying" ]; then
+                                       r="|AM"
+                               else
+                                       r="|AM/REBASE"
                                fi
+                       elif [ -f "$g/MERGE_HEAD" ]; then
+                               r="|MERGING"
+                       elif [ -f "$g/BISECT_LOG" ]; then
+                               r="|BISECTING"
                        fi
+
+                       b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+
+                               b="$(
+                               case "${GIT_PS1_DESCRIBE_STYLE-}" in
+                               (contains)
+                                       git describe --contains HEAD ;;
+                               (branch)
+                                       git describe --contains --all HEAD ;;
+                               (describe)
+                                       git describe HEAD ;;
+                               (* | default)
+                                       git describe --exact-match HEAD ;;
+                               esac 2>/dev/null)" ||
+
+                               b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
+                               b="unknown"
+                               b="($b)"
+                       }
                fi
 
                local w
@@ -120,7 +130,7 @@ __git_ps1 ()
                local c
 
                if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
-                       if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then
+                       if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
                                c="BARE:"
                        else
                                b="GIT_DIR!"
@@ -140,12 +150,10 @@ __git_ps1 ()
                        fi
                fi
 
-               if [ -n "$b" ]; then
-                       if [ -n "${1-}" ]; then
-                               printf "$1" "$c${b##refs/heads/}$w$i$r"
-                       else
-                               printf " (%s)" "$c${b##refs/heads/}$w$i$r"
-                       fi
+               if [ -n "${1-}" ]; then
+                       printf "$1" "$c${b##refs/heads/}$w$i$r"
+               else
+                       printf " (%s)" "$c${b##refs/heads/}$w$i$r"
                fi
        fi
 }
@@ -910,6 +918,26 @@ _git_diff ()
        __git_complete_file
 }
 
+__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
+                       tkdiff vimdiff gvimdiff xxdiff
+"
+
+_git_difftool ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --tool=*)
+               __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
+               return
+               ;;
+       --*)
+               __gitcomp "--tool="
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 __git_fetch_options="
        --quiet --verbose --append --upload-pack --force --keep --depth=
        --tags --no-tags
@@ -1096,6 +1124,7 @@ __git_log_shortlog_options="
 "
 
 __git_log_pretty_formats="oneline short medium full fuller email raw format:"
+__git_log_date_formats="relative iso8601 rfc2822 short local default raw"
 
 _git_log ()
 {
@@ -1119,9 +1148,7 @@ _git_log ()
                return
                ;;
        --date=*)
-               __gitcomp "
-                       relative iso8601 rfc2822 short local default
-               " "" "${cur##--date=}"
+               __gitcomp "$__git_log_date_formats" "" "${cur##--date=}"
                return
                ;;
        --*)
@@ -1172,10 +1199,7 @@ _git_mergetool ()
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --tool=*)
-               __gitcomp "
-                       kdiff3 tkdiff meld xxdiff emerge
-                       vimdiff gvimdiff ecmerge opendiff
-                       " "" "${cur##--tool=}"
+               __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
                return
                ;;
        --*)
@@ -1266,18 +1290,39 @@ _git_rebase ()
        __gitcomp "$(__git_refs)"
 }
 
+__git_send_email_confirm_options="always never auto cc compose"
+__git_send_email_suppresscc_options="author self cc ccbody sob cccmd body all"
+
 _git_send_email ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
+       --confirm=*)
+               __gitcomp "
+                       $__git_send_email_confirm_options
+                       " "" "${cur##--confirm=}"
+               return
+               ;;
+       --suppress-cc=*)
+               __gitcomp "
+                       $__git_send_email_suppresscc_options
+                       " "" "${cur##--suppress-cc=}"
+
+               return
+               ;;
+       --smtp-encryption=*)
+               __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}"
+               return
+               ;;
        --*)
                __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
-                       --compose --dry-run --envelope-sender --from --identity
+                       --compose --confirm= --dry-run --envelope-sender
+                       --from --identity
                        --in-reply-to --no-chain-reply-to --no-signed-off-by-cc
                        --no-suppress-from --no-thread --quiet
                        --signed-off-by-cc --smtp-pass --smtp-server
-                       --smtp-server-port --smtp-ssl --smtp-user --subject
-                       --suppress-cc --suppress-from --thread --to
+                       --smtp-server-port --smtp-encryption= --smtp-user
+                       --subject --suppress-cc= --suppress-from --thread --to
                        --validate --no-validate"
                return
                ;;
@@ -1285,6 +1330,35 @@ _git_send_email ()
        COMPREPLY=()
 }
 
+__git_config_get_set_variables ()
+{
+       local prevword word config_file= c=$COMP_CWORD
+       while [ $c -gt 1 ]; do
+               word="${COMP_WORDS[c]}"
+               case "$word" in
+               --global|--system|--file=*)
+                       config_file="$word"
+                       break
+                       ;;
+               -f|--file)
+                       config_file="$word $prevword"
+                       break
+                       ;;
+               esac
+               prevword=$word
+               c=$((--c))
+       done
+
+       for i in $(git --git-dir="$(__gitdir)" config $config_file --list \
+                       2>/dev/null); do
+               case "$i" in
+               *.*)
+                       echo "${i/=*/}"
+                       ;;
+               esac
+       done
+}
+
 _git_config ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -1316,7 +1390,8 @@ _git_config ()
                __gitcomp "$(__git_merge_strategies)"
                return
                ;;
-       color.branch|color.diff|color.interactive|color.status|color.ui)
+       color.branch|color.diff|color.interactive|\
+       color.showbranch|color.status|color.ui)
                __gitcomp "always never auto"
                return
                ;;
@@ -1331,6 +1406,30 @@ _git_config ()
                        "
                return
                ;;
+       help.format)
+               __gitcomp "man info web html"
+               return
+               ;;
+       log.date)
+               __gitcomp "$__git_log_date_formats"
+               return
+               ;;
+       sendemail.aliasesfiletype)
+               __gitcomp "mutt mailrc pine elm gnus"
+               return
+               ;;
+       sendemail.confirm)
+               __gitcomp "$__git_send_email_confirm_options"
+               return
+               ;;
+       sendemail.suppresscc)
+               __gitcomp "$__git_send_email_suppresscc_options"
+               return
+               ;;
+       --get|--get-all|--unset|--unset-all)
+               __gitcomp "$(__git_config_get_set_variables)"
+               return
+               ;;
        *.*)
                COMPREPLY=()
                return
@@ -1359,6 +1458,39 @@ _git_config ()
                __gitcomp "$(__git_heads)" "$pfx" "$cur" "."
                return
                ;;
+       guitool.*.*)
+               local pfx="${cur%.*}."
+               cur="${cur##*.}"
+               __gitcomp "
+                       argprompt cmd confirm needsfile noconsole norescan
+                       prompt revprompt revunmerged title
+                       " "$pfx" "$cur"
+               return
+               ;;
+       difftool.*.*)
+               local pfx="${cur%.*}."
+               cur="${cur##*.}"
+               __gitcomp "cmd path" "$pfx" "$cur"
+               return
+               ;;
+       man.*.*)
+               local pfx="${cur%.*}."
+               cur="${cur##*.}"
+               __gitcomp "cmd path" "$pfx" "$cur"
+               return
+               ;;
+       mergetool.*.*)
+               local pfx="${cur%.*}."
+               cur="${cur##*.}"
+               __gitcomp "cmd path trustExitCode" "$pfx" "$cur"
+               return
+               ;;
+       pager.*)
+               local pfx="${cur%.*}."
+               cur="${cur#*.}"
+               __gitcomp "$(__git_all_commands)" "$pfx" "$cur"
+               return
+               ;;
        remote.*.*)
                local pfx="${cur%.*}."
                cur="${cur##*.}"
@@ -1374,8 +1506,15 @@ _git_config ()
                __gitcomp "$(__git_remotes)" "$pfx" "$cur" "."
                return
                ;;
+       url.*.*)
+               local pfx="${cur%.*}."
+               cur="${cur##*.}"
+               __gitcomp "insteadof" "$pfx" "$cur"
+               return
+               ;;
        esac
        __gitcomp "
+               alias.
                apply.whitespace
                branch.autosetupmerge
                branch.autosetuprebase
@@ -1393,11 +1532,15 @@ _git_config ()
                color.diff.old
                color.diff.plain
                color.diff.whitespace
+               color.grep
+               color.grep.external
+               color.grep.match
                color.interactive
                color.interactive.header
                color.interactive.help
                color.interactive.prompt
                color.pager
+               color.showbranch
                color.status
                color.status.added
                color.status.changed
@@ -1410,6 +1553,7 @@ _git_config ()
                core.autocrlf
                core.bare
                core.compression
+               core.createObject
                core.deltaBaseCacheLimit
                core.editor
                core.excludesfile
@@ -1440,11 +1584,21 @@ _git_config ()
                diff.renameLimit
                diff.renameLimit.
                diff.renames
+               diff.suppressBlankEmpty
+               diff.tool
+               diff.wordRegex
+               difftool.
+               difftool.prompt
                fetch.unpackLimit
+               format.attach
+               format.cc
                format.headers
                format.numbered
                format.pretty
+               format.signoff
+               format.subjectprefix
                format.suffix
+               format.thread
                gc.aggressiveWindow
                gc.auto
                gc.autopacklimit
@@ -1455,6 +1609,7 @@ _git_config ()
                gc.rerereresolved
                gc.rerereunresolved
                gitcvs.allbinary
+               gitcvs.commitmsgannotation
                gitcvs.dbTableNamePrefix
                gitcvs.dbdriver
                gitcvs.dbname
@@ -1463,6 +1618,7 @@ _git_config ()
                gitcvs.enabled
                gitcvs.logfile
                gitcvs.usecrlfattr
+               guitool.
                gui.blamehistoryctx
                gui.commitmsgwidth
                gui.copyblamethreshold
@@ -1489,13 +1645,24 @@ _git_config ()
                http.sslVerify
                i18n.commitEncoding
                i18n.logOutputEncoding
+               imap.folder
+               imap.host
+               imap.pass
+               imap.port
+               imap.preformattedHTML
+               imap.sslverify
+               imap.tunnel
+               imap.user
                instaweb.browser
                instaweb.httpd
                instaweb.local
                instaweb.modulepath
                instaweb.port
+               interactive.singlekey
                log.date
                log.showroot
+               mailmap.file
+               man.
                man.viewer
                merge.conflictstyle
                merge.log
@@ -1503,7 +1670,9 @@ _git_config ()
                merge.stat
                merge.tool
                merge.verbosity
+               mergetool.
                mergetool.keepBackup
+               mergetool.prompt
                pack.compression
                pack.deltaCacheLimit
                pack.deltaCacheSize
@@ -1513,8 +1682,11 @@ _git_config ()
                pack.threads
                pack.window
                pack.windowMemory
+               pager.
                pull.octopus
                pull.twohead
+               push.default
+               rebase.stat
                receive.denyCurrentBranch
                receive.denyDeletes
                receive.denyNonFastForwards
@@ -1523,11 +1695,32 @@ _git_config ()
                repack.usedeltabaseoffset
                rerere.autoupdate
                rerere.enabled
+               sendemail.aliasesfile
+               sendemail.aliasesfiletype
+               sendemail.bcc
+               sendemail.cc
+               sendemail.cccmd
+               sendemail.chainreplyto
+               sendemail.confirm
+               sendemail.envelopesender
+               sendemail.multiedit
+               sendemail.signedoffbycc
+               sendemail.smtpencryption
+               sendemail.smtppass
+               sendemail.smtpserver
+               sendemail.smtpserverport
+               sendemail.smtpuser
+               sendemail.suppresscc
+               sendemail.suppressfrom
+               sendemail.thread
+               sendemail.to
+               sendemail.validate
                showbranch.default
                status.relativePaths
                status.showUntrackedFiles
                tar.umask
                transfer.unpackLimit
+               url.
                user.email
                user.name
                user.signingkey
@@ -1642,7 +1835,7 @@ _git_show ()
                return
                ;;
        --*)
-               __gitcomp "--pretty= --format=
+               __gitcomp "--pretty= --format= --abbrev-commit --oneline
                        $__git_diff_common_options
                        "
                return
@@ -1659,7 +1852,8 @@ _git_show_branch ()
                __gitcomp "
                        --all --remotes --topo-order --current --more=
                        --list --independent --merge-base --no-name
-                       --sha1-name --topics --reflog
+                       --color --no-color
+                       --sha1-name --sparse --topics --reflog
                        "
                return
                ;;
@@ -1901,6 +2095,7 @@ _git ()
        config)      _git_config ;;
        describe)    _git_describe ;;
        diff)        _git_diff ;;
+       difftool)    _git_difftool ;;
        fetch)       _git_fetch ;;
        format-patch) _git_format_patch ;;
        fsck)        _git_fsck ;;
index 90e7900e6d7aff2fadf9ba04f8d982733493411c..f3b57bf1d21e8256bf084076e50cbc9ff84a1ee8 100644 (file)
@@ -59,7 +59,7 @@ static void convert_ascii_sha1(void *buffer)
        struct entry *entry;
 
        if (get_sha1_hex(buffer, sha1))
-               die("expected sha1, got '%s'", (char*) buffer);
+               die("expected sha1, got '%s'", (char *) buffer);
        entry = convert_entry(sha1);
        memcpy(buffer, sha1_to_hex(entry->new_sha1), 40);
 }
@@ -100,7 +100,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
                if (!slash) {
                        newlen += sprintf(new + newlen, "%o %s", mode, path);
                        new[newlen++] = '\0';
-                       hashcpy((unsigned char*)new + newlen, (unsigned char *) buffer + len - 20);
+                       hashcpy((unsigned char *)new + newlen, (unsigned char *) buffer + len - 20);
                        newlen += 20;
 
                        used += len;
@@ -271,7 +271,7 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu
        unsigned long orig_size = size;
 
        if (memcmp(buffer, "tree ", 5))
-               die("Bad commit '%s'", (char*) buffer);
+               die("Bad commit '%s'", (char *) buffer);
        convert_ascii_sha1((char *) buffer + 5);
        buffer = (char *) buffer + 46;    /* "tree " + "hex sha1" + "\n" */
        while (!memcmp(buffer, "parent ", 7)) {
diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool
deleted file mode 100755 (executable)
index 0deda3a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env perl
-# Copyright (c) 2009 David Aguilar
-#
-# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
-# git-difftool-helper script.  This script exports
-# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
-# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper.
-# Any arguments that are unknown to this script are forwarded to 'git diff'.
-
-use strict;
-use warnings;
-use Cwd qw(abs_path);
-use File::Basename qw(dirname);
-
-my $DIR = abs_path(dirname($0));
-
-
-sub usage
-{
-       print << 'USAGE';
-usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options]
-USAGE
-       exit 1;
-}
-
-sub setup_environment
-{
-       $ENV{PATH} = "$DIR:$ENV{PATH}";
-       $ENV{GIT_PAGER} = '';
-       $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper';
-}
-
-sub exe
-{
-       my $exe = shift;
-       return defined $ENV{COMSPEC} ? "$exe.exe" : $exe;
-}
-
-sub generate_command
-{
-       my @command = (exe('git'), 'diff');
-       my $skip_next = 0;
-       my $idx = -1;
-       for my $arg (@ARGV) {
-               $idx++;
-               if ($skip_next) {
-                       $skip_next = 0;
-                       next;
-               }
-               if ($arg eq '-t' or $arg eq '--tool') {
-                       usage() if $#ARGV <= $idx;
-                       $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
-                       $skip_next = 1;
-                       next;
-               }
-               if ($arg =~ /^--tool=/) {
-                       $ENV{GIT_DIFF_TOOL} = substr($arg, 7);
-                       next;
-               }
-               if ($arg eq '--no-prompt') {
-                       $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
-                       next;
-               }
-               if ($arg eq '-h' or $arg eq '--help') {
-                       usage();
-               }
-               push @command, $arg;
-       }
-       return @command
-}
-
-setup_environment();
-exec(generate_command());
diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper
deleted file mode 100755 (executable)
index 9c0a134..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-#!/bin/sh
-# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
-# It supports kdiff3, kompare, tkdiff, xxdiff, meld, opendiff,
-# emerge, ecmerge, vimdiff, gvimdiff, and custom user-configurable tools.
-# This script is typically launched by using the 'git difftool'
-# convenience command.
-#
-# Copyright (c) 2009 David Aguilar
-
-# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
-should_prompt () {
-       ! test -n "$GIT_DIFFTOOL_NO_PROMPT"
-}
-
-# Should we keep the backup .orig file?
-keep_backup_mode="$(git config --bool merge.keepBackup || echo true)"
-keep_backup () {
-       test "$keep_backup_mode" = "true"
-}
-
-# This function manages the backup .orig file.
-# A backup $MERGED.orig file is created if changes are detected.
-cleanup_temp_files () {
-       if test -n "$MERGED"; then
-               if keep_backup && test "$MERGED" -nt "$BACKUP"; then
-                       test -f "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
-               else
-                       rm -f -- "$BACKUP"
-               fi
-       fi
-}
-
-# This is called when users Ctrl-C out of git-difftool-helper
-sigint_handler () {
-       cleanup_temp_files
-       exit 1
-}
-
-# This function prepares temporary files and launches the appropriate
-# merge tool.
-launch_merge_tool () {
-       # Merged is the filename as it appears in the work tree
-       # Local is the contents of a/filename
-       # Remote is the contents of b/filename
-       # Custom merge tool commands might use $BASE so we provide it
-       MERGED="$1"
-       LOCAL="$2"
-       REMOTE="$3"
-       BASE="$1"
-       ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
-       BACKUP="$MERGED.BACKUP.$ext"
-
-       # Create and ensure that we clean up $BACKUP
-       test -f "$MERGED" && cp -- "$MERGED" "$BACKUP"
-       trap sigint_handler INT
-
-       # $LOCAL and $REMOTE are temporary files so prompt
-       # the user with the real $MERGED name before launching $merge_tool.
-       if should_prompt; then
-               printf "\nViewing: '$MERGED'\n"
-               printf "Hit return to launch '%s': " "$merge_tool"
-               read ans
-       fi
-
-       # Run the appropriate merge tool command
-       case "$merge_tool" in
-       kdiff3)
-               basename=$(basename "$MERGED")
-               "$merge_tool_path" --auto \
-                       --L1 "$basename (A)" \
-                       --L2 "$basename (B)" \
-                       -o "$MERGED" "$LOCAL" "$REMOTE" \
-                       > /dev/null 2>&1
-               ;;
-
-       kompare)
-               "$merge_tool_path" "$LOCAL" "$REMOTE"
-               ;;
-
-       tkdiff)
-               "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
-               ;;
-
-       meld)
-               "$merge_tool_path" "$LOCAL" "$REMOTE"
-               ;;
-
-       vimdiff)
-               "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE"
-               ;;
-
-       gvimdiff)
-               "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE"
-               ;;
-
-       xxdiff)
-               "$merge_tool_path" \
-                       -X \
-                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
-                       -R 'Accel.Search: "Ctrl+F"' \
-                       -R 'Accel.SearchForward: "Ctrl-G"' \
-                       --merged-file "$MERGED" \
-                       "$LOCAL" "$REMOTE"
-               ;;
-
-       opendiff)
-               "$merge_tool_path" "$LOCAL" "$REMOTE" \
-                       -merge "$MERGED" | cat
-               ;;
-
-       ecmerge)
-               "$merge_tool_path" "$LOCAL" "$REMOTE" \
-                       --default --mode=merge2 --to="$MERGED"
-               ;;
-
-       emerge)
-               "$merge_tool_path" -f emerge-files-command \
-                       "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
-               ;;
-
-       *)
-               if test -n "$merge_tool_cmd"; then
-                       ( eval $merge_tool_cmd )
-               fi
-               ;;
-       esac
-
-       cleanup_temp_files
-}
-
-# Verifies that (difftool|mergetool).<tool>.cmd exists
-valid_custom_tool() {
-       merge_tool_cmd="$(git config difftool.$1.cmd)"
-       test -z "$merge_tool_cmd" &&
-       merge_tool_cmd="$(git config mergetool.$1.cmd)"
-       test -n "$merge_tool_cmd"
-}
-
-# Verifies that the chosen merge tool is properly setup.
-# Built-in merge tools are always valid.
-valid_tool() {
-       case "$1" in
-       kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
-               ;; # happy
-       *)
-               if ! valid_custom_tool "$1"
-               then
-                       return 1
-               fi
-               ;;
-       esac
-}
-
-# Sets up the merge_tool_path variable.
-# This handles the difftool.<tool>.path configuration.
-# This also falls back to mergetool defaults.
-init_merge_tool_path() {
-       merge_tool_path=$(git config difftool."$1".path)
-       test -z "$merge_tool_path" &&
-       merge_tool_path=$(git config mergetool."$1".path)
-       if test -z "$merge_tool_path"; then
-               case "$1" in
-               emerge)
-                       merge_tool_path=emacs
-                       ;;
-               *)
-                       merge_tool_path="$1"
-                       ;;
-               esac
-       fi
-}
-
-# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
-test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
-test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
-
-# If merge tool was not specified then use the diff.tool
-# configuration variable.  If that's invalid then reset merge_tool.
-# Fallback to merge.tool.
-if test -z "$merge_tool"; then
-       merge_tool=$(git config diff.tool)
-       test -z "$merge_tool" &&
-       merge_tool=$(git config merge.tool)
-       if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
-               echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
-               echo >&2 "Resetting to default..."
-               unset merge_tool
-       fi
-fi
-
-# Try to guess an appropriate merge tool if no tool has been set.
-if test -z "$merge_tool"; then
-       # We have a $DISPLAY so try some common UNIX merge tools
-       if test -n "$DISPLAY"; then
-               # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare
-               if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
-                       merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff"
-               else
-                       merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff"
-               fi
-       fi
-       if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
-               # $EDITOR is emacs so add emerge as a candidate
-               merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
-       elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
-               # $EDITOR is vim so add vimdiff as a candidate
-               merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
-       else
-               merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
-       fi
-       echo "merge tool candidates: $merge_tool_candidates"
-
-       # Loop over each candidate and stop when a valid merge tool is found.
-       for i in $merge_tool_candidates
-       do
-               init_merge_tool_path $i
-               if type "$merge_tool_path" > /dev/null 2>&1; then
-                       merge_tool=$i
-                       break
-               fi
-       done
-
-       if test -z "$merge_tool" ; then
-               echo "No known merge resolution program available."
-               exit 1
-       fi
-
-else
-       # A merge tool has been set, so verify that it's valid.
-       if ! valid_tool "$merge_tool"; then
-               echo >&2 "Unknown merge tool $merge_tool"
-               exit 1
-       fi
-
-       init_merge_tool_path "$merge_tool"
-
-       if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
-               echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
-               exit 1
-       fi
-fi
-
-
-# Launch the merge tool on each path provided by 'git diff'
-while test $# -gt 6
-do
-       launch_merge_tool "$1" "$2" "$5"
-       shift 7
-done
old mode 100644 (file)
new mode 100755 (executable)
index 60cbab6..2a66063
 #   --pretty %s", displaying the commit id, author, date and log
 #   message.  To list full patches separated by a blank line, you
 #   could set this to "git show -C %s; echo".
+#   To list a gitweb/cgit URL *and* a full patch for each change set, use this:
+#     "t=%s; printf 'http://.../?id=%%s' \$t; echo;echo; git show -C \$t; echo"
+#   Be careful if "..." contains things that will be expanded by shell "eval"
+#   or printf.
 #
 # Notes
 # -----
index 39f96aa115e0a20024d2f41138db6b2b8c6d5320..000147bbe4a00525d68efb1358c013812e10dcca 100644 (file)
@@ -1,12 +1,12 @@
 appp.sh is a script that is supposed to be used together with ExternalEditor
-for Mozilla Thundebird. It will let you include patches inline in e-mails
+for Mozilla Thunderbird. It will let you include patches inline in e-mails
 in an easy way.
 
 Usage:
 - Generate the patch with git format-patch.
 - Start writing a new e-mail in Thunderbird.
 - Press the external editor button (or Ctrl-E) to run appp.sh
-- Select the previosly generated patch file.
+- Select the previously generated patch file.
 - Finish editing the e-mail.
 
 Any text that is entered into the message editor before appp.sh is called
diff --git a/ctype.c b/ctype.c
index b90ec004f29c30c4b6a6ea5339599d7a8db0fb8c..7ee64c7d77dd4a5665f70d80ffba1bcdecb9a408 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -10,7 +10,7 @@ enum {
        A = GIT_ALPHA,
        D = GIT_DIGIT,
        G = GIT_GLOB_SPECIAL,   /* *, ?, [, \\ */
-       R = GIT_REGEX_SPECIAL,  /* $, (, ), +, ., ^, {, | * */
+       R = GIT_REGEX_SPECIAL,  /* $, (, ), +, ., ^, {, | */
 };
 
 unsigned char sane_ctype[256] = {
index 13401f1baf57dc87a7a95bd778f4e1becbdbe323..daa4c8e8c95924c6fb446884b3ed44c454425b54 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -444,27 +444,27 @@ static void parse_extra_args(char *extra_args, int buflen)
        if (hostname) {
 #ifndef NO_IPV6
                struct addrinfo hints;
-               struct addrinfo *ai, *ai0;
+               struct addrinfo *ai;
                int gai;
                static char addrbuf[HOST_NAME_MAX + 1];
 
                memset(&hints, 0, sizeof(hints));
                hints.ai_flags = AI_CANONNAME;
 
-               gai = getaddrinfo(hostname, 0, &hints, &ai0);
+               gai = getaddrinfo(hostname, 0, &hints, &ai);
                if (!gai) {
-                       for (ai = ai0; ai; ai = ai->ai_next) {
-                               struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
-
-                               inet_ntop(AF_INET, &sin_addr->sin_addr,
-                                         addrbuf, sizeof(addrbuf));
-                               free(canon_hostname);
-                               canon_hostname = xstrdup(ai->ai_canonname);
-                               free(ip_address);
-                               ip_address = xstrdup(addrbuf);
-                               break;
-                       }
-                       freeaddrinfo(ai0);
+                       struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
+
+                       inet_ntop(AF_INET, &sin_addr->sin_addr,
+                                 addrbuf, sizeof(addrbuf));
+                       free(ip_address);
+                       ip_address = xstrdup(addrbuf);
+
+                       free(canon_hostname);
+                       canon_hostname = xstrdup(ai->ai_canonname ?
+                                                ai->ai_canonname : ip_address);
+
+                       freeaddrinfo(ai);
                }
 #else
                struct hostent *hent;
diff --git a/date.c b/date.c
index 1165d30adfa783f7cbaa871e38a1370f9f9c4996..409a17d46424083b62f21e7e278393cee7bfa080 100644 (file)
--- a/date.c
+++ b/date.c
@@ -871,13 +871,15 @@ unsigned long approxidate(const char *date)
        int number = 0;
        struct tm tm, now;
        struct timeval tv;
+       time_t time_sec;
        char buffer[50];
 
        if (parse_date(date, buffer, sizeof(buffer)) > 0)
                return strtoul(buffer, NULL, 10);
 
        gettimeofday(&tv, NULL);
-       localtime_r(&tv.tv_sec, &tm);
+       time_sec = tv.tv_sec;
+       localtime_r(&time_sec, &tm);
        now = tm;
        for (;;) {
                unsigned char c = *date;
index 82d9e221eabab53acc418d0db6327e480836a5ed..2f8a63e38881587fe29fcb72a5272ef54b9efa6e 100644 (file)
@@ -8,7 +8,9 @@
 
 static unsigned int hash_obj(const struct object *obj, unsigned int n)
 {
-       unsigned int hash = *(unsigned int *)obj->sha1;
+       unsigned int hash;
+
+       memcpy(&hash, obj->sha1, sizeof(unsigned int));
        return hash % n;
 }
 
@@ -16,7 +18,7 @@ static void *insert_decoration(struct decoration *n, const struct object *base,
 {
        int size = n->size;
        struct object_decoration *hash = n->hash;
-       int j = hash_obj(base, size);
+       unsigned int j = hash_obj(base, size);
 
        while (hash[j].base) {
                if (hash[j].base == base) {
@@ -68,7 +70,7 @@ void *add_decoration(struct decoration *n, const struct object *obj,
 /* Lookup a decoration pointer */
 void *lookup_decoration(struct decoration *n, const struct object *obj)
 {
-       int j;
+       unsigned int j;
 
        /* nothing to lookup */
        if (!n->size)
index a310fb2ad08cfb5fac01f5519e8b95b2338b07db..0aba6cda3c01e17b07bb7235b0395ba50256aedd 100644 (file)
@@ -214,7 +214,7 @@ static int get_stat_data(struct cache_entry *ce,
        const unsigned char *sha1 = ce->sha1;
        unsigned int mode = ce->ce_mode;
 
-       if (!cached) {
+       if (!cached && !ce_uptodate(ce)) {
                int changed;
                struct stat st;
                changed = check_removed(ce, &st);
index 42c1dd8ad3b0633767bf577975a895722f882565..4ebc1dbd87d9b90ad2aaa5c7d4601761e2d1d724 100644 (file)
@@ -233,7 +233,7 @@ void diff_no_index(struct rev_info *revs,
        if (prefix) {
                int len = strlen(prefix);
 
-               revs->diffopt.paths = xcalloc(2, sizeof(char*));
+               revs->diffopt.paths = xcalloc(2, sizeof(char *));
                for (i = 0; i < 2; i++) {
                        const char *p = argv[argc - 2 + i];
                        /*
diff --git a/diff.c b/diff.c
index 3ac71686ebef3d3f9c8b0b72adf612e9535031a5..dcfbcb0215766efefa786b18d793c4bf96740b8c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -189,7 +189,7 @@ static void remove_tempfile(void)
        int i;
        for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
                if (diff_temp[i].name == diff_temp[i].tmp_path)
-                       unlink(diff_temp[i].name);
+                       unlink_or_warn(diff_temp[i].name);
                diff_temp[i].name = NULL;
        }
 }
@@ -839,10 +839,9 @@ static int scale_linear(int it, int width, int max_change)
 }
 
 static void show_name(FILE *file,
-                     const char *prefix, const char *name, int len,
-                     const char *reset, const char *set)
+                     const char *prefix, const char *name, int len)
 {
-       fprintf(file, " %s%s%-*s%s |", set, prefix, len, name, reset);
+       fprintf(file, " %s%-*s |", prefix, len, name);
 }
 
 static void show_graph(FILE *file, char ch, int cnt, const char *set, const char *reset)
@@ -876,7 +875,7 @@ static void fill_print_name(struct diffstat_file *file)
        file->print_name = pname;
 }
 
-static void show_stats(struct diffstat_tdata, struct diff_options *options)
+static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
        int i, len, add, del, adds = 0, dels = 0;
        int max_change = 0, max_len = 0;
@@ -956,7 +955,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                }
 
                if (data->files[i]->is_binary) {
-                       show_name(options->file, prefix, name, len, reset, set);
+                       show_name(options->file, prefix, name, len);
                        fprintf(options->file, "  Bin ");
                        fprintf(options->file, "%s%d%s", del_c, deleted, reset);
                        fprintf(options->file, " -> ");
@@ -966,7 +965,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                        continue;
                }
                else if (data->files[i]->is_unmerged) {
-                       show_name(options->file, prefix, name, len, reset, set);
+                       show_name(options->file, prefix, name, len);
                        fprintf(options->file, "  Unmerged\n");
                        continue;
                }
@@ -988,7 +987,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                        add = scale_linear(add, width, max_change);
                        del = scale_linear(del, width, max_change);
                }
-               show_name(options->file, prefix, name, len, reset, set);
+               show_name(options->file, prefix, name, len);
                fprintf(options->file, "%5d%s", added + deleted,
                                added + deleted ? " " : "");
                show_graph(options->file, '+', add, add_c, reset);
@@ -996,8 +995,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                fprintf(options->file, "\n");
        }
        fprintf(options->file,
-              "%s %d files changed, %d insertions(+), %d deletions(-)%s\n",
-              set, total_files, adds, dels, reset);
+              " %d files changed, %d insertions(+), %d deletions(-)\n",
+              total_files, adds, dels);
 }
 
 static void show_shortstats(struct diffstat_t* data, struct diff_options *options)
@@ -1025,7 +1024,7 @@ static void show_shortstats(struct diffstat_t* data, struct diff_options *option
               total_files, adds, dels);
 }
 
-static void show_numstat(struct diffstat_tdata, struct diff_options *options)
+static void show_numstat(struct diffstat_t *data, struct diff_options *options)
 {
        int i;
 
@@ -2015,18 +2014,15 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
                        die("stat(%s): %s", name, strerror(errno));
                }
                if (S_ISLNK(st.st_mode)) {
-                       int ret;
-                       char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
-                       ret = readlink(name, buf, sizeof(buf));
-                       if (ret < 0)
+                       struct strbuf sb = STRBUF_INIT;
+                       if (strbuf_readlink(&sb, name, st.st_size) < 0)
                                die("readlink(%s)", name);
-                       if (ret == sizeof(buf))
-                               die("symlink too long: %s", name);
-                       prep_temp_blob(name, temp, buf, ret,
+                       prep_temp_blob(name, temp, sb.buf, sb.len,
                                       (one->sha1_valid ?
                                        one->sha1 : null_sha1),
                                       (one->sha1_valid ?
                                        one->mode : S_IFLNK));
+                       strbuf_release(&sb);
                }
                else {
                        /* we can borrow from the file in the work tree */
index 0b0d6b8c8c2ab8833bb5d929ef0d3cb7891ec582..63ac998bfaf64da807bec0ae0bd57c391fb651fe 100644 (file)
@@ -267,7 +267,7 @@ static int find_identical_files(struct file_similarity *src,
                        int score;
                        struct diff_filespec *source = p->filespec;
 
-                       /* False hash collission? */
+                       /* False hash collision? */
                        if (hashcmp(source->sha1, target->sha1))
                                continue;
                        /* Non-regular files? If so, the modes must match! */
diff --git a/dir.c b/dir.c
index c91ebfb46f929f926e1925c2db830c5847f3223b..bbfcb566e63310d38848b0b76076fb051a7446c8 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -53,7 +53,7 @@ int common_prefix(const char **pathspec)
 }
 
 /*
- * Does 'match' matches the given name?
+ * Does 'match' match the given name?
  * A match is found if
  *
  * (1) the 'match' string is leading directory of 'name', or
@@ -156,7 +156,7 @@ void add_exclude(const char *string, const char *base,
        if (len && string[len - 1] == '/') {
                char *s;
                x = xmalloc(sizeof(*x) + len);
-               s = (char*)(x+1);
+               s = (char *)(x+1);
                memcpy(s, string, len - 1);
                s[len - 1] = '\0';
                string = s;
@@ -290,7 +290,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
        dir->basebuf[baselen] = '\0';
 }
 
-/* Scan the list and let the last match determines the fate.
+/* Scan the list and let the last match determine the fate.
  * Return 1 for exclude, 0 for include and -1 for undecided.
  */
 static int excluded_1(const char *pathname,
@@ -396,7 +396,7 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathna
 
 static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
 {
-       if (cache_name_pos(pathname, len) >= 0)
+       if (!cache_name_is_other(pathname, len))
                return NULL;
 
        ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
@@ -576,7 +576,7 @@ static int get_dtype(struct dirent *de, const char *path)
  */
 static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
 {
-       DIR *fdir = opendir(path);
+       DIR *fdir = opendir(*path ? path : ".");
        int contents = 0;
 
        if (fdir) {
diff --git a/entry.c b/entry.c
index 5daacc2fe51eada819bedea05f958fbf87f5b889..cc841edf9051460b3a382ea25c0097f245ec8884 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -35,7 +35,7 @@ static void create_directories(const char *path, int path_len,
                 */
                if (mkdir(buf, 0777)) {
                        if (errno == EEXIST && state->force &&
-                           !unlink(buf) && !mkdir(buf, 0777))
+                           !unlink_or_warn(buf) && !mkdir(buf, 0777))
                                continue;
                        die("cannot create directory at %s", buf);
                }
@@ -147,7 +147,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
 
                wrote = write_in_full(fd, new, size);
                /* use fstat() only when path == ce->name */
-               if (state->refresh_cache && !to_tempfile && !state->base_dir_len) {
+               if (fstat_is_reliable() &&
+                   state->refresh_cache && !to_tempfile && !state->base_dir_len) {
                        fstat(fd, &st);
                        fstat_done = 1;
                }
index 4696885b224ac12964fce2eb06617b7ab5633854..801a005ef1b23ef13cfa9ece676c550fe35dedc0 100644 (file)
@@ -43,6 +43,10 @@ unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
 enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
 enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
 enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
+#ifndef OBJECT_CREATION_MODE
+#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
+#endif
+enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
index 23c496d6839646ec61a7172f83c86e244463498f..a2a24588a99957d5af759ca6d8858366430ab3a3 100644 (file)
@@ -76,7 +76,7 @@ Format of STDIN stream:
     delim lf;
 
      # note: declen indicates the length of binary_data in bytes.
-     # declen does not include the lf preceeding the binary data.
+     # declen does not include the lf preceding the binary data.
      #
   exact_data ::= 'data' sp declen lf
     binary_data;
@@ -133,8 +133,8 @@ Format of STDIN stream:
      # always escapes the related input from comment processing.
      #
      # In case it is not clear, the '#' that starts the comment
-     # must be the first character on that the line (an lf have
-     # preceeded it).
+     # must be the first character on that line (an lf
+     # preceded it).
      #
   comment ::= '#' not_lf* lf;
   not_lf  ::= # Any byte that is not ASCII newline (LF);
@@ -212,7 +212,7 @@ struct tree_content;
 struct tree_entry
 {
        struct tree_content *tree;
-       struct atom_strname;
+       struct atom_str *name;
        struct tree_entry_ms
        {
                uint16_t mode;
@@ -313,7 +313,7 @@ static unsigned int object_entry_alloc = 5000;
 static struct object_entry_pool *blocks;
 static struct object_entry *object_table[1 << 16];
 static struct mark_set *marks;
-static const charmark_file;
+static const char *mark_file;
 
 /* Our last blob */
 static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 };
@@ -672,7 +672,7 @@ static struct branch *lookup_branch(const char *name)
 static struct branch *new_branch(const char *name)
 {
        unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz;
-       struct branchb = lookup_branch(name);
+       struct branch *b = lookup_branch(name);
 
        if (b)
                die("Invalid attempt to create duplicate branch: %s", name);
@@ -931,7 +931,7 @@ static void unkeep_all_packs(void)
                struct packed_git *p = all_packs[k];
                snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
                         get_object_directory(), sha1_to_hex(p->sha1));
-               unlink(name);
+               unlink_or_warn(name);
        }
 }
 
@@ -953,7 +953,7 @@ static void end_packfile(void)
                close(pack_data->pack_fd);
                idx_name = keep_pack(create_index());
 
-               /* Register the packfile with core git's machinary. */
+               /* Register the packfile with core git's machinery. */
                new_p = add_packed_git(idx_name, strlen(idx_name), 1);
                if (!new_p)
                        die("core git rejected index %s", idx_name);
@@ -981,7 +981,7 @@ static void end_packfile(void)
        }
        else {
                close(old_p->pack_fd);
-               unlink(old_p->pack_name);
+               unlink_or_warn(old_p->pack_name);
        }
        free(old_p);
 
@@ -1035,7 +1035,7 @@ static int store_object(
        git_SHA_CTX c;
        z_stream s;
 
-       hdrlen = sprintf((char*)hdr,"%s %lu", typename(type),
+       hdrlen = sprintf((char *)hdr,"%s %lu", typename(type),
                (unsigned long)dat->len) + 1;
        git_SHA1_Init(&c);
        git_SHA1_Update(&c, hdr, hdrlen);
@@ -1217,7 +1217,7 @@ static const char *get_mode(const char *str, uint16_t *modep)
 
 static void load_tree(struct tree_entry *root)
 {
-       unsigned charsha1 = root->versions[1].sha1;
+       unsigned char *sha1 = root->versions[1].sha1;
        struct object_entry *myoe;
        struct tree_content *t;
        unsigned long size;
@@ -1258,8 +1258,8 @@ static void load_tree(struct tree_entry *root)
                e->versions[0].mode = e->versions[1].mode;
                e->name = to_atom(c, strlen(c));
                c += e->name->str_len + 1;
-               hashcpy(e->versions[0].sha1, (unsigned char*)c);
-               hashcpy(e->versions[1].sha1, (unsigned char*)c);
+               hashcpy(e->versions[0].sha1, (unsigned char *)c);
+               hashcpy(e->versions[1].sha1, (unsigned char *)c);
                c += 20;
        }
        free(buf);
diff --git a/fsck.h b/fsck.h
index 990ee02335a2e2693e32baa82b259c23843f2aa0..008456b675b6e5c8a5a07e0b8628a41e3acc733a 100644 (file)
--- a/fsck.h
+++ b/fsck.h
@@ -23,7 +23,7 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...);
  * the return value is:
  *    -1       error in processing the object
  *    <0       return value of the callback, which lead to an abort
- *    >0       return value of the first sigaled error >0 (in the case of no other errors)
+ *    >0       return value of the first signaled error >0 (in the case of no other errors)
  *    0                everything OK
  */
 int fsck_walk(struct object *obj, fsck_walk_func walk, void *data);
index def062a9e2cbc67b78522aa47151d47cd50f0f33..a06172c69f59391a04b75a3866a3fbcb98a21ba0 100755 (executable)
@@ -620,11 +620,12 @@ sub parse_diff {
        if ($diff_use_color) {
                @colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);
        }
-       my (@hunk) = { TEXT => [], DISPLAY => [] };
+       my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
 
        for (my $i = 0; $i < @diff; $i++) {
                if ($diff[$i] =~ /^@@ /) {
-                       push @hunk, { TEXT => [], DISPLAY => [] };
+                       push @hunk, { TEXT => [], DISPLAY => [],
+                               TYPE => 'hunk' };
                }
                push @{$hunk[-1]{TEXT}}, $diff[$i];
                push @{$hunk[-1]{DISPLAY}},
@@ -636,8 +637,8 @@ sub parse_diff {
 sub parse_diff_header {
        my $src = shift;
 
-       my $head = { TEXT => [], DISPLAY => [] };
-       my $mode = { TEXT => [], DISPLAY => [] };
+       my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
+       my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
 
        for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
                my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
@@ -684,6 +685,7 @@ sub split_hunk {
                my $this = +{
                        TEXT => [],
                        DISPLAY => [],
+                       TYPE => 'hunk',
                        OLD => $o_ofs,
                        NEW => $n_ofs,
                        OCNT => 0,
@@ -765,6 +767,96 @@ sub split_hunk {
        return @split;
 }
 
+sub find_last_o_ctx {
+       my ($it) = @_;
+       my $text = $it->{TEXT};
+       my ($o_ofs, $o_cnt) = parse_hunk_header($text->[0]);
+       my $i = @{$text};
+       my $last_o_ctx = $o_ofs + $o_cnt;
+       while (0 < --$i) {
+               my $line = $text->[$i];
+               if ($line =~ /^ /) {
+                       $last_o_ctx--;
+                       next;
+               }
+               last;
+       }
+       return $last_o_ctx;
+}
+
+sub merge_hunk {
+       my ($prev, $this) = @_;
+       my ($o0_ofs, $o0_cnt, $n0_ofs, $n0_cnt) =
+           parse_hunk_header($prev->{TEXT}[0]);
+       my ($o1_ofs, $o1_cnt, $n1_ofs, $n1_cnt) =
+           parse_hunk_header($this->{TEXT}[0]);
+
+       my (@line, $i, $ofs, $o_cnt, $n_cnt);
+       $ofs = $o0_ofs;
+       $o_cnt = $n_cnt = 0;
+       for ($i = 1; $i < @{$prev->{TEXT}}; $i++) {
+               my $line = $prev->{TEXT}[$i];
+               if ($line =~ /^\+/) {
+                       $n_cnt++;
+                       push @line, $line;
+                       next;
+               }
+
+               last if ($o1_ofs <= $ofs);
+
+               $o_cnt++;
+               $ofs++;
+               if ($line =~ /^ /) {
+                       $n_cnt++;
+               }
+               push @line, $line;
+       }
+
+       for ($i = 1; $i < @{$this->{TEXT}}; $i++) {
+               my $line = $this->{TEXT}[$i];
+               if ($line =~ /^\+/) {
+                       $n_cnt++;
+                       push @line, $line;
+                       next;
+               }
+               $ofs++;
+               $o_cnt++;
+               if ($line =~ /^ /) {
+                       $n_cnt++;
+               }
+               push @line, $line;
+       }
+       my $head = ("@@ -$o0_ofs" .
+                   (($o_cnt != 1) ? ",$o_cnt" : '') .
+                   " +$n0_ofs" .
+                   (($n_cnt != 1) ? ",$n_cnt" : '') .
+                   " @@\n");
+       @{$prev->{TEXT}} = ($head, @line);
+}
+
+sub coalesce_overlapping_hunks {
+       my (@in) = @_;
+       my @out = ();
+
+       my ($last_o_ctx, $last_was_dirty);
+
+       for (grep { $_->{USE} } @in) {
+               my $text = $_->{TEXT};
+               my ($o_ofs) = parse_hunk_header($text->[0]);
+               if (defined $last_o_ctx &&
+                   $o_ofs <= $last_o_ctx &&
+                   !$_->{DIRTY} &&
+                   !$last_was_dirty) {
+                       merge_hunk($out[-1], $_);
+               }
+               else {
+                       push @out, $_;
+               }
+               $last_o_ctx = find_last_o_ctx($out[-1]);
+               $last_was_dirty = $_->{DIRTY};
+       }
+       return @out;
+}
 
 sub color_diff {
        return map {
@@ -873,7 +965,12 @@ sub edit_hunk_loop {
                if (!defined $text) {
                        return undef;
                }
-               my $newhunk = { TEXT => $text, USE => 1 };
+               my $newhunk = {
+                       TEXT => $text,
+                       TYPE => $hunk->[$ix]->{TYPE},
+                       USE => 1,
+                       DIRTY => 1,
+               };
                if (diff_applies($head,
                                 @{$hunk}[0..$ix-1],
                                 $newhunk,
@@ -894,6 +991,7 @@ sub help_patch_cmd {
        print colored $help_color, <<\EOF ;
 y - stage this hunk
 n - do not stage this hunk
+q - quit, do not stage this hunk nor any of the remaining ones
 a - stage this and all the remaining hunks in the file
 d - do not stage this hunk nor any of the remaining hunks in the file
 g - select a hunk to go to
@@ -930,7 +1028,7 @@ sub patch_update_cmd {
                                        @mods);
        }
        for (@them) {
-               patch_update_file($_->{VALUE});
+               return 0 if patch_update_file($_->{VALUE});
        }
 }
 
@@ -976,6 +1074,7 @@ sub display_hunks {
 }
 
 sub patch_update_file {
+       my $quit = 0;
        my ($ix, $num);
        my $path = shift;
        my ($head, @hunk) = parse_diff($path);
@@ -985,32 +1084,7 @@ sub patch_update_file {
        }
 
        if (@{$mode->{TEXT}}) {
-               while (1) {
-                       print @{$mode->{DISPLAY}};
-                       print colored $prompt_color,
-                               "Stage mode change [y/n/a/d/?]? ";
-                       my $line = prompt_single_character;
-                       if ($line =~ /^y/i) {
-                               $mode->{USE} = 1;
-                               last;
-                       }
-                       elsif ($line =~ /^n/i) {
-                               $mode->{USE} = 0;
-                               last;
-                       }
-                       elsif ($line =~ /^a/i) {
-                               $_->{USE} = 1 foreach ($mode, @hunk);
-                               last;
-                       }
-                       elsif ($line =~ /^d/i) {
-                               $_->{USE} = 0 foreach ($mode, @hunk);
-                               last;
-                       }
-                       else {
-                               help_patch_cmd('');
-                               next;
-                       }
-               }
+               unshift @hunk, $mode;
        }
 
        $num = scalar @hunk;
@@ -1054,14 +1128,19 @@ sub patch_update_file {
                }
                last if (!$undecided);
 
-               if (hunk_splittable($hunk[$ix]{TEXT})) {
+               if ($hunk[$ix]{TYPE} eq 'hunk' &&
+                   hunk_splittable($hunk[$ix]{TEXT})) {
                        $other .= ',s';
                }
-               $other .= ',e';
+               if ($hunk[$ix]{TYPE} eq 'hunk') {
+                       $other .= ',e';
+               }
                for (@{$hunk[$ix]{DISPLAY}}) {
                        print;
                }
-               print colored $prompt_color, "Stage this hunk [y,n,a,d,/$other,?]? ";
+               print colored $prompt_color, 'Stage ',
+                 ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'),
+                 " [y,n,q,a,d,/$other,?]? ";
                my $line = prompt_single_character;
                if ($line) {
                        if ($line =~ /^y/i) {
@@ -1113,6 +1192,16 @@ sub patch_update_file {
                                }
                                next;
                        }
+                       elsif ($line =~ /^q/i) {
+                               while ($ix < $num) {
+                                       if (!defined $hunk[$ix]{USE}) {
+                                               $hunk[$ix]{USE} = 0;
+                                       }
+                                       $ix++;
+                               }
+                               $quit = 1;
+                               next;
+                       }
                        elsif ($line =~ m|^/(.*)|) {
                                my $regex = $1;
                                if ($1 eq "") {
@@ -1193,7 +1282,7 @@ sub patch_update_file {
                                $num = scalar @hunk;
                                next;
                        }
-                       elsif ($line =~ /^e/) {
+                       elsif ($other =~ /e/ && $line =~ /^e/) {
                                my $newhunk = edit_hunk_loop($head, \@hunk, $ix);
                                if (defined $newhunk) {
                                        splice @hunk, $ix, 1, $newhunk;
@@ -1212,11 +1301,10 @@ sub patch_update_file {
                }
        }
 
+       @hunk = coalesce_overlapping_hunks(@hunk);
+
        my $n_lofs = 0;
        my @result = ();
-       if ($mode->{USE}) {
-               push @result, @{$mode->{TEXT}};
-       }
        for (@hunk) {
                if ($_->{USE}) {
                        push @result, @{$_->{TEXT}};
@@ -1229,6 +1317,7 @@ sub patch_update_file {
                open $fh, '| git apply --cached --recount';
                for (@{$head->{TEXT}}, @result) {
                        print $fh $_;
+                       print STDERR $_;
                }
                if (!close $fh) {
                        for (@{$head->{TEXT}}, @result) {
@@ -1239,6 +1328,7 @@ sub patch_update_file {
        }
 
        print "\n";
+       return $quit;
 }
 
 sub diff_cmd {
index d3390755fc687a611e89320a7bbfb4ead512c863..578780be138b216dc89333e1fde87ddcb91e5e54 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -36,12 +36,15 @@ cd_to_toplevel
 git var GIT_COMMITTER_IDENT >/dev/null ||
        die "You need to set your committer info first"
 
+if git rev-parse --verify -q HEAD >/dev/null
+then
+       HAS_HEAD=yes
+else
+       HAS_HEAD=
+fi
+
 sq () {
-       for sqarg
-       do
-               printf "%s" "$sqarg" |
-               sed -e 's/'\''/'\''\\'\'''\''/g' -e 's/.*/ '\''&'\''/'
-       done
+       git rev-parse --sq-quote "$@"
 }
 
 stop_here () {
@@ -290,16 +293,26 @@ else
                : >"$dotest/rebasing"
        else
                : >"$dotest/applying"
-               git update-ref ORIG_HEAD HEAD
+               if test -n "$HAS_HEAD"
+               then
+                       git update-ref ORIG_HEAD HEAD
+               else
+                       git update-ref -d ORIG_HEAD >/dev/null 2>&1
+               fi
        fi
 fi
 
 case "$resolved" in
 '')
-       files=$(git diff-index --cached --name-only HEAD --) || exit
+       case "$HAS_HEAD" in
+       '')
+               files=$(git ls-files) ;;
+       ?*)
+               files=$(git diff-index --cached --name-only HEAD --) ;;
+       esac || exit
        if test "$files"
        then
-               : >"$dotest/dirtyindex"
+               test -n "$HAS_HEAD" && : >"$dotest/dirtyindex"
                die "Dirty index: cannot apply patches (dirty: $files)"
        fi
 esac
@@ -541,18 +554,20 @@ do
        fi
 
        tree=$(git write-tree) &&
-       parent=$(git rev-parse --verify HEAD) &&
        commit=$(
                if test -n "$ignore_date"
                then
                        GIT_AUTHOR_DATE=
                fi
+               parent=$(git rev-parse --verify -q HEAD) ||
+               echo >&2 "applying to an empty history"
+
                if test -n "$committer_date_is_author_date"
                then
                        GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
                        export GIT_COMMITTER_DATE
                fi &&
-               git commit-tree $tree -p $parent <"$dotest/final-commit"
+               git commit-tree $tree ${parent:+-p} $parent <"$dotest/final-commit"
        ) &&
        git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
        stop_here $this
index 24712ff304af89317793fa4c54d39f4c579bb345..8969553658bb5f4f2191f370062af9af33989d88 100755 (executable)
@@ -33,16 +33,6 @@ require_work_tree
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 
-sq() {
-       @@PERL@@ -e '
-               for (@ARGV) {
-                       s/'\''/'\'\\\\\'\''/g;
-                       print " '\''$_'\''";
-               }
-               print "\n";
-       ' "$@"
-}
-
 bisect_autostart() {
        test -s "$GIT_DIR/BISECT_START" || {
                echo >&2 'You need to start by "git bisect start"'
@@ -107,7 +97,7 @@ bisect_start() {
        for arg; do
            case "$arg" in --) has_double_dash=1; break ;; esac
        done
-       orig_args=$(sq "$@")
+       orig_args=$(git rev-parse --sq-quote "$@")
        bad_seen=0
        eval=''
        while [ $# -gt 0 ]; do
@@ -147,7 +137,7 @@ bisect_start() {
        # Write new start state.
        #
        echo "$start_head" >"$GIT_DIR/BISECT_START" &&
-       sq "$@" >"$GIT_DIR/BISECT_NAMES" &&
+       git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
        eval "$eval" &&
        echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
        #
@@ -177,10 +167,6 @@ is_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
@@ -199,7 +185,7 @@ bisect_skip() {
             *..*)
                 revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;;
             *)
-                revs=$(sq "$arg") ;;
+                revs=$(git rev-parse --sq-quote "$arg") ;;
            esac
             all="$all $revs"
         done
@@ -279,162 +265,22 @@ bisect_auto_next() {
        bisect_next_check && bisect_next || :
 }
 
-exit_if_skipped_commits () {
-       _tried=$1
-       _bad=$2
-       if test -n "$_tried" ; then
-               echo "There are only 'skip'ped commit left to test."
-               echo "The first bad commit could be any of:"
-               echo "$_tried" | tr '[|]' '[\012]'
-               test -n "$_bad" && echo "$_bad"
-               echo "We cannot bisect more!"
-               exit 2
-       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
-
-       # 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
-       eval=$(eval "git bisect--helper --next-vars") &&
-       eval "$eval" || exit
-
-       if [ -z "$bisect_rev" ]; then
-               # We should exit here only if the "bad"
-               # commit is also a "skip" commit (see above).
-               exit_if_skipped_commits "$bisect_tried"
-               echo "$bad was both good and bad"
-               exit 1
-       fi
-       if [ "$bisect_rev" = "$bad" ]; then
-               exit_if_skipped_commits "$bisect_tried" "$bad"
-               echo "$bisect_rev is first bad commit"
-               git diff-tree --pretty $bisect_rev
-               exit 0
-       fi
+       # Perform all bisection computation, display and checkout
+       git bisect--helper --next-all
+       res=$?
+
+        # Check if we should exit because bisection is finished
+       test $res -eq 10 && exit 0
 
-       bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)"
+       # Check for an error in the bisection process
+       test $res -ne 0 && exit $res
+
+       return 0
 }
 
 bisect_visualize() {
index f09f244061ab9be5905b69e701faef8f416fd53e..c7cf2d5d9cdbfd4ed20c8b8ea49a36af7c138a4e 100644 (file)
@@ -46,6 +46,7 @@
 #define _ALL_SOURCE 1
 #define _GNU_SOURCE 1
 #define _BSD_SOURCE 1
+#define _NETBSD_SOURCE 1
 
 #include <unistd.h>
 #include <stdio.h>
@@ -408,4 +409,16 @@ void git_qsort(void *base, size_t nmemb, size_t size,
 #endif
 #endif
 
+#ifdef UNRELIABLE_FSTAT
+#define fstat_is_reliable() 0
+#else
+#define fstat_is_reliable() 1
+#endif
+
+/*
+ * Preserves errno, prints a message, but gives no warning for ENOENT.
+ * Always returns the return value of unlink(2).
+ */
+int unlink_or_warn(const char *path);
+
 #endif
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
new file mode 100755 (executable)
index 0000000..57e8e32
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
+# This script is typically launched by using the 'git difftool'
+# convenience command.
+#
+# Copyright (c) 2009 David Aguilar
+
+# Load common functions from git-mergetool--lib
+TOOL_MODE=diff
+. git-mergetool--lib
+
+# difftool.prompt controls the default prompt/no-prompt behavior
+# and is overridden with $GIT_DIFFTOOL*_PROMPT.
+should_prompt () {
+       prompt=$(git config --bool difftool.prompt || echo true)
+       if test "$prompt" = true; then
+               test -z "$GIT_DIFFTOOL_NO_PROMPT"
+       else
+               test -n "$GIT_DIFFTOOL_PROMPT"
+       fi
+}
+
+# Sets up shell variables and runs a merge tool
+launch_merge_tool () {
+       # Merged is the filename as it appears in the work tree
+       # Local is the contents of a/filename
+       # Remote is the contents of b/filename
+       # Custom merge tool commands might use $BASE so we provide it
+       MERGED="$1"
+       LOCAL="$2"
+       REMOTE="$3"
+       BASE="$1"
+
+       # $LOCAL and $REMOTE are temporary files so prompt
+       # the user with the real $MERGED name before launching $merge_tool.
+       if should_prompt; then
+               printf "\nViewing: '$MERGED'\n"
+               printf "Hit return to launch '%s': " "$merge_tool"
+               read ans
+       fi
+
+       # Run the appropriate merge tool command
+       run_merge_tool "$merge_tool"
+}
+
+# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
+test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
+test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
+
+if test -z "$merge_tool"; then
+       merge_tool="$(get_merge_tool)" || exit
+fi
+
+# Launch the merge tool on each path provided by 'git diff'
+while test $# -gt 6
+do
+       launch_merge_tool "$1" "$2" "$5"
+       shift 7
+done
diff --git a/git-difftool.perl b/git-difftool.perl
new file mode 100755 (executable)
index 0000000..ba5e60a
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env perl
+# Copyright (c) 2009 David Aguilar
+#
+# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
+# git-difftool--helper script.
+#
+# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
+# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL
+# are exported for use by git-difftool--helper.
+#
+# Any arguments that are unknown to this script are forwarded to 'git diff'.
+
+use strict;
+use warnings;
+use Cwd qw(abs_path);
+use File::Basename qw(dirname);
+
+my $DIR = abs_path(dirname($0));
+
+
+sub usage
+{
+       print << 'USAGE';
+usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options]
+USAGE
+       exit 1;
+}
+
+sub setup_environment
+{
+       $ENV{PATH} = "$DIR:$ENV{PATH}";
+       $ENV{GIT_PAGER} = '';
+       $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper';
+}
+
+sub exe
+{
+       my $exe = shift;
+       if ($^O eq 'MSWin32' || $^O eq 'msys') {
+               return "$exe.exe";
+       }
+       return $exe;
+}
+
+sub generate_command
+{
+       my @command = (exe('git'), 'diff');
+       my $skip_next = 0;
+       my $idx = -1;
+       for my $arg (@ARGV) {
+               $idx++;
+               if ($skip_next) {
+                       $skip_next = 0;
+                       next;
+               }
+               if ($arg eq '-t' || $arg eq '--tool') {
+                       usage() if $#ARGV <= $idx;
+                       $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
+                       $skip_next = 1;
+                       next;
+               }
+               if ($arg =~ /^--tool=/) {
+                       $ENV{GIT_DIFF_TOOL} = substr($arg, 7);
+                       next;
+               }
+               if ($arg eq '-y' || $arg eq '--no-prompt') {
+                       $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
+                       delete $ENV{GIT_DIFFTOOL_PROMPT};
+                       next;
+               }
+               if ($arg eq '--prompt') {
+                       $ENV{GIT_DIFFTOOL_PROMPT} = 'true';
+                       delete $ENV{GIT_DIFFTOOL_NO_PROMPT};
+                       next;
+               }
+               if ($arg eq '-h' || $arg eq '--help') {
+                       usage();
+               }
+               push @command, $arg;
+       }
+       return @command
+}
+
+setup_environment();
+
+# ActiveState Perl for Win32 does not implement POSIX semantics of
+# exec* system call. It just spawns the given executable and finishes
+# the starting program, exiting with code 0.
+# system will at least catch the errors returned by git diff,
+# allowing the caller of git difftool better handling of failures.
+my $rc = system(generate_command());
+exit($rc | ($rc >> 8));
index b90d3df3a7db97dbc8a16e9e73b705d52bf8fd20..37e044db40bb89470bb64a4108c86d5173e03b5a 100755 (executable)
@@ -430,7 +430,7 @@ if [ "$filter_tag_name" ]; then
                if [ "$type" = "tag" ]; then
                        # Dereference to a commit
                        sha1t="$sha1"
-                       sha1="$(git rev-parse "$sha1"^{commit} 2>/dev/null)" || continue
+                       sha1="$(git rev-parse -q "$sha1"^{commit})" || continue
                fi
 
                [ -f "../map/$sha1" ] || continue
index 3ad8a21b30128ce21b6b6c28094d9af5e5866faf..b3580e9e48b6ac5d1a7fbd010f032445702f140f 100644 (file)
@@ -105,8 +105,11 @@ endif
 
 ifeq ($(uname_S),Darwin)
        TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app
-       ifeq ($(shell expr "$(uname_R)" : '9\.'),2)
-               TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app
+       ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n)
+               TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app
+               ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n)
+                       TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app
+               endif
        endif
        TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app)
 endif
index e018e076f8a1b927ac07f612cf097992643a5db7..14b92ba786554f4e714c89191e5584a825964ab2 100755 (executable)
@@ -122,6 +122,7 @@ unset oguimsg
 set _appname {Git Gui}
 set _gitdir {}
 set _gitexec {}
+set _githtmldir {}
 set _reponame {}
 set _iscygwin {}
 set _search_path {}
@@ -168,6 +169,28 @@ proc gitexec {args} {
        return [eval [list file join $_gitexec] $args]
 }
 
+proc githtmldir {args} {
+       global _githtmldir
+       if {$_githtmldir eq {}} {
+               if {[catch {set _githtmldir [git --html-path]}]} {
+                       # Git not installed or option not yet supported
+                       return {}
+               }
+               if {[is_Cygwin]} {
+                       set _githtmldir [exec cygpath \
+                               --windows \
+                               --absolute \
+                               $_githtmldir]
+               } else {
+                       set _githtmldir [file normalize $_githtmldir]
+               }
+       }
+       if {$args eq {}} {
+               return $_githtmldir
+       }
+       return [eval [list file join $_githtmldir] $args]
+}
+
 proc reponame {} {
        return $::_reponame
 }
@@ -640,10 +663,13 @@ font create font_diffbold
 font create font_diffitalic
 
 foreach class {Button Checkbutton Entry Label
-               Labelframe Listbox Menu Message
+               Labelframe Listbox Message
                Radiobutton Spinbox Text} {
        option add *$class.font font_ui
 }
+if {![is_MacOSX]} {
+       option add *Menu.font font_ui
+}
 unset class
 
 if {[is_Windows] || [is_MacOSX]} {
@@ -699,7 +725,7 @@ proc apply_config {} {
 
 set default_config(branch.autosetupmerge) true
 set default_config(merge.tool) {}
-set default_config(merge.keepbackup) true
+set default_config(mergetool.keepbackup) true
 set default_config(merge.diffstat) true
 set default_config(merge.summary) false
 set default_config(merge.verbosity) 2
@@ -769,9 +795,9 @@ if {![regsub {^git version } $_git_version {} _git_version]} {
 set _real_git_version $_git_version
 regsub -- {[\-\.]dirty$} $_git_version {} _git_version
 regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
-regsub {\.rc[0-9]+$} $_git_version {} _git_version
+regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
 regsub {\.GIT$} $_git_version {} _git_version
-regsub {\.[a-zA-Z]+\.[0-9]+$} $_git_version {} _git_version
+regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
 
 if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
        catch {wm withdraw .}
@@ -1108,6 +1134,7 @@ set current_diff_path {}
 set is_3way_diff 0
 set is_conflict_diff 0
 set selected_commit_type new
+set diff_empty_count 0
 
 set nullid "0000000000000000000000000000000000000000"
 set nullid2 "0000000000000000000000000000000000000001"
@@ -1924,7 +1951,7 @@ proc do_explore {} {
                # freedesktop.org-conforming system is our best shot
                set explorer "xdg-open"
        }
-       eval exec $explorer [file dirname [gitdir]] &
+       eval exec $explorer [list [file nativename [file dirname [gitdir]]]] &
 }
 
 set is_quitting 0
@@ -2277,6 +2304,12 @@ set ui_comm {}
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
+if {[is_MacOSX]} {
+       # -- Apple Menu (Mac OS X only)
+       #
+       .mbar add cascade -label Apple -menu .mbar.apple
+       menu .mbar.apple
+}
 .mbar add cascade -label [mc Repository] -menu .mbar.repository
 .mbar add cascade -label [mc Edit] -menu .mbar.edit
 if {[is_enabled branch]} {
@@ -2292,7 +2325,6 @@ if {[is_enabled transport]} {
 if {[is_enabled multicommit] || [is_enabled singlecommit]} {
        .mbar add cascade -label [mc Tools] -menu .mbar.tools
 }
-. configure -menu .mbar
 
 # -- Repository Menu
 #
@@ -2545,19 +2577,7 @@ if {[is_enabled transport]} {
 }
 
 if {[is_MacOSX]} {
-       # -- Apple Menu (Mac OS X only)
-       #
-       .mbar add cascade -label Apple -menu .mbar.apple
-       menu .mbar.apple
-
-       .mbar.apple add command -label [mc "About %s" [appname]] \
-               -command do_about
-       .mbar.apple add separator
-       .mbar.apple add command \
-               -label [mc "Preferences..."] \
-               -command do_options \
-               -accelerator $M1T-,
-       bind . <$M1B-,> do_options
+       proc ::tk::mac::ShowPreferences {} {do_options}
 } else {
        # -- Edit Menu
        #
@@ -2585,17 +2605,23 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 .mbar add cascade -label [mc Help] -menu .mbar.help
 menu .mbar.help
 
-if {![is_MacOSX]} {
+if {[is_MacOSX]} {
+       .mbar.apple add command -label [mc "About %s" [appname]] \
+               -command do_about
+       .mbar.apple add separator
+} else {
        .mbar.help add command -label [mc "About %s" [appname]] \
                -command do_about
 }
+. configure -menu .mbar
 
+set doc_path [githtmldir]
+if {$doc_path ne {}} {
+       set doc_path [file join $doc_path index.html]
 
-set doc_path [file dirname [gitexec]]
-set doc_path [file join $doc_path Documentation index.html]
-
-if {[is_Cygwin]} {
-       set doc_path [exec cygpath --mixed $doc_path]
+       if {[is_Cygwin]} {
+               set doc_path [exec cygpath --mixed $doc_path]
+       }
 }
 
 if {[file isfile $doc_path]} {
@@ -2944,7 +2970,7 @@ $ctxm add command \
        -command {tk_textPaste $ui_comm}
 $ctxm add command \
        -label [mc Delete] \
-       -command {$ui_comm delete sel.first sel.last}
+       -command {catch {$ui_comm delete sel.first sel.last}}
 $ctxm add separator
 $ctxm add command \
        -label [mc "Select All"] \
index ef1930b4911591566be4561b8c17c24e1cfbfaad..20d5e42307c70a976e56f922f787610cde5bac9f 100644 (file)
@@ -51,7 +51,7 @@ constructor dialog {} {
                $w.check \
                [mc "Delete Only If Merged Into"] \
                ]
-       $w_check none [mc "Always (Do not perform merge test.)"]
+       $w_check none [mc "Always (Do not perform merge checks)"]
        pack $w.check -anchor nw -fill x -pady 5 -padx 5
 
        foreach h [load_all_heads] {
@@ -112,7 +112,7 @@ method _delete {} {
        }
        if {$to_delete eq {}} return
        if {$check_cmt eq {}} {
-               set msg [mc "Recovering deleted branches is difficult. \n\n Delete the selected branches?"]
+               set msg [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]
                if {[tk_messageBox \
                        -icon warning \
                        -type yesno \
index caca88831b7066c573917542d24a52e832dcff34..9e7412c446f715588b9cfe21654a3447e8680e12 100644 (file)
@@ -9,6 +9,7 @@ field w_cons   {}; # embedded console window object
 field new_expr   ; # expression the user saw/thinks this is
 field new_hash   ; # commit SHA-1 we are switching to
 field new_ref    ; # ref we are updating/creating
+field old_hash   ; # commit SHA-1 that was checked out when we started
 
 field parent_w      .; # window that started us
 field merge_type none; # type of merge to apply to existing branch
@@ -280,11 +281,11 @@ method _start_checkout {} {
 
        # -- Our in memory state should match the repository.
        #
-       repository_state curType curHEAD curMERGE_HEAD
+       repository_state curType old_hash curMERGE_HEAD
        if {[string match amend* $commit_type]
                && $curType eq {normal}
-               && $curHEAD eq $HEAD} {
-       } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
+               && $old_hash eq $HEAD} {
+       } elseif {$commit_type ne $curType || $HEAD ne $old_hash} {
                info_popup [mc "Last scanned state does not match repository state.
 
 Another Git program has modified this repository since the last scan.  A rescan must be performed before the current branch can be changed.
@@ -297,7 +298,7 @@ The rescan will be automatically started now.
                return
        }
 
-       if {$curHEAD eq $new_hash} {
+       if {$old_hash eq $new_hash} {
                _after_readtree $this
        } elseif {[is_config_true gui.trustmtime]} {
                _readtree $this
@@ -453,13 +454,47 @@ method _after_readtree {} {
 If you wanted to be on a branch, create one now starting from 'This Detached Checkout'."]
        }
 
+       # -- Run the post-checkout hook.
+       #
+       set fd_ph [githook_read post-checkout $old_hash $new_hash 1]
+       if {$fd_ph ne {}} {
+               global pch_error
+               set pch_error {}
+               fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+               fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph]
+       } else {
+               _update_repo_state $this
+       }
+}
+
+method _postcheckout_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}]} {
+                       hook_failed_popup post-checkout $pch_error 0
+               }
+               unset pch_error
+               _update_repo_state $this
+               return
+       }
+       fconfigure $fd_ph -blocking 0
+}
+
+method _update_repo_state {} {
        # -- Update our repository state.  If we were previously in
        #    amend mode we need to toss the current buffer and do a
        #    full rescan to update our file lists.  If we weren't in
        #    amend mode our file lists are accurate and we can avoid
        #    the rescan.
        #
+       global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
+       global ui_comm
+
        unlock_index
+       set name [_name $this]
        set selected_commit_type new
        if {[string match amend* $commit_type]} {
                $ui_comm delete 0.0 end
index f9ff62a3b22fcc481c88dc35268d06d2fc4a5795..633cc572bbd076ff957c0b8194b6645e899e53ad 100644 (file)
@@ -398,6 +398,8 @@ method _do_new {} {
        grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
        pack $w_body.where -fill x
 
+       grid columnconfigure $w_body.where 1 -weight 1
+
        trace add variable @local_path write [cb _write_local_path]
        bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]]
        update
@@ -964,7 +966,34 @@ method _readtree_wait {fd} {
                return
        }
 
-       set done 1
+       # -- Run the post-checkout hook.
+       #
+       set fd_ph [githook_read post-checkout [string repeat 0 40] \
+               [git rev-parse HEAD] 1]
+       if {$fd_ph ne {}} {
+               global pch_error
+               set pch_error {}
+               fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+               fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph]
+       } else {
+               set done 1
+       }
+}
+
+method _postcheckout_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}]} {
+                       hook_failed_popup post-checkout $pch_error 0
+               }
+               unset pch_error
+               set done 1
+               return
+       }
+       fconfigure $fd_ph -blocking 0
 }
 
 ######################################################################
@@ -998,6 +1027,8 @@ method _do_open {} {
        grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
        pack $w_body.where -fill x
 
+       grid columnconfigure $w_body.where 1 -weight 1
+
        trace add variable @local_path write [cb _write_local_path]
        bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]]
        update
index 9cc84105952d02f0171be0e23f0a82373bae0545..7f459cd5647f690a5e48ed7c29fc0d75eef89d0c 100644 (file)
@@ -115,6 +115,23 @@ proc create_new_commit {} {
        rescan ui_ready
 }
 
+proc setup_commit_encoding {msg_wt {quiet 0}} {
+       global repo_config
+
+       if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
+               set enc utf-8
+       }
+       set use_enc [tcl_encoding $enc]
+       if {$use_enc ne {}} {
+               fconfigure $msg_wt -encoding $use_enc
+       } else {
+               if {!$quiet} {
+                       error_popup [mc "warning: Tcl does not support encoding '%s'." $enc]
+               }
+               fconfigure $msg_wt -encoding utf-8
+       }
+}
+
 proc commit_tree {} {
        global HEAD commit_type file_states ui_comm repo_config
        global pch_error
@@ -200,16 +217,7 @@ A good commit message has the following format:
        set msg_p [gitdir GITGUI_EDITMSG]
        set msg_wt [open $msg_p w]
        fconfigure $msg_wt -translation lf
-       if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
-               set enc utf-8
-       }
-       set use_enc [tcl_encoding $enc]
-       if {$use_enc ne {}} {
-               fconfigure $msg_wt -encoding $use_enc
-       } else {
-               error_popup [mc "warning: Tcl does not support encoding '%s'." $enc]
-               fconfigure $msg_wt -encoding utf-8
-       }
+       setup_commit_encoding $msg_wt
        puts $msg_wt $msg
        close $msg_wt
 
@@ -362,6 +370,7 @@ A rescan will be automatically started now.
                append reflogm " ($commit_type)"
        }
        set msg_fd [open $msg_p r]
+       setup_commit_encoding $msg_fd 1
        gets $msg_fd subject
        close $msg_fd
        append reflogm {: } $subject
@@ -398,8 +407,8 @@ A rescan will be automatically started now.
        #
        set fd_ph [githook_read post-commit]
        if {$fd_ph ne {}} {
-               upvar #0 pch_error$cmt_id pc_err
-               set pc_err {}
+               global pch_error
+               set pch_error {}
                fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
                fileevent $fd_ph readable \
                        [list commit_postcommit_wait $fd_ph $cmt_id]
@@ -461,7 +470,7 @@ A rescan will be automatically started now.
 }
 
 proc commit_postcommit_wait {fd_ph cmt_id} {
-       upvar #0 pch_error$cmt_id pch_error
+       global pch_error
 
        append pch_error [read $fd_ph]
        fconfigure $fd_ph -blocking 1
index bbbf15c875f437f486f652d204bcebf1e5f1a8e4..925b3f56c1c23cc5e0c2b270b9f7e160013c9009 100644 (file)
@@ -51,11 +51,16 @@ proc force_diff_encoding {enc} {
 
 proc handle_empty_diff {} {
        global current_diff_path file_states file_lists
+       global diff_empty_count
 
        set path $current_diff_path
        set s $file_states($path)
        if {[lindex $s 0] ne {_M}} return
 
+       # Prevent infinite rescan loops
+       incr diff_empty_count
+       if {$diff_empty_count > 1} return
+
        info_popup [mc "No differences detected.
 
 %s has no changes.
@@ -310,6 +315,7 @@ proc read_diff {fd cont_info} {
        global ui_diff diff_active
        global is_3way_diff is_conflict_diff current_diff_header
        global current_diff_queue
+       global diff_empty_count
 
        $ui_diff conf -state normal
        while {[gets $fd line] >= 0} {
@@ -415,7 +421,10 @@ proc read_diff {fd cont_info} {
 
                if {[$ui_diff index end] eq {2.0}} {
                        handle_empty_diff
+               } else {
+                       set diff_empty_count 0
                }
+
                set callback [lindex $cont_info 1]
                if {$callback ne {}} {
                        eval $callback
index eb2b4b56a4db4c20727432c7a71d5192d580ce9e..3fe90e697002baaa1c5fa8df4c3d3eae199b062d 100644 (file)
@@ -88,7 +88,7 @@ proc merge_load_stages {path cont} {
        set merge_stages(3) {}
        set merge_stages_buf {}
 
-       set merge_stages_fd [eval git_read ls-files -u -z -- $path]
+       set merge_stages_fd [eval git_read ls-files -u -z -- {$path}]
 
        fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary
        fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont]
@@ -382,7 +382,7 @@ proc merge_tool_finish {fd} {
                delete_temp_files $mtool_tmpfiles
                ui_status [mc "Merge tool failed."]
        } else {
-               if {[is_config_true merge.keepbackup]} {
+               if {[is_config_true mergetool.keepbackup]} {
                        file rename -force -- $backup "$mtool_target.orig"
                }
 
index 89eb0f70f289e48e2b875e2cd49eb026a266ca0e..4e02fc0d393ff9fe8d2983fec99a03db7f36273a 100644 (file)
@@ -213,9 +213,7 @@ method _delete {} {
                -type yesno \
                -title [wm title $w] \
                -parent $w \
-               -message [mc "Recovering deleted branches is difficult.
-
-Delete the selected branches?"]] ne yes} {
+               -message [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]] ne yes} {
                return
        }
 
index 38c3151b05c732d919943e44629bfc0a8c9fb617..2f20eb39c0e25d68e4e6b46fe3b14a46b84ae83e 100644 (file)
@@ -54,7 +54,7 @@ proc do_cygwin_shortcut {} {
                                        $argv0]
                                win32_create_lnk $fn [list \
                                        $sh -c \
-                                       "CHERE_INVOKING=1 source /etc/profile;[sq $me]" \
+                                       "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \
                                        ] \
                                        [file dirname [file normalize [gitdir]]]
                        } err]} {
index 6ae63b6c7c61cb8f773ba5b9367c948820a0873a..95e6e5553ea86482d0fe9be77b07e805e01e3393 100644 (file)
@@ -146,7 +146,7 @@ proc tools_complete {fullname w {ok 1}} {
        }
 
        if {$ok} {
-               set msg [mc "Tool completed succesfully: %s" $fullname]
+               set msg [mc "Tool completed successfully: %s" $fullname]
        } else {
                set msg [mc "Tool failed: %s" $fullname]
        }
index a6f730b4eb38365b5156b715e9bb2fd8772c672c..51abb50bb627d05d702de2d794c47b874c9667ca 100644 (file)
@@ -773,16 +773,6 @@ msgstr "Immer (ohne Zusammenführungstest)"
 msgid "The following branches are not completely merged into %s:"
 msgstr "Folgende Zweige sind noch nicht mit »%s« zusammengeführt:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"Gelöschte Zweige können nur mit größerem Aufwand wiederhergestellt werden.\n"
-"\n"
-"Gewählte Zweige jetzt löschen?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2506,7 +2496,7 @@ msgstr "Starten: %s"
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "Werkzeug erfolgreich abgeschlossen: %s"
 
 #: lib/tools.tcl:151
index 45773ab3d89f84757cf1f7dc0a7d0626ce88f1ec..a944ace6ced4c68b55b7b25023d546521a8ecd68 100644 (file)
@@ -62,7 +62,7 @@ msgstr ""
 "\n"
 "%s nécessite au moins Git 1.5.0.\n"
 "\n"
-"Peut'on considérer que '%s' est en version 1.5.0 ?\n"
+"Peut-on considérer que '%s' est en version 1.5.0 ?\n"
 
 #: git-gui.sh:1062
 msgid "Git directory not found:"
@@ -82,7 +82,7 @@ msgstr "Aucun répertoire de travail"
 
 #: git-gui.sh:1247 lib/checkout_op.tcl:305
 msgid "Refreshing file status..."
-msgstr "Rafraichissement du status des fichiers..."
+msgstr "Rafraîchissement du statut des fichiers..."
 
 #: git-gui.sh:1303
 msgid "Scanning for modified files ..."
@@ -163,7 +163,7 @@ msgstr "Dépôt"
 
 #: git-gui.sh:2281
 msgid "Edit"
-msgstr "Edition"
+msgstr "Édition"
 
 #: git-gui.sh:2283 lib/choose_rev.tcl:561
 msgid "Branch"
@@ -199,7 +199,7 @@ msgstr "Naviguer dans la branche..."
 
 #: git-gui.sh:2316
 msgid "Visualize Current Branch's History"
-msgstr "Visualiser historique branche courante"
+msgstr "Visualiser l'historique de la branche courante"
 
 #: git-gui.sh:2320
 msgid "Visualize All Branch History"
@@ -208,12 +208,12 @@ msgstr "Voir l'historique de toutes les branches"
 #: git-gui.sh:2327
 #, tcl-format
 msgid "Browse %s's Files"
-msgstr "Naviguer l'arborescence de %s"
+msgstr "Parcourir l'arborescence de %s"
 
 #: git-gui.sh:2329
 #, tcl-format
 msgid "Visualize %s's History"
-msgstr "Voir l'historique de la branche: %s"
+msgstr "Voir l'historique de la branche : %s"
 
 #: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67
 msgid "Database Statistics"
@@ -230,7 +230,7 @@ msgstr "Vérifier le dépôt"
 #: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7
 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71
 msgid "Create Desktop Icon"
-msgstr "Créer icône sur bureau"
+msgstr "Créer une icône sur le bureau"
 
 #: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191
 msgid "Quit"
@@ -320,7 +320,7 @@ msgstr "Désindexer"
 
 #: git-gui.sh:2484 lib/index.tcl:410
 msgid "Revert Changes"
-msgstr "Annuler les modifications (revert)"
+msgstr "Annuler les modifications"
 
 #: git-gui.sh:2491 git-gui.sh:3069
 msgid "Show Less Context"
@@ -382,7 +382,7 @@ msgstr "Documentation en ligne"
 
 #: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56
 msgid "Show SSH Key"
-msgstr "Montrer clé SSH"
+msgstr "Montrer la clé SSH"
 
 #: git-gui.sh:2707
 #, tcl-format
@@ -445,7 +445,7 @@ msgstr "Fichier :"
 
 #: git-gui.sh:3078
 msgid "Refresh"
-msgstr "Rafraichir"
+msgstr "Rafraîchir"
 
 #: git-gui.sh:3099
 msgid "Decrease Font Size"
@@ -457,7 +457,7 @@ msgstr "Agrandir la police"
 
 #: git-gui.sh:3111 lib/blame.tcl:281
 msgid "Encoding"
-msgstr "Encodage"
+msgstr "Codage des caractères"
 
 #: git-gui.sh:3122
 msgid "Apply/Reverse Hunk"
@@ -469,7 +469,7 @@ msgstr "Appliquer/Inverser la ligne"
 
 #: git-gui.sh:3137
 msgid "Run Merge Tool"
-msgstr "Lancer outil de merge"
+msgstr "Lancer l'outil de fusion"
 
 #: git-gui.sh:3142
 msgid "Use Remote Version"
@@ -527,7 +527,7 @@ msgid ""
 "Tcl binary distributed by Cygwin."
 msgstr ""
 "\n"
-"Ceci est du à un problème connu avec\n"
+"Ceci est dû à un problème connu avec\n"
 "le binaire Tcl distribué par Cygwin."
 
 #: git-gui.sh:3336
@@ -630,11 +630,11 @@ msgstr "Fichier original :"
 
 #: lib/blame.tcl:1021
 msgid "Cannot find HEAD commit:"
-msgstr "Impossible de trouver le commit HEAD:"
+msgstr "Impossible de trouver le commit HEAD :"
 
 #: lib/blame.tcl:1076
 msgid "Cannot find parent commit:"
-msgstr "Impossible de trouver le commit parent:"
+msgstr "Impossible de trouver le commit parent :"
 
 #: lib/blame.tcl:1091
 msgid "Unable to display parent"
@@ -646,7 +646,7 @@ msgstr "Erreur lors du chargement des différences :"
 
 #: lib/blame.tcl:1232
 msgid "Originally By:"
-msgstr "A l'origine par :"
+msgstr "À l'origine par :"
 
 #: lib/blame.tcl:1238
 msgid "In File:"
@@ -691,11 +691,11 @@ msgstr "Détacher de la branche locale"
 
 #: lib/branch_create.tcl:22
 msgid "Create Branch"
-msgstr "Créer branche"
+msgstr "Créer une branche"
 
 #: lib/branch_create.tcl:27
 msgid "Create New Branch"
-msgstr "Créer nouvelle branche"
+msgstr "Créer une nouvelle branche"
 
 #: lib/branch_create.tcl:31 lib/choose_repository.tcl:377
 msgid "Create"
@@ -719,7 +719,7 @@ msgstr "Révision initiale"
 
 #: lib/branch_create.tcl:72
 msgid "Update Existing Branch:"
-msgstr "Mettre à jour branche existante :"
+msgstr "Mettre à jour une branche existante :"
 
 #: lib/branch_create.tcl:75
 msgid "No"
@@ -727,7 +727,7 @@ msgstr "Non"
 
 #: lib/branch_create.tcl:80
 msgid "Fast Forward Only"
-msgstr "Mise-à-jour rectiligne seulement (fast-forward)"
+msgstr "Mise à jour rectiligne seulement (fast-forward)"
 
 #: lib/branch_create.tcl:85 lib/checkout_op.tcl:536
 msgid "Reset"
@@ -769,7 +769,7 @@ msgstr "Branches locales"
 
 #: lib/branch_delete.tcl:52
 msgid "Delete Only If Merged Into"
-msgstr "Supprimer seulement si fusionnée dans:"
+msgstr "Supprimer seulement si fusionnée dans :"
 
 #: lib/branch_delete.tcl:54
 msgid "Always (Do not perform merge test.)"
@@ -780,23 +780,13 @@ msgstr "Toujours (Ne pas faire de test de fusion.)"
 msgid "The following branches are not completely merged into %s:"
 msgstr "Les branches suivantes ne sont pas complètement fusionnées dans %s :"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"Récupérer des branches supprimées est difficile.\n"
-"\n"
-"Supprimer les branches sélectionnées ?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
 "Failed to delete branches:\n"
 "%s"
 msgstr ""
-"La suppression des branches suivantes a échouée :\n"
+"La suppression des branches suivantes a échoué :\n"
 "%s"
 
 #: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22
@@ -902,11 +892,11 @@ msgstr "La stratégie de fusion '%s' n'est pas supportée."
 #: lib/checkout_op.tcl:261
 #, tcl-format
 msgid "Failed to update '%s'."
-msgstr "La mise à jour de '%s' a échouée."
+msgstr "La mise à jour de '%s' a échoué."
 
 #: lib/checkout_op.tcl:273
 msgid "Staging area (index) is already locked."
-msgstr "L'index (staging area) est déjà vérouillé"
+msgstr "L'index (staging area) est déjà verrouillé."
 
 #: lib/checkout_op.tcl:288
 msgid ""
@@ -918,7 +908,7 @@ msgid ""
 "The rescan will be automatically started now.\n"
 msgstr ""
 "L'état lors de la dernière synchronisation ne correspond plus à l'état du "
-"dépôt\n"
+"dépôt.\n"
 "\n"
 "Un autre programme Git a modifié ce dépôt depuis la dernière "
 "synchronisation. Une resynchronisation doit être effectuée avant de pouvoir "
@@ -956,9 +946,9 @@ msgid ""
 "If you wanted to be on a branch, create one now starting from 'This Detached "
 "Checkout'."
 msgstr ""
-"Vous n'êtes plus ur une branche locale.\n"
+"Vous n'êtes plus sur une branche locale.\n"
 "\n"
-"Si vous vouliez être sur une branche, créez en une maintenant en partant de "
+"Si vous vouliez être sur une branche, créez-en une maintenant en partant de "
 "'Cet emprunt détaché'."
 
 #: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472
@@ -1000,7 +990,7 @@ msgstr ""
 "mis à jour avec succès, mais la mise à jour d'un fichier interne à Git a "
 "échouée.\n"
 "\n"
-"Cela n'aurait pas du se produire. %s va abandonner et se terminer."
+"Cela n'aurait pas dû se produire. %s va abandonner et se terminer."
 
 #: lib/choose_font.tcl:39
 msgid "Select"
@@ -1023,8 +1013,8 @@ msgid ""
 "This is example text.\n"
 "If you like this text, it can be your font."
 msgstr ""
-"C'est un texte d'exemple.\n"
-"Si vous aimez ce texte, vous pouvez choisir cette police"
+"Ceci est un texte d'exemple.\n"
+"Si vous aimez ce texte, vous pouvez choisir cette police."
 
 #: lib/choose_repository.tcl:28
 msgid "Git Gui"
@@ -1040,7 +1030,7 @@ msgstr "Nouveau..."
 
 #: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465
 msgid "Clone Existing Repository"
-msgstr "Cloner dépôt existant"
+msgstr "Cloner un dépôt existant"
 
 #: lib/choose_repository.tcl:106
 msgid "Clone..."
@@ -1048,7 +1038,7 @@ msgstr "Cloner..."
 
 #: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983
 msgid "Open Existing Repository"
-msgstr "Ouvrir dépôt existant"
+msgstr "Ouvrir un dépôt existant"
 
 #: lib/choose_repository.tcl:119
 msgid "Open..."
@@ -1056,17 +1046,17 @@ msgstr "Ouvrir..."
 
 #: lib/choose_repository.tcl:132
 msgid "Recent Repositories"
-msgstr "Dépôt récemment utilisés"
+msgstr "Dépôts récemment utilisés"
 
 #: lib/choose_repository.tcl:138
 msgid "Open Recent Repository:"
-msgstr "Ouvrir dépôt récent :"
+msgstr "Ouvrir un dépôt récent :"
 
 #: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309
 #: lib/choose_repository.tcl:316
 #, tcl-format
 msgid "Failed to create repository %s:"
-msgstr "La création du dépôt %s a échouée :"
+msgstr "La création du dépôt %s a échoué :"
 
 #: lib/choose_repository.tcl:387
 msgid "Directory:"
@@ -1093,11 +1083,11 @@ msgstr "Cloner"
 
 #: lib/choose_repository.tcl:473
 msgid "Source Location:"
-msgstr "Emplacement source:"
+msgstr "Emplacement source :"
 
 #: lib/choose_repository.tcl:484
 msgid "Target Directory:"
-msgstr "Répertoire cible:"
+msgstr "Répertoire cible :"
 
 #: lib/choose_repository.tcl:496
 msgid "Clone Type:"
@@ -1137,7 +1127,7 @@ msgstr "L'emplacement %s existe déjà."
 
 #: lib/choose_repository.tcl:622
 msgid "Failed to configure origin"
-msgstr "La configuration de l'origine a échouée."
+msgstr "La configuration de l'origine a échoué."
 
 #: lib/choose_repository.tcl:634
 msgid "Counting objects"
@@ -1242,7 +1232,7 @@ msgstr "fichiers"
 
 #: lib/choose_repository.tcl:962
 msgid "Initial file checkout failed."
-msgstr "Chargement initial du fichier échoué."
+msgstr "Le chargement initial du fichier a échoué."
 
 #: lib/choose_repository.tcl:978
 msgid "Open"
@@ -1284,7 +1274,7 @@ msgstr "Révision invalide : %s"
 
 #: lib/choose_rev.tcl:338
 msgid "No revision selected."
-msgstr "Pas de révision selectionnée."
+msgstr "Pas de révision sélectionnée."
 
 #: lib/choose_rev.tcl:346
 msgid "Revision expression is empty."
@@ -1292,7 +1282,7 @@ msgstr "L'expression de révision est vide."
 
 #: lib/choose_rev.tcl:531
 msgid "Updated"
-msgstr "Mise-à-jour:"
+msgstr "Mise à jour:"
 
 #: lib/choose_rev.tcl:559
 msgid "URL"
@@ -1320,8 +1310,8 @@ msgid ""
 msgstr ""
 "Impossible de corriger pendant une fusion.\n"
 "\n"
-"Vous êtes actuellement au milieu d'une fusion qui n'a pas été completement "
-"terminée. Vous ne pouvez pas corriger le commit précédant sauf si vous "
+"Vous êtes actuellement au milieu d'une fusion qui n'a pas été complètement "
+"terminée. Vous ne pouvez pas corriger le commit précédent sauf si vous "
 "abandonnez la fusion courante.\n"
 
 #: lib/commit.tcl:49
@@ -1409,7 +1399,7 @@ msgstr ""
 #: lib/commit.tcl:211
 #, tcl-format
 msgid "warning: Tcl does not support encoding '%s'."
-msgstr "attention : Tcl ne supporte pas l'encodage '%s'."
+msgstr "attention : Tcl ne supporte pas lcodage '%s'."
 
 #: lib/commit.tcl:227
 msgid "Calling pre-commit hook..."
@@ -1469,12 +1459,12 @@ msgstr "commit-tree a échoué :"
 
 #: lib/commit.tcl:373
 msgid "update-ref failed:"
-msgstr "update-ref a échoué"
+msgstr "update-ref a échoué :"
 
 #: lib/commit.tcl:461
 #, tcl-format
 msgid "Created commit %s: %s"
-msgstr "Commit créé %s : %s"
+msgstr "Commit %s créé : %s"
 
 #: lib/console.tcl:59
 msgid "Working... please wait..."
@@ -1581,24 +1571,24 @@ msgid ""
 "LOCAL: deleted\n"
 "REMOTE:\n"
 msgstr ""
-"LOCAL: supprimé\n"
-"DISTANT:\n"
+"LOCAL : supprimé\n"
+"DISTANT :\n"
 
 #: lib/diff.tcl:125
 msgid ""
 "REMOTE: deleted\n"
 "LOCAL:\n"
 msgstr ""
-"DISTANT: supprimé\n"
-"LOCAL:\n"
+"DISTANT : supprimé\n"
+"LOCAL :\n"
 
 #: lib/diff.tcl:132
 msgid "LOCAL:\n"
-msgstr "LOCAL:\n"
+msgstr "LOCAL :\n"
 
 #: lib/diff.tcl:135
 msgid "REMOTE:\n"
-msgstr "DISTANT:\n"
+msgstr "DISTANT :\n"
 
 #: lib/diff.tcl:197 lib/diff.tcl:296
 #, tcl-format
@@ -1624,7 +1614,7 @@ msgid ""
 "* Showing only first %d bytes.\n"
 msgstr ""
 "* Le fichier non suivi fait %d octets.\n"
-"* On montre seulement les premiers %d octets.\n"
+"* Seuls les %d premiers octets sont montrés.\n"
 
 #: lib/diff.tcl:228
 #, tcl-format
@@ -1635,7 +1625,7 @@ msgid ""
 msgstr ""
 "\n"
 "* Fichier suivi raccourcis ici de %s.\n"
-"* Pour voir le fichier entier, utiliser un éditeur externe.\n"
+"* Pour voir le fichier entier, utilisez un éditeur externe.\n"
 
 #: lib/diff.tcl:436
 msgid "Failed to unstage selected hunk."
@@ -1680,7 +1670,7 @@ msgstr "Vous devez corriger les erreurs suivantes avant de pouvoir commiter."
 
 #: lib/index.tcl:6
 msgid "Unable to unlock the index."
-msgstr "Impossible de dévérouiller l'index."
+msgstr "Impossible de déverrouiller l'index."
 
 #: lib/index.tcl:15
 msgid "Index Error"
@@ -1700,12 +1690,12 @@ msgstr "Continuer"
 
 #: lib/index.tcl:31
 msgid "Unlock Index"
-msgstr "Déverouiller l'index"
+msgstr "Déverrouiller l'index"
 
 #: lib/index.tcl:287
 #, tcl-format
 msgid "Unstaging %s from commit"
-msgstr "Désindexation de: %s"
+msgstr "Désindexation de : %s"
 
 #: lib/index.tcl:326
 msgid "Ready to commit."
@@ -1804,11 +1794,11 @@ msgid ""
 msgstr ""
 "Vous êtes au milieu d'une modification.\n"
 "\n"
-"Le fichier %s est modifié.\n"
+"Le fichier %s a été modifié.\n"
 "\n"
 "Vous devriez terminer le commit courant avant de lancer une fusion. En "
 "faisait comme cela, vous éviterez de devoir éventuellement abandonner une "
-"fusion ayant échouée.\n"
+"fusion ayant échoué.\n"
 
 #: lib/merge.tcl:107
 #, tcl-format
@@ -1826,7 +1816,7 @@ msgstr "La fusion s'est faite avec succès."
 
 #: lib/merge.tcl:133
 msgid "Merge failed.  Conflict resolution is required."
-msgstr "La fusion a echouée. Il est nécessaire de résoudre les conflicts."
+msgstr "La fusion a echoué. Il est nécessaire de résoudre les conflits."
 
 #: lib/merge.tcl:158
 #, tcl-format
@@ -1914,16 +1904,16 @@ msgid ""
 "\n"
 "This operation can be undone only by restarting the merge."
 msgstr ""
-"Noter que le diff ne montre que les modifications en conflict.\n"
+"Noter que le diff ne montre que les modifications en conflit.\n"
 "\n"
 "%s sera écrasé.\n"
 "\n"
-"Cette opération ne peut être défaite qu'en relançant la fusion."
+"Cette opération ne peut être inversée qu'en relançant la fusion."
 
 #: lib/mergetool.tcl:45
 #, tcl-format
 msgid "File %s seems to have unresolved conflicts, still stage?"
-msgstr "Le fichier %s semble avoir des conflicts non résolus, indéxer quand même ?"
+msgstr "Le fichier %s semble avoir des conflits non résolus, indexer quand même ?"
 
 #: lib/mergetool.tcl:60
 #, tcl-format
@@ -1932,11 +1922,11 @@ msgstr "Ajouter une résolution pour %s"
 
 #: lib/mergetool.tcl:141
 msgid "Cannot resolve deletion or link conflicts using a tool"
-msgstr "Impossible de résoudre la suppression ou de relier des conflicts en utilisant un outil"
+msgstr "Impossible de résoudre la suppression ou de relier des conflits en utilisant un outil"
 
 #: lib/mergetool.tcl:146
 msgid "Conflict file does not exist"
-msgstr "Le fichier en conflict n'existe pas."
+msgstr "Le fichier en conflit n'existe pas."
 
 #: lib/mergetool.tcl:264
 #, tcl-format
@@ -1958,7 +1948,7 @@ msgid ""
 "Error retrieving versions:\n"
 "%s"
 msgstr ""
-"Erreur lors de la récupération des versions:\n"
+"Erreur lors de la récupération des versions :\n"
 "%s"
 
 #: lib/mergetool.tcl:343
@@ -1968,7 +1958,7 @@ msgid ""
 "\n"
 "%s"
 msgstr ""
-"Impossible de lancer l'outil de fusion:\n"
+"Impossible de lancer l'outil de fusion :\n"
 "\n"
 "%s"
 
@@ -1983,12 +1973,12 @@ msgstr "L'outil de fusion a échoué."
 #: lib/option.tcl:11
 #, tcl-format
 msgid "Invalid global encoding '%s'"
-msgstr "Encodage global invalide '%s'"
+msgstr "Codage global '%s' invalide"
 
 #: lib/option.tcl:19
 #, tcl-format
 msgid "Invalid repo encoding '%s'"
-msgstr "Encodage de dépôt invalide '%s'"
+msgstr "Codage de dépôt '%s' invalide"
 
 #: lib/option.tcl:117
 msgid "Restore Defaults"
@@ -2001,7 +1991,7 @@ msgstr "Sauvegarder"
 #: lib/option.tcl:131
 #, tcl-format
 msgid "%s Repository"
-msgstr "Dépôt: %s"
+msgstr "Dépôt : %s"
 
 #: lib/option.tcl:132
 msgid "Global (All Repositories)"
@@ -2069,7 +2059,7 @@ msgstr "Nouveau modèle de nom de branche"
 
 #: lib/option.tcl:155
 msgid "Default File Contents Encoding"
-msgstr "Encodage du contenu des fichiers par défaut"
+msgstr "Codage du contenu des fichiers par défaut"
 
 #: lib/option.tcl:203
 msgid "Change"
@@ -2098,11 +2088,11 @@ msgstr "Préférences"
 
 #: lib/option.tcl:314
 msgid "Failed to completely save options:"
-msgstr "La sauvegarde complète des options a échouée :"
+msgstr "La sauvegarde complète des options a échoué :"
 
 #: lib/remote.tcl:163
 msgid "Remove Remote"
-msgstr "Supprimer dépôt distant"
+msgstr "Supprimer un dépôt distant"
 
 #: lib/remote.tcl:168
 msgid "Prune from"
@@ -2118,11 +2108,11 @@ msgstr "Pousser vers"
 
 #: lib/remote_add.tcl:19
 msgid "Add Remote"
-msgstr "Ajouter dépôt distant"
+msgstr "Ajouter un dépôt distant"
 
 #: lib/remote_add.tcl:24
 msgid "Add New Remote"
-msgstr "Ajouter nouveau dépôt distant"
+msgstr "Ajouter un nouveau dépôt distant"
 
 #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36
 msgid "Add"
@@ -2134,7 +2124,7 @@ msgstr "Détails des dépôts distants"
 
 #: lib/remote_add.tcl:50
 msgid "Location:"
-msgstr "Emplacement:"
+msgstr "Emplacement :"
 
 #: lib/remote_add.tcl:62
 msgid "Further Action"
@@ -2146,7 +2136,7 @@ msgstr "Récupérer immédiatement"
 
 #: lib/remote_add.tcl:71
 msgid "Initialize Remote Repository and Push"
-msgstr "Initialiser dépôt distant et pousser"
+msgstr "Initialiser un dépôt distant et pousser"
 
 #: lib/remote_add.tcl:77
 msgid "Do Nothing Else Now"
@@ -2193,7 +2183,7 @@ msgstr "Mise en place de %s (à %s)"
 
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Branch Remotely"
-msgstr "Supprimer branche à distance"
+msgstr "Supprimer une branche à distance"
 
 #: lib/remote_branch_delete.tcl:47
 msgid "From Repository"
@@ -2244,8 +2234,8 @@ msgid ""
 "One or more of the merge tests failed because you have not fetched the "
 "necessary commits.  Try fetching from %s first."
 msgstr ""
-"Une ou plusieurs des tests de fusion ont échoués parce que vous n'avez pas "
-"récupéré les commits nécessaires. Essayez de récupéré à partir de %s d'abord."
+"Un ou plusieurs des tests de fusion ont échoué parce que vous n'avez pas "
+"récupéré les commits nécessaires. Essayez de récupérer à partir de %s d'abord."
 
 #: lib/remote_branch_delete.tcl:207
 msgid "Please select one or more branches to delete."
@@ -2257,14 +2247,14 @@ msgid ""
 "\n"
 "Delete the selected branches?"
 msgstr ""
-"Récupérer des branches supprimées est difficile.\n"
+"Il est difficile de récupérer des branches supprimées.\n"
 "\n"
-"Souhaitez vous supprimer les branches sélectionnées ?"
+"Supprimer les branches sélectionnées ?"
 
 #: lib/remote_branch_delete.tcl:226
 #, tcl-format
 msgid "Deleting branches from %s"
-msgstr "Supprimer les branches de %s"
+msgstr "Suppression des branches de %s"
 
 #: lib/remote_branch_delete.tcl:286
 msgid "No repository selected."
@@ -2285,7 +2275,7 @@ msgstr "Suivant"
 
 #: lib/search.tcl:24
 msgid "Prev"
-msgstr "Précédant"
+msgstr "Précédent"
 
 #: lib/search.tcl:25
 msgid "Case-Sensitive"
@@ -2293,7 +2283,7 @@ msgstr "Sensible à la casse"
 
 #: lib/shortcut.tcl:20 lib/shortcut.tcl:61
 msgid "Cannot write shortcut:"
-msgstr "Impossible d'écrire le raccourcis :"
+msgstr "Impossible d'écrire le raccourci :"
 
 #: lib/shortcut.tcl:136
 msgid "Cannot write icon:"
@@ -2318,7 +2308,7 @@ msgstr "Réinitialisation du dictionnaire à %s."
 
 #: lib/spellcheck.tcl:73
 msgid "Spell checker silently failed on startup"
-msgstr "La vérification d'orthographe a échouée silentieusement au démarrage"
+msgstr "La vérification d'orthographe a échoué silencieusement au démarrage"
 
 #: lib/spellcheck.tcl:80
 msgid "Unrecognized spell checker"
@@ -2351,11 +2341,11 @@ msgstr "Générer une clé"
 
 #: lib/sshkey.tcl:56
 msgid "Copy To Clipboard"
-msgstr "Copier dans le presse papier"
+msgstr "Copier dans le presse-papier"
 
 #: lib/sshkey.tcl:70
 msgid "Your OpenSSH Public Key"
-msgstr "Votre clé publique Open SSH"
+msgstr "Votre clé publique OpenSSH"
 
 #: lib/sshkey.tcl:78
 msgid "Generating..."
@@ -2368,7 +2358,7 @@ msgid ""
 "\n"
 "%s"
 msgstr ""
-"Impossible de lancer ssh-keygen:\n"
+"Impossible de lancer ssh-keygen :\n"
 "\n"
 "%s"
 
@@ -2398,7 +2388,7 @@ msgstr "Lancer %s nécessite qu'un fichier soit sélectionné."
 #: lib/tools.tcl:90
 #, tcl-format
 msgid "Are you sure you want to run %s?"
-msgstr "Êtes vous sûr de vouloir lancer %s ?"
+msgstr "Êtes-vous sûr de vouloir lancer %s ?"
 
 #: lib/tools.tcl:110
 #, tcl-format
@@ -2412,7 +2402,7 @@ msgstr "Lancement de : %s"
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "L'outil a terminé avec succès : %s"
 
 #: lib/tools.tcl:151
@@ -2422,11 +2412,11 @@ msgstr "L'outil a échoué : %s"
 
 #: lib/tools_dlg.tcl:22
 msgid "Add Tool"
-msgstr "Ajouter outil"
+msgstr "Ajouter un outil"
 
 #: lib/tools_dlg.tcl:28
 msgid "Add New Tool Command"
-msgstr "Ajouter nouvelle commande d'outil"
+msgstr "Ajouter une nouvelle commande d'outil"
 
 #: lib/tools_dlg.tcl:33
 msgid "Add globally"
@@ -2438,7 +2428,7 @@ msgstr "Détails sur l'outil"
 
 #: lib/tools_dlg.tcl:48
 msgid "Use '/' separators to create a submenu tree:"
-msgstr "Utiliser les séparateurs '/' pour créer un arbre de sous menus :"
+msgstr "Utiliser les séparateurs '/' pour créer un arbre de sous-menus :"
 
 #: lib/tools_dlg.tcl:61
 msgid "Command:"
@@ -2462,7 +2452,7 @@ msgstr "Ne pas montrer la fenêtre de sortie des commandes"
 
 #: lib/tools_dlg.tcl:97
 msgid "Run only if a diff is selected ($FILENAME not empty)"
-msgstr "Lancer seulement si un diff est selectionné ($FILENAME non vide)"
+msgstr "Lancer seulement si un diff est sélectionné ($FILENAME non vide)"
 
 #: lib/tools_dlg.tcl:121
 msgid "Please supply a name for the tool."
@@ -2479,7 +2469,7 @@ msgid ""
 "Could not add tool:\n"
 "%s"
 msgstr ""
-"Impossible d'ajouter l'outil:\n"
+"Impossible d'ajouter l'outil :\n"
 "%s"
 
 #: lib/tools_dlg.tcl:190
index 15aea0dc64fd9711bf7246d347ceaafc773d874b..53b7d3634d842a43f8043e3f825d4232e17588aa 100644 (file)
@@ -753,13 +753,6 @@ msgstr ""
 msgid "The following branches are not completely merged into %s:"
 msgstr ""
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2220,7 +2213,7 @@ msgstr ""
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr ""
 
 #: lib/tools.tcl:151
index f761b6415298809897f4f1cccdd0ea325ccbb1dc..0f87bc1cbeedca8d9040777a5484500d1071c2e6 100644 (file)
@@ -776,16 +776,6 @@ msgstr "Mindig (Ne legyen merge teszt.)"
 msgid "The following branches are not completely merged into %s:"
 msgstr "A következő branchek nem teljesen lettek merge-ölve ebbe: %s:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"A törölt branchek visszaállítása bonyolult. \n"
-"\n"
-" Biztosan törli a kiválasztott brancheket?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2399,7 +2389,7 @@ msgstr "Futtatás: %s..."
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "Az eszköz sikeresen befejeződött: %s"
 
 #: lib/tools.tcl:151
index 294e5958874f41c52071313cd107124b38c710a3..762632c22f9e5567bf4603e2958401e6156f1872 100644 (file)
@@ -778,16 +778,6 @@ msgstr "Sempre (Non effettuare verifiche di fusione)."
 msgid "The following branches are not completely merged into %s:"
 msgstr "I rami seguenti non sono stati fusi completamente in %s:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"Ricomporre rami cancellati può essere complicato. \n"
-"\n"
-" Eliminare i rami selezionati?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2418,7 +2408,7 @@ msgstr "Eseguo: %s"
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "Il programma esterno è terminato con successo: %s"
 
 #: lib/tools.tcl:151
index 09d60bef74990e43a9515437d9b4de53e5df0b98..63c4695103a764acbf116df1946fd0bc311c47f0 100644 (file)
@@ -773,16 +773,6 @@ msgstr "無条件(マージテストしない)"
 msgid "The following branches are not completely merged into %s:"
 msgstr "以下のブランチは %s に完全にマージされていません:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"ブランチを削除すると元に戻すのは困難です。 \n"
-"\n"
-" 選択したブランチを削除しますか?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2382,7 +2372,7 @@ msgstr "実行中: %s"
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "ツールが完了しました: %s"
 
 #: lib/tools.tcl:151
index 1c5137d84ca8797238dbcf1cbc6fd80218fbca5f..6de93c28c2e2b7cb0413521c987161c4a4fcb59d 100644 (file)
@@ -761,16 +761,6 @@ msgstr "Alltid (Ikke utfør sammenslåingstest.)"
 msgid "The following branches are not completely merged into %s:"
 msgstr "Følgende grener er ikke fullstendig slått sammen med %s:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"Gjenoppretting av fjernede grener er vanskelig. \n"
-"\n"
-" Fjern valgte grener?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2331,7 +2321,7 @@ msgstr "Kjører: %s"
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "Verktøyet ble fullført med suksess: %s"
 
 #: lib/tools.tcl:151
index db55b3e0a69813cba16932212ee1b2ce0f5b2b9a..0ffc4a418fccb4453c1601ca87668e2d185e14db 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 07:18+0100\n"
+"POT-Creation-Date: 2008-12-08 08:31-0800\n"
 "PO-Revision-Date: 2007-10-22 22:30-0200\n"
 "Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n"
 "Language-Team: Russian Translation <git@vger.kernel.org>\n"
@@ -15,33 +15,33 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: git-gui.sh:41 git-gui.sh:634 git-gui.sh:648 git-gui.sh:661 git-gui.sh:744
-#: git-gui.sh:763
+#: git-gui.sh:41 git-gui.sh:737 git-gui.sh:751 git-gui.sh:764 git-gui.sh:847
+#: git-gui.sh:866
 msgid "git-gui: fatal error"
 msgstr "git-gui: критическая ошибка"
 
-#: git-gui.sh:593
+#: git-gui.sh:689
 #, tcl-format
 msgid "Invalid font specified in %s:"
 msgstr "В %s установлен неверный шрифт:"
 
-#: git-gui.sh:620
+#: git-gui.sh:723
 msgid "Main Font"
 msgstr "Шрифт интерфейса"
 
-#: git-gui.sh:621
+#: git-gui.sh:724
 msgid "Diff/Console Font"
 msgstr "Шрифт консоли и изменений (diff)"
 
-#: git-gui.sh:635
+#: git-gui.sh:738
 msgid "Cannot find git in PATH."
 msgstr "git не найден в PATH."
 
-#: git-gui.sh:662
+#: git-gui.sh:765
 msgid "Cannot parse Git version string:"
 msgstr "Невозможно распознать строку версии Git: "
 
-#: git-gui.sh:680
+#: git-gui.sh:783
 #, tcl-format
 msgid ""
 "Git version cannot be determined.\n"
@@ -53,384 +53,451 @@ msgid ""
 "Assume '%s' is version 1.5.0?\n"
 msgstr ""
 "Невозможно определить версию Git\n"
+"\n"
 "%s указывает на версию '%s'.\n"
 "\n"
 "для %s требуется версия Git, начиная с 1.5.0\n"
 "\n"
 "Принять '%s' как версию 1.5.0?\n"
 
-#: git-gui.sh:918
+#: git-gui.sh:1062
 msgid "Git directory not found:"
 msgstr "Каталог Git не найден:"
 
-#: git-gui.sh:925
+#: git-gui.sh:1069
 msgid "Cannot move to top of working directory:"
 msgstr "Невозможно перейти к корню рабочего каталога репозитория: "
 
-#: git-gui.sh:932
+#: git-gui.sh:1076
 msgid "Cannot use funny .git directory:"
-msgstr "Каталог.git испорчен: "
+msgstr "Каталог .git испорчен: "
 
-#: git-gui.sh:937
+#: git-gui.sh:1081
 msgid "No working directory"
 msgstr "Отсутствует рабочий каталог"
 
-#: git-gui.sh:1084 lib/checkout_op.tcl:283
+#: git-gui.sh:1247 lib/checkout_op.tcl:305
 msgid "Refreshing file status..."
 msgstr "Обновление информации о состоянии файлов..."
 
-#: git-gui.sh:1149
+#: git-gui.sh:1303
 msgid "Scanning for modified files ..."
 msgstr "Поиск измененных файлов..."
 
-#: git-gui.sh:1324 lib/browser.tcl:246
+#: git-gui.sh:1367
+msgid "Calling prepare-commit-msg hook..."
+msgstr "Вызов программы поддержки репозитория prepare-commit-msg..."
+
+#: git-gui.sh:1384
+msgid "Commit declined by prepare-commit-msg hook."
+msgstr "Сохранение прервано программой поддержки репозитория prepare-commit-msg"
+
+#: git-gui.sh:1542 lib/browser.tcl:246
 msgid "Ready."
 msgstr "Готово."
 
-#: git-gui.sh:1590
+#: git-gui.sh:1819
 msgid "Unmodified"
 msgstr "Не изменено"
 
-#: git-gui.sh:1592
+#: git-gui.sh:1821
 msgid "Modified, not staged"
 msgstr "Изменено, не подготовлено"
 
-#: git-gui.sh:1593 git-gui.sh:1598
+#: git-gui.sh:1822 git-gui.sh:1830
 msgid "Staged for commit"
 msgstr "Подготовлено для сохранения"
 
-#: git-gui.sh:1594 git-gui.sh:1599
+#: git-gui.sh:1823 git-gui.sh:1831
 msgid "Portions staged for commit"
 msgstr "Части, подготовленные для сохранения"
 
-#: git-gui.sh:1595 git-gui.sh:1600
+#: git-gui.sh:1824 git-gui.sh:1832
 msgid "Staged for commit, missing"
 msgstr "Подготовлено для сохранения, отсутствует"
 
-#: git-gui.sh:1597
+#: git-gui.sh:1826
+msgid "File type changed, not staged"
+msgstr "Тип файла изменён, не подготовлено"
+
+#: git-gui.sh:1827
+msgid "File type changed, staged"
+msgstr "Тип файла изменён, подготовлено"
+
+#: git-gui.sh:1829
 msgid "Untracked, not staged"
 msgstr "Не отслеживается, не подготовлено"
 
-#: git-gui.sh:1602
+#: git-gui.sh:1834
 msgid "Missing"
 msgstr "Отсутствует"
 
-#: git-gui.sh:1603
+#: git-gui.sh:1835
 msgid "Staged for removal"
 msgstr "Подготовлено для удаления"
 
-#: git-gui.sh:1604
+#: git-gui.sh:1836
 msgid "Staged for removal, still present"
 msgstr "Подготовлено для удаления, еще не удалено"
 
-#: git-gui.sh:1606 git-gui.sh:1607 git-gui.sh:1608 git-gui.sh:1609
+#: git-gui.sh:1838 git-gui.sh:1839 git-gui.sh:1840 git-gui.sh:1841
+#: git-gui.sh:1842 git-gui.sh:1843
 msgid "Requires merge resolution"
-msgstr "Требуется разрешение конфликта при объединении"
+msgstr "Требуется разрешение конфликта при слиянии"
 
-#: git-gui.sh:1644
+#: git-gui.sh:1878
 msgid "Starting gitk... please wait..."
-msgstr "Ð\97апÑ\83Ñ\81каеÑ\82Ñ\81Ñ\8f gitk... Ð¿Ð¾Ð¶Ð°Ð»Ñ\83йÑ\81Ñ\82а, Ð¶Ð´Ð¸Ñ\82е..."
+msgstr "Ð\97апÑ\83Ñ\81каеÑ\82Ñ\81Ñ\8f gitk... Ð\9fодождиÑ\82е, Ð¿Ð¾Ð¶Ð°Ð»Ñ\83йÑ\81Ñ\82а..."
 
-#: git-gui.sh:1653
-#, tcl-format
-msgid ""
-"Unable to start gitk:\n"
-"\n"
-"%s does not exist"
-msgstr ""
-"Не удалось запустить gitk:\n"
-"\n"
-"%s не существует"
+#: git-gui.sh:1887
+msgid "Couldn't find gitk in PATH"
+msgstr "gitk не найден в PATH."
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36
+#: git-gui.sh:2280 lib/choose_repository.tcl:36
 msgid "Repository"
 msgstr "Репозиторий"
 
-#: git-gui.sh:1861
+#: git-gui.sh:2281
 msgid "Edit"
 msgstr "Редактировать"
 
-#: git-gui.sh:1863 lib/choose_rev.tcl:561
+#: git-gui.sh:2283 lib/choose_rev.tcl:561
 msgid "Branch"
 msgstr "Ветвь"
 
-#: git-gui.sh:1866 lib/choose_rev.tcl:548
+#: git-gui.sh:2286 lib/choose_rev.tcl:548
 msgid "Commit@@noun"
 msgstr "Состояние"
 
-#: git-gui.sh:1869 lib/merge.tcl:120 lib/merge.tcl:149 lib/merge.tcl:167
+#: git-gui.sh:2289 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168
 msgid "Merge"
-msgstr "Ð\9eбÑ\8aединиÑ\82Ñ\8c"
+msgstr "СлиÑ\8fние"
 
-#: git-gui.sh:1870 lib/choose_rev.tcl:557
+#: git-gui.sh:2290 lib/choose_rev.tcl:557
 msgid "Remote"
 msgstr "Внешние репозитории"
 
-#: git-gui.sh:1879
+#: git-gui.sh:2293
+msgid "Tools"
+msgstr "Вспомогательные операции"
+
+#: git-gui.sh:2302
+msgid "Explore Working Copy"
+msgstr "Просмотр рабочего каталога"
+
+#: git-gui.sh:2307
 msgid "Browse Current Branch's Files"
 msgstr "Просмотреть файлы текущей ветви"
 
-#: git-gui.sh:1883
+#: git-gui.sh:2311
 msgid "Browse Branch Files..."
 msgstr "Показать файлы ветви..."
 
-#: git-gui.sh:1888
+#: git-gui.sh:2316
 msgid "Visualize Current Branch's History"
-msgstr "Ð\98Ñ\81Ñ\82оÑ\80иÑ\8f Ñ\82екÑ\83Ñ\89ей Ð²ÐµÑ\82ви Ð½Ð°Ð³Ð»Ñ\8fдно"
+msgstr "Ð\9fоказаÑ\82Ñ\8c Ð¸Ñ\81Ñ\82оÑ\80иÑ\8e Ñ\82екÑ\83Ñ\89ей Ð²ÐµÑ\82ви"
 
-#: git-gui.sh:1892
+#: git-gui.sh:2320
 msgid "Visualize All Branch History"
-msgstr "Ð\98Ñ\81Ñ\82оÑ\80иÑ\8f Ð²Ñ\81еÑ\85 Ð²ÐµÑ\82вей Ð½Ð°Ð³Ð»Ñ\8fдно"
+msgstr "Ð\9fоказаÑ\82Ñ\8c Ð¸Ñ\81Ñ\82оÑ\80иÑ\8e Ð²Ñ\81еÑ\85 Ð²ÐµÑ\82вей"
 
-#: git-gui.sh:1899
+#: git-gui.sh:2327
 #, tcl-format
 msgid "Browse %s's Files"
 msgstr "Показать файлы ветви %s"
 
-#: git-gui.sh:1901
+#: git-gui.sh:2329
 #, tcl-format
 msgid "Visualize %s's History"
-msgstr "Ð\98Ñ\81Ñ\82оÑ\80иÑ\8f Ð²ÐµÑ\82ви %s Ð½Ð°Ð³Ð»Ñ\8fдно"
+msgstr "Ð\9fоказаÑ\82Ñ\8c Ð¸Ñ\81Ñ\82оÑ\80иÑ\8e Ð²ÐµÑ\82ви %s"
 
-#: git-gui.sh:1906 lib/database.tcl:27 lib/database.tcl:67
+#: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67
 msgid "Database Statistics"
 msgstr "Статистика базы данных"
 
-#: git-gui.sh:1909 lib/database.tcl:34
+#: git-gui.sh:2337 lib/database.tcl:34
 msgid "Compress Database"
 msgstr "Сжать базу данных"
 
-#: git-gui.sh:1912
+#: git-gui.sh:2340
 msgid "Verify Database"
 msgstr "Проверить базу данных"
 
-#: git-gui.sh:1919 git-gui.sh:1923 git-gui.sh:1927 lib/shortcut.tcl:7
+#: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7
 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71
 msgid "Create Desktop Icon"
 msgstr "Создать ярлык на рабочем столе"
 
-#: git-gui.sh:1932 lib/choose_repository.tcl:177 lib/choose_repository.tcl:185
+#: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191
 msgid "Quit"
 msgstr "Выход"
 
-#: git-gui.sh:1939
+#: git-gui.sh:2371
 msgid "Undo"
 msgstr "Отменить"
 
-#: git-gui.sh:1942
+#: git-gui.sh:2374
 msgid "Redo"
 msgstr "Повторить"
 
-#: git-gui.sh:1946 git-gui.sh:2443
+#: git-gui.sh:2378 git-gui.sh:2937
 msgid "Cut"
 msgstr "Вырезать"
 
-#: git-gui.sh:1949 git-gui.sh:2446 git-gui.sh:2520 git-gui.sh:2614
+#: git-gui.sh:2381 git-gui.sh:2940 git-gui.sh:3014 git-gui.sh:3096
 #: lib/console.tcl:69
 msgid "Copy"
 msgstr "Копировать"
 
-#: git-gui.sh:1952 git-gui.sh:2449
+#: git-gui.sh:2384 git-gui.sh:2943
 msgid "Paste"
 msgstr "Вставить"
 
-#: git-gui.sh:1955 git-gui.sh:2452 lib/branch_delete.tcl:26
+#: git-gui.sh:2387 git-gui.sh:2946 lib/branch_delete.tcl:26
 #: lib/remote_branch_delete.tcl:38
 msgid "Delete"
 msgstr "Удалить"
 
-#: git-gui.sh:1959 git-gui.sh:2456 git-gui.sh:2618 lib/console.tcl:71
+#: git-gui.sh:2391 git-gui.sh:2950 git-gui.sh:3100 lib/console.tcl:71
 msgid "Select All"
 msgstr "Выделить все"
 
-#: git-gui.sh:1968
+#: git-gui.sh:2400
 msgid "Create..."
 msgstr "Создать..."
 
-#: git-gui.sh:1974
+#: git-gui.sh:2406
 msgid "Checkout..."
 msgstr "Перейти..."
 
-#: git-gui.sh:1980
+#: git-gui.sh:2412
 msgid "Rename..."
 msgstr "Переименовать..."
 
-#: git-gui.sh:1985 git-gui.sh:2085
+#: git-gui.sh:2417
 msgid "Delete..."
 msgstr "Удалить..."
 
-#: git-gui.sh:1990
+#: git-gui.sh:2422
 msgid "Reset..."
 msgstr "Сбросить..."
 
-#: git-gui.sh:2002 git-gui.sh:2389
+#: git-gui.sh:2432
+msgid "Done"
+msgstr "Завершено"
+
+#: git-gui.sh:2434
+msgid "Commit@@verb"
+msgstr "Сохранить"
+
+#: git-gui.sh:2443 git-gui.sh:2878
 msgid "New Commit"
 msgstr "Новое состояние"
 
-#: git-gui.sh:2010 git-gui.sh:2396
+#: git-gui.sh:2451 git-gui.sh:2885
 msgid "Amend Last Commit"
 msgstr "Исправить последнее состояние"
 
-#: git-gui.sh:2019 git-gui.sh:2356 lib/remote_branch_delete.tcl:99
+#: git-gui.sh:2461 git-gui.sh:2839 lib/remote_branch_delete.tcl:99
 msgid "Rescan"
 msgstr "Перечитать"
 
-#: git-gui.sh:2025
+#: git-gui.sh:2467
 msgid "Stage To Commit"
 msgstr "Подготовить для сохранения"
 
-#: git-gui.sh:2031
+#: git-gui.sh:2473
 msgid "Stage Changed Files To Commit"
 msgstr "Подготовить измененные файлы для сохранения"
 
-#: git-gui.sh:2037
+#: git-gui.sh:2479
 msgid "Unstage From Commit"
 msgstr "Убрать из подготовленного"
 
-#: git-gui.sh:2042 lib/index.tcl:395
+#: git-gui.sh:2484 lib/index.tcl:410
 msgid "Revert Changes"
 msgstr "Отменить изменения"
 
-#: git-gui.sh:2049 git-gui.sh:2368 git-gui.sh:2467
-msgid "Sign Off"
-msgstr "Ð\9fодпиÑ\81аÑ\82Ñ\8c"
+#: git-gui.sh:2491 git-gui.sh:3083
+msgid "Show Less Context"
+msgstr "Ð\9cенÑ\8cÑ\88е ÐºÐ¾Ð½Ñ\82екÑ\81Ñ\82а"
 
-#: git-gui.sh:2053 git-gui.sh:2372
-msgid "Commit@@verb"
-msgstr "Сохранить"
+#: git-gui.sh:2495 git-gui.sh:3087
+msgid "Show More Context"
+msgstr "Больше контекста"
+
+#: git-gui.sh:2502 git-gui.sh:2852 git-gui.sh:2961
+msgid "Sign Off"
+msgstr "Вставить Signed-off-by"
 
-#: git-gui.sh:2064
+#: git-gui.sh:2518
 msgid "Local Merge..."
-msgstr "Локальное объединение..."
+msgstr "Локальное слияние..."
 
-#: git-gui.sh:2069
+#: git-gui.sh:2523
 msgid "Abort Merge..."
-msgstr "Прервать объединение..."
+msgstr "Прервать слияние..."
+
+#: git-gui.sh:2535 git-gui.sh:2575
+msgid "Add..."
+msgstr "Добавить..."
 
-#: git-gui.sh:2081
+#: git-gui.sh:2539
 msgid "Push..."
 msgstr "Отправить..."
 
-#: git-gui.sh:2092 lib/choose_repository.tcl:41
-msgid "Apple"
-msgstr ""
+#: git-gui.sh:2543
+msgid "Delete Branch..."
+msgstr "Удалить ветвь..."
 
-#: git-gui.sh:2095 git-gui.sh:2117 lib/about.tcl:14
-#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50
+#: git-gui.sh:2553 git-gui.sh:2589 lib/about.tcl:14
+#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53
 #, tcl-format
 msgid "About %s"
 msgstr "О %s"
 
-#: git-gui.sh:2099
+#: git-gui.sh:2557
 msgid "Preferences..."
 msgstr "Настройки..."
 
-#: git-gui.sh:2107 git-gui.sh:2639
+#: git-gui.sh:2565 git-gui.sh:3129
 msgid "Options..."
 msgstr "Настройки..."
 
-#: git-gui.sh:2113 lib/choose_repository.tcl:47
+#: git-gui.sh:2576
+msgid "Remove..."
+msgstr "Удалить..."
+
+#: git-gui.sh:2585 lib/choose_repository.tcl:50
 msgid "Help"
 msgstr "Помощь"
 
-#: git-gui.sh:2154
+#: git-gui.sh:2611
 msgid "Online Documentation"
 msgstr "Документация в интернете"
 
-#: git-gui.sh:2238
+#: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56
+msgid "Show SSH Key"
+msgstr "Показать ключ SSH"
+
+#: git-gui.sh:2721
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr "критическая ошибка: %s: нет такого файла или каталога"
 
-#: git-gui.sh:2271
+#: git-gui.sh:2754
 msgid "Current Branch:"
 msgstr "Текущая ветвь:"
 
-#: git-gui.sh:2292
+#: git-gui.sh:2775
 msgid "Staged Changes (Will Commit)"
 msgstr "Подготовлено (будет сохранено)"
 
-#: git-gui.sh:2312
+#: git-gui.sh:2795
 msgid "Unstaged Changes"
 msgstr "Изменено (не будет сохранено)"
 
-#: git-gui.sh:2362
+#: git-gui.sh:2845
 msgid "Stage Changed"
 msgstr "Подготовить все"
 
-#: git-gui.sh:2378 lib/transport.tcl:93 lib/transport.tcl:182
+#: git-gui.sh:2864 lib/transport.tcl:104 lib/transport.tcl:193
 msgid "Push"
 msgstr "Отправить"
 
-#: git-gui.sh:2408
+#: git-gui.sh:2899
 msgid "Initial Commit Message:"
 msgstr "Комментарий к первому состоянию:"
 
-#: git-gui.sh:2409
+#: git-gui.sh:2900
 msgid "Amended Commit Message:"
 msgstr "Комментарий к исправленному состоянию:"
 
-#: git-gui.sh:2410
+#: git-gui.sh:2901
 msgid "Amended Initial Commit Message:"
 msgstr "Комментарий к исправленному первоначальному состоянию:"
 
-#: git-gui.sh:2411
+#: git-gui.sh:2902
 msgid "Amended Merge Commit Message:"
-msgstr "Комментарий к исправленному объединению:"
+msgstr "Комментарий к исправленному слиянию:"
 
-#: git-gui.sh:2412
+#: git-gui.sh:2903
 msgid "Merge Commit Message:"
-msgstr "Комментарий к объединению:"
+msgstr "Комментарий к слиянию:"
 
-#: git-gui.sh:2413
+#: git-gui.sh:2904
 msgid "Commit Message:"
 msgstr "Комментарий к состоянию:"
 
-#: git-gui.sh:2459 git-gui.sh:2622 lib/console.tcl:73
+#: git-gui.sh:2953 git-gui.sh:3104 lib/console.tcl:73
 msgid "Copy All"
 msgstr "Копировать все"
 
-#: git-gui.sh:2483 lib/blame.tcl:107
+#: git-gui.sh:2977 lib/blame.tcl:104
 msgid "File:"
 msgstr "Файл:"
 
-#: git-gui.sh:2589
-msgid "Apply/Reverse Hunk"
-msgstr "Применить/Убрать изменение"
-
-#: git-gui.sh:2595
-msgid "Show Less Context"
-msgstr "Меньше контекста"
-
-#: git-gui.sh:2602
-msgid "Show More Context"
-msgstr "Больше контекста"
-
-#: git-gui.sh:2610
+#: git-gui.sh:3092
 msgid "Refresh"
 msgstr "Обновить"
 
-#: git-gui.sh:2631
+#: git-gui.sh:3113
 msgid "Decrease Font Size"
 msgstr "Уменьшить размер шрифта"
 
-#: git-gui.sh:2635
+#: git-gui.sh:3117
 msgid "Increase Font Size"
 msgstr "Увеличить размер шрифта"
 
-#: git-gui.sh:2646
+#: git-gui.sh:3125 lib/blame.tcl:281
+msgid "Encoding"
+msgstr "Кодировка"
+
+#: git-gui.sh:3136
+msgid "Apply/Reverse Hunk"
+msgstr "Применить/Убрать изменение"
+
+#: git-gui.sh:3141
+msgid "Apply/Reverse Line"
+msgstr "Применить/Убрать строку"
+
+#: git-gui.sh:3151
+msgid "Run Merge Tool"
+msgstr "Запустить программу слияния"
+
+#: git-gui.sh:3156
+msgid "Use Remote Version"
+msgstr "Взять внешнюю версию"
+
+#: git-gui.sh:3160
+msgid "Use Local Version"
+msgstr "Взять локальную версию"
+
+#: git-gui.sh:3164
+msgid "Revert To Base"
+msgstr "Отменить изменения"
+
+#: git-gui.sh:3183
 msgid "Unstage Hunk From Commit"
 msgstr "Не сохранять часть"
 
-#: git-gui.sh:2648
+#: git-gui.sh:3184
+msgid "Unstage Line From Commit"
+msgstr "Убрать строку из подготовленного"
+
+#: git-gui.sh:3186
 msgid "Stage Hunk For Commit"
 msgstr "Подготовить часть для сохранения"
 
-#: git-gui.sh:2667
+#: git-gui.sh:3187
+msgid "Stage Line For Commit"
+msgstr "Подготовить строку для сохранения"
+
+#: git-gui.sh:3210
 msgid "Initializing..."
 msgstr "Инициализация..."
 
-#: git-gui.sh:2762
+#: git-gui.sh:3315
 #, tcl-format
 msgid ""
 "Possible environment issues exist.\n"
@@ -447,7 +514,7 @@ msgstr ""
 "запущенными из %s\n"
 "\n"
 
-#: git-gui.sh:2792
+#: git-gui.sh:3345
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
@@ -457,7 +524,7 @@ msgstr ""
 "Это известная проблема с Tcl,\n"
 "распространяемым Cygwin."
 
-#: git-gui.sh:2797
+#: git-gui.sh:3350
 #, tcl-format
 msgid ""
 "\n"
@@ -478,64 +545,108 @@ msgstr ""
 msgid "git-gui - a graphical user interface for Git."
 msgstr "git-gui - графический пользовательский интерфейс к Git."
 
-#: lib/blame.tcl:77
+#: lib/blame.tcl:72
 msgid "File Viewer"
 msgstr "Просмотр файла"
 
-#: lib/blame.tcl:81
+#: lib/blame.tcl:78
 msgid "Commit:"
 msgstr "Сохраненное состояние:"
 
-#: lib/blame.tcl:264
+#: lib/blame.tcl:271
 msgid "Copy Commit"
 msgstr "Скопировать SHA-1"
 
-#: lib/blame.tcl:384
+#: lib/blame.tcl:275
+msgid "Find Text..."
+msgstr "Найти текст..."
+
+#: lib/blame.tcl:284
+msgid "Do Full Copy Detection"
+msgstr "Провести полный поиск копий"
+
+#: lib/blame.tcl:288
+msgid "Show History Context"
+msgstr "Показать исторический контекст"
+
+#: lib/blame.tcl:291
+msgid "Blame Parent Commit"
+msgstr "Рассмотреть состояние предка"
+
+#: lib/blame.tcl:450
 #, tcl-format
 msgid "Reading %s..."
 msgstr "Чтение %s..."
 
-#: lib/blame.tcl:488
+#: lib/blame.tcl:557
 msgid "Loading copy/move tracking annotations..."
 msgstr "Загрузка аннотации копирований/переименований..."
 
-#: lib/blame.tcl:508
+#: lib/blame.tcl:577
 msgid "lines annotated"
 msgstr "строк прокомментировано"
 
-#: lib/blame.tcl:689
+#: lib/blame.tcl:769
 msgid "Loading original location annotations..."
 msgstr "Загрузка аннотаций первоначального положения объекта..."
 
-#: lib/blame.tcl:692
+#: lib/blame.tcl:772
 msgid "Annotation complete."
 msgstr "Аннотация завершена."
 
-#: lib/blame.tcl:746
+#: lib/blame.tcl:802
+msgid "Busy"
+msgstr "Занят"
+
+#: lib/blame.tcl:803
+msgid "Annotation process is already running."
+msgstr "Аннотация уже запущена"
+
+#: lib/blame.tcl:842
+msgid "Running thorough copy detection..."
+msgstr "Выполнение полного поиска копий..."
+
+#: lib/blame.tcl:910
 msgid "Loading annotation..."
 msgstr "Загрузка аннотации..."
 
-#: lib/blame.tcl:802
+#: lib/blame.tcl:963
 msgid "Author:"
 msgstr "Автор:"
 
-#: lib/blame.tcl:806
+#: lib/blame.tcl:967
 msgid "Committer:"
 msgstr "Сохранил:"
 
-#: lib/blame.tcl:811
+#: lib/blame.tcl:972
 msgid "Original File:"
 msgstr "Исходный файл:"
 
-#: lib/blame.tcl:925
+#: lib/blame.tcl:1020
+msgid "Cannot find HEAD commit:"
+msgstr "Невозможно найти текущее состояние:"
+
+#: lib/blame.tcl:1075
+msgid "Cannot find parent commit:"
+msgstr "Невозможно найти состояние предка:"
+
+#: lib/blame.tcl:1090
+msgid "Unable to display parent"
+msgstr "Не могу показать предка"
+
+#: lib/blame.tcl:1091 lib/diff.tcl:297
+msgid "Error loading diff:"
+msgstr "Ошибка загрузки изменений:"
+
+#: lib/blame.tcl:1231
 msgid "Originally By:"
 msgstr "Источник:"
 
-#: lib/blame.tcl:931
+#: lib/blame.tcl:1237
 msgid "In File:"
 msgstr "Файл:"
 
-#: lib/blame.tcl:936
+#: lib/blame.tcl:1242
 msgid "Copied Or Moved Here By:"
 msgstr "Скопировано/перемещено в:"
 
@@ -549,16 +660,18 @@ msgstr "Перейти"
 
 #: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35
 #: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282
-#: lib/checkout_op.tcl:522 lib/choose_font.tcl:43 lib/merge.tcl:171
-#: lib/option.tcl:103 lib/remote_branch_delete.tcl:42 lib/transport.tcl:97
+#: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:172
+#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42
+#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352
+#: lib/transport.tcl:108
 msgid "Cancel"
-msgstr "Ð\9eÑ\82мениÑ\82Ñ\8c"
+msgstr "Ð\9eÑ\82мена"
 
-#: lib/branch_checkout.tcl:32 lib/browser.tcl:287
+#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328
 msgid "Revision"
 msgstr "Версия"
 
-#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:242
+#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280
 msgid "Options"
 msgstr "Настройки"
 
@@ -578,7 +691,7 @@ msgstr "Создание ветви"
 msgid "Create New Branch"
 msgstr "Создать новую ветвь"
 
-#: lib/branch_create.tcl:31 lib/choose_repository.tcl:371
+#: lib/branch_create.tcl:31 lib/choose_repository.tcl:377
 msgid "Create"
 msgstr "Создать"
 
@@ -586,7 +699,7 @@ msgstr "Создать"
 msgid "Branch Name"
 msgstr "Название ветви"
 
-#: lib/branch_create.tcl:43
+#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50
 msgid "Name:"
 msgstr "Название:"
 
@@ -610,7 +723,7 @@ msgstr "Нет"
 msgid "Fast Forward Only"
 msgstr "Только Fast Forward"
 
-#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514
+#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536
 msgid "Reset"
 msgstr "Сброс"
 
@@ -650,26 +763,16 @@ msgstr "Локальные ветви"
 
 #: lib/branch_delete.tcl:52
 msgid "Delete Only If Merged Into"
-msgstr "Удалить только в случае, если было объединение с"
+msgstr "Удалить только в случае, если было слияние с"
 
 #: lib/branch_delete.tcl:54
 msgid "Always (Do not perform merge test.)"
-msgstr "Всегда (не выполнять проверку на объединение)"
+msgstr "Всегда (не выполнять проверку на слияние)"
 
 #: lib/branch_delete.tcl:103
 #, tcl-format
 msgid "The following branches are not completely merged into %s:"
-msgstr "Следующие ветви объединены с %s не полностью:"
-
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"Восстанавливать удаленные ветви сложно. \n"
-"\n"
-" Удалить выбранные ветви?"
+msgstr "Ветви, которые не полностью сливаются с %s:"
 
 #: lib/branch_delete.tcl:141
 #, tcl-format
@@ -700,7 +803,7 @@ msgstr "Новое название:"
 msgid "Please select a branch to rename."
 msgstr "Укажите ветвь для переименования."
 
-#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:179
+#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201
 #, tcl-format
 msgid "Branch '%s' already exists."
 msgstr "Ветвь '%s' уже существует."
@@ -731,32 +834,38 @@ msgstr "[На уровень выше]"
 msgid "Browse Branch Files"
 msgstr "Показать файлы ветви"
 
-#: lib/browser.tcl:278 lib/choose_repository.tcl:387
-#: lib/choose_repository.tcl:474 lib/choose_repository.tcl:484
-#: lib/choose_repository.tcl:987
+#: lib/browser.tcl:278 lib/choose_repository.tcl:394
+#: lib/choose_repository.tcl:480 lib/choose_repository.tcl:491
+#: lib/choose_repository.tcl:995
 msgid "Browse"
 msgstr "Показать"
 
-#: lib/checkout_op.tcl:79
+#: lib/checkout_op.tcl:84
 #, tcl-format
 msgid "Fetching %s from %s"
 msgstr "Получение %s из %s "
 
-#: lib/checkout_op.tcl:127
+#: lib/checkout_op.tcl:132
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
 msgstr "критическая ошибка: невозможно разрешить %s"
 
-#: lib/checkout_op.tcl:140 lib/console.tcl:81 lib/database.tcl:31
+#: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31
+#: lib/sshkey.tcl:53
 msgid "Close"
 msgstr "Закрыть"
 
-#: lib/checkout_op.tcl:169
+#: lib/checkout_op.tcl:174
 #, tcl-format
 msgid "Branch '%s' does not exist."
 msgstr "Ветвь '%s' не существует "
 
-#: lib/checkout_op.tcl:206
+#: lib/checkout_op.tcl:193
+#, tcl-format
+msgid "Failed to configure simplified git-pull for '%s'."
+msgstr "Ошибка создания упрощённой конфигурации git pull для '%s'."
+
+#: lib/checkout_op.tcl:228
 #, tcl-format
 msgid ""
 "Branch '%s' already exists.\n"
@@ -767,23 +876,23 @@ msgstr ""
 "Ветвь '%s' уже существует.\n"
 "\n"
 "Она не может быть прокручена(fast-forward) к %s.\n"
-"Требуется объединение."
+"Требуется слияние."
 
-#: lib/checkout_op.tcl:220
+#: lib/checkout_op.tcl:242
 #, tcl-format
 msgid "Merge strategy '%s' not supported."
-msgstr "СÑ\82Ñ\80аÑ\82егиÑ\8f Ð¾Ð±Ñ\8aединениÑ\8f '%s' Ð½Ðµ Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f."
+msgstr "Ð\9dеизвеÑ\81Ñ\82наÑ\8f Ñ\81Ñ\82Ñ\80аÑ\82егиÑ\8f Ñ\81лиÑ\8fниÑ\8f: '%s'."
 
-#: lib/checkout_op.tcl:239
+#: lib/checkout_op.tcl:261
 #, tcl-format
 msgid "Failed to update '%s'."
 msgstr "Не удалось обновить '%s'."
 
-#: lib/checkout_op.tcl:251
+#: lib/checkout_op.tcl:273
 msgid "Staging area (index) is already locked."
 msgstr "Рабочая область заблокирована другим процессом."
 
-#: lib/checkout_op.tcl:266
+#: lib/checkout_op.tcl:288
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
@@ -799,30 +908,30 @@ msgstr ""
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
-#: lib/checkout_op.tcl:322
+#: lib/checkout_op.tcl:344
 #, tcl-format
 msgid "Updating working directory to '%s'..."
 msgstr "Обновление рабочего каталога из '%s'..."
 
-#: lib/checkout_op.tcl:323
+#: lib/checkout_op.tcl:345
 msgid "files checked out"
 msgstr "файлы извлечены"
 
-#: lib/checkout_op.tcl:353
+#: lib/checkout_op.tcl:375
 #, tcl-format
 msgid "Aborted checkout of '%s' (file level merging is required)."
-msgstr "Прерван переход на '%s' (требуется объединение на уровне файлов)"
+msgstr "Прерван переход на '%s' (требуется слияние содержания файлов)"
 
-#: lib/checkout_op.tcl:354
+#: lib/checkout_op.tcl:376
 msgid "File level merge required."
-msgstr "Требуется объединение на уровне файлов."
+msgstr "Требуется слияние содержания файлов."
 
-#: lib/checkout_op.tcl:358
+#: lib/checkout_op.tcl:380
 #, tcl-format
 msgid "Staying on branch '%s'."
 msgstr "Ветвь '%s' остается текущей."
 
-#: lib/checkout_op.tcl:429
+#: lib/checkout_op.tcl:451
 msgid ""
 "You are no longer on a local branch.\n"
 "\n"
@@ -834,30 +943,30 @@ msgstr ""
 "Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, "
 "начиная с 'Текущего отсоединенного состояния'."
 
-#: lib/checkout_op.tcl:446 lib/checkout_op.tcl:450
+#: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472
 #, tcl-format
 msgid "Checked out '%s'."
 msgstr "Ветвь '%s' сделана текущей."
 
-#: lib/checkout_op.tcl:478
+#: lib/checkout_op.tcl:500
 #, tcl-format
 msgid "Resetting '%s' to '%s' will lose the following commits:"
 msgstr "Сброс '%s' в '%s' приведет к потере следующих сохраненных состояний: "
 
-#: lib/checkout_op.tcl:500
+#: lib/checkout_op.tcl:522
 msgid "Recovering lost commits may not be easy."
 msgstr "Восстановить потерянные сохраненные состояния будет сложно."
 
-#: lib/checkout_op.tcl:505
+#: lib/checkout_op.tcl:527
 #, tcl-format
 msgid "Reset '%s'?"
 msgstr "Сбросить '%s'?"
 
-#: lib/checkout_op.tcl:510 lib/merge.tcl:163
+#: lib/checkout_op.tcl:532 lib/merge.tcl:164 lib/tools_dlg.tcl:343
 msgid "Visualize"
 msgstr "Наглядно"
 
-#: lib/checkout_op.tcl:578
+#: lib/checkout_op.tcl:600
 #, tcl-format
 msgid ""
 "Failed to set current branch.\n"
@@ -900,224 +1009,228 @@ msgstr ""
 
 #: lib/choose_repository.tcl:28
 msgid "Git Gui"
-msgstr ""
+msgstr "Git Gui"
 
-#: lib/choose_repository.tcl:81 lib/choose_repository.tcl:376
+#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:382
 msgid "Create New Repository"
 msgstr "Создать новый репозиторий"
 
-#: lib/choose_repository.tcl:87
+#: lib/choose_repository.tcl:93
 msgid "New..."
 msgstr "Новый..."
 
-#: lib/choose_repository.tcl:94 lib/choose_repository.tcl:460
+#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465
 msgid "Clone Existing Repository"
 msgstr "Склонировать существующий репозиторий"
 
-#: lib/choose_repository.tcl:100
+#: lib/choose_repository.tcl:106
 msgid "Clone..."
 msgstr "Склонировать..."
 
-#: lib/choose_repository.tcl:107 lib/choose_repository.tcl:976
+#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983
 msgid "Open Existing Repository"
 msgstr "Выбрать существующий репозиторий"
 
-#: lib/choose_repository.tcl:113
+#: lib/choose_repository.tcl:119
 msgid "Open..."
 msgstr "Открыть..."
 
-#: lib/choose_repository.tcl:126
+#: lib/choose_repository.tcl:132
 msgid "Recent Repositories"
 msgstr "Недавние репозитории"
 
-#: lib/choose_repository.tcl:132
+#: lib/choose_repository.tcl:138
 msgid "Open Recent Repository:"
 msgstr "Открыть последний репозиторий"
 
-#: lib/choose_repository.tcl:296 lib/choose_repository.tcl:303
-#: lib/choose_repository.tcl:310
+#: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309
+#: lib/choose_repository.tcl:316
 #, tcl-format
 msgid "Failed to create repository %s:"
 msgstr "Не удалось создать репозиторий %s:"
 
-#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:387
 msgid "Directory:"
 msgstr "Каталог:"
 
-#: lib/choose_repository.tcl:412 lib/choose_repository.tcl:537
-#: lib/choose_repository.tcl:1011
+#: lib/choose_repository.tcl:417 lib/choose_repository.tcl:544
+#: lib/choose_repository.tcl:1017
 msgid "Git Repository"
 msgstr "Репозиторий"
 
-#: lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:442
 #, tcl-format
 msgid "Directory %s already exists."
 msgstr "Каталог '%s' уже существует."
 
-#: lib/choose_repository.tcl:441
+#: lib/choose_repository.tcl:446
 #, tcl-format
 msgid "File %s already exists."
 msgstr "Файл '%s' уже существует."
 
-#: lib/choose_repository.tcl:455
+#: lib/choose_repository.tcl:460
 msgid "Clone"
 msgstr "Склонировать"
 
-#: lib/choose_repository.tcl:468
-msgid "URL:"
-msgstr "Ссылка:"
+#: lib/choose_repository.tcl:473
+msgid "Source Location:"
+msgstr "Исходное положение:"
+
+#: lib/choose_repository.tcl:484
+msgid "Target Directory:"
+msgstr "Каталог назначения:"
 
-#: lib/choose_repository.tcl:489
+#: lib/choose_repository.tcl:496
 msgid "Clone Type:"
 msgstr "Тип клона:"
 
-#: lib/choose_repository.tcl:495
+#: lib/choose_repository.tcl:502
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)"
 
-#: lib/choose_repository.tcl:501
+#: lib/choose_repository.tcl:508
 msgid "Full Copy (Slower, Redundant Backup)"
 msgstr "Полная копия (Медленный, создает резервную копию)"
 
-#: lib/choose_repository.tcl:507
+#: lib/choose_repository.tcl:514
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)"
 
-#: lib/choose_repository.tcl:543 lib/choose_repository.tcl:590
-#: lib/choose_repository.tcl:736 lib/choose_repository.tcl:806
-#: lib/choose_repository.tcl:1017 lib/choose_repository.tcl:1025
+#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597
+#: lib/choose_repository.tcl:743 lib/choose_repository.tcl:813
+#: lib/choose_repository.tcl:1023 lib/choose_repository.tcl:1031
 #, tcl-format
 msgid "Not a Git repository: %s"
 msgstr "Каталог не является репозиторием: %s"
 
-#: lib/choose_repository.tcl:579
+#: lib/choose_repository.tcl:586
 msgid "Standard only available for local repository."
 msgstr "Стандартный клон возможен только для локального репозитория."
 
-#: lib/choose_repository.tcl:583
+#: lib/choose_repository.tcl:590
 msgid "Shared only available for local repository."
 msgstr "Общий клон возможен только для локального репозитория."
 
-#: lib/choose_repository.tcl:604
+#: lib/choose_repository.tcl:611
 #, tcl-format
 msgid "Location %s already exists."
 msgstr "Путь '%s' уже существует."
 
-#: lib/choose_repository.tcl:615
+#: lib/choose_repository.tcl:622
 msgid "Failed to configure origin"
 msgstr "Не могу сконфигурировать исходный репозиторий."
 
-#: lib/choose_repository.tcl:627
+#: lib/choose_repository.tcl:634
 msgid "Counting objects"
 msgstr "Считаю объекты"
 
-#: lib/choose_repository.tcl:628
+#: lib/choose_repository.tcl:635
 msgid "buckets"
 msgstr ""
 
-#: lib/choose_repository.tcl:652
+#: lib/choose_repository.tcl:659
 #, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
 msgstr "Не могу скопировать objects/info/alternates: %s"
 
-#: lib/choose_repository.tcl:688
+#: lib/choose_repository.tcl:695
 #, tcl-format
 msgid "Nothing to clone from %s."
 msgstr "Нечего клонировать с %s."
 
-#: lib/choose_repository.tcl:690 lib/choose_repository.tcl:904
-#: lib/choose_repository.tcl:916
+#: lib/choose_repository.tcl:697 lib/choose_repository.tcl:911
+#: lib/choose_repository.tcl:923
 msgid "The 'master' branch has not been initialized."
 msgstr "Не инициализирована ветвь 'master'."
 
-#: lib/choose_repository.tcl:703
+#: lib/choose_repository.tcl:710
 msgid "Hardlinks are unavailable.  Falling back to copying."
-msgstr "\"Жесткие ссылки\" не доступны. Буду использовать копирование."
+msgstr "\"Жесткие ссылки\" недоступны. Будет использовано копирование."
 
-#: lib/choose_repository.tcl:715
+#: lib/choose_repository.tcl:722
 #, tcl-format
 msgid "Cloning from %s"
 msgstr "Клонирование %s"
 
-#: lib/choose_repository.tcl:746
+#: lib/choose_repository.tcl:753
 msgid "Copying objects"
 msgstr "Копирование objects"
 
-#: lib/choose_repository.tcl:747
+#: lib/choose_repository.tcl:754
 msgid "KiB"
 msgstr "КБ"
 
-#: lib/choose_repository.tcl:771
+#: lib/choose_repository.tcl:778
 #, tcl-format
 msgid "Unable to copy object: %s"
 msgstr "Не могу скопировать объект: %s"
 
-#: lib/choose_repository.tcl:781
+#: lib/choose_repository.tcl:788
 msgid "Linking objects"
 msgstr "Создание ссылок на objects"
 
-#: lib/choose_repository.tcl:782
+#: lib/choose_repository.tcl:789
 msgid "objects"
 msgstr "объекты"
 
-#: lib/choose_repository.tcl:790
+#: lib/choose_repository.tcl:797
 #, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr "Не могу \"жестко связать\" объект: %s"
 
-#: lib/choose_repository.tcl:845
+#: lib/choose_repository.tcl:852
 msgid "Cannot fetch branches and objects.  See console output for details."
 msgstr ""
 "Не могу получить ветви и объекты. Дополнительная информация на консоли."
 
-#: lib/choose_repository.tcl:856
+#: lib/choose_repository.tcl:863
 msgid "Cannot fetch tags.  See console output for details."
 msgstr "Не могу получить метки. Дополнительная информация на консоли."
 
-#: lib/choose_repository.tcl:880
+#: lib/choose_repository.tcl:887
 msgid "Cannot determine HEAD.  See console output for details."
 msgstr "Не могу определить HEAD. Дополнительная информация на консоли."
 
-#: lib/choose_repository.tcl:889
+#: lib/choose_repository.tcl:896
 #, tcl-format
 msgid "Unable to cleanup %s"
 msgstr "Не могу очистить %s"
 
-#: lib/choose_repository.tcl:895
+#: lib/choose_repository.tcl:902
 msgid "Clone failed."
 msgstr "Клонирование не удалось."
 
-#: lib/choose_repository.tcl:902
+#: lib/choose_repository.tcl:909
 msgid "No default branch obtained."
 msgstr "Не было получено ветви по умолчанию."
 
-#: lib/choose_repository.tcl:913
+#: lib/choose_repository.tcl:920
 #, tcl-format
 msgid "Cannot resolve %s as a commit."
 msgstr "Не могу распознать %s как состояние."
 
-#: lib/choose_repository.tcl:925
+#: lib/choose_repository.tcl:932
 msgid "Creating working directory"
 msgstr "Создаю рабочий каталог"
 
-#: lib/choose_repository.tcl:926 lib/index.tcl:65 lib/index.tcl:127
-#: lib/index.tcl:193
+#: lib/choose_repository.tcl:933 lib/index.tcl:65 lib/index.tcl:128
+#: lib/index.tcl:196
 msgid "files"
 msgstr "файлов"
 
-#: lib/choose_repository.tcl:955
+#: lib/choose_repository.tcl:962
 msgid "Initial file checkout failed."
 msgstr "Не удалось получить начальное состояние файлов репозитория."
 
-#: lib/choose_repository.tcl:971
+#: lib/choose_repository.tcl:978
 msgid "Open"
 msgstr "Открыть"
 
-#: lib/choose_repository.tcl:981
+#: lib/choose_repository.tcl:988
 msgid "Repository:"
 msgstr "Репозиторий:"
 
-#: lib/choose_repository.tcl:1031
+#: lib/choose_repository.tcl:1037
 #, tcl-format
 msgid "Failed to open repository %s:"
 msgstr "Не удалось открыть репозиторий %s:"
@@ -1140,7 +1253,7 @@ msgstr "Ветвь слежения"
 
 #: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538
 msgid "Tag"
-msgstr "Таг"
+msgstr "Ð\9cеÑ\82ка"
 
 #: lib/choose_rev.tcl:317
 #, tcl-format
@@ -1182,24 +1295,24 @@ msgid ""
 "completed.  You cannot amend the prior commit unless you first abort the "
 "current merge activity.\n"
 msgstr ""
-"Ð\9dевозможно Ð¸Ñ\81пÑ\80авиÑ\82Ñ\8c Ñ\81оÑ\81Ñ\82оÑ\8fние Ð²Ð¾ Ð²Ñ\80емÑ\8f Ð¾Ð±Ñ\8aединения.\n"
+"Ð\9dевозможно Ð¸Ñ\81пÑ\80авиÑ\82Ñ\8c Ñ\81оÑ\81Ñ\82оÑ\8fние Ð²Ð¾ Ð²Ñ\80емÑ\8f Ð¾Ð¿ÐµÑ\80аÑ\86ии Ñ\81лиÑ\8fния.\n"
 "\n"
-"Текущее объединение не завершено. Невозможно исправить предыдущее "
-"сохраненное состояние не прерывая текущее объединение.\n"
+"Текущее слияние не завершено. Невозможно исправить предыдущее "
+"сохраненное состояние, не прерывая эту операцию.\n"
 
-#: lib/commit.tcl:49
+#: lib/commit.tcl:48
 msgid "Error loading commit data for amend:"
 msgstr "Ошибка при загрузке данных для исправления сохраненного состояния:"
 
-#: lib/commit.tcl:76
+#: lib/commit.tcl:75
 msgid "Unable to obtain your identity:"
 msgstr "Невозможно получить информацию об авторстве:"
 
-#: lib/commit.tcl:81
+#: lib/commit.tcl:80
 msgid "Invalid GIT_COMMITTER_IDENT:"
 msgstr "Неверный GIT_COMMITTER_IDENT:"
 
-#: lib/commit.tcl:133
+#: lib/commit.tcl:132
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
@@ -1215,7 +1328,7 @@ msgstr ""
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
-#: lib/commit.tcl:154
+#: lib/commit.tcl:155
 #, tcl-format
 msgid ""
 "Unmerged files cannot be committed.\n"
@@ -1223,12 +1336,12 @@ msgid ""
 "File %s has merge conflicts.  You must resolve them and stage the file "
 "before committing.\n"
 msgstr ""
-"Нельзя сохранить необъединенные файлы.\n"
+"Нельзя сохранить файлы с незавершённой операцей слияния.\n"
 "\n"
-"Для файла %s возник конфликт объединения. Разрешите конфликт и добавьте к "
+"Для файла %s возник конфликт слияния. Разрешите конфликт и добавьте к "
 "подготовленным файлам перед сохранением.\n"
 
-#: lib/commit.tcl:162
+#: lib/commit.tcl:163
 #, tcl-format
 msgid ""
 "Unknown file state %s detected.\n"
@@ -1239,7 +1352,7 @@ msgstr ""
 "\n"
 "Файл %s не может быть сохранен данной программой.\n"
 
-#: lib/commit.tcl:170
+#: lib/commit.tcl:171
 msgid ""
 "No changes to commit.\n"
 "\n"
@@ -1249,7 +1362,7 @@ msgstr ""
 "\n"
 "Подготовьте хотя бы один файл до создания сохраненного состояния.\n"
 
-#: lib/commit.tcl:183
+#: lib/commit.tcl:186
 msgid ""
 "Please supply a commit message.\n"
 "\n"
@@ -1267,45 +1380,45 @@ msgstr ""
 "- вторая строка пустая\n"
 "- оставшиеся строки: опишите, что дают ваши изменения.\n"
 
-#: lib/commit.tcl:207
+#: lib/commit.tcl:210
 #, tcl-format
 msgid "warning: Tcl does not support encoding '%s'."
 msgstr "предупреждение: Tcl не поддерживает кодировку '%s'."
 
-#: lib/commit.tcl:221
+#: lib/commit.tcl:226
 msgid "Calling pre-commit hook..."
 msgstr "Вызов программы поддержки репозитория pre-commit..."
 
-#: lib/commit.tcl:236
+#: lib/commit.tcl:241
 msgid "Commit declined by pre-commit hook."
 msgstr "Сохранение прервано программой поддержки репозитория pre-commit"
 
-#: lib/commit.tcl:259
+#: lib/commit.tcl:264
 msgid "Calling commit-msg hook..."
 msgstr "Вызов программы поддержки репозитория commit-msg..."
 
-#: lib/commit.tcl:274
+#: lib/commit.tcl:279
 msgid "Commit declined by commit-msg hook."
 msgstr "Сохранение прервано программой поддержки репозитория commit-msg"
 
-#: lib/commit.tcl:287
+#: lib/commit.tcl:292
 msgid "Committing changes..."
 msgstr "Сохранение изменений..."
 
-#: lib/commit.tcl:303
+#: lib/commit.tcl:308
 msgid "write-tree failed:"
 msgstr "Программа write-tree завершилась с ошибкой:"
 
-#: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368
+#: lib/commit.tcl:309 lib/commit.tcl:353 lib/commit.tcl:373
 msgid "Commit failed."
 msgstr "Сохранить состояние не удалось."
 
-#: lib/commit.tcl:321
+#: lib/commit.tcl:326
 #, tcl-format
 msgid "Commit %s appears to be corrupt"
 msgstr "Состояние %s выглядит поврежденным"
 
-#: lib/commit.tcl:326
+#: lib/commit.tcl:331
 msgid ""
 "No changes to commit.\n"
 "\n"
@@ -1315,23 +1428,23 @@ msgid ""
 msgstr ""
 "Отсутствуют изменения для сохранения.\n"
 "\n"
-"Ни один файл не был изменен и не было объединения.\n"
+"Ни один файл не был изменен и не было слияния.\n"
 "\n"
 "Сейчас автоматически запустится перечитывание репозитория.\n"
 
-#: lib/commit.tcl:333
+#: lib/commit.tcl:338
 msgid "No changes to commit."
 msgstr "Отуствуют измения для сохранения."
 
-#: lib/commit.tcl:347
+#: lib/commit.tcl:352
 msgid "commit-tree failed:"
 msgstr "Программа commit-tree завершилась с ошибкой:"
 
-#: lib/commit.tcl:367
+#: lib/commit.tcl:372
 msgid "update-ref failed:"
 msgstr "Программа update-ref завершилась с ошибкой:"
 
-#: lib/commit.tcl:454
+#: lib/commit.tcl:460
 #, tcl-format
 msgid "Created commit %s: %s"
 msgstr "Создано состояние %s: %s "
@@ -1406,7 +1519,7 @@ msgstr ""
 msgid "Invalid date from Git: %s"
 msgstr "Неправильная дата в репозитории: %s"
 
-#: lib/diff.tcl:42
+#: lib/diff.tcl:59
 #, tcl-format
 msgid ""
 "No differences detected.\n"
@@ -1428,40 +1541,101 @@ msgstr ""
 "\n"
 "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы."
 
-#: lib/diff.tcl:81
+#: lib/diff.tcl:99
 #, tcl-format
 msgid "Loading diff of %s..."
 msgstr "Загрузка изменений в %s..."
 
-#: lib/diff.tcl:114 lib/diff.tcl:184
+#: lib/diff.tcl:120
+msgid ""
+"LOCAL: deleted\n"
+"REMOTE:\n"
+msgstr ""
+"ЛОКАЛЬНО: удалён\n"
+"ВНЕШНИЙ:\n"
+
+#: lib/diff.tcl:125
+msgid ""
+"REMOTE: deleted\n"
+"LOCAL:\n"
+msgstr ""
+"ВНЕШНИЙ: удалён\n"
+"ЛОКАЛЬНО:\n"
+
+#: lib/diff.tcl:132
+msgid "LOCAL:\n"
+msgstr "ЛОКАЛЬНО:\n"
+
+#: lib/diff.tcl:135
+msgid "REMOTE:\n"
+msgstr "ВНЕШНИЙ:\n"
+
+#: lib/diff.tcl:197 lib/diff.tcl:296
 #, tcl-format
 msgid "Unable to display %s"
 msgstr "Не могу показать %s"
 
-#: lib/diff.tcl:115
+#: lib/diff.tcl:198
 msgid "Error loading file:"
 msgstr "Ошибка загрузки файла:"
 
-#: lib/diff.tcl:122
+#: lib/diff.tcl:205
 msgid "Git Repository (subproject)"
 msgstr "Репозиторий Git (подпроект)"
 
-#: lib/diff.tcl:134
+#: lib/diff.tcl:217
 msgid "* Binary file (not showing content)."
 msgstr "* Двоичный файл (содержимое не показано)"
 
-#: lib/diff.tcl:185
-msgid "Error loading diff:"
-msgstr "Ошибка загрузки diff:"
+#: lib/diff.tcl:222
+#, tcl-format
+msgid ""
+"* Untracked file is %d bytes.\n"
+"* Showing only first %d bytes.\n"
+msgstr ""
+"* Размер неподготовленого файла %d байт.\n"
+"* Показано первых %d байт.\n"
+
+#: lib/diff.tcl:228
+#, tcl-format
+msgid ""
+"\n"
+"* Untracked file clipped here by %s.\n"
+"* To see the entire file, use an external editor.\n"
+msgstr ""
+"\n"
+"* Неподготовленый файл обрезан: %s.\n"
+"* Чтобы увидеть весь файл, используйте программу-редактор.\n"
 
-#: lib/diff.tcl:303
+#: lib/diff.tcl:436
 msgid "Failed to unstage selected hunk."
 msgstr "Не удалось исключить выбранную часть."
 
-#: lib/diff.tcl:310
+#: lib/diff.tcl:443
 msgid "Failed to stage selected hunk."
 msgstr "Не удалось подготовить к сохранению выбранную часть."
 
+#: lib/diff.tcl:509
+msgid "Failed to unstage selected line."
+msgstr "Не удалось исключить выбранную строку."
+
+#: lib/diff.tcl:517
+msgid "Failed to stage selected line."
+msgstr "Не удалось подготовить к сохранению выбранную строку."
+
+#: lib/encoding.tcl:443
+msgid "Default"
+msgstr "По умолчанию"
+
+#: lib/encoding.tcl:448
+#, tcl-format
+msgid "System (%s)"
+msgstr "Системная (%s)"
+
+#: lib/encoding.tcl:459 lib/encoding.tcl:465
+msgid "Other"
+msgstr "Другая"
+
 #: lib/error.tcl:20 lib/error.tcl:114
 msgid "error"
 msgstr "ошибка"
@@ -1480,7 +1654,7 @@ msgstr "Не удалось разблокировать индекс"
 
 #: lib/index.tcl:15
 msgid "Index Error"
-msgstr "Ð\9eÑ\88ибка Ð¸Ð½Ð´ÐµÐºÑ\81а"
+msgstr "Ð\9eÑ\88ибка Ð² Ð¸Ð½Ð´ÐµÐºÑ\81е"
 
 #: lib/index.tcl:21
 msgid ""
@@ -1498,50 +1672,59 @@ msgstr "Продолжить"
 msgid "Unlock Index"
 msgstr "Разблокировать индекс"
 
-#: lib/index.tcl:282
+#: lib/index.tcl:287
 #, tcl-format
 msgid "Unstaging %s from commit"
 msgstr "Удаление %s из подготовленного"
 
-#: lib/index.tcl:313
+#: lib/index.tcl:326
 msgid "Ready to commit."
 msgstr "Подготовлено для сохранения"
 
-#: lib/index.tcl:326
+#: lib/index.tcl:339
 #, tcl-format
 msgid "Adding %s"
 msgstr "Добавление %s..."
 
-#: lib/index.tcl:381
+#: lib/index.tcl:396
 #, tcl-format
 msgid "Revert changes in file %s?"
 msgstr "Отменить изменения в файле %s?"
 
-#: lib/index.tcl:383
+#: lib/index.tcl:398
 #, tcl-format
 msgid "Revert changes in these %i files?"
 msgstr "Отменить изменения в %i файле(-ах)?"
 
-#: lib/index.tcl:391
+#: lib/index.tcl:406
 msgid "Any unstaged changes will be permanently lost by the revert."
 msgstr ""
 "Любые изменения, не подготовленные к сохранению, будут потеряны при данной "
 "операции."
 
-#: lib/index.tcl:394
+#: lib/index.tcl:409
 msgid "Do Nothing"
 msgstr "Ничего не делать"
 
+#: lib/index.tcl:427
+msgid "Reverting selected files"
+msgstr "Удаление изменений в выбраных файлах"
+
+#: lib/index.tcl:431
+#, tcl-format
+msgid "Reverting %s"
+msgstr "Отмена изменений в %s"
+
 #: lib/merge.tcl:13
 msgid ""
 "Cannot merge while amending.\n"
 "\n"
 "You must finish amending this commit before starting any type of merge.\n"
 msgstr ""
-"Невозможно выполнить объединение во время исправления.\n"
+"Невозможно выполнить слияние во время исправления.\n"
 "\n"
 "Завершите исправление данного состояния перед выполнением операции "
-"объединения.\n"
+"слияния.\n"
 
 #: lib/merge.tcl:27
 msgid ""
@@ -1559,7 +1742,7 @@ msgstr ""
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
-#: lib/merge.tcl:44
+#: lib/merge.tcl:45
 #, tcl-format
 msgid ""
 "You are in the middle of a conflicted merge.\n"
@@ -1569,14 +1752,14 @@ msgid ""
 "You must resolve them, stage the file, and commit to complete the current "
 "merge.  Only then can you begin another merge.\n"
 msgstr ""
-"Предыдущее объединение не завершено из-за конфликта.\n"
+"Предыдущее слияние не завершено из-за конфликта.\n"
 "\n"
-"Для файла %s возник конфликт объединения.\n"
+"Для файла %s возник конфликт слияния.\n"
 "\n"
 "Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно "
-"начать следующее объединение.\n"
+"начать следующее слияние.\n"
 
-#: lib/merge.tcl:54
+#: lib/merge.tcl:55
 #, tcl-format
 msgid ""
 "You are in the middle of a change.\n"
@@ -1590,36 +1773,37 @@ msgstr ""
 "\n"
 "Файл %s изменен.\n"
 "\n"
-"Подготовьте и сохраните измения перед началом объединения. В случае "
-"необходимости это позволит прервать операцию объединения.\n"
+"Подготовьте и сохраните измения перед началом слияния. В случае "
+"необходимости это позволит прервать операцию слияния.\n"
 
-#: lib/merge.tcl:106
+#: lib/merge.tcl:107
 #, tcl-format
 msgid "%s of %s"
 msgstr "%s из %s"
 
-#: lib/merge.tcl:119
+#: lib/merge.tcl:120
+#, tcl-format
 msgid "Merging %s and %s..."
-msgstr "Ð\9eбÑ\8aединение %s и %s..."
+msgstr "СлиÑ\8fние %s и %s..."
 
-#: lib/merge.tcl:130
+#: lib/merge.tcl:131
 msgid "Merge completed successfully."
-msgstr "Ð\9eбÑ\8aединение успешно завершено."
+msgstr "СлиÑ\8fние успешно завершено."
 
-#: lib/merge.tcl:132
+#: lib/merge.tcl:133
 msgid "Merge failed.  Conflict resolution is required."
-msgstr "Не удалось завершить объединение. Требуется разрешение конфликта."
+msgstr "Не удалось завершить слияние. Требуется разрешение конфликта."
 
-#: lib/merge.tcl:157
+#: lib/merge.tcl:158
 #, tcl-format
 msgid "Merge Into %s"
-msgstr "Ð\9eбÑ\8aединиÑ\82Ñ\8c с %s"
+msgstr "СлиÑ\8fние с %s"
 
-#: lib/merge.tcl:176
+#: lib/merge.tcl:177
 msgid "Revision To Merge"
-msgstr "Версия для объединения"
+msgstr "Версия, с которой провести слияние"
 
-#: lib/merge.tcl:211
+#: lib/merge.tcl:212
 msgid ""
 "Cannot abort while amending.\n"
 "\n"
@@ -1629,7 +1813,7 @@ msgstr ""
 "\n"
 "Завершите текущее исправление сохраненного состояния.\n"
 
-#: lib/merge.tcl:221
+#: lib/merge.tcl:222
 msgid ""
 "Abort merge?\n"
 "\n"
@@ -1637,13 +1821,13 @@ msgid ""
 "\n"
 "Continue with aborting the current merge?"
 msgstr ""
-"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c Ð¾Ð±Ñ\8aединение?\n"
+"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c Ð¾Ð¿ÐµÑ\80аÑ\86иÑ\8e Ñ\81лиÑ\8fниÑ\8f?\n"
 "\n"
-"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n"
+"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n"
 "\n"
 "Продолжить?"
 
-#: lib/merge.tcl:227
+#: lib/merge.tcl:228
 msgid ""
 "Reset changes?\n"
 "\n"
@@ -1651,130 +1835,346 @@ msgid ""
 "\n"
 "Continue with resetting the current changes?"
 msgstr ""
-"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c Ð¾Ð±Ñ\8aединение?\n"
+"Ð\9fÑ\80еÑ\80ваÑ\82Ñ\8c Ð¾Ð¿ÐµÑ\80аÑ\86иÑ\8e Ñ\81лиÑ\8fниÑ\8f?\n"
 "\n"
-"Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n"
+"Прерывание этой операции приведет к потере *ВСЕХ* несохраненных изменений.\n"
 "\n"
 "Продолжить?"
 
-#: lib/merge.tcl:238
+#: lib/merge.tcl:239
 msgid "Aborting"
 msgstr "Прерываю"
 
-#: lib/merge.tcl:238
+#: lib/merge.tcl:239
 msgid "files reset"
 msgstr "изменения в файлах отменены"
 
-#: lib/merge.tcl:265
+#: lib/merge.tcl:267
 msgid "Abort failed."
 msgstr "Прервать не удалось."
 
-#: lib/merge.tcl:267
+#: lib/merge.tcl:269
 msgid "Abort completed.  Ready."
 msgstr "Прервано."
 
-#: lib/option.tcl:95
+#: lib/mergetool.tcl:8
+msgid "Force resolution to the base version?"
+msgstr "Использовать базовую версию для разрешения конфликта?"
+
+#: lib/mergetool.tcl:9
+msgid "Force resolution to this branch?"
+msgstr "Использовать версию этой ветви для разрешения конфликта?"
+
+#: lib/mergetool.tcl:10
+msgid "Force resolution to the other branch?"
+msgstr "Использовать версию другой ветви для разрешения конфликта?"
+
+#: lib/mergetool.tcl:14
+#, 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 ""
+"Внимание! Список изменений показывает только конфликтующие отличия.\n"
+"\n"
+"%s будет переписан.\n"
+"\n"
+"Это действие можно отменить только перезапуском операции слияния."
+
+#: lib/mergetool.tcl:45
+#, tcl-format
+msgid "File %s seems to have unresolved conflicts, still stage?"
+msgstr ""
+"Файл %s кажется содержит необработаные конфликты. "
+"Продолжить подготовку к сохранению?"
+
+#: lib/mergetool.tcl:60
+#, tcl-format
+msgid "Adding resolution for %s"
+msgstr "Добавляю результат разрешения для %s"
+
+#: lib/mergetool.tcl:141
+msgid "Cannot resolve deletion or link conflicts using a tool"
+msgstr ""
+"Программа слияния не обрабатывает конфликты с удалением или участием ссылок"
+
+#: lib/mergetool.tcl:146
+msgid "Conflict file does not exist"
+msgstr "Конфликтующий файл не существует"
+
+#: lib/mergetool.tcl:264
+#, tcl-format
+msgid "Not a GUI merge tool: '%s'"
+msgstr "'%s' не является программой слияния"
+
+#: lib/mergetool.tcl:268
+#, tcl-format
+msgid "Unsupported merge tool '%s'"
+msgstr "Неизвестная программа слияния '%s'"
+
+#: lib/mergetool.tcl:303
+msgid "Merge tool is already running, terminate it?"
+msgstr "Программа слияния уже работает. Прервать?"
+
+#: lib/mergetool.tcl:323
+#, tcl-format
+msgid ""
+"Error retrieving versions:\n"
+"%s"
+msgstr ""
+"Ошибка получения версий:\n"
+"%s"
+
+#: lib/mergetool.tcl:343
+#, tcl-format
+msgid ""
+"Could not start the merge tool:\n"
+"\n"
+"%s"
+msgstr ""
+"Ошибка запуска программы слияния:\n"
+"\n"
+"%s"
+
+#: lib/mergetool.tcl:347
+msgid "Running merge tool..."
+msgstr "Запуск программы слияния..."
+
+#: lib/mergetool.tcl:375 lib/mergetool.tcl:383
+msgid "Merge tool failed."
+msgstr "Ошибка выполнения программы слияния."
+
+#: lib/option.tcl:11
+#, tcl-format
+msgid "Invalid global encoding '%s'"
+msgstr "Ошибка в глобальной установке кодировки '%s'"
+
+#: lib/option.tcl:19
+#, tcl-format
+msgid "Invalid repo encoding '%s'"
+msgstr "Неверная кодировка репозитория: '%s'"
+
+#: lib/option.tcl:117
 msgid "Restore Defaults"
 msgstr "Восстановить настройки по умолчанию"
 
-#: lib/option.tcl:99
+#: lib/option.tcl:121
 msgid "Save"
 msgstr "Сохранить"
 
-#: lib/option.tcl:109
+#: lib/option.tcl:131
 #, tcl-format
 msgid "%s Repository"
-msgstr "для репозитория %s"
+msgstr "Ð\94ля репозитория %s"
 
-#: lib/option.tcl:110
+#: lib/option.tcl:132
 msgid "Global (All Repositories)"
 msgstr "Общие (для всех репозиториев)"
 
-#: lib/option.tcl:116
+#: lib/option.tcl:138
 msgid "User Name"
 msgstr "Имя пользователя"
 
-#: lib/option.tcl:117
+#: lib/option.tcl:139
 msgid "Email Address"
 msgstr "Адрес электронной почты"
 
-#: lib/option.tcl:119
+#: lib/option.tcl:141
 msgid "Summarize Merge Commits"
-msgstr "Суммарный комментарий при объединении"
+msgstr "Суммарный комментарий при слиянии"
 
-#: lib/option.tcl:120
+#: lib/option.tcl:142
 msgid "Merge Verbosity"
-msgstr "Уровень детальности сообщений при объединении"
+msgstr "Уровень детальности сообщений при слиянии"
 
-#: lib/option.tcl:121
+#: lib/option.tcl:143
 msgid "Show Diffstat After Merge"
-msgstr "Показать отчет об изменениях после объединения"
+msgstr "Показать отчет об изменениях после слияния"
+
+#: lib/option.tcl:144
+msgid "Use Merge Tool"
+msgstr "Использовать для слияния программу"
 
-#: lib/option.tcl:123
+#: lib/option.tcl:146
 msgid "Trust File Modification Timestamps"
 msgstr "Доверять времени модификации файла"
 
-#: lib/option.tcl:124
+#: lib/option.tcl:147
 msgid "Prune Tracking Branches During Fetch"
 msgstr "Чистка ветвей слежения при получении изменений"
 
-#: lib/option.tcl:125
+#: lib/option.tcl:148
 msgid "Match Tracking Branches"
 msgstr "Имя новой ветви взять из имен ветвей слежения"
 
-#: lib/option.tcl:126
+#: lib/option.tcl:149
+msgid "Blame Copy Only On Changed Files"
+msgstr "Поиск копий только в изменённых файлах"
+
+#: lib/option.tcl:150
+msgid "Minimum Letters To Blame Copy On"
+msgstr "Минимальное количество символов для поиска копий"
+
+#: lib/option.tcl:151
+msgid "Blame History Context Radius (days)"
+msgstr "Радиус исторического контекста (в днях)"
+
+#: lib/option.tcl:152
 msgid "Number of Diff Context Lines"
 msgstr "Число строк в контексте diff"
 
-#: lib/option.tcl:127
+#: lib/option.tcl:153
 msgid "Commit Message Text Width"
-msgstr "Ширина комментария к состоянию:"
+msgstr "Ширина текста комментария"
 
-#: lib/option.tcl:128
+#: lib/option.tcl:154
 msgid "New Branch Name Template"
 msgstr "Шаблон для имени новой ветви"
 
-#: lib/option.tcl:192
+#: lib/option.tcl:155
+msgid "Default File Contents Encoding"
+msgstr "Кодировка содержания файла по умолчанию"
+
+#: lib/option.tcl:203
+msgid "Change"
+msgstr "Изменить"
+
+#: lib/option.tcl:230
 msgid "Spelling Dictionary:"
 msgstr "Словарь для проверки правописания:"
 
-#: lib/option.tcl:216
+#: lib/option.tcl:254
 msgid "Change Font"
-msgstr "Изменить шрифт"
+msgstr "Изменить"
 
-#: lib/option.tcl:220
+#: lib/option.tcl:258
 #, tcl-format
 msgid "Choose %s"
 msgstr "Выберите %s"
 
 # carbon copy
-#: lib/option.tcl:226
+#: lib/option.tcl:264
 msgid "pt."
-msgstr ""
+msgstr "pt."
 
-#: lib/option.tcl:240
+#: lib/option.tcl:278
 msgid "Preferences"
 msgstr "Настройки"
 
-#: lib/option.tcl:275
+#: lib/option.tcl:314
 msgid "Failed to completely save options:"
 msgstr "Не удалось полностью сохранить настройки:"
 
+#: lib/remote.tcl:163
+msgid "Remove Remote"
+msgstr "Удалить ссылку на внешний репозиторий"
+
+#: lib/remote.tcl:168
+msgid "Prune from"
+msgstr "Чистка"
+
+#: lib/remote.tcl:173
+msgid "Fetch from"
+msgstr "Получение из"
+
+#: lib/remote.tcl:215
+msgid "Push to"
+msgstr "Отправить"
+
+#: lib/remote_add.tcl:19
+msgid "Add Remote"
+msgstr "Зарегистрировать внешний репозиторий"
+
+#: lib/remote_add.tcl:24
+msgid "Add New Remote"
+msgstr "Добавить внешний репозиторий"
+
+#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36
+msgid "Add"
+msgstr ""
+
+#: lib/remote_add.tcl:37
+msgid "Remote Details"
+msgstr "Информация о внешнем репозитории"
+
+#: lib/remote_add.tcl:50
+msgid "Location:"
+msgstr "Положение:"
+
+#: lib/remote_add.tcl:62
+msgid "Further Action"
+msgstr "Следующая операция"
+
+#: lib/remote_add.tcl:65
+msgid "Fetch Immediately"
+msgstr "Скачать сразу"
+
+#: lib/remote_add.tcl:71
+msgid "Initialize Remote Repository and Push"
+msgstr "Инициализировать внешний репозиторий и отправить"
+
+#: lib/remote_add.tcl:77
+msgid "Do Nothing Else Now"
+msgstr "Больше ничего не делать"
+
+#: lib/remote_add.tcl:101
+msgid "Please supply a remote name."
+msgstr "Укажите название внешнего репозитория."
+
+#: lib/remote_add.tcl:114
+#, tcl-format
+msgid "'%s' is not an acceptable remote name."
+msgstr "Недопустимое название внешнего репозитория '%s'."
+
+#: lib/remote_add.tcl:125
+#, tcl-format
+msgid "Failed to add remote '%s' of location '%s'."
+msgstr "Не удалось добавить '%s' из '%s'. "
+
+#: lib/remote_add.tcl:133 lib/transport.tcl:6
+#, tcl-format
+msgid "fetch %s"
+msgstr "получение %s"
+
+#: lib/remote_add.tcl:134
+#, tcl-format
+msgid "Fetching the %s"
+msgstr "Получение %s"
+
+#: lib/remote_add.tcl:157
+#, tcl-format
+msgid "Do not know how to initialize repository at location '%s'."
+msgstr "Невозможно инициалировать репозиторий в '%s'."
+
+#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63
+#: lib/transport.tcl:81
+#, tcl-format
+msgid "push %s"
+msgstr "отправить %s"
+
+#: lib/remote_add.tcl:164
+#, tcl-format
+msgid "Setting up the %s (at %s)"
+msgstr "Настройка %s (в %s)"
+
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
-msgid "Delete Remote Branch"
-msgstr "УдалиÑ\82Ñ\8c Ð²Ð½ÐµÑ\88нÑ\8eÑ\8e Ð²ÐµÑ\82вÑ\8c"
+msgid "Delete Branch Remotely"
+msgstr "Удаление Ð²ÐµÑ\82ви Ð²Ð¾ Ð²Ð½ÐµÑ\88нем Ñ\80епозиÑ\82оÑ\80ии"
 
 #: lib/remote_branch_delete.tcl:47
 msgid "From Repository"
 msgstr "Из репозитория"
 
-#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123
+#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134
 msgid "Remote:"
 msgstr "внешний:"
 
-#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:138
-msgid "Arbitrary URL:"
-msgstr "по Ñ\83казанномÑ\83 URL:"
+#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149
+msgid "Arbitrary Location:"
+msgstr "Указаное Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ðµ:"
 
 #: lib/remote_branch_delete.tcl:84
 msgid "Branches"
@@ -1786,15 +2186,15 @@ msgstr "Удалить только в случае, если"
 
 #: lib/remote_branch_delete.tcl:111
 msgid "Merged Into:"
-msgstr "Ð\9eбÑ\8aединено с:"
+msgstr "СлиÑ\8fние с:"
 
 #: lib/remote_branch_delete.tcl:119
 msgid "Always (Do not perform merge checks)"
-msgstr "Ð\92Ñ\81егда (не Ð²Ñ\8bполнÑ\8fÑ\82Ñ\8c Ð¿Ñ\80овеÑ\80кÑ\83 Ð¾Ð±Ñ\8aединений)"
+msgstr "Ð\92Ñ\81егда (не Ð²Ñ\8bполнÑ\8fÑ\82Ñ\8c Ð¿Ñ\80овеÑ\80кÑ\83 Ð½Ð° Ñ\81лиÑ\8fние)"
 
 #: lib/remote_branch_delete.tcl:152
 msgid "A branch is required for 'Merged Into'."
-msgstr "Ð\94лÑ\8f Ð¾Ð¿Ñ\86ии 'Ð\9eбÑ\8aединено с' требуется указать ветвь."
+msgstr "Ð\94лÑ\8f Ð¾Ð¿Ñ\86ии 'СлиÑ\8fние с' требуется указать ветвь."
 
 #: lib/remote_branch_delete.tcl:184
 #, tcl-format
@@ -1803,7 +2203,8 @@ msgid ""
 "\n"
 " - %s"
 msgstr ""
-"Следующие ветви объединены с %s не полностью:\n"
+"Следующие ветви могут быть объединены с %s при помощи операции слияния:\n"
+"\n"
 " - %s"
 
 #: lib/remote_branch_delete.tcl:189
@@ -1812,7 +2213,7 @@ msgid ""
 "One or more of the merge tests failed because you have not fetched the "
 "necessary commits.  Try fetching from %s first."
 msgstr ""
-"Ð\9eдин Ð¸Ð»Ð¸ Ð½ÐµÑ\81колÑ\8cко Ñ\82еÑ\81Ñ\82ов Ð½Ð° Ð¾Ð±Ñ\8aединение не прошли, потому что Вы не "
+"Ð\9dекоÑ\82оÑ\80Ñ\8bе Ñ\82еÑ\81Ñ\82Ñ\8b Ð½Ð° Ñ\81лиÑ\8fние не прошли, потому что Вы не "
 "получили необходимые состояния. Попытайтесь получить их из %s."
 
 #: lib/remote_branch_delete.tcl:207
@@ -1843,17 +2244,21 @@ msgstr "Не указан репозиторий."
 msgid "Scanning %s..."
 msgstr "Перечитывание %s... "
 
-#: lib/remote.tcl:165
-msgid "Prune from"
-msgstr "ЧиÑ\81Ñ\82ка"
+#: lib/search.tcl:21
+msgid "Find:"
+msgstr "Ð\9fоиÑ\81к:"
 
-#: lib/remote.tcl:170
-msgid "Fetch from"
-msgstr "Ð\9fолÑ\83Ñ\87ение Ð¸Ð·"
+#: lib/search.tcl:23
+msgid "Next"
+msgstr "Ð\94алÑ\8cÑ\88е"
 
-#: lib/remote.tcl:213
-msgid "Push to"
-msgstr "Отправить"
+#: lib/search.tcl:24
+msgid "Prev"
+msgstr "Обратно"
+
+#: lib/search.tcl:25
+msgid "Case-Sensitive"
+msgstr "Игн. большие/маленькие"
 
 #: lib/shortcut.tcl:20 lib/shortcut.tcl:61
 msgid "Cannot write shortcut:"
@@ -1888,27 +2293,192 @@ msgstr "Программа проверки правописания не смо
 msgid "Unrecognized spell checker"
 msgstr "Нераспознаная программа проверки правописания"
 
-#: lib/spellcheck.tcl:180
+#: lib/spellcheck.tcl:186
 msgid "No Suggestions"
 msgstr "Исправлений не найдено"
 
-#: lib/spellcheck.tcl:381
+#: lib/spellcheck.tcl:388
 msgid "Unexpected EOF from spell checker"
 msgstr "Программа проверки правописания прервала передачу данных"
 
-#: lib/spellcheck.tcl:385
+#: lib/spellcheck.tcl:392
 msgid "Spell Checker Failed"
 msgstr "Ошибка проверки правописания"
 
+#: lib/sshkey.tcl:31
+msgid "No keys found."
+msgstr "Ключ не найден"
+
+#: lib/sshkey.tcl:34
+#, tcl-format
+msgid "Found a public key in: %s"
+msgstr "Публичный ключ из %s"
+
+#: lib/sshkey.tcl:40
+msgid "Generate Key"
+msgstr "Создать ключ"
+
+#: lib/sshkey.tcl:56
+msgid "Copy To Clipboard"
+msgstr "Скопировать в буфер обмена"
+
+#: lib/sshkey.tcl:70
+msgid "Your OpenSSH Public Key"
+msgstr "Ваш публичный ключ OpenSSH"
+
+#: lib/sshkey.tcl:78
+msgid "Generating..."
+msgstr "Создание..."
+
+#: lib/sshkey.tcl:84
+#, tcl-format
+msgid ""
+"Could not start ssh-keygen:\n"
+"\n"
+"%s"
+msgstr ""
+"Ошибка запуска ssh-keygen:\n"
+"\n"
+"%s"
+
+#: lib/sshkey.tcl:111
+msgid "Generation failed."
+msgstr "Ключ не создан."
+
+#: lib/sshkey.tcl:118
+msgid "Generation succeded, but no keys found."
+msgstr "Создание ключа завершилось, но результат не был найден"
+
+#: lib/sshkey.tcl:121
+#, tcl-format
+msgid "Your key is in: %s"
+msgstr "Ваш ключ находится в: %s"
+
 #: lib/status_bar.tcl:83
 #, tcl-format
 msgid "%s ... %*i of %*i %s (%3i%%)"
 msgstr "%s ... %*i из %*i %s (%3i%%)"
 
-#: lib/transport.tcl:6
+#: lib/tools.tcl:75
 #, tcl-format
-msgid "fetch %s"
-msgstr "получение %s"
+msgid "Running %s requires a selected file."
+msgstr "Запуск %s требует выбранного файла."
+
+#: lib/tools.tcl:90
+#, tcl-format
+msgid "Are you sure you want to run %s?"
+msgstr "Действительно запустить %s?"
+
+#: lib/tools.tcl:110
+#, tcl-format
+msgid "Tool: %s"
+msgstr "Вспомогательная операция: %s"
+
+#: lib/tools.tcl:111
+#, tcl-format
+msgid "Running: %s"
+msgstr "Выполнение: %s"
+
+#: lib/tools.tcl:149
+#, tcl-format
+msgid "Tool completed succesfully: %s"
+msgstr "Программа %s успешно завершилась."
+
+#: lib/tools.tcl:151
+#, tcl-format
+msgid "Tool failed: %s"
+msgstr "Ошибка выполнения программы: %s"
+
+#: lib/tools_dlg.tcl:22
+msgid "Add Tool"
+msgstr "Добавить вспомогательную операцию"
+
+#: lib/tools_dlg.tcl:28
+msgid "Add New Tool Command"
+msgstr "Новая вспомогательная операция"
+
+#: lib/tools_dlg.tcl:33
+msgid "Add globally"
+msgstr "Добавить для всех репозиториев"
+
+#: lib/tools_dlg.tcl:45
+msgid "Tool Details"
+msgstr "Описание вспомогательной операции"
+
+#: lib/tools_dlg.tcl:48
+msgid "Use '/' separators to create a submenu tree:"
+msgstr "Испольуйте '/' для создания подменю"
+
+#: lib/tools_dlg.tcl:61
+msgid "Command:"
+msgstr "Команда:"
+
+#: lib/tools_dlg.tcl:74
+msgid "Show a dialog before running"
+msgstr "Показать диалог перед запуском"
+
+#: lib/tools_dlg.tcl:80
+msgid "Ask the user to select a revision (sets $REVISION)"
+msgstr "Запрос на выбор версии (устанавливает $REVISION)"
+
+#: lib/tools_dlg.tcl:85
+msgid "Ask the user for additional arguments (sets $ARGS)"
+msgstr "Запрос дополнительных аргументов (устанавливает $ARGS)"
+
+#: lib/tools_dlg.tcl:92
+msgid "Don't show the command output window"
+msgstr "Не показывать окно вывода команды"
+
+#: lib/tools_dlg.tcl:97
+msgid "Run only if a diff is selected ($FILENAME not empty)"
+msgstr "Запуск только если показан список изменений ($FILENAME не пусто)"
+
+#: lib/tools_dlg.tcl:121
+msgid "Please supply a name for the tool."
+msgstr "Укажите название вспомогательной операции."
+
+#: lib/tools_dlg.tcl:129
+#, tcl-format
+msgid "Tool '%s' already exists."
+msgstr "Вспомогательная операция '%s' уже существует."
+
+#: lib/tools_dlg.tcl:151
+#, tcl-format
+msgid ""
+"Could not add tool:\n"
+"%s"
+msgstr ""
+"Ошибка добавления программы:\n"
+"%s"
+
+#: lib/tools_dlg.tcl:190
+msgid "Remove Tool"
+msgstr "Удалить программу"
+
+#: lib/tools_dlg.tcl:196
+msgid "Remove Tool Commands"
+msgstr "Удалить команды программы"
+
+#: lib/tools_dlg.tcl:200
+msgid "Remove"
+msgstr "Удалить"
+
+#: lib/tools_dlg.tcl:236
+msgid "(Blue denotes repository-local tools)"
+msgstr "(Синим выделены программы локальные репозиторию)"
+
+#: lib/tools_dlg.tcl:297
+#, tcl-format
+msgid "Run Command: %s"
+msgstr "Запуск команды: %s"
+
+#: lib/tools_dlg.tcl:311
+msgid "Arguments"
+msgstr "Аргументы"
+
+#: lib/tools_dlg.tcl:348
+msgid "OK"
+msgstr "OK"
 
 #: lib/transport.tcl:7
 #, tcl-format
@@ -1926,48 +2496,46 @@ msgstr "чистка внешнего %s"
 msgid "Pruning tracking branches deleted from %s"
 msgstr "Чистка ветвей слежения, удаленных из %s"
 
-#: lib/transport.tcl:25 lib/transport.tcl:71
-#, tcl-format
-msgid "push %s"
-msgstr "отправить %s"
-
 #: lib/transport.tcl:26
 #, tcl-format
 msgid "Pushing changes to %s"
 msgstr "Отправка изменений в %s "
 
-#: lib/transport.tcl:72
+#: lib/transport.tcl:64
+#, tcl-format
+msgid "Mirroring to %s"
+msgstr "Точное копирование в %s"
+
+#: lib/transport.tcl:82
 #, tcl-format
 msgid "Pushing %s %s to %s"
 msgstr "Отправка %s %s в %s"
 
-#: lib/transport.tcl:89
+#: lib/transport.tcl:100
 msgid "Push Branches"
 msgstr "Отправить изменения в ветвях"
 
-#: lib/transport.tcl:103
+#: lib/transport.tcl:114
 msgid "Source Branches"
 msgstr "Исходные ветви"
 
-#: lib/transport.tcl:120
+#: lib/transport.tcl:131
 msgid "Destination Repository"
 msgstr "Репозиторий назначения"
 
-#: lib/transport.tcl:158
+#: lib/transport.tcl:169
 msgid "Transfer Options"
 msgstr "Настройки отправки"
 
-#: lib/transport.tcl:160
+#: lib/transport.tcl:171
 msgid "Force overwrite existing branch (may discard changes)"
 msgstr "Намеренно переписать существующую ветвь (возможна потеря изменений)"
 
-#: lib/transport.tcl:164
+#: lib/transport.tcl:175
 msgid "Use thin pack (for slow network connections)"
 msgstr "Использовать thin pack (для медленных сетевых подключений)"
 
-#: lib/transport.tcl:168
+#: lib/transport.tcl:179
 msgid "Include tags"
-msgstr "Передать таги"
+msgstr "Передать метки"
 
-#~ msgid "Next >"
-#~ msgstr "Дальше >"
index 167654c7094c73f85b212ce5f48c401a31fca91b..c1535f94e86f2d619b4609965324a7c8ca0b396c 100644 (file)
@@ -780,16 +780,6 @@ msgstr "Alltid (utför inte sammanslagningstest)."
 msgid "The following branches are not completely merged into %s:"
 msgstr "Följande grenar är inte till fullo sammanslagna med %s:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"Det är svårt att återställa borttagna grenar.\n"
-"\n"
-" Ta bort valda grenar?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
@@ -2398,7 +2388,7 @@ msgstr "Exekverar: %s"
 
 #: lib/tools.tcl:149
 #, tcl-format
-msgid "Tool completed succesfully: %s"
+msgid "Tool completed successfully: %s"
 msgstr "Verktyget avslutades framgångsrikt: %s"
 
 #: lib/tools.tcl:151
index d2c686667163ec4cd83045efd429e3413564290e..91c1be23c2bb8e87a6e08188f5a0f0b860af4242 100644 (file)
@@ -676,16 +676,6 @@ msgstr "总是合并 (不作合并测试.)"
 msgid "The following branches are not completely merged into %s:"
 msgstr "下列分支没有完全被合并到 %s:"
 
-#: lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult. \n"
-"\n"
-" Delete the selected branches?"
-msgstr ""
-"恢复被删除的分支非常困难.\n"
-"\n"
-"是否要删除所选分支?"
-
 #: lib/branch_delete.tcl:141
 #, tcl-format
 msgid ""
index 53c3a94686813936445efbb055dc4f02885c70e9..66bbb2f8faaf83bc87819a9e288a0592f400e147 100644 (file)
@@ -3,7 +3,12 @@
 exec wish "$0" -- "$@"
 
 if { $argc >=2 && [lindex $argv 0] == "--working-dir" } {
-       cd [lindex $argv 1]
+       set workdir [lindex $argv 1]
+       cd $workdir
+       if {[lindex [file split $workdir] end] eq {.git}} {
+               # Workaround for Explorer right click "Git GUI Here" on .git/
+               cd ..
+       }
        set argv [lrange $argv 2 end]
        incr argc -2
 }
index e1eb9632660146396a0b5f3f2a410d8cb027ff9d..9c2c1b7202462370509a7bdb391982ae32564bd6 100755 (executable)
@@ -113,6 +113,10 @@ case "${1:-.}${2:-.}${3:-.}" in
        src1=`git-unpack-file $2`
        git merge-file "$src1" "$orig" "$src2"
        ret=$?
+       msg=
+       if [ $ret -ne 0 ]; then
+               msg='content conflict'
+       fi
 
        # Create the working tree file, using "our tree" version from the
        # index, and then store the result of the merge.
@@ -120,7 +124,10 @@ case "${1:-.}${2:-.}${3:-.}" in
        rm -f -- "$orig" "$src1" "$src2"
 
        if [ "$6" != "$7" ]; then
-               echo "ERROR: Permissions conflict: $5->$6,$7."
+               if [ -n "$msg" ]; then
+                       msg="$msg, "
+               fi
+               msg="${msg}permissions conflict: $5->$6,$7"
                ret=1
        fi
        if [ "$1" = '' ]; then
@@ -128,7 +135,7 @@ case "${1:-.}${2:-.}${3:-.}" in
        fi
 
        if [ $ret -ne 0 ]; then
-               echo "ERROR: Merge conflict in $4"
+               echo "ERROR: $msg in $4"
                exit 1
        fi
        exec git update-index -- "$4"
index 93bcfc2f5dce418d00f26257788932d5c738785c..c9da747fcfe504b1fd233c68d91e549def0f3571 100755 (executable)
@@ -37,10 +37,10 @@ then
        exit 2
 fi
 
-git update-index --refresh 2>/dev/null
+git update-index -q --refresh
 git read-tree -u -m --aggressive $bases $head $remotes || exit 2
 echo "Trying simple merge."
-if result_tree=$(git write-tree  2>/dev/null)
+if result_tree=$(git write-tree 2>/dev/null)
 then
        exit 0
 else
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
new file mode 100644 (file)
index 0000000..8b5e6a8
--- /dev/null
@@ -0,0 +1,385 @@
+# git-mergetool--lib is a library for common merge tool functions
+diff_mode() {
+       test "$TOOL_MODE" = diff
+}
+
+merge_mode() {
+       test "$TOOL_MODE" = merge
+}
+
+translate_merge_tool_path () {
+       case "$1" in
+       vimdiff)
+               echo vim
+               ;;
+       gvimdiff)
+               echo gvim
+               ;;
+       emerge)
+               echo emacs
+               ;;
+       *)
+               echo "$1"
+               ;;
+       esac
+}
+
+check_unchanged () {
+       if test "$MERGED" -nt "$BACKUP"; then
+               status=0
+       else
+               while true; do
+                       echo "$MERGED seems unchanged."
+                       printf "Was the merge successful? [y/n] "
+                       read answer < /dev/tty
+                       case "$answer" in
+                       y*|Y*) status=0; break ;;
+                       n*|N*) status=1; break ;;
+                       esac
+               done
+       fi
+}
+
+valid_tool () {
+       case "$1" in
+       kdiff3 | tkdiff | xxdiff | meld | opendiff | \
+       emerge | vimdiff | gvimdiff | ecmerge | diffuse)
+               ;; # happy
+       tortoisemerge)
+               if ! merge_mode; then
+                       return 1
+               fi
+               ;;
+       kompare)
+               if ! diff_mode; then
+                       return 1
+               fi
+               ;;
+       *)
+               if test -z "$(get_merge_tool_cmd "$1")"; then
+                       return 1
+               fi
+               ;;
+       esac
+}
+
+get_merge_tool_cmd () {
+       # Prints the custom command for a merge tool
+       if test -n "$1"; then
+               merge_tool="$1"
+       else
+               merge_tool="$(get_merge_tool)"
+       fi
+       if diff_mode; then
+               echo "$(git config difftool.$merge_tool.cmd ||
+                       git config mergetool.$merge_tool.cmd)"
+       else
+               echo "$(git config mergetool.$merge_tool.cmd)"
+       fi
+}
+
+run_merge_tool () {
+       merge_tool_path="$(get_merge_tool_path "$1")" || exit
+       base_present="$2"
+       status=0
+
+       case "$1" in
+       kdiff3)
+               if merge_mode; then
+                       if $base_present; then
+                               ("$merge_tool_path" --auto \
+                                       --L1 "$MERGED (Base)" \
+                                       --L2 "$MERGED (Local)" \
+                                       --L3 "$MERGED (Remote)" \
+                                       -o "$MERGED" \
+                                       "$BASE" "$LOCAL" "$REMOTE" \
+                               > /dev/null 2>&1)
+                       else
+                               ("$merge_tool_path" --auto \
+                                       --L1 "$MERGED (Local)" \
+                                       --L2 "$MERGED (Remote)" \
+                                       -o "$MERGED" \
+                                       "$LOCAL" "$REMOTE" \
+                               > /dev/null 2>&1)
+                       fi
+                       status=$?
+               else
+                       ("$merge_tool_path" --auto \
+                               --L1 "$MERGED (A)" \
+                               --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
+                       > /dev/null 2>&1)
+               fi
+               ;;
+       kompare)
+               "$merge_tool_path" "$LOCAL" "$REMOTE"
+               ;;
+       tkdiff)
+               if merge_mode; then
+                       if $base_present; then
+                               "$merge_tool_path" -a "$BASE" \
+                                       -o "$MERGED" "$LOCAL" "$REMOTE"
+                       else
+                               "$merge_tool_path" \
+                                       -o "$MERGED" "$LOCAL" "$REMOTE"
+                       fi
+                       status=$?
+               else
+                       "$merge_tool_path" "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       meld)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
+                       check_unchanged
+               else
+                       "$merge_tool_path" "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       diffuse)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       if $base_present; then
+                               "$merge_tool_path" \
+                                       "$LOCAL" "$MERGED" "$REMOTE" \
+                                       "$BASE" | cat
+                       else
+                               "$merge_tool_path" \
+                                       "$LOCAL" "$MERGED" "$REMOTE" | cat
+                       fi
+                       check_unchanged
+               else
+                       "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+               fi
+               ;;
+       vimdiff)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       "$merge_tool_path" -d -c "wincmd l" \
+                               "$LOCAL" "$MERGED" "$REMOTE"
+                       check_unchanged
+               else
+                       "$merge_tool_path" -d -c "wincmd l" \
+                               "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       gvimdiff)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       "$merge_tool_path" -d -c "wincmd l" -f \
+                               "$LOCAL" "$MERGED" "$REMOTE"
+                       check_unchanged
+               else
+                       "$merge_tool_path" -d -c "wincmd l" -f \
+                               "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       xxdiff)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       if $base_present; then
+                               "$merge_tool_path" -X --show-merged-pane \
+                                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+                                       -R 'Accel.Search: "Ctrl+F"' \
+                                       -R 'Accel.SearchForward: "Ctrl-G"' \
+                                       --merged-file "$MERGED" \
+                                       "$LOCAL" "$BASE" "$REMOTE"
+                       else
+                               "$merge_tool_path" -X $extra \
+                                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+                                       -R 'Accel.Search: "Ctrl+F"' \
+                                       -R 'Accel.SearchForward: "Ctrl-G"' \
+                                       --merged-file "$MERGED" \
+                                       "$LOCAL" "$REMOTE"
+                       fi
+                       check_unchanged
+               else
+                       "$merge_tool_path" \
+                               -R 'Accel.Search: "Ctrl+F"' \
+                               -R 'Accel.SearchForward: "Ctrl-G"' \
+                               "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       opendiff)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       if $base_present; then
+                               "$merge_tool_path" "$LOCAL" "$REMOTE" \
+                                       -ancestor "$BASE" \
+                                       -merge "$MERGED" | cat
+                       else
+                               "$merge_tool_path" "$LOCAL" "$REMOTE" \
+                                       -merge "$MERGED" | cat
+                       fi
+                       check_unchanged
+               else
+                       "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+               fi
+               ;;
+       ecmerge)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       if $base_present; then
+                               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
+                                       --default --mode=merge3 --to="$MERGED"
+                       else
+                               "$merge_tool_path" "$LOCAL" "$REMOTE" \
+                                       --default --mode=merge2 --to="$MERGED"
+                       fi
+                       check_unchanged
+               else
+                       "$merge_tool_path" --default --mode=diff2 \
+                               "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       emerge)
+               if merge_mode; then
+                       if $base_present; then
+                               "$merge_tool_path" \
+                                       -f emerge-files-with-ancestor-command \
+                                       "$LOCAL" "$REMOTE" "$BASE" \
+                                       "$(basename "$MERGED")"
+                       else
+                               "$merge_tool_path" \
+                                       -f emerge-files-command \
+                                       "$LOCAL" "$REMOTE" \
+                                       "$(basename "$MERGED")"
+                       fi
+                       status=$?
+               else
+                       "$merge_tool_path" -f emerge-files-command \
+                               "$LOCAL" "$REMOTE"
+               fi
+               ;;
+       tortoisemerge)
+               if $base_present; then
+                       touch "$BACKUP"
+                       "$merge_tool_path" \
+                               -base:"$BASE" -mine:"$LOCAL" \
+                               -theirs:"$REMOTE" -merged:"$MERGED"
+                       check_unchanged
+               else
+                       echo "TortoiseMerge cannot be used without a base" 1>&2
+                       status=1
+               fi
+               ;;
+       *)
+               merge_tool_cmd="$(get_merge_tool_cmd "$1")"
+               if test -z "$merge_tool_cmd"; then
+                       if merge_mode; then
+                               status=1
+                       fi
+                       break
+               fi
+               if merge_mode; then
+                       trust_exit_code="$(git config --bool \
+                               mergetool."$1".trustExitCode || echo false)"
+                       if test "$trust_exit_code" = "false"; then
+                               touch "$BACKUP"
+                               ( eval $merge_tool_cmd )
+                               check_unchanged
+                       else
+                               ( eval $merge_tool_cmd )
+                               status=$?
+                       fi
+               else
+                       ( eval $merge_tool_cmd )
+               fi
+               ;;
+       esac
+       return $status
+}
+
+guess_merge_tool () {
+       if merge_mode; then
+               tools="tortoisemerge"
+       else
+               tools="kompare"
+       fi
+       if test -n "$DISPLAY"; then
+               if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
+                       tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
+               else
+                       tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
+               fi
+               tools="$tools gvimdiff diffuse ecmerge"
+       fi
+       if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then
+               # $EDITOR is emacs so add emerge as a candidate
+               tools="$tools emerge vimdiff"
+       elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then
+               # $EDITOR is vim so add vimdiff as a candidate
+               tools="$tools vimdiff emerge"
+       else
+               tools="$tools emerge vimdiff"
+       fi
+       echo >&2 "merge tool candidates: $tools"
+
+       # Loop over each candidate and stop when a valid merge tool is found.
+       for i in $tools
+       do
+               merge_tool_path="$(translate_merge_tool_path "$i")"
+               if type "$merge_tool_path" > /dev/null 2>&1; then
+                       echo "$i"
+                       return 0
+               fi
+       done
+
+       echo >&2 "No known merge resolution program available."
+       return 1
+}
+
+get_configured_merge_tool () {
+       # Diff mode first tries diff.tool and falls back to merge.tool.
+       # Merge mode only checks merge.tool
+       if diff_mode; then
+               merge_tool=$(git config diff.tool || git config merge.tool)
+       else
+               merge_tool=$(git config merge.tool)
+       fi
+       if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
+               echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
+               echo >&2 "Resetting to default..."
+               return 1
+       fi
+       echo "$merge_tool"
+}
+
+get_merge_tool_path () {
+       # A merge tool has been set, so verify that it's valid.
+       if test -n "$1"; then
+               merge_tool="$1"
+       else
+               merge_tool="$(get_merge_tool)"
+       fi
+       if ! valid_tool "$merge_tool"; then
+               echo >&2 "Unknown merge tool $merge_tool"
+               exit 1
+       fi
+       if diff_mode; then
+               merge_tool_path=$(git config difftool."$merge_tool".path ||
+                                 git config mergetool."$merge_tool".path)
+       else
+               merge_tool_path=$(git config mergetool."$merge_tool".path)
+       fi
+       if test -z "$merge_tool_path"; then
+               merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
+       fi
+       if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
+       ! type "$merge_tool_path" > /dev/null 2>&1; then
+               echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
+                        "'$merge_tool_path'"
+               exit 1
+       fi
+       echo "$merge_tool_path"
+}
+
+get_merge_tool () {
+       # Check if a merge tool has been configured
+       merge_tool=$(get_configured_merge_tool)
+       # Try to guess an appropriate merge tool if no tool has been set.
+       if test -z "$merge_tool"; then
+               merge_tool="$(guess_merge_tool)" || exit
+       fi
+       echo "$merge_tool"
+}
index 87fa88af5526c8e27b823a65ca15bee4085f8ef2..b52a7410bcb7b37dce0f4d6213dddedd2c1e42e7 100755 (executable)
@@ -11,7 +11,9 @@
 USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...'
 SUBDIRECTORY_OK=Yes
 OPTIONS_SPEC=
+TOOL_MODE=merge
 . git-sh-setup
+. git-mergetool--lib
 require_work_tree
 
 # Returns true if the mode reflects a symlink
@@ -110,22 +112,6 @@ resolve_deleted_merge () {
        done
 }
 
-check_unchanged () {
-    if test "$MERGED" -nt "$BACKUP" ; then
-       status=0;
-    else
-       while true; do
-           echo "$MERGED seems unchanged."
-           printf "Was the merge successful? [y/n] "
-           read answer < /dev/tty
-           case "$answer" in
-               y*|Y*) status=0; break ;;
-               n*|N*) status=1; break ;;
-           esac
-       done
-    fi
-}
-
 checkout_staged_file () {
     tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^    ]*\)    ')
 
@@ -137,7 +123,7 @@ checkout_staged_file () {
 merge_file () {
     MERGED="$1"
 
-    f=`git ls-files -u -- "$MERGED"`
+    f=$(git ls-files -u -- "$MERGED")
     if test -z "$f" ; then
        if test ! -f "$MERGED" ; then
            echo "$MERGED: file not found"
@@ -156,9 +142,9 @@ merge_file () {
     mv -- "$MERGED" "$BACKUP"
     cp -- "$BACKUP" "$MERGED"
 
-    base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'`
-    local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'`
-    remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'`
+    base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
+    local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
+    remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
 
     base_present   && checkout_staged_file 1 "$MERGED" "$BASE"
     local_present  && checkout_staged_file 2 "$MERGED" "$LOCAL"
@@ -188,97 +174,13 @@ merge_file () {
        read ans
     fi
 
-    case "$merge_tool" in
-       kdiff3)
-           if base_present ; then
-               ("$merge_tool_path" --auto --L1 "$MERGED (Base)" --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" \
-                   -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
-           else
-               ("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \
-                   -o "$MERGED" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
-           fi
-           status=$?
-           ;;
-       tkdiff)
-           if base_present ; then
-               "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"
-           else
-               "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
-           fi
-           status=$?
-           ;;
-       meld)
-           touch "$BACKUP"
-           "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
-           check_unchanged
-           ;;
-       vimdiff)
-           touch "$BACKUP"
-           "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE"
-           check_unchanged
-           ;;
-       gvimdiff)
-           touch "$BACKUP"
-           "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE"
-           check_unchanged
-           ;;
-       xxdiff)
-           touch "$BACKUP"
-           if base_present ; then
-               "$merge_tool_path" -X --show-merged-pane \
-                   -R 'Accel.SaveAsMerged: "Ctrl-S"' \
-                   -R 'Accel.Search: "Ctrl+F"' \
-                   -R 'Accel.SearchForward: "Ctrl-G"' \
-                   --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
-           else
-               "$merge_tool_path" -X --show-merged-pane \
-                   -R 'Accel.SaveAsMerged: "Ctrl-S"' \
-                   -R 'Accel.Search: "Ctrl+F"' \
-                   -R 'Accel.SearchForward: "Ctrl-G"' \
-                   --merged-file "$MERGED" "$LOCAL" "$REMOTE"
-           fi
-           check_unchanged
-           ;;
-       opendiff)
-           touch "$BACKUP"
-           if base_present; then
-               "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat
-           else
-               "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat
-           fi
-           check_unchanged
-           ;;
-       ecmerge)
-           touch "$BACKUP"
-           if base_present; then
-               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"
-           else
-               "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"
-           fi
-           check_unchanged
-           ;;
-       emerge)
-           if base_present ; then
-               "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")"
-           else
-               "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
-           fi
-           status=$?
-           ;;
-       *)
-           if test -n "$merge_tool_cmd"; then
-               if test "$merge_tool_trust_exit_code" = "false"; then
-                   touch "$BACKUP"
-                   ( eval $merge_tool_cmd )
-                   check_unchanged
-               else
-                   ( eval $merge_tool_cmd )
-                   status=$?
-               fi
-           fi
-           ;;
-    esac
-    if test "$status" -ne 0; then
+    if base_present; then
+           present=true
+    else
+           present=false
+    fi
+
+    if ! run_merge_tool "$merge_tool" "$present"; then
        echo "merge of $MERGED failed" 1>&2
        mv -- "$BACKUP" "$MERGED"
 
@@ -308,7 +210,7 @@ do
        -t|--tool*)
            case "$#,$1" in
                *,*=*)
-                   merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+                   merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
                    ;;
                1,*)
                    usage ;;
@@ -337,38 +239,6 @@ do
     shift
 done
 
-valid_custom_tool()
-{
-    merge_tool_cmd="$(git config mergetool.$1.cmd)"
-    test -n "$merge_tool_cmd"
-}
-
-valid_tool() {
-       case "$1" in
-               kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
-                       ;; # happy
-               *)
-                       if ! valid_custom_tool "$1"; then
-                               return 1
-                       fi
-                       ;;
-       esac
-}
-
-init_merge_tool_path() {
-       merge_tool_path=`git config mergetool.$1.path`
-       if test -z "$merge_tool_path" ; then
-               case "$1" in
-                       emerge)
-                               merge_tool_path=emacs
-                               ;;
-                       *)
-                               merge_tool_path=$1
-                               ;;
-               esac
-       fi
-}
-
 prompt_after_failed_merge() {
     while true; do
        printf "Continue merging other unresolved paths (y/n) ? "
@@ -387,67 +257,16 @@ prompt_after_failed_merge() {
 }
 
 if test -z "$merge_tool"; then
-    merge_tool=`git config merge.tool`
-    if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
-           echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
-           echo >&2 "Resetting to default..."
-           unset merge_tool
-    fi
-fi
-
-if test -z "$merge_tool" ; then
-    if test -n "$DISPLAY"; then
-        if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
-            merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff"
-        else
-            merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff"
-        fi
-    fi
-    if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
-        merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
-    elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
-        merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
-    else
-        merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
-    fi
-    echo "merge tool candidates: $merge_tool_candidates"
-    for i in $merge_tool_candidates; do
-        init_merge_tool_path $i
-        if type "$merge_tool_path" > /dev/null 2>&1; then
-            merge_tool=$i
-            break
-        fi
-    done
-    if test -z "$merge_tool" ; then
-       echo "No known merge resolution program available."
-       exit 1
-    fi
-else
-    if ! valid_tool "$merge_tool"; then
-        echo >&2 "Unknown merge_tool $merge_tool"
-        exit 1
-    fi
-
-    init_merge_tool_path "$merge_tool"
-
-    merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
-    merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
-
-    if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
-        echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
-        exit 1
-    fi
-
-    if ! test -z "$merge_tool_cmd"; then
-        merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)"
-    fi
+    merge_tool=$(get_merge_tool "$merge_tool") || exit
 fi
+merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
+merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
 
 last_status=0
 rollup_status=0
 
 if test $# -eq 0 ; then
-    files=`git ls-files -u | sed -e 's/^[^     ]*      //' | sort -u`
+    files=$(git ls-files -u | sed -e 's/^[^    ]*      //' | sort -u)
     if test -z "$files" ; then
        echo "No files need merging"
        exit 0
index 695a4094bb4230341618bd6f16d0bea9bff2e826..a296719861ec3b7aab5e530e67dc99b58267a56a 100755 (executable)
@@ -2,7 +2,7 @@
 
 # git-ls-remote could be called from outside a git managed repository;
 # this would fail in that case and would issue an error message.
-GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || :;
+GIT_DIR=$(git rev-parse -q --git-dir) || :;
 
 get_data_source () {
        case "$1" in
index 8c750270e9ee1466180c2fbbc8e688d5131a17fe..35261539ab80ffa46fef945dce1a82c5636c1b49 100755 (executable)
@@ -147,7 +147,7 @@ then
        echo >&2 "Warning: fetch updated the current branch head."
        echo >&2 "Warning: fast forwarding your working tree from"
        echo >&2 "Warning: commit $orig_head."
-       git update-index --refresh 2>/dev/null
+       git update-index -q --refresh
        git read-tree -u -m "$orig_head" "$curr_head" ||
                die 'Cannot fast-forward your working tree.
 After making sure that you saved anything precious from
index 04267c58dd81075233a165bba307e0ddee5a7611..3d6a98218a23cdda4a4cf3752c5a0f7030c2bad5 100755 (executable)
@@ -210,6 +210,7 @@ my %config_settings = (
     "envelopesender" => \$envelope_sender,
     "multiedit" => \$multiedit,
     "confirm"   => \$confirm,
+    "from" => \$sender,
 );
 
 # Handle Uncouth Termination
@@ -409,7 +410,7 @@ my %parse_alias = (
        mailrc => sub { my $fh = shift; while (<$fh>) {
                if (/^alias\s+(\S+)\s+(.*)$/) {
                        # spaces delimit multiple addresses
-                       $aliases{$1} = [ split(/\s+/, $2) ];
+                       $aliases{$1} = [ quotewords('\s+', 0, $2) ];
                }}},
        pine => sub { my $fh = shift; my $f='\t[^\t]*';
                for (my $x = ''; defined($x); $x = $_) {
@@ -418,6 +419,14 @@ my %parse_alias = (
                        $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
                        $aliases{$1} = [ split_addrs($2) ];
                }},
+       elm => sub  { my $fh = shift;
+                     while (<$fh>) {
+                         if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
+                             my ($alias, $addr) = ($1, $2);
+                              $aliases{$alias} = [ split_addrs($addr) ];
+                         }
+                     } },
+
        gnus => sub { my $fh = shift; while (<$fh>) {
                if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
                        $aliases{$1} = [ $2 ];
index 7c2e060ae770710ed7ed27d0aed4cfd2e8145810..ab1ed02a663b7e6252fe33f5224cb9653bcd50f2 100755 (executable)
@@ -15,6 +15,7 @@ require_work_tree
 command=
 branch=
 quiet=
+reference=
 cached=
 nofetch=
 
@@ -91,6 +92,7 @@ module_clone()
 {
        path=$1
        url=$2
+       reference="$3"
 
        # If there already is a directory at the submodule path,
        # expect it to be empty (since that is the default checkout
@@ -106,7 +108,12 @@ module_clone()
        test -e "$path" &&
        die "A file already exist at path '$path'"
 
-       git-clone -n "$url" "$path" ||
+       if test -n "$reference"
+       then
+               git-clone "$reference" -n "$url" "$path"
+       else
+               git-clone -n "$url" "$path"
+       fi ||
        die "Clone of '$url' into submodule path '$path' failed"
 }
 
@@ -131,6 +138,15 @@ cmd_add()
                -q|--quiet)
                        quiet=1
                        ;;
+               --reference)
+                       case "$2" in '') usage ;; esac
+                       reference="--reference=$2"
+                       shift
+                       ;;
+               --reference=*)
+                       reference="$1"
+                       shift
+                       ;;
                --)
                        shift
                        break
@@ -203,9 +219,16 @@ cmd_add()
                git config submodule."$path".url "$url"
        else
 
-               module_clone "$path" "$realrepo" || exit
-               (unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) ||
-               die "Unable to checkout submodule '$path'"
+               module_clone "$path" "$realrepo" "$reference" || exit
+               (
+                       unset GIT_DIR
+                       cd "$path" &&
+                       # ash fails to wordsplit ${branch:+-b "$branch"...}
+                       case "$branch" in
+                       '') git checkout -f -q ;;
+                       ?*) git checkout -f -q -b "$branch" "origin/$branch" ;;
+                       esac
+               ) || die "Unable to checkout submodule '$path'"
        fi
 
        git add "$path" ||
@@ -307,13 +330,22 @@ cmd_update()
                        quiet=1
                        ;;
                -i|--init)
+                       init=1
                        shift
-                       cmd_init "$@" || return
                        ;;
                -N|--no-fetch)
                        shift
                        nofetch=1
                        ;;
+               --reference)
+                       case "$2" in '') usage ;; esac
+                       reference="--reference=$2"
+                       shift 2
+                       ;;
+               --reference=*)
+                       reference="$1"
+                       shift
+                       ;;
                --)
                        shift
                        break
@@ -327,6 +359,11 @@ cmd_update()
                esac
        done
 
+       if test -n "$init"
+       then
+               cmd_init "--" "$@" || return
+       fi
+
        module_list "$@" |
        while read mode sha1 stage path
        do
@@ -344,7 +381,7 @@ cmd_update()
 
                if ! test -d "$path"/.git -o -f "$path"/.git
                then
-                       module_clone "$path" "$url" || exit
+                       module_clone "$path" "$url" "$reference"|| exit
                        subsha1=
                else
                        subsha1=$(unset GIT_DIR; cd "$path" &&
index c5965c9aafe8d5f990e64e88cea1061f84584b58..33017974d0a098bdaff707ccf0e8660aa5009079 100755 (executable)
@@ -5,7 +5,7 @@ use warnings;
 use strict;
 use vars qw/   $AUTHOR $VERSION
                $sha1 $sha1_short $_revision $_repository
-               $_q $_authors %users/;
+               $_q $_authors $_authors_prog %users/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';
 
@@ -39,6 +39,7 @@ use Digest::MD5;
 use IO::File qw//;
 use File::Basename qw/dirname basename/;
 use File::Path qw/mkpath/;
+use File::Spec;
 use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
 use IPC::Open3;
 use Git;
@@ -76,6 +77,7 @@ my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                     'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex );
 my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
                'authors-file|A=s' => \$_authors,
+               'authors-prog=s' => \$_authors_prog,
                'repack:i' => \$Git::SVN::_repack,
                'noMetadata' => \$Git::SVN::_no_metadata,
                'useSvmProps' => \$Git::SVN::_use_svm_props,
@@ -147,7 +149,7 @@ my %cmd = (
                   'dry-run|n' => \$_dry_run } ],
        'set-tree' => [ \&cmd_set_tree,
                        "Set an SVN repository to a git tree-ish",
-                       { 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ],
+                       { 'stdin' => \$_stdin, %cmt_opts, %fc_opts, } ],
        'create-ignore' => [ \&cmd_create_ignore,
                             'Create a .gitignore per svn:ignore',
                             { 'revision|r=i' => \$_revision
@@ -263,6 +265,9 @@ usage(0) if $_help;
 version() if $_version;
 usage(1) unless defined $cmd;
 load_authors() if $_authors;
+if (defined $_authors_prog) {
+       $_authors_prog = "'" . File::Spec->rel2abs($_authors_prog) . "'";
+}
 
 unless ($cmd =~ /^(?:clone|init|multi-init|commit-diff)$/) {
        Git::SVN::Migration::migration_check();
@@ -361,6 +366,7 @@ sub cmd_clone {
        $path = basename($url) if !defined $path || !length $path;
        cmd_init($url, $path);
        Git::SVN::fetch_all($Git::SVN::default_repo_id);
+       command_oneline('config', 'svn.authorsfile', $_authors) if $_authors;
 }
 
 sub cmd_init {
@@ -1172,16 +1178,27 @@ sub get_commit_entry {
        }
        rename $commit_editmsg, $commit_msg or croak $!;
        {
+               require Encode;
                # SVN requires messages to be UTF-8 when entering the repo
                local $/;
                open $log_fh, '<', $commit_msg or croak $!;
                binmode $log_fh;
                chomp($log_entry{log} = <$log_fh>);
 
-               if (my $enc = Git::config('i18n.commitencoding')) {
-                       require Encode;
-                       Encode::from_to($log_entry{log}, $enc, 'UTF-8');
+               my $enc = Git::config('i18n.commitencoding') || 'UTF-8';
+               my $msg = $log_entry{log};
+
+               eval { $msg = Encode::decode($enc, $msg, 1) };
+               if ($@) {
+                       die "Could not decode as $enc:\n", $msg,
+                           "\nPerhaps you need to set i18n.commitencoding\n";
                }
+
+               eval { $msg = Encode::encode('UTF-8', $msg, 1) };
+               die "Could not encode as UTF-8:\n$msg\n" if $@;
+
+               $log_entry{log} = $msg;
+
                close $log_fh or croak $!;
        }
        unlink $commit_msg;
@@ -2663,12 +2680,33 @@ sub other_gs {
        $gs
 }
 
+sub call_authors_prog {
+       my ($orig_author) = @_;
+       my $author = `$::_authors_prog $orig_author`;
+       if ($? != 0) {
+               die "$::_authors_prog failed with exit code $?\n"
+       }
+       if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
+               my ($name, $email) = ($1, $2);
+               $email = undef if length $2 == 0;
+               return [$name, $email];
+       } else {
+               die "Author: $orig_author: $::_authors_prog returned "
+                       . "invalid author format: $author\n";
+       }
+}
+
 sub check_author {
        my ($author) = @_;
        if (!defined $author || length $author == 0) {
                $author = '(no author)';
-       } elsif (defined $::_authors && ! defined $::users{$author}) {
-               die "Author: $author not defined in $::_authors file\n";
+       }
+       if (!defined $::users{$author}) {
+               if (defined $::_authors_prog) {
+                       $::users{$author} = call_authors_prog($author);
+               } elsif (defined $::_authors) {
+                       die "Author: $author not defined in $::_authors file\n";
+               }
        }
        $author;
 }
@@ -4438,6 +4476,7 @@ sub gs_fetch_loop_common {
        my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
        my $longest_path = longest_common_path($gsv, $globs);
        my $ra_url = $self->{url};
+       my $find_trailing_edge;
        while (1) {
                my %revs;
                my $err;
@@ -4455,8 +4494,10 @@ sub gs_fetch_loop_common {
                               sub { $revs{$_[1]} = _cb(@_) });
                if ($err) {
                        print "Checked through r$max\r";
+               } else {
+                       $find_trailing_edge = 1;
                }
-               if ($err && $max >= $head) {
+               if ($err and $find_trailing_edge) {
                        print STDERR "Path '$longest_path' ",
                                     "was probably deleted:\n",
                                     $err->expanded_message,
@@ -4468,13 +4509,14 @@ sub gs_fetch_loop_common {
                                my $ok;
                                $self->get_log([$longest_path], $min, $hi,
                                               0, 1, 1, sub {
-                                              $ok ||= $_[1];
+                                              $ok = $_[1];
                                               $revs{$_[1]} = _cb(@_) });
                                if ($ok) {
                                        print STDERR "r$min .. r$ok OK\n";
                                        last;
                                }
                        }
+                       $find_trailing_edge = 0;
                }
                $SVN::Error::handler = $err_handler;
 
diff --git a/git.c b/git.c
index bfb6508ad0f0a49b6e7006619920fd00e768d7f3..5a00726d09a13d5f70ab0378e02bbbd299124d5c 100644 (file)
--- a/git.c
+++ b/git.c
@@ -47,7 +47,7 @@ static void commit_pager_choice(void) {
        }
 }
 
-static int handle_options(const char*** argv, int* argc, int* envchanged)
+static int handle_options(const char ***argv, int *argc, int *envchanged)
 {
        int handled = 0;
 
@@ -136,7 +136,7 @@ static int handle_alias(int *argcp, const char ***argv)
        int envchanged = 0, ret = 0, saved_errno = errno;
        const char *subdir;
        int count, option_count;
-       const char** new_argv;
+       const char **new_argv;
        const char *alias_command;
        char *alias_string;
        int unused_nongit;
@@ -187,10 +187,10 @@ static int handle_alias(int *argcp, const char ***argv)
                                  "trace: alias expansion: %s =>",
                                  alias_command);
 
-               new_argv = xrealloc(new_argv, sizeof(char*) *
+               new_argv = xrealloc(new_argv, sizeof(char *) *
                                    (count + *argcp + 1));
                /* insert after command name */
-               memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp);
+               memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
                new_argv[count+*argcp] = NULL;
 
                *argv = new_argv;
@@ -497,7 +497,7 @@ int main(int argc, const char **argv)
 
        /*
         * We use PATH to find git commands, but we prepend some higher
-        * precidence paths: the "--exec-path" option, the GIT_EXEC_PATH
+        * precedence paths: the "--exec-path" option, the GIT_EXEC_PATH
         * environment, and the $(gitexecdir) from the Makefile at build
         * time.
         */
index 1773ae63eb54f3b602b782a3633034aab2f828ae..1a7887b2528140d63b84a72843c0d0ef64f56538 100644 (file)
@@ -521,7 +521,7 @@ proc updatecommits {} {
     incr viewactive($view)
     set viewcomplete($view) 0
     reset_pending_select {}
-    nowbusy $view "Reading"
+    nowbusy $view [mc "Reading"]
     if {$showneartags} {
        getallcommits
     }
@@ -1830,7 +1830,9 @@ proc setoptions {} {
     option add *Button.font uifont startupFile
     option add *Checkbutton.font uifont startupFile
     option add *Radiobutton.font uifont startupFile
-    option add *Menu.font uifont startupFile
+    if {[tk windowingsystem] ne "aqua"} {
+       option add *Menu.font uifont startupFile
+    }
     option add *Menubutton.font uifont startupFile
     option add *Label.font uifont startupFile
     option add *Message.font uifont startupFile
@@ -1910,8 +1912,8 @@ proc makewindow {} {
 
     # The "mc" arguments here are purely so that xgettext
     # sees the following string as needing to be translated
-    makemenu .bar {
-       {mc "File" cascade {
+    set file {
+       mc "File" cascade {
            {mc "Update" command updatecommits -accelerator F5}
            {mc "Reload" command reloadcommits -accelerator Meta1-F5}
            {mc "Reread references" command rereadrefs}
@@ -1921,21 +1923,41 @@ proc makewindow {} {
            {xx "" separator}
            {mc "Quit" command doquit -accelerator Meta1-Q}
        }}
-       {mc "Edit" cascade {
+    set edit {
+       mc "Edit" cascade {
            {mc "Preferences" command doprefs}
        }}
-       {mc "View" cascade {
+    set view {
+       mc "View" cascade {
            {mc "New view..." command {newview 0} -accelerator Shift-F4}
            {mc "Edit view..." command editview -state disabled -accelerator F4}
            {mc "Delete view" command delview -state disabled}
            {xx "" separator}
            {mc "All files" radiobutton {selectedview 0} -command {showview 0}}
        }}
-       {mc "Help" cascade {
+    if {[tk windowingsystem] ne "aqua"} {
+       set help {
+       mc "Help" cascade {
            {mc "About gitk" command about}
            {mc "Key bindings" command keys}
        }}
+       set bar [list $file $edit $view $help]
+    } else {
+       proc ::tk::mac::ShowPreferences {} {doprefs}
+       proc ::tk::mac::Quit {} {doquit}
+       lset file end [lreplace [lindex $file end] end-1 end]
+       set apple {
+       xx "Apple" cascade {
+           {mc "About gitk" command about}
+           {xx "" separator}
+       }}
+       set help {
+       mc "Help" cascade {
+           {mc "Key bindings" command keys}
+       }}
+       set bar [list $apple $file $view $help]
     }
+    makemenu .bar $bar
     . configure -menu .bar
 
     # the gui has upper and lower half, parts of a paned window.
@@ -2229,10 +2251,16 @@ proc makewindow {} {
        }
     }
 
+    if {[info exists geometry(state)] && $geometry(state) eq "zoomed"} {
+        wm state . $geometry(state)
+    }
+
     if {[tk windowingsystem] eq {aqua}} {
         set M1B M1
+        set ::BM "3"
     } else {
         set M1B Control
+        set ::BM "2"
     }
 
     bind .pwbottom <Configure> {resizecdetpanes %W %w}
@@ -2250,10 +2278,14 @@ proc makewindow {} {
                 set delta [expr {- (%D)}]
                 allcanvs yview scroll $delta units
             }
+            bindall <Shift-MouseWheel> {
+                set delta [expr {- (%D)}]
+                $canv xview scroll $delta units
+            }
         }
     }
-    bindall <2> "canvscan mark %W %x %y"
-    bindall <B2-Motion> "canvscan dragto %W %x %y"
+    bindall <$::BM> "canvscan mark %W %x %y"
+    bindall <B$::BM-Motion> "canvscan dragto %W %x %y"
     bindkey <Home> selfirstline
     bindkey <End> sellastline
     bind . <Key-Up> "selnextline -1"
@@ -2285,6 +2317,7 @@ proc makewindow {} {
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
     bindkey / {focus $fstring}
+    bindkey <Key-KP_Divide> {focus $fstring}
     bindkey <Key-Return> {dofind 1 1}
     bindkey ? {dofind -1 1}
     bindkey f nextfile
@@ -2331,6 +2364,10 @@ proc makewindow {} {
        {mc "Create new branch" command mkbranch}
        {mc "Cherry-pick this commit" command cherrypick}
        {mc "Reset HEAD branch to here" command resethead}
+       {mc "Mark this commit" command markhere}
+       {mc "Return to mark" command gotomark}
+       {mc "Find descendant of this and mark" command find_common_desc}
+       {mc "Compare with marked commit" command compare_commits}
     }
     $rowctxmenu configure -tearoff 0
 
@@ -2487,6 +2524,9 @@ proc savestuff {w} {
     if {![winfo viewable .]} return
     catch {
        set f [open "~/.gitk-new" w]
+       if {$::tcl_platform(platform) eq {windows}} {
+           file attributes "~/.gitk-new" -hidden true
+       }
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
        puts $f [list set uifont $uifont]
@@ -2512,6 +2552,7 @@ proc savestuff {w} {
        puts $f [list set perfile_attrs $perfile_attrs]
 
        puts $f "set geometry(main) [wm geometry .]"
+       puts $f "set geometry(state) [wm state .]"
        puts $f "set geometry(topwidth) [winfo width .tf]"
        puts $f "set geometry(topheight) [winfo height .tf]"
         puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\""
@@ -3204,9 +3245,8 @@ proc external_diff {} {
     set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir]
 
     if {$difffromfile ne {} && $difftofile ne {}} {
-        set cmd [concat | [shellsplit $extdifftool] \
-                    [list $difffromfile $difftofile]]
-        if {[catch {set fl [open $cmd r]} err]} {
+        set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile]
+        if {[catch {set fl [open |$cmd r]} err]} {
             file delete -force $diffdir
             error_popup "$extdifftool: [mc "command failed:"] $err"
         } else {
@@ -3737,7 +3777,7 @@ proc editview {} {
     set newviewopts($curview,perm) $viewperm($curview)
     set newviewopts($curview,cmd)  $viewargscmd($curview)
     decode_view_opts $curview $viewargs($curview)
-    vieweditor $top $curview "Gitk: edit view $viewname($curview)"
+    vieweditor $top $curview "[mc "Gitk: edit view"] $viewname($curview)"
 }
 
 proc vieweditor {top n title} {
@@ -4046,7 +4086,7 @@ proc ishighlighted {id} {
 }
 
 proc bolden {id font} {
-    global canv linehtag currentid boldids need_redisplay
+    global canv linehtag currentid boldids need_redisplay markedid
 
     # need_redisplay = 1 means the display is stale and about to be redrawn
     if {$need_redisplay} return
@@ -4059,6 +4099,9 @@ proc bolden {id font} {
                   -fill [$canv cget -selectbackground]]
        $canv lower $t
     }
+    if {[info exists markedid] && $id eq $markedid} {
+       make_idmark $id
+    }
 }
 
 proc bolden_name {id font} {
@@ -5563,7 +5606,7 @@ proc drawcmittext {id row col} {
     global cmitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
     global linehtag linentag linedtag selectedline
-    global canvxmax boldids boldnameids fgcolor
+    global canvxmax boldids boldnameids fgcolor markedid
     global mainheadid nullid nullid2 circleitem circlecolors ctxbut
 
     # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right
@@ -5645,6 +5688,9 @@ proc drawcmittext {id row col} {
     if {$selectedline == $row} {
        make_secsel $id
     }
+    if {[info exists markedid] && $markedid eq $id} {
+       make_idmark $id
+    }
     set xr [expr {$xt + [font measure $font $headline]}]
     if {$xr > $canvxmax} {
        set canvxmax $xr
@@ -6443,6 +6489,17 @@ proc setlink {id lk} {
     }
 }
 
+proc appendshortlink {id {pre {}} {post {}}} {
+    global ctext linknum
+
+    $ctext insert end $pre
+    $ctext tag delete link$linknum
+    $ctext insert end [string range $id 0 7] link$linknum
+    $ctext insert end $post
+    setlink $id link$linknum
+    incr linknum
+}
+
 proc makelink {id} {
     global pendinglinks
 
@@ -6499,7 +6556,7 @@ proc appendrefs {pos ids var} {
        }
     }
     if {[llength $tags] > $maxrefs} {
-       $ctext insert $pos "many ([llength $tags])"
+       $ctext insert $pos "[mc "many"] ([llength $tags])"
     } else {
        set tags [lsort -index 0 -decreasing $tags]
        set sep {}
@@ -6586,6 +6643,16 @@ proc make_secsel {id} {
     $canv3 lower $t
 }
 
+proc make_idmark {id} {
+    global linehtag canv fgcolor
+
+    if {![info exists linehtag($id)]} return
+    $canv delete markid
+    set t [eval $canv create rect [$canv bbox $linehtag($id)] \
+              -tags markid -outline $fgcolor]
+    $canv raise $t
+}
+
 proc selectline {l isnew {desired_loc {}}} {
     global canv ctext commitinfo selectedline
     global canvy0 linespc parents children curview
@@ -7216,7 +7283,7 @@ proc getblobdiffs {ids} {
     set diffnparents 0
     set diffinhdr 0
     set diffencoding [get_path_encoding {}]
-    fconfigure $bdf -blocking 0 -encoding binary
+    fconfigure $bdf -blocking 0 -encoding binary -eofchar {}
     set blobdifffd($ids) $bdf
     filerun $bdf [list getblobdiffline $bdf $diffids]
 }
@@ -7367,7 +7434,8 @@ proc getblobdiffline {bdf ids} {
            $ctext insert end "$line\n" filesep
 
        } else {
-           set line [encoding convertfrom $diffencoding $line]
+           set line [string map {\x1A ^Z} \
+                          [encoding convertfrom $diffencoding $line]]
            # parse the prefix - one ' ', '-' or '+' for each parent
            set prefix [string range $line 0 [expr {$diffnparents - 1}]]
            set tag [expr {$diffnparents > 1? "m": "d"}]
@@ -7970,7 +8038,7 @@ proc mstime {} {
 
 proc rowmenu {x y id} {
     global rowctxmenu selectedline rowmenuid curview
-    global nullid nullid2 fakerowmenu mainhead
+    global nullid nullid2 fakerowmenu mainhead markedid
 
     stopfinding
     set rowmenuid $id
@@ -7986,6 +8054,15 @@ proc rowmenu {x y id} {
        } else {
            $menu entryconfigure 7 -label [mc "Detached head: can't reset" $mainhead] -state disabled
        }
+       if {[info exists markedid] && $markedid ne $id} {
+           $menu entryconfigure 9 -state normal
+           $menu entryconfigure 10 -state normal
+           $menu entryconfigure 11 -state normal
+       } else {
+           $menu entryconfigure 9 -state disabled
+           $menu entryconfigure 10 -state disabled
+           $menu entryconfigure 11 -state disabled
+       }
     } else {
        set menu $fakerowmenu
     }
@@ -7995,6 +8072,162 @@ proc rowmenu {x y id} {
     tk_popup $menu $x $y
 }
 
+proc markhere {} {
+    global rowmenuid markedid canv
+
+    set markedid $rowmenuid
+    make_idmark $markedid
+}
+
+proc gotomark {} {
+    global markedid
+
+    if {[info exists markedid]} {
+       selbyid $markedid
+    }
+}
+
+proc replace_by_kids {l r} {
+    global curview children
+
+    set id [commitonrow $r]
+    set l [lreplace $l 0 0]
+    foreach kid $children($curview,$id) {
+       lappend l [rowofcommit $kid]
+    }
+    return [lsort -integer -decreasing -unique $l]
+}
+
+proc find_common_desc {} {
+    global markedid rowmenuid curview children
+
+    if {![info exists markedid]} return
+    if {![commitinview $markedid $curview] ||
+       ![commitinview $rowmenuid $curview]} return
+    #set t1 [clock clicks -milliseconds]
+    set l1 [list [rowofcommit $markedid]]
+    set l2 [list [rowofcommit $rowmenuid]]
+    while 1 {
+       set r1 [lindex $l1 0]
+       set r2 [lindex $l2 0]
+       if {$r1 eq {} || $r2 eq {}} break
+       if {$r1 == $r2} {
+           selectline $r1 1
+           break
+       }
+       if {$r1 > $r2} {
+           set l1 [replace_by_kids $l1 $r1]
+       } else {
+           set l2 [replace_by_kids $l2 $r2]
+       }
+    }
+    #set t2 [clock clicks -milliseconds]
+    #puts "took [expr {$t2-$t1}]ms"
+}
+
+proc compare_commits {} {
+    global markedid rowmenuid curview children
+
+    if {![info exists markedid]} return
+    if {![commitinview $markedid $curview]} return
+    addtohistory [list do_cmp_commits $markedid $rowmenuid]
+    do_cmp_commits $markedid $rowmenuid
+}
+
+proc getpatchid {id} {
+    global patchids
+
+    if {![info exists patchids($id)]} {
+       set cmd [diffcmd [list $id] {-p --root}]
+       # trim off the initial "|"
+       set cmd [lrange $cmd 1 end]
+       if {[catch {
+           set x [eval exec $cmd | git patch-id]
+           set patchids($id) [lindex $x 0]
+       }]} {
+           set patchids($id) "error"
+       }
+    }
+    return $patchids($id)
+}
+
+proc do_cmp_commits {a b} {
+    global ctext curview parents children patchids commitinfo
+
+    $ctext conf -state normal
+    clear_ctext
+    init_flist {}
+    for {set i 0} {$i < 100} {incr i} {
+       set skipa 0
+       set skipb 0
+       if {[llength $parents($curview,$a)] > 1} {
+           appendshortlink $a [mc "Skipping merge commit "] "\n"
+           set skipa 1
+       } else {
+           set patcha [getpatchid $a]
+       }
+       if {[llength $parents($curview,$b)] > 1} {
+           appendshortlink $b [mc "Skipping merge commit "] "\n"
+           set skipb 1
+       } else {
+           set patchb [getpatchid $b]
+       }
+       if {!$skipa && !$skipb} {
+           set heada [lindex $commitinfo($a) 0]
+           set headb [lindex $commitinfo($b) 0]
+           if {$patcha eq "error"} {
+               appendshortlink $a [mc "Error getting patch ID for "] \
+                   [mc " - stopping\n"]
+               break
+           }
+           if {$patchb eq "error"} {
+               appendshortlink $b [mc "Error getting patch ID for "] \
+                   [mc " - stopping\n"]
+               break
+           }
+           if {$patcha eq $patchb} {
+               if {$heada eq $headb} {
+                   appendshortlink $a [mc "Commit "]
+                   appendshortlink $b " == " "  $heada\n"
+               } else {
+                   appendshortlink $a [mc "Commit "] "  $heada\n"
+                   appendshortlink $b [mc " is the same patch as\n       "] \
+                       "  $headb\n"
+               }
+               set skipa 1
+               set skipb 1
+           } else {
+               $ctext insert end "\n"
+               appendshortlink $a [mc "Commit "] "  $heada\n"
+               appendshortlink $b [mc " differs from\n       "] \
+                   "  $headb\n"
+               $ctext insert end [mc "- stopping\n"]
+               break
+           }
+       }
+       if {$skipa} {
+           if {[llength $children($curview,$a)] != 1} {
+               $ctext insert end "\n"
+               appendshortlink $a [mc "Commit "] \
+                   [mc " has %s children - stopping\n" \
+                        [llength $children($curview,$a)]]
+               break
+           }
+           set a [lindex $children($curview,$a) 0]
+       }
+       if {$skipb} {
+           if {[llength $children($curview,$b)] != 1} {
+               appendshortlink $b [mc "Commit "] \
+                   [mc " has %s children - stopping\n" \
+                        [llength $children($curview,$b)]]
+               break
+           }
+           set b [lindex $children($curview,$b) 0]
+       }
+    }
+    $ctext conf -state disabled
+}
+
 proc diffvssel {dirn} {
     global rowmenuid selectedline
 
@@ -8189,7 +8422,7 @@ proc domktag {} {
 }
 
 proc redrawtags {id} {
-    global canv linehtag idpos currentid curview cmitlisted
+    global canv linehtag idpos currentid curview cmitlisted markedid
     global canvxmax iddrawn circleitem mainheadid circlecolors
 
     if {![commitinview $id $curview]} return
@@ -8214,6 +8447,9 @@ proc redrawtags {id} {
     if {[info exists currentid] && $currentid == $id} {
        make_secsel $id
     }
+    if {[info exists markedid] && $markedid eq $id} {
+       make_idmark $id
+    }
 }
 
 proc mktagcan {} {
@@ -10197,7 +10433,7 @@ proc doprefs {} {
 proc choose_extdiff {} {
     global extdifftool
 
-    set prog [tk_getOpenFile -title "External diff tool" -multiple false]
+    set prog [tk_getOpenFile -title [mc "External diff tool"] -multiple false]
     if {$prog ne {}} {
        set extdifftool $prog
     }
@@ -10240,6 +10476,7 @@ proc setfg {c} {
     }
     allcanvs itemconf text -fill $c
     $canv itemconf circle -outline $c
+    $canv itemconf markid -outline $c
 }
 
 proc prefscan {} {
@@ -10689,9 +10926,15 @@ catch {
     }
 }
 
-set mainfont {Helvetica 9}
-set textfont {Courier 9}
-set uifont {Helvetica 9 bold}
+if {[tk windowingsystem] eq "aqua"} {
+    set mainfont {{Lucida Grande} 9}
+    set textfont {Monaco 9}
+    set uifont {{Lucida Grande} 9 bold}
+} else {
+    set mainfont {Helvetica 9}
+    set textfont {Courier 9}
+    set uifont {Helvetica 9 bold}
+}
 set tabstop 8
 set findmergefiles 0
 set maxgraphpct 50
@@ -10712,7 +10955,11 @@ set datetimeformat "%Y-%m-%d %H:%M:%S"
 set autoselect 1
 set perfile_attrs 0
 
-set extdifftool "meld"
+if {[tk windowingsystem] eq "aqua"} {
+    set extdifftool "opendiff"
+} else {
+    set extdifftool "meld"
+}
 
 set colors {green red blue magenta darkgrey brown orange}
 set bgcolor white
@@ -10883,9 +11130,33 @@ set lserial 0
 set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
 setcoords
 makewindow
+catch {
+    image create photo gitlogo      -width 16 -height 16
+
+    image create photo gitlogominus -width  4 -height  2
+    gitlogominus put #C00000 -to 0 0 4 2
+    gitlogo copy gitlogominus -to  1 5
+    gitlogo copy gitlogominus -to  6 5
+    gitlogo copy gitlogominus -to 11 5
+    image delete gitlogominus
+
+    image create photo gitlogoplus  -width  4 -height  4
+    gitlogoplus  put #008000 -to 1 0 3 4
+    gitlogoplus  put #008000 -to 0 1 4 3
+    gitlogo copy gitlogoplus  -to  1 9
+    gitlogo copy gitlogoplus  -to  6 9
+    gitlogo copy gitlogoplus  -to 11 9
+    image delete gitlogoplus
+
+    image create photo gitlogo32    -width 32 -height 32
+    gitlogo32 copy gitlogo -zoom 2 2
+
+    wm iconphoto . -default gitlogo gitlogo32
+}
 # wait for the window to become visible
 tkwait visibility .
 wm title . "[file tail $argv0]: [file tail [pwd]]"
+update
 readrefs
 
 if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} {
diff --git a/gitk-git/po/ru.po b/gitk-git/po/ru.po
new file mode 100644 (file)
index 0000000..704eba8
--- /dev/null
@@ -0,0 +1,1085 @@
+#
+# Translation of gitk to Russian.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gitk\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-04-24 16:00+0200\n"
+"PO-Revision-Date: 2009-04-24 16:00+0200\n"
+"Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n"
+"Language-Team: Russian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: gitk:113
+msgid "Couldn't get list of unmerged files:"
+msgstr ""
+"Невозможно получить список файлов незавершённой операции слияния:"
+
+#: gitk:268
+msgid "Error parsing revisions:"
+msgstr "Ошибка в идентификаторе версии:"
+
+#: gitk:323
+msgid "Error executing --argscmd command:"
+msgstr "Ошибка выполнения команды заданой --argscmd:"
+
+#: gitk:336
+msgid "No files selected: --merge specified but no files are unmerged."
+msgstr ""
+"Файлы не выбраны: указан --merge, но не было найдено ни одного файла "
+"где эта операция должна быть завершена."
+
+#: gitk:339
+msgid ""
+"No files selected: --merge specified but no unmerged files are within file "
+"limit."
+msgstr ""
+"Файлы не выбраны: указан --merge, но в рамках указаного "
+"ограничения на имена файлов нет ни одного "
+"где эта операция должна быть завершена."
+
+#: gitk:361 gitk:508
+msgid "Error executing git log:"
+msgstr "Ошибка запуска git log:"
+
+#: gitk:379
+msgid "Reading"
+msgstr "Чтение"
+
+#: gitk:439 gitk:4021
+msgid "Reading commits..."
+msgstr "Чтение версий..."
+
+#: gitk:442 gitk:1560 gitk:4024
+msgid "No commits selected"
+msgstr "Ничего не выбрано"
+
+#: gitk:1436
+msgid "Can't parse git log output:"
+msgstr "Ошибка обработки вывода команды git log:"
+
+#: gitk:1656
+msgid "No commit information available"
+msgstr "Нет информации о состоянии"
+
+#: gitk:1791 gitk:1815 gitk:3814 gitk:8478 gitk:10014 gitk:10186
+msgid "OK"
+msgstr "Ok"
+
+#: gitk:1817 gitk:3816 gitk:8078 gitk:8152 gitk:8259 gitk:8308 gitk:8480
+#: gitk:10015 gitk:10187
+msgid "Cancel"
+msgstr "Отмена"
+
+#: gitk:1915
+msgid "Update"
+msgstr "Обновить"
+
+#: gitk:1916
+msgid "Reload"
+msgstr "Перечитать"
+
+#: gitk:1917
+msgid "Reread references"
+msgstr "Обновить список ссылок"
+
+#: gitk:1918
+msgid "List references"
+msgstr "Список ссылок"
+
+#: gitk:1920
+msgid "Start git gui"
+msgstr "Запустить git gui"
+
+#: gitk:1922
+msgid "Quit"
+msgstr "Завершить"
+
+#: gitk:1914
+msgid "File"
+msgstr "Файл"
+
+#: gitk:1925
+msgid "Preferences"
+msgstr "Настройки"
+
+#: gitk:1924
+msgid "Edit"
+msgstr "Редактировать"
+
+#: gitk:1928
+msgid "New view..."
+msgstr "Новое представление..."
+
+#: gitk:1929
+msgid "Edit view..."
+msgstr "Редактировать представление..."
+
+#: gitk:1930
+msgid "Delete view"
+msgstr "Удалить представление"
+
+#: gitk:1932
+msgid "All files"
+msgstr "Все файлы"
+
+#: gitk:1927 gitk:3626
+msgid "View"
+msgstr "Представление"
+
+#: gitk:1935 gitk:2609
+msgid "About gitk"
+msgstr "О gitk"
+
+#: gitk:1936
+msgid "Key bindings"
+msgstr "Назначения клавиатуры"
+
+#: gitk:1934
+msgid "Help"
+msgstr "Подсказка"
+
+#: gitk:1994
+msgid "SHA1 ID: "
+msgstr "SHA1:"
+
+#: gitk:2025
+msgid "Row"
+msgstr "Строка"
+
+#: gitk:2056
+msgid "Find"
+msgstr "Поиск"
+
+#: gitk:2057
+msgid "next"
+msgstr "След."
+
+#: gitk:2058
+msgid "prev"
+msgstr "Пред."
+
+#: gitk:2059
+msgid "commit"
+msgstr "состояние"
+
+#: gitk:2062 gitk:2064 gitk:4179 gitk:4202 gitk:4226 gitk:6164 gitk:6236
+#: gitk:6320
+msgid "containing:"
+msgstr "содержащее:"
+
+#: gitk:2065 gitk:3117 gitk:3122 gitk:4254
+msgid "touching paths:"
+msgstr "касательно файлов:"
+
+#: gitk:2066 gitk:4259
+msgid "adding/removing string:"
+msgstr "добавив/удалив строку:"
+
+#: gitk:2075 gitk:2077
+msgid "Exact"
+msgstr "Точно"
+
+#: gitk:2077 gitk:4334 gitk:6132
+msgid "IgnCase"
+msgstr "Игнорировать большие/маленькие"
+
+#: gitk:2077 gitk:4228 gitk:4332 gitk:6128
+msgid "Regexp"
+msgstr "Регулярные выражения"
+
+#: gitk:2079 gitk:2080 gitk:4353 gitk:4383 gitk:4390 gitk:6256 gitk:6324
+msgid "All fields"
+msgstr "Во всех полях"
+
+#: gitk:2080 gitk:4351 gitk:4383 gitk:6195
+msgid "Headline"
+msgstr "Заголовок"
+
+#: gitk:2081 gitk:4351 gitk:6195 gitk:6324 gitk:6737
+msgid "Comments"
+msgstr "Комментарии"
+
+#: gitk:2081 gitk:4351 gitk:4355 gitk:4390 gitk:6195 gitk:6672 gitk:7923
+#: gitk:7938
+msgid "Author"
+msgstr "Автор"
+
+#: gitk:2081 gitk:4351 gitk:6195 gitk:6674
+msgid "Committer"
+msgstr "Сохранивший состояние"
+
+#: gitk:2110
+msgid "Search"
+msgstr "Найти"
+
+#: gitk:2117
+msgid "Diff"
+msgstr "Сравнить"
+
+#: gitk:2119
+msgid "Old version"
+msgstr "Старая версия"
+
+#: gitk:2121
+msgid "New version"
+msgstr "Новая версия"
+
+#: gitk:2123
+msgid "Lines of context"
+msgstr "Строк контекста"
+
+#: gitk:2133
+msgid "Ignore space change"
+msgstr "Игнорировать пробелы"
+
+#: gitk:2191
+msgid "Patch"
+msgstr "Патч"
+
+#: gitk:2193
+msgid "Tree"
+msgstr "Файлы"
+
+#: gitk:2326 gitk:2339
+msgid "Diff this -> selected"
+msgstr "Сравнить это состояние с выделеным"
+
+#: gitk:2327 gitk:2340
+msgid "Diff selected -> this"
+msgstr "Сравнить выделеное с этим состоянием"
+
+#: gitk:2328 gitk:2341
+msgid "Make patch"
+msgstr "Создать патч"
+
+#: gitk:2329 gitk:8136
+msgid "Create tag"
+msgstr "Создать метку"
+
+#: gitk:2330 gitk:8239
+msgid "Write commit to file"
+msgstr "Сохранить изменения в файл"
+
+#: gitk:2331 gitk:8296
+msgid "Create new branch"
+msgstr "Создать ветвь"
+
+#: gitk:2332
+msgid "Cherry-pick this commit"
+msgstr "Скопировать это состояние"
+
+#: gitk:2333
+msgid "Reset HEAD branch to here"
+msgstr "Установить HEAD на это состояние"
+
+#: gitk:2347
+msgid "Check out this branch"
+msgstr "Перейти на эту ветвь"
+
+#: gitk:2348
+msgid "Remove this branch"
+msgstr "Удалить эту ветвь"
+
+#: gitk:2355
+msgid "Highlight this too"
+msgstr "Подсветить этот тоже"
+
+#: gitk:2356
+msgid "Highlight this only"
+msgstr "Подсветить только этот"
+
+#: gitk:2357
+msgid "External diff"
+msgstr "Программа сравнения"
+
+#: gitk:2358
+msgid "Blame parent commit"
+msgstr "Аннотировать родительское состояние"
+
+#: gitk:2365
+msgid "Show origin of this line"
+msgstr "Показать источник этой строки"
+
+#: gitk:2366
+msgid "Run git gui blame on this line"
+msgstr "Запустить git gui blame для этой строки"
+
+#: gitk:2611
+msgid ""
+"\n"
+"Gitk - a commit viewer for git\n"
+"\n"
+"Copyright © 2005-2008 Paul Mackerras\n"
+"\n"
+"Use and redistribute under the terms of the GNU General Public License"
+msgstr ""
+"\n"
+"Gitk - программа просмотра истории репозиториев Git\n"
+"\n"
+"Copyright (c) 2005-2008 Paul Mackerras\n"
+"\n"
+"Использование и распространение согласно условиям GNU General Public License"
+
+#: gitk:2619 gitk:2681 gitk:8661
+msgid "Close"
+msgstr "Закрыть"
+
+#: gitk:2638
+msgid "Gitk key bindings"
+msgstr "Назначения клавиатуры в Gitk"
+
+#: gitk:2641
+msgid "Gitk key bindings:"
+msgstr "Назначения клавиатуры в Gitk:"
+
+#: gitk:2643
+#, tcl-format
+msgid "<%s-Q>\t\tQuit"
+msgstr "<%s-Q>\t\tЗавершить"
+
+#: gitk:2644
+msgid "<Home>\t\tMove to first commit"
+msgstr "<Home>\t\tПерейти к первому состоянию"
+
+#: gitk:2645
+msgid "<End>\t\tMove to last commit"
+msgstr "<End>\t\tПерейти к последнему состоянию"
+
+#: gitk:2646
+msgid "<Up>, p, i\tMove up one commit"
+msgstr "<Up>, p, i\tПерейти к следующему состоянию"
+
+#: gitk:2647
+msgid "<Down>, n, k\tMove down one commit"
+msgstr "<Down>, n, k\tПерейти к предыдущему состоянию"
+
+#: gitk:2648
+msgid "<Left>, z, j\tGo back in history list"
+msgstr "<Left>, z, j\tПоказать ранее посещённое состояние"
+
+#: gitk:2649
+msgid "<Right>, x, l\tGo forward in history list"
+msgstr "<Right>, x, l\tПоказать следующее посещённое состояние"
+
+#: gitk:2650
+msgid "<PageUp>\tMove up one page in commit list"
+msgstr "<PageUp>\tПерейти на страницу выше в списке состояний"
+
+#: gitk:2651
+msgid "<PageDown>\tMove down one page in commit list"
+msgstr "<PageDown>\tПерейти на страницу ниже в списке состояний"
+
+#: gitk:2652
+#, tcl-format
+msgid "<%s-Home>\tScroll to top of commit list"
+msgstr "<%s-Home>\tПоказать начало списка состояний"
+
+#: gitk:2653
+#, tcl-format
+msgid "<%s-End>\tScroll to bottom of commit list"
+msgstr "<%s-End>\tПоказать конец списка состояний"
+
+#: gitk:2654
+#, tcl-format
+msgid "<%s-Up>\tScroll commit list up one line"
+msgstr "<%s-Up>\tПровернуть список состояний вверх"
+
+#: gitk:2655
+#, tcl-format
+msgid "<%s-Down>\tScroll commit list down one line"
+msgstr "<%s-Down>\tПровернуть список состояний вниз"
+
+#: gitk:2656
+#, tcl-format
+msgid "<%s-PageUp>\tScroll commit list up one page"
+msgstr "<%s-PageUp>\tПровернуть список состояний на страницу вверх"
+
+#: gitk:2657
+#, tcl-format
+msgid "<%s-PageDown>\tScroll commit list down one page"
+msgstr "<%s-PageDown>\tПровернуть список состояний на страницу вниз"
+
+#: gitk:2658
+msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
+msgstr ""
+"<Shift-Up>\tПоиск в обратном порядке (вверх, среди новых состояний)"
+
+#: gitk:2659
+msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
+msgstr "<Shift-Down>\tПоиск (вниз, среди старых состояний)"
+
+#: gitk:2660
+msgid "<Delete>, b\tScroll diff view up one page"
+msgstr "<Delete>, b\tПрокрутить список изменений на страницу выше"
+
+#: gitk:2661
+msgid "<Backspace>\tScroll diff view up one page"
+msgstr "<Backspace>\tПрокрутить список изменений на страницу выше"
+
+#: gitk:2662
+msgid "<Space>\t\tScroll diff view down one page"
+msgstr "<Leertaste>\t\tПрокрутить список изменений на страницу ниже"
+
+#: gitk:2663
+msgid "u\t\tScroll diff view up 18 lines"
+msgstr "u\t\tПрокрутить список изменений на 18 строк вверх"
+
+#: gitk:2664
+msgid "d\t\tScroll diff view down 18 lines"
+msgstr "d\t\tПрокрутить список изменений на 18 строк вниз"
+
+#: gitk:2665
+#, tcl-format
+msgid "<%s-F>\t\tFind"
+msgstr "<%s-F>\t\tПоиск"
+
+#: gitk:2666
+#, tcl-format
+msgid "<%s-G>\t\tMove to next find hit"
+msgstr "<%s-G>\t\tПерейти к следующему найденому состоянию"
+
+#: gitk:2667
+msgid "<Return>\tMove to next find hit"
+msgstr "<Return>\tПерейти к следующему найденому состоянию"
+
+#: gitk:2668
+msgid "/\t\tFocus the search box"
+msgstr "/\t\tПерейти к полю поиска"
+
+#: gitk:2669
+msgid "?\t\tMove to previous find hit"
+msgstr "?\t\tПерейти к предыдущему найденому состоянию"
+
+#: gitk:2670
+msgid "f\t\tScroll diff view to next file"
+msgstr "f\t\tПрокрутить список изменений к следующему файлу"
+
+#: gitk:2671
+#, tcl-format
+msgid "<%s-S>\t\tSearch for next hit in diff view"
+msgstr "<%s-S>\t\tПродолжить поиск в списке изменений"
+
+#: gitk:2672
+#, tcl-format
+msgid "<%s-R>\t\tSearch for previous hit in diff view"
+msgstr "<%s-R>\t\tПерейти к предыдущему найденому тексту в списке изменений"
+
+#: gitk:2673
+#, tcl-format
+msgid "<%s-KP+>\tIncrease font size"
+msgstr "<%s-KP+>\tУвеличить размер шрифта"
+
+#: gitk:2674
+#, tcl-format
+msgid "<%s-plus>\tIncrease font size"
+msgstr "<%s-plus>\tУвеличить размер шрифта"
+
+#: gitk:2675
+#, tcl-format
+msgid "<%s-KP->\tDecrease font size"
+msgstr "<%s-KP->\tУменьшить размер шрифта"
+
+#: gitk:2676
+#, tcl-format
+msgid "<%s-minus>\tDecrease font size"
+msgstr "<%s-minus>\tУменьшить размер шрифта"
+
+#: gitk:2677
+msgid "<F5>\t\tUpdate"
+msgstr "<F5>\t\tОбновить"
+
+#: gitk:3132
+#, tcl-format
+msgid "Error getting \"%s\" from %s:"
+msgstr "Ошибка получения \"%s\" из %s:"
+
+#: gitk:3189 gitk:3198
+#, tcl-format
+msgid "Error creating temporary directory %s:"
+msgstr "Ошибка создания временного каталога %s:"
+
+#: gitk:3211
+msgid "command failed:"
+msgstr "ошибка выполнения команды:"
+
+#: gitk:3357
+msgid "No such commit"
+msgstr "Состояние не найдено"
+
+#: gitk:3371
+msgid "git gui blame: command failed:"
+msgstr "git gui blame: ошибка выполнения команды:"
+
+#: gitk:3402
+#, tcl-format
+msgid "Couldn't read merge head: %s"
+msgstr "Ошибка чтения MERGE_HEAD: %s"
+
+#: gitk:3410
+#, tcl-format
+msgid "Error reading index: %s"
+msgstr "Ошибка чтения индекса: %s"
+
+#: gitk:3435
+#, tcl-format
+msgid "Couldn't start git blame: %s"
+msgstr "Ошибка запуска git blame: %s"
+
+#: gitk:3438 gitk:6163
+msgid "Searching"
+msgstr "Поиск"
+
+#: gitk:3470
+#, tcl-format
+msgid "Error running git blame: %s"
+msgstr "Ошибка выполнения git blame: %s"
+
+#: gitk:3498
+#, tcl-format
+msgid "That line comes from commit %s,  which is not in this view"
+msgstr ""
+"Эта строка принадлежит состоянию %s, которое не показано в этом "
+"представлении"
+
+#: gitk:3512
+msgid "External diff viewer failed:"
+msgstr "Ошибка выполнения программы сравнения:"
+
+#: gitk:3630
+msgid "Gitk view definition"
+msgstr "Gitk определение представлений"
+
+#: gitk:3634
+msgid "Remember this view"
+msgstr "Запомнить представление"
+
+#: gitk:3635
+msgid "Commits to include (arguments to git log):"
+msgstr "Включить состояния (аргументы для git-log):"
+
+#: gitk:3636
+msgid "Use all refs"
+msgstr "Использовать все ветви"
+
+#: gitk:3637
+msgid "Strictly sort by date"
+msgstr "Строгая сортировка по дате"
+
+#: gitk:3638
+msgid "Mark branch sides"
+msgstr "Отметить стороны ветвей"
+
+#: gitk:3639
+msgid "Since date:"
+msgstr "С даты:"
+
+#: gitk:3640
+msgid "Until date:"
+msgstr "По дату:"
+
+#: gitk:3641
+msgid "Max count:"
+msgstr "Макс. количество:"
+
+#: gitk:3642
+msgid "Skip:"
+msgstr "Пропустить:"
+
+#: gitk:3643
+msgid "Limit to first parent"
+msgstr "Ограничить первым предком"
+
+#: gitk:3644
+msgid "Command to generate more commits to include:"
+msgstr "Дополнительная команда для списка состояний:"
+
+#: gitk:3753
+msgid "Name"
+msgstr "Имя"
+
+#: gitk:3801
+msgid "Enter files and directories to include, one per line:"
+msgstr "Файлы и каталоги для ограничения истории, по одному на строку:"
+
+#: gitk:3815
+msgid "Apply (F5)"
+msgstr "Применить (F5)"
+
+#: gitk:3853
+msgid "Error in commit selection arguments:"
+msgstr "Ошибка в параметрах выбора состояний:"
+
+#: gitk:3906 gitk:3958 gitk:4403 gitk:4417 gitk:5675 gitk:10867 gitk:10868
+msgid "None"
+msgstr "Ни одного"
+
+#: gitk:4351 gitk:6195 gitk:7925 gitk:7940
+msgid "Date"
+msgstr "Дата"
+
+#: gitk:4351 gitk:6195
+msgid "CDate"
+msgstr "Дата ввода"
+
+#: gitk:4500 gitk:4505
+msgid "Descendant"
+msgstr "Порождённое"
+
+#: gitk:4501
+msgid "Not descendant"
+msgstr "Не порождённое"
+
+#: gitk:4508 gitk:4513
+msgid "Ancestor"
+msgstr "Предок"
+
+#: gitk:4509
+msgid "Not ancestor"
+msgstr "Не предок"
+
+#: gitk:4799
+msgid "Local changes checked in to index but not committed"
+msgstr "Изменения зарегистрированные в индексе, но не сохранённые"
+
+#: gitk:4835
+msgid "Local uncommitted changes, not checked in to index"
+msgstr "Изменения в рабочем каталоге, не зарегистрированные в индексе"
+
+#: gitk:6676
+msgid "Tags:"
+msgstr "Таги:"
+
+#: gitk:6693 gitk:6699 gitk:7918
+msgid "Parent"
+msgstr "Предок"
+
+#: gitk:6704
+msgid "Child"
+msgstr "Потомок"
+
+#: gitk:6713
+msgid "Branch"
+msgstr "Ветвь"
+
+#: gitk:6716
+msgid "Follows"
+msgstr "Следует за"
+
+#: gitk:6719
+msgid "Precedes"
+msgstr "Предшествует"
+
+#: gitk:7212
+#, tcl-format
+msgid "Error getting diffs: %s"
+msgstr "Ошибка получения изменений: %s"
+
+#: gitk:7751
+msgid "Goto:"
+msgstr "Перейти к:"
+
+#: gitk:7753
+msgid "SHA1 ID:"
+msgstr "SHA1 ID:"
+
+#: gitk:7772
+#, tcl-format
+msgid "Short SHA1 id %s is ambiguous"
+msgstr "Сокращённый SHA1 идентификатор %s неоднозначен"
+
+#: gitk:7784
+#, tcl-format
+msgid "SHA1 id %s is not known"
+msgstr "SHA1 идентификатор %s не найден"
+
+#: gitk:7786
+#, tcl-format
+msgid "Tag/Head %s is not known"
+msgstr "Метка или ветвь %s не найдена"
+
+#: gitk:7928
+msgid "Children"
+msgstr "Потомки"
+
+#: gitk:7985
+#, tcl-format
+msgid "Reset %s branch to here"
+msgstr "Установить ветвь %s на это состояние"
+
+#: gitk:7987
+msgid "Detached head: can't reset"
+msgstr "Состояние не принадлежит ни одной ветви, переход невозможен"
+
+#: gitk:8019
+msgid "Top"
+msgstr "Верх"
+
+#: gitk:8020
+msgid "From"
+msgstr "От"
+
+#: gitk:8025
+msgid "To"
+msgstr "До"
+
+#: gitk:8049
+msgid "Generate patch"
+msgstr "Создать патч"
+
+#: gitk:8051
+msgid "From:"
+msgstr "От:"
+
+#: gitk:8060
+msgid "To:"
+msgstr "До:"
+
+#: gitk:8069
+msgid "Reverse"
+msgstr "В обратном порядке"
+
+#: gitk:8071 gitk:8253
+msgid "Output file:"
+msgstr "Файл для сохранения:"
+
+#: gitk:8077
+msgid "Generate"
+msgstr "Создать"
+
+#: gitk:8115
+msgid "Error creating patch:"
+msgstr "Ошибка создания патча:"
+
+#: gitk:8138 gitk:8241 gitk:8298
+msgid "ID:"
+msgstr "ID:"
+
+#: gitk:8147
+msgid "Tag name:"
+msgstr "Имя метки:"
+
+#: gitk:8151 gitk:8307
+msgid "Create"
+msgstr "Создать"
+
+#: gitk:8168
+msgid "No tag name specified"
+msgstr "Не задано имя метки"
+
+#: gitk:8172
+#, tcl-format
+msgid "Tag \"%s\" already exists"
+msgstr "Метка \"%s\" уже существует"
+
+#: gitk:8178
+msgid "Error creating tag:"
+msgstr "Ошибка создания метки:"
+
+#: gitk:8250
+msgid "Command:"
+msgstr "Команда:"
+
+#: gitk:8258
+msgid "Write"
+msgstr "Запись"
+
+#: gitk:8276
+msgid "Error writing commit:"
+msgstr "Ошибка сохранения состояния:"
+
+#: gitk:8303
+msgid "Name:"
+msgstr "Имя:"
+
+#: gitk:8326
+msgid "Please specify a name for the new branch"
+msgstr "Укажите имя для новой ветви"
+
+#: gitk:8331
+#, tcl-format
+msgid "Branch '%s' already exists. Overwrite?"
+msgstr "Ветвь '%s' уже существует. Переписать?"
+
+#: gitk:8397
+#, tcl-format
+msgid "Commit %s is already included in branch %s -- really re-apply it?"
+msgstr ""
+"Состояние %s уже принадлежит ветви %s. Продолжить операцию?"
+
+#: gitk:8402
+msgid "Cherry-picking"
+msgstr "Копирование изменений"
+
+#: gitk:8411
+#, tcl-format
+msgid ""
+"Cherry-pick failed because of local changes to file '%s'.\n"
+"Please commit, reset or stash your changes and try again."
+msgstr ""
+"Копирование невозможно из-за изменений в файле '%s'.\n"
+"Сохраните или отмените изменения и повторите операцию."
+
+#: gitk:8417
+msgid ""
+"Cherry-pick failed because of merge conflict.\n"
+"Do you wish to run git citool to resolve it?"
+msgstr ""
+"Копирование изменений невозможно из-за незавершённой операции "
+"слияния.\nЗапустить git citool для завершения этой операции?"
+
+#: gitk:8433
+msgid "No changes committed"
+msgstr "Изменения не сохранены"
+
+#: gitk:8459
+msgid "Confirm reset"
+msgstr "Подтвердите операцию перехода"
+
+#: gitk:8461
+#, tcl-format
+msgid "Reset branch %s to %s?"
+msgstr "Установить ветвь %s на состояние %s?"
+
+#: gitk:8465
+msgid "Reset type:"
+msgstr "Тип операции перехода:"
+
+#: gitk:8469
+msgid "Soft: Leave working tree and index untouched"
+msgstr "Лёгкий: оставить рабочий каталог и индекс неизменными"
+
+#: gitk:8472
+msgid "Mixed: Leave working tree untouched, reset index"
+msgstr ""
+"Смешаный: оставить рабочий каталог неизменным, установить индекс"
+
+#: gitk:8475
+msgid ""
+"Hard: Reset working tree and index\n"
+"(discard ALL local changes)"
+msgstr ""
+"Жесткий: переписать индекс и рабочий каталог\n"
+"(все изменения в рабочем каталоги будут потеряны)"
+
+#: gitk:8492
+msgid "Resetting"
+msgstr "Установка"
+
+#: gitk:8549
+msgid "Checking out"
+msgstr "Переход"
+
+#: gitk:8602
+msgid "Cannot delete the currently checked-out branch"
+msgstr "Активная ветвь не может быть удалена"
+
+#: gitk:8608
+#, tcl-format
+msgid ""
+"The commits on branch %s aren't on any other branch.\n"
+"Really delete branch %s?"
+msgstr ""
+"Состояния ветви %s больше не принадлежат никакой другой ветви.\n"
+"Действительно удалить ветвь %s?"
+
+#: gitk:8639
+#, tcl-format
+msgid "Tags and heads: %s"
+msgstr "Метки и ветви: %s"
+
+#: gitk:8654
+msgid "Filter"
+msgstr "Фильтровать"
+
+#: gitk:8949
+msgid ""
+"Error reading commit topology information; branch and preceding/following "
+"tag information will be incomplete."
+msgstr ""
+"Ошибка чтения истории проекта; информация о ветвях и состояниях "
+"вокруг меток (до/после) может быть неполной."
+
+#: gitk:9935
+msgid "Tag"
+msgstr "Метка"
+
+#: gitk:9935
+msgid "Id"
+msgstr "Id"
+
+#: gitk:9983
+msgid "Gitk font chooser"
+msgstr "Шрифт Gitk"
+
+#: gitk:10000
+msgid "B"
+msgstr "Ж"
+
+#: gitk:10003
+msgid "I"
+msgstr "К"
+
+#: gitk:10098
+msgid "Gitk preferences"
+msgstr "Настройки Gitk"
+
+#: gitk:10100
+msgid "Commit list display options"
+msgstr "Параметры показа списка состояний"
+
+#: gitk:10103
+msgid "Maximum graph width (lines)"
+msgstr "Макс. ширина графа (строк)"
+
+#: gitk:10107
+#, tcl-format
+msgid "Maximum graph width (% of pane)"
+msgstr "Макс. ширина графа (% ширины панели)"
+
+#: gitk:10111
+msgid "Show local changes"
+msgstr "Показывать изменения в рабочем каталоге"
+
+#: gitk:10114
+msgid "Auto-select SHA1"
+msgstr "Выделить SHA1"
+
+#: gitk:10118
+msgid "Diff display options"
+msgstr "Параметры показа изменений"
+
+#: gitk:10120
+msgid "Tab spacing"
+msgstr "Ширина табуляции"
+
+#: gitk:10123
+msgid "Display nearby tags"
+msgstr "Показывать близкие метки"
+
+#: gitk:10126
+msgid "Limit diffs to listed paths"
+msgstr "Ограничить показ изменений выбраными файлами"
+
+#: gitk:10129
+msgid "Support per-file encodings"
+msgstr "Поддержка кодировок в отдельных файлах"
+
+#: gitk:10135
+msgid "External diff tool"
+msgstr "Программа для показа изменений"
+
+#: gitk:10137
+msgid "Choose..."
+msgstr "Выберите..."
+
+#: gitk:10142
+msgid "Colors: press to choose"
+msgstr "Цвета: нажмите для выбора"
+
+#: gitk:10145
+msgid "Background"
+msgstr "Фон"
+
+#: gitk:10146 gitk:10176
+msgid "background"
+msgstr "фон"
+
+#: gitk:10149
+msgid "Foreground"
+msgstr "Передний план"
+
+#: gitk:10150
+msgid "foreground"
+msgstr "передний план"
+
+#: gitk:10153
+msgid "Diff: old lines"
+msgstr "Изменения: старый текст"
+
+#: gitk:10154
+msgid "diff old lines"
+msgstr "старый текст изменения"
+
+#: gitk:10158
+msgid "Diff: new lines"
+msgstr "Изменения: новый текст"
+
+#: gitk:10159
+msgid "diff new lines"
+msgstr "новый текст изменения"
+
+#: gitk:10163
+msgid "Diff: hunk header"
+msgstr "Изменения: заголовок блока"
+
+#: gitk:10165
+msgid "diff hunk header"
+msgstr "заголовок блока изменений"
+
+#: gitk:10169
+msgid "Marked line bg"
+msgstr "Фон выбраной строки"
+
+#: gitk:10171
+msgid "marked line background"
+msgstr "фон выбраной строки"
+
+#: gitk:10175
+msgid "Select bg"
+msgstr "Выберите фон"
+
+#: gitk:10179
+msgid "Fonts: press to choose"
+msgstr "Шрифт: нажмите для выбора"
+
+#: gitk:10181
+msgid "Main font"
+msgstr "Основной шрифт"
+
+#: gitk:10182
+msgid "Diff display font"
+msgstr "Шрифт показа изменений"
+
+#: gitk:10183
+msgid "User interface font"
+msgstr "Шрифт интерфейса"
+
+#: gitk:10210
+#, tcl-format
+msgid "Gitk: choose color for %s"
+msgstr "Gitk: выберите цвет для %s"
+
+#: gitk:10656
+msgid ""
+"Sorry, gitk cannot run with this version of Tcl/Tk.\n"
+" Gitk requires at least Tcl/Tk 8.4."
+msgstr ""
+"К сожалению gitk не может работать с этой версий Tcl/Tk.\n"
+"Требуется как минимум Tcl/Tk 8.4."
+
+#: gitk:10773
+msgid "Cannot find a git repository here."
+msgstr "Git-репозитарий не найден в текущем каталоге."
+
+#: gitk:10777
+#, tcl-format
+msgid "Cannot find the git directory \"%s\"."
+msgstr "Git-репозитарий \"%s\" не найден."
+
+#: gitk:10824
+#, tcl-format
+msgid "Ambiguous argument '%s': both revision and filename"
+msgstr "Неоднозначный аргумент '%s': существует как версия и имя файла"
+
+#: gitk:10836
+msgid "Bad arguments to gitk:"
+msgstr "Неправильные аргументы для gitk:"
+
+#: gitk:10896
+msgid "Command line"
+msgstr "Командная строка"
+
index 8433dd1d45780b3947cc4a0b31ee2059ea6e65bf..ccda890c0ef1b2d1fb1c451d3f9a10d97817c8f6 100644 (file)
@@ -206,7 +206,7 @@ not include variables usually directly set during build):
  * $fallback_encoding
    Gitweb assumes this charset if line contains non-UTF-8 characters.
    Fallback decoding is used without error checking, so it can be even
-   'utf-8'. Value mist be valid encodig; see Encoding::Supported(3pm) man
+   'utf-8'. Value must be valid encoding; see Encoding::Supported(3pm) man
    page for a list.   By default 'latin1', aka. 'iso-8859-1'.
  * @diff_opts
    Rename detection options for git-diff and git-diff-tree. By default
index 33ef190ceb99565f804783ba9fe76987ad6bea89..1e7e2d8387efb810afb3b9c9d279cc59f52d932e 100755 (executable)
@@ -458,8 +458,8 @@ sub filter_snapshot_fmts {
        @fmts = map {
                exists $known_snapshot_format_aliases{$_} ?
                       $known_snapshot_format_aliases{$_} : $_} @fmts;
-       @fmts = grep(exists $known_snapshot_formats{$_}, @fmts);
-
+       @fmts = grep {
+               exists $known_snapshot_formats{$_} } @fmts;
 }
 
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
@@ -688,11 +688,12 @@ sub evaluate_path_info {
                # extensions. Allowed extensions are both the defined suffix
                # (which includes the initial dot already) and the snapshot
                # format key itself, with a prepended dot
-               while (my ($fmt, %opt) = each %known_snapshot_formats) {
+               while (my ($fmt, $opt) = each %known_snapshot_formats) {
                        my $hash = $refname;
-                       my $sfx;
-                       $hash =~ s/(\Q$opt{'suffix'}\E|\Q.$fmt\E)$//;
-                       next unless $sfx = $1;
+                       unless ($hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//) {
+                               next;
+                       }
+                       my $sfx = $1;
                        # a valid suffix was found, so set the snapshot format
                        # and reset the hash parameter
                        $input_params{'snapshot_format'} = $fmt;
@@ -828,7 +829,7 @@ if (!defined $action) {
 if (!defined($actions{$action})) {
        die_error(400, "Unknown action");
 }
-if ($action !~ m/^(opml|project_list|project_index)$/ &&
+if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
     !$project) {
        die_error(400, "Project needed");
 }
@@ -838,7 +839,7 @@ exit;
 ## ======================================================================
 ## action links
 
-sub href (%) {
+sub href {
        my %params = @_;
        # default is to use -absolute url() i.e. $my_uri
        my $href = $params{-full} ? $my_url : $my_uri;
@@ -1036,7 +1037,7 @@ sub esc_url {
 }
 
 # replace invalid utf8 character with SUBSTITUTION sequence
-sub esc_html ($;%) {
+sub esc_html {
        my $str = shift;
        my %opts = @_;
 
@@ -1235,7 +1236,7 @@ sub chop_and_escape_str {
        if ($chopped eq $str) {
                return esc_html($chopped);
        } else {
-               $str =~ s/([[:cntrl:]])/?/g;
+               $str =~ s/[[:cntrl:]]/?/g;
                return $cgi->span({-title=>$str}, esc_html($chopped));
        }
 }
@@ -1296,7 +1297,7 @@ use constant {
 };
 
 # submodule/subproject, a commit object reference
-sub S_ISGITLINK($) {
+sub S_ISGITLINK {
        my $mode = shift;
 
        return (($mode & S_IFMT) == S_IFGITLINK)
@@ -1458,6 +1459,7 @@ sub format_subject_html {
        $extra = '' unless defined($extra);
 
        if (length($short) < length($long)) {
+               $long =~ s/[[:cntrl:]]/?/g;
                return $cgi->a({-href => $href, -class => "list subject",
                                -title => to_utf8($long)},
                       esc_html($short) . $extra);
@@ -1838,7 +1840,7 @@ sub git_cmd {
 # Try to avoid using this function wherever possible.
 sub quote_command {
        return join(' ',
-                   map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ));
+               map { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ );
 }
 
 # get HEAD ref of given project as hash
@@ -2050,7 +2052,7 @@ sub git_get_project_description {
        my $path = shift;
 
        $git_dir = "$projectroot/$path";
-       open my $fd, "$git_dir/description"
+       open my $fd, '<', "$git_dir/description"
                or return git_get_project_config('description');
        my $descr = <$fd>;
        close $fd;
@@ -2065,18 +2067,17 @@ sub git_get_project_ctags {
        my $ctags = {};
 
        $git_dir = "$projectroot/$path";
-       unless (opendir D, "$git_dir/ctags") {
-               return $ctags;
-       }
-       foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir(D)) {
-               open CT, $_ or next;
-               my $val = <CT>;
+       opendir my $dh, "$git_dir/ctags"
+               or return $ctags;
+       foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) {
+               open my $ct, '<', $_ or next;
+               my $val = <$ct>;
                chomp $val;
-               close CT;
+               close $ct;
                my $ctag = $_; $ctag =~ s#.*/##;
                $ctags->{$ctag} = $val;
        }
-       closedir D;
+       closedir $dh;
        $ctags;
 }
 
@@ -2129,7 +2130,7 @@ sub git_get_project_url_list {
        my $path = shift;
 
        $git_dir = "$projectroot/$path";
-       open my $fd, "$git_dir/cloneurl"
+       open my $fd, '<', "$git_dir/cloneurl"
                or return wantarray ?
                @{ config_to_multi(git_get_project_config('url')) } :
                   config_to_multi(git_get_project_config('url'));
@@ -2187,7 +2188,7 @@ sub git_get_projects_list {
                # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
                # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
                my %paths;
-               open my ($fd), $projects_list or return;
+               open my $fd, '<', $projects_list or return;
        PROJECT:
                while (my $line = <$fd>) {
                        chomp $line;
@@ -2250,7 +2251,7 @@ sub git_get_project_list_from_file {
        # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
        # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
        if (-f $projects_list) {
-               open (my $fd , $projects_list);
+               open(my $fd, '<', $projects_list);
                while (my $line = <$fd>) {
                        chomp $line;
                        my ($pr, $ow) = split ' ', $line;
@@ -2615,7 +2616,7 @@ sub parsed_difftree_line {
 }
 
 # parse line of git-ls-tree output
-sub parse_ls_tree_line ($;%) {
+sub parse_ls_tree_line {
        my $line = shift;
        my %opts = @_;
        my %res;
@@ -2804,18 +2805,18 @@ sub mimetype_guess_file {
        -r $mimemap or return undef;
 
        my %mimemap;
-       open(MIME, $mimemap) or return undef;
-       while (<MIME>) {
+       open(my $mh, '<', $mimemap) or return undef;
+       while (<$mh>) {
                next if m/^#/; # skip comments
-               my ($mime, $exts) = split(/\t+/);
+               my ($mimetype, $exts) = split(/\t+/);
                if (defined $exts) {
                        my @exts = split(/\s+/, $exts);
                        foreach my $ext (@exts) {
-                               $mimemap{$ext} = $mime;
+                               $mimemap{$ext} = $mimetype;
                        }
                }
        }
-       close(MIME);
+       close($mh);
 
        $filename =~ /\.([^.]*)$/;
        return $mimemap{$1};
@@ -3213,7 +3214,6 @@ sub git_print_header_div {
              "\n</div>\n";
 }
 
-#sub git_print_authorship (\%) {
 sub git_print_authorship {
        my $co = shift;
 
@@ -3269,8 +3269,7 @@ sub git_print_page_path {
        print "<br/></div>\n";
 }
 
-# sub git_print_log (\@;%) {
-sub git_print_log ($;%) {
+sub git_print_log {
        my $log = shift;
        my %opts = @_;
 
@@ -3328,7 +3327,7 @@ sub git_get_link_target {
        open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
                or return;
        {
-               local $/;
+               local $/ = undef;
                $link_target = <$fd>;
        }
        close $fd
@@ -3341,10 +3340,7 @@ sub git_get_link_target {
 # return target of link relative to top directory (top tree);
 # return undef if it is not possible (including absolute links).
 sub normalize_link_target {
-       my ($link_target, $basedir, $hash_base) = @_;
-
-       # we can normalize symlink target only if $hash_base is provided
-       return unless $hash_base;
+       my ($link_target, $basedir) = @_;
 
        # absolute symlinks (beginning with '/') cannot be normalized
        return if (substr($link_target, 0, 1) eq '/');
@@ -3400,7 +3396,7 @@ sub git_print_tree_entry {
                if (S_ISLNK(oct $t->{'mode'})) {
                        my $link_target = git_get_link_target($t->{'hash'});
                        if ($link_target) {
-                               my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
+                               my $norm_target = normalize_link_target($link_target, $basedir);
                                if (defined $norm_target) {
                                        print " -> " .
                                              $cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
@@ -3993,7 +3989,7 @@ sub fill_project_list_info {
                            ($pname !~ /\/$/) &&
                            (-d "$projectroot/$pname")) {
                                $pr->{'forks'} = "-d $projectroot/$pname";
-                       }       else {
+                       } else {
                                $pr->{'forks'} = 0;
                        }
                }
@@ -4803,11 +4799,10 @@ sub git_blob_plain {
                -content_disposition =>
                        ($sandbox ? 'attachment' : 'inline')
                        . '; filename="' . $save_as . '"');
-       undef $/;
+       local $/ = undef;
        binmode STDOUT, ':raw';
        print <$fd>;
        binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
-       $/ = "\n";
        close $fd;
 }
 
@@ -4909,12 +4904,16 @@ sub git_tree {
                }
        }
        die_error(404, "No such tree") unless defined($hash);
-       $/ = "\0";
-       open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
-               or die_error(500, "Open git-ls-tree failed");
-       my @entries = map { chomp; $_ } <$fd>;
-       close $fd or die_error(404, "Reading tree failed");
-       $/ = "\n";
+
+       my @entries = ();
+       {
+               local $/ = "\0";
+               open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
+                       or die_error(500, "Open git-ls-tree failed");
+               @entries = map { chomp; $_ } <$fd>;
+               close $fd
+                       or die_error(404, "Reading tree failed");
+       }
 
        my $refs = git_get_references();
        my $ref = format_ref_marker($refs, $hash_base);
@@ -5809,7 +5808,7 @@ sub git_search {
 
                print "<table class=\"pickaxe search\">\n";
                my $alternate = 1;
-               $/ = "\n";
+               local $/ = "\n";
                open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,
                        '--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext",
                        ($search_use_regexp ? '--pickaxe-regex' : ());
@@ -5879,7 +5878,7 @@ sub git_search {
                print "<table class=\"grep_search\">\n";
                my $alternate = 1;
                my $matches = 0;
-               $/ = "\n";
+               local $/ = "\n";
                open my $fd, "-|", git_cmd(), 'grep', '-n',
                        $search_use_regexp ? ('-E', '-i') : '-F',
                        $searchtext, $co{'tree'};
@@ -6282,7 +6281,7 @@ XML
        # end of feed
        if ($format eq 'rss') {
                print "</channel>\n</rss>\n";
-       }       elsif ($format eq 'atom') {
+       } elsif ($format eq 'atom') {
                print "</feed>\n";
        }
 }
diff --git a/graph.c b/graph.c
index 162a516ee15cca1f8ab118dd41b803a5d76e42ff..f8d7a5c0f6d17538a72b75e8de9dd092829a0262 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "commit.h"
+#include "color.h"
 #include "graph.h"
 #include "diff.h"
 #include "revision.h"
@@ -34,7 +35,7 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
  * 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
+ * Since the first line will not include the graph output, the caller is
  * responsible for printing this line's graph (perhaps via
  * graph_show_commit() or graph_show_oneline()) before calling
  * graph_show_strbuf().
@@ -43,27 +44,9 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
 
 /*
  * TODO:
- * - Add colors to the graph.
- *   Pick a color for each column, and print all characters
- *   in that column with the specified color.
- *
  * - Limit the number of columns, similar to the way gitk does.
  *   If we reach more than a specified number of columns, omit
  *   sections of some columns.
- *
- * - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states
- *   could be made more compact by printing horizontal lines, instead of
- *   long diagonal lines.  For example, during collapsing, something like
- *   this:          instead of this:
- *   | | | | |      | | | | |
- *   | |_|_|/       | | | |/
- *   |/| | |        | | |/|
- *   | | | |        | |/| |
- *                  |/| | |
- *                  | | | |
- *
- *   If there are several parallel diagonal lines, they will need to be
- *   replaced with horizontal lines on subsequent rows.
  */
 
 struct column {
@@ -72,9 +55,10 @@ struct column {
         */
        struct commit *commit;
        /*
-        * XXX: Once we add support for colors, struct column could also
-        * contain the color of its branch line.
+        * The color to (optionally) print this column in.  This is an
+        * index into column_colors.
         */
+       unsigned short color;
 };
 
 enum graph_state {
@@ -86,6 +70,41 @@ enum graph_state {
        GRAPH_COLLAPSING
 };
 
+/*
+ * The list of available column colors.
+ */
+static char column_colors[][COLOR_MAXLEN] = {
+       GIT_COLOR_RED,
+       GIT_COLOR_GREEN,
+       GIT_COLOR_YELLOW,
+       GIT_COLOR_BLUE,
+       GIT_COLOR_MAGENTA,
+       GIT_COLOR_CYAN,
+       GIT_COLOR_BOLD GIT_COLOR_RED,
+       GIT_COLOR_BOLD GIT_COLOR_GREEN,
+       GIT_COLOR_BOLD GIT_COLOR_YELLOW,
+       GIT_COLOR_BOLD GIT_COLOR_BLUE,
+       GIT_COLOR_BOLD GIT_COLOR_MAGENTA,
+       GIT_COLOR_BOLD GIT_COLOR_CYAN,
+};
+
+#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
+
+static const char *column_get_color_code(const struct column *c)
+{
+       return column_colors[c->color];
+}
+
+static void strbuf_write_column(struct strbuf *sb, const struct column *c,
+                               char col_char)
+{
+       if (c->color < COLUMN_COLORS_MAX)
+               strbuf_addstr(sb, column_get_color_code(c));
+       strbuf_addch(sb, col_char);
+       if (c->color < COLUMN_COLORS_MAX)
+               strbuf_addstr(sb, GIT_COLOR_RESET);
+}
+
 struct git_graph {
        /*
         * The commit currently being processed
@@ -185,6 +204,11 @@ struct git_graph {
         * temporary array each time we have to output a collapsing line.
         */
        int *new_mapping;
+       /*
+        * The current default column color being used.  This is
+        * stored as an index into the array column_colors.
+        */
+       unsigned short default_column_color;
 };
 
 struct git_graph *graph_init(struct rev_info *opt)
@@ -201,6 +225,7 @@ struct git_graph *graph_init(struct rev_info *opt)
        graph->num_columns = 0;
        graph->num_new_columns = 0;
        graph->mapping_size = 0;
+       graph->default_column_color = 0;
 
        /*
         * Allocate a reasonably large default number of columns
@@ -312,6 +337,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph)
        return next_interesting_parent(graph, parents);
 }
 
+static unsigned short graph_get_current_column_color(const struct git_graph *graph)
+{
+       if (!DIFF_OPT_TST(&graph->revs->diffopt, COLOR_DIFF))
+               return COLUMN_COLORS_MAX;
+       return graph->default_column_color;
+}
+
+/*
+ * Update the graph's default column color.
+ */
+static void graph_increment_column_color(struct git_graph *graph)
+{
+       graph->default_column_color = (graph->default_column_color + 1) %
+               COLUMN_COLORS_MAX;
+}
+
+static unsigned short graph_find_commit_color(const struct git_graph *graph,
+                                             const struct commit *commit)
+{
+       int i;
+       for (i = 0; i < graph->num_columns; i++) {
+               if (graph->columns[i].commit == commit)
+                       return graph->columns[i].color;
+       }
+       return graph_get_current_column_color(graph);
+}
+
 static void graph_insert_into_new_columns(struct git_graph *graph,
                                          struct commit *commit,
                                          int *mapping_index)
@@ -334,6 +386,7 @@ static void graph_insert_into_new_columns(struct git_graph *graph,
         * This commit isn't already in new_columns.  Add it.
         */
        graph->new_columns[graph->num_new_columns].commit = commit;
+       graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit);
        graph->mapping[*mapping_index] = graph->num_new_columns;
        *mapping_index += 2;
        graph->num_new_columns++;
@@ -445,6 +498,12 @@ static void graph_update_columns(struct git_graph *graph)
                        for (parent = first_interesting_parent(graph);
                             parent;
                             parent = next_interesting_parent(graph, parent)) {
+                               /*
+                                * If this is a merge increment the current
+                                * color.
+                                */
+                               if (graph->num_parents > 1)
+                                       graph_increment_column_color(graph);
                                graph_insert_into_new_columns(graph,
                                                              parent->item,
                                                              &mapping_idx);
@@ -560,7 +619,8 @@ static int graph_is_mapping_correct(struct git_graph *graph)
        return 1;
 }
 
-static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
+static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb,
+                                  int chars_written)
 {
        /*
         * Add additional spaces to the end of the strbuf, so that all
@@ -570,10 +630,10 @@ static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
         * aligned for the entire commit.
         */
        int extra;
-       if (sb->len >= graph->width)
+       if (chars_written >= graph->width)
                return;
 
-       extra = graph->width - sb->len;
+       extra = graph->width - chars_written;
        strbuf_addf(sb, "%*s", (int) extra, "");
 }
 
@@ -596,10 +656,11 @@ static void graph_output_padding_line(struct git_graph *graph,
         * Output a padding row, that leaves all branch lines unchanged
         */
        for (i = 0; i < graph->num_new_columns; i++) {
-               strbuf_addstr(sb, "| ");
+               strbuf_write_column(sb, &graph->new_columns[i], '|');
+               strbuf_addch(sb, ' ');
        }
 
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, graph->num_new_columns * 2);
 }
 
 static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
@@ -609,7 +670,7 @@ static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
         * of the graph is missing.
         */
        strbuf_addstr(sb, "...");
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, 3);
 
        if (graph->num_parents >= 3 &&
            graph->commit_index < (graph->num_columns - 1))
@@ -623,6 +684,7 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
 {
        int num_expansion_rows;
        int i, seen_this;
+       int chars_written;
 
        /*
         * This function formats a row that increases the space around a commit
@@ -645,11 +707,14 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
         * Output the row
         */
        seen_this = 0;
+       chars_written = 0;
        for (i = 0; i < graph->num_columns; i++) {
                struct column *col = &graph->columns[i];
                if (col->commit == graph->commit) {
                        seen_this = 1;
-                       strbuf_addf(sb, "| %*s", graph->expansion_row, "");
+                       strbuf_write_column(sb, col, '|');
+                       strbuf_addf(sb, "%*s", graph->expansion_row, "");
+                       chars_written += 1 + graph->expansion_row;
                } else if (seen_this && (graph->expansion_row == 0)) {
                        /*
                         * This is the first line of the pre-commit output.
@@ -662,17 +727,22 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
                         */
                        if (graph->prev_state == GRAPH_POST_MERGE &&
                            graph->prev_commit_index < i)
-                               strbuf_addstr(sb, "\\ ");
+                               strbuf_write_column(sb, col, '\\');
                        else
-                               strbuf_addstr(sb, "| ");
+                               strbuf_write_column(sb, col, '|');
+                       chars_written++;
                } else if (seen_this && (graph->expansion_row > 0)) {
-                       strbuf_addstr(sb, "\\ ");
+                       strbuf_write_column(sb, col, '\\');
+                       chars_written++;
                } else {
-                       strbuf_addstr(sb, "| ");
+                       strbuf_write_column(sb, col, '|');
+                       chars_written++;
                }
+               strbuf_addch(sb, ' ');
+               chars_written++;
        }
 
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, chars_written);
 
        /*
         * Increment graph->expansion_row,
@@ -714,10 +784,34 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
        strbuf_addch(sb, '*');
 }
 
+/*
+ * Draw an octopus merge and return the number of characters written.
+ */
+static int graph_draw_octopus_merge(struct git_graph *graph,
+                                   struct strbuf *sb)
+{
+       /*
+        * Here dashless_commits represents the number of parents
+        * which don't need to have dashes (because their edges fit
+        * neatly under the commit).
+        */
+       const int dashless_commits = 2;
+       int col_num, i;
+       int num_dashes =
+               ((graph->num_parents - dashless_commits) * 2) - 1;
+       for (i = 0; i < num_dashes; i++) {
+               col_num = (i / 2) + dashless_commits;
+               strbuf_write_column(sb, &graph->new_columns[col_num], '-');
+       }
+       col_num = (i / 2) + dashless_commits;
+       strbuf_write_column(sb, &graph->new_columns[col_num], '.');
+       return num_dashes + 1;
+}
+
 static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
 {
        int seen_this = 0;
-       int i, j;
+       int i, chars_written;
 
        /*
         * Output the row containing this commit
@@ -727,7 +821,9 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
         * children that we have already processed.)
         */
        seen_this = 0;
+       chars_written = 0;
        for (i = 0; i <= graph->num_columns; i++) {
+               struct column *col = &graph->columns[i];
                struct commit *col_commit;
                if (i == graph->num_columns) {
                        if (seen_this)
@@ -740,18 +836,14 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
                if (col_commit == graph->commit) {
                        seen_this = 1;
                        graph_output_commit_char(graph, sb);
+                       chars_written++;
 
-                       if (graph->num_parents < 3)
-                               strbuf_addch(sb, ' ');
-                       else {
-                               int num_dashes =
-                                       ((graph->num_parents - 2) * 2) - 1;
-                               for (j = 0; j < num_dashes; j++)
-                                       strbuf_addch(sb, '-');
-                               strbuf_addstr(sb, ". ");
-                       }
+                       if (graph->num_parents > 2)
+                               chars_written += graph_draw_octopus_merge(graph,
+                                                                         sb);
                } else if (seen_this && (graph->num_parents > 2)) {
-                       strbuf_addstr(sb, "\\ ");
+                       strbuf_write_column(sb, col, '\\');
+                       chars_written++;
                } else if (seen_this && (graph->num_parents == 2)) {
                        /*
                         * This is a 2-way merge commit.
@@ -768,15 +860,19 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
                         */
                        if (graph->prev_state == GRAPH_POST_MERGE &&
                            graph->prev_commit_index < i)
-                               strbuf_addstr(sb, "\\ ");
+                               strbuf_write_column(sb, col, '\\');
                        else
-                               strbuf_addstr(sb, "| ");
+                               strbuf_write_column(sb, col, '|');
+                       chars_written++;
                } else {
-                       strbuf_addstr(sb, "| ");
+                       strbuf_write_column(sb, col, '|');
+                       chars_written++;
                }
+               strbuf_addch(sb, ' ');
+               chars_written++;
        }
 
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, chars_written);
 
        /*
         * Update graph->state
@@ -789,37 +885,75 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
                graph_update_state(graph, GRAPH_COLLAPSING);
 }
 
+static struct column *find_new_column_by_commit(struct git_graph *graph,
+                                               struct commit *commit)
+{
+       int i;
+       for (i = 0; i < graph->num_new_columns; i++) {
+               if (graph->new_columns[i].commit == commit)
+                       return &graph->new_columns[i];
+       }
+       return 0;
+}
+
 static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
 {
        int seen_this = 0;
-       int i, j;
+       int i, j, chars_written;
 
        /*
         * Output the post-merge row
         */
+       chars_written = 0;
        for (i = 0; i <= graph->num_columns; i++) {
+               struct column *col = &graph->columns[i];
                struct commit *col_commit;
                if (i == graph->num_columns) {
                        if (seen_this)
                                break;
                        col_commit = graph->commit;
                } else {
-                       col_commit = graph->columns[i].commit;
+                       col_commit = col->commit;
                }
 
                if (col_commit == graph->commit) {
+                       /*
+                        * Since the current commit is a merge find
+                        * the columns for the parent commits in
+                        * new_columns and use those to format the
+                        * edges.
+                        */
+                       struct commit_list *parents = NULL;
+                       struct column *par_column;
                        seen_this = 1;
-                       strbuf_addch(sb, '|');
-                       for (j = 0; j < graph->num_parents - 1; j++)
-                               strbuf_addstr(sb, "\\ ");
+                       parents = first_interesting_parent(graph);
+                       assert(parents);
+                       par_column = find_new_column_by_commit(graph, parents->item);
+                       assert(par_column);
+
+                       strbuf_write_column(sb, par_column, '|');
+                       chars_written++;
+                       for (j = 0; j < graph->num_parents - 1; j++) {
+                               parents = next_interesting_parent(graph, parents);
+                               assert(parents);
+                               par_column = find_new_column_by_commit(graph, parents->item);
+                               assert(par_column);
+                               strbuf_write_column(sb, par_column, '\\');
+                               strbuf_addch(sb, ' ');
+                       }
+                       chars_written += j * 2;
                } else if (seen_this) {
-                       strbuf_addstr(sb, "\\ ");
+                       strbuf_write_column(sb, col, '\\');
+                       strbuf_addch(sb, ' ');
+                       chars_written += 2;
                } else {
-                       strbuf_addstr(sb, "| ");
+                       strbuf_write_column(sb, col, '|');
+                       strbuf_addch(sb, ' ');
+                       chars_written += 2;
                }
        }
 
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, chars_written);
 
        /*
         * Update graph->state
@@ -834,6 +968,9 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
 {
        int i;
        int *tmp_mapping;
+       short used_horizontal = 0;
+       int horizontal_edge = -1;
+       int horizontal_edge_target = -1;
 
        /*
         * Clear out the new_mapping array
@@ -871,6 +1008,23 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
                         * Move to the left by one
                         */
                        graph->new_mapping[i - 1] = target;
+                       /*
+                        * If there isn't already an edge moving horizontally
+                        * select this one.
+                        */
+                       if (horizontal_edge == -1) {
+                               int j;
+                               horizontal_edge = i;
+                               horizontal_edge_target = target;
+                               /*
+                                * The variable target is the index of the graph
+                                * column, and therefore target*2+3 is the
+                                * actual screen column of the first horizontal
+                                * line.
+                                */
+                               for (j = (target * 2)+3; j < (i - 2); j += 2)
+                                       graph->new_mapping[j] = target;
+                       }
                } else if (graph->new_mapping[i - 1] == target) {
                        /*
                         * There is a branch line to our left
@@ -891,10 +1045,21 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
                         *
                         * The space just to the left of this
                         * branch should always be empty.
+                        *
+                        * The branch to the left of that space
+                        * should be our eventual target.
                         */
                        assert(graph->new_mapping[i - 1] > target);
                        assert(graph->new_mapping[i - 2] < 0);
+                       assert(graph->new_mapping[i - 3] == target);
                        graph->new_mapping[i - 2] = target;
+                       /*
+                        * Mark this branch as the horizontal edge to
+                        * prevent any other edges from moving
+                        * horizontally.
+                        */
+                       if (horizontal_edge == -1)
+                               horizontal_edge = i;
                }
        }
 
@@ -912,12 +1077,27 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
                if (target < 0)
                        strbuf_addch(sb, ' ');
                else if (target * 2 == i)
-                       strbuf_addch(sb, '|');
-               else
-                       strbuf_addch(sb, '/');
+                       strbuf_write_column(sb, &graph->new_columns[target], '|');
+               else if (target == horizontal_edge_target &&
+                        i != horizontal_edge - 1) {
+                               /*
+                                * Set the mappings for all but the
+                                * first segment to -1 so that they
+                                * won't continue into the next line.
+                                */
+                               if (i != (target * 2)+3)
+                                       graph->new_mapping[i] = -1;
+                               used_horizontal = 1;
+                       strbuf_write_column(sb, &graph->new_columns[target], '_');
+               } else {
+                       if (used_horizontal && i < horizontal_edge)
+                               graph->new_mapping[i] = -1;
+                       strbuf_write_column(sb, &graph->new_columns[target], '/');
+
+               }
        }
 
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, graph->mapping_size);
 
        /*
         * Swap mapping and new_mapping
@@ -979,9 +1159,10 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
         * children that we have already processed.)
         */
        for (i = 0; i < graph->num_columns; i++) {
-               struct commit *col_commit = graph->columns[i].commit;
+               struct column *col = &graph->columns[i];
+               struct commit *col_commit = col->commit;
                if (col_commit == graph->commit) {
-                       strbuf_addch(sb, '|');
+                       strbuf_write_column(sb, col, '|');
 
                        if (graph->num_parents < 3)
                                strbuf_addch(sb, ' ');
@@ -991,11 +1172,12 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
                                        strbuf_addch(sb, ' ');
                        }
                } else {
-                       strbuf_addstr(sb, "| ");
+                       strbuf_write_column(sb, col, '|');
+                       strbuf_addch(sb, ' ');
                }
        }
 
-       graph_pad_horizontally(graph, sb);
+       graph_pad_horizontally(graph, sb, graph->num_columns);
 
        /*
         * Update graph->prev_state since we have output a padding line
diff --git a/grep.c b/grep.c
index f3a27d7d6e141bd8813b978edbe33d16aa764fb4..cc6d5b04c15b670c55bdb9e2089e0b71f72453cc 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -72,6 +72,8 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
        struct grep_expr *x;
 
        p = *list;
+       if (!p)
+               return NULL;
        switch (p->token) {
        case GREP_PATTERN: /* atom */
        case GREP_PATTERN_HEAD:
@@ -84,8 +86,6 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
        case GREP_OPEN_PAREN:
                *list = p->next;
                x = compile_pattern_or(list);
-               if (!x)
-                       return NULL;
                if (!*list || (*list)->token != GREP_CLOSE_PAREN)
                        die("unmatched parenthesis");
                *list = (*list)->next;
@@ -101,6 +101,8 @@ static struct grep_expr *compile_pattern_not(struct grep_pat **list)
        struct grep_expr *x;
 
        p = *list;
+       if (!p)
+               return NULL;
        switch (p->token) {
        case GREP_NOT:
                if (!p->next)
@@ -303,6 +305,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
 {
        int hit = 0;
        int saved_ch = 0;
+       const char *start = bol;
 
        if ((p->token != GREP_PATTERN) &&
            ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
@@ -357,12 +360,17 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
                        bol = pmatch[0].rm_so + bol + 1;
                        while (word_char(bol[-1]) && bol < eol)
                                bol++;
+                       eflags |= REG_NOTBOL;
                        if (bol < eol)
                                goto again;
                }
        }
        if (p->token == GREP_PATTERN_HEAD && saved_ch)
                *eol = saved_ch;
+       if (hit) {
+               pmatch[0].rm_so += bol - start;
+               pmatch[0].rm_eo += bol - start;
+       }
        return hit;
 }
 
@@ -372,6 +380,8 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
        int h = 0;
        regmatch_t match;
 
+       if (!x)
+               die("Not a valid grep expression");
        switch (x->node) {
        case GREP_NODE_ATOM:
                h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
diff --git a/grep.h b/grep.h
index a67005de62d1442e7ba6a8dc27320225a0d55819..464e272edf4594539915a89d68628fd3959b8ee3 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -61,23 +61,23 @@ struct grep_opt {
        struct grep_expr *pattern_expression;
        int prefix_length;
        regex_t regexp;
-       unsigned linenum:1;
-       unsigned invert:1;
-       unsigned status_only:1;
-       unsigned name_only:1;
-       unsigned unmatch_name_only:1;
-       unsigned count:1;
-       unsigned word_regexp:1;
-       unsigned fixed:1;
-       unsigned all_match:1;
+       int linenum;
+       int invert;
+       int status_only;
+       int name_only;
+       int unmatch_name_only;
+       int count;
+       int word_regexp;
+       int fixed;
+       int all_match;
 #define GREP_BINARY_DEFAULT    0
 #define GREP_BINARY_NOMATCH    1
 #define GREP_BINARY_TEXT       2
-       unsigned binary:2;
-       unsigned extended:1;
-       unsigned relative:1;
-       unsigned pathname:1;
-       unsigned null_following_name:1;
+       int binary;
+       int extended;
+       int relative;
+       int pathname;
+       int null_following_name;
        int color;
        char color_match[COLOR_MAXLEN];
        const char *color_external;
index 5138224cc372482fb60afd350fa40e37d019f367..43e2dda2e147d47461d52bbd8f66cce8e2739773 100644 (file)
@@ -315,9 +315,9 @@ static void start_fetch_loose(struct transfer_request *request)
                 "%s.temp", filename);
 
        snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
        rename(request->tmpfile, prevfile);
-       unlink(request->tmpfile);
+       unlink_or_warn(request->tmpfile);
 
        if (request->local_fileno != -1)
                error("fd leakage in start: %d", request->local_fileno);
@@ -372,7 +372,7 @@ static void start_fetch_loose(struct transfer_request *request)
                } while (prev_read > 0);
                close(prevlocal);
        }
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
 
        /* Reset inflate/SHA1 if there was an error reading the previous temp
           file; also rewind to the beginning of the local file. */
@@ -784,7 +784,7 @@ static void finish_request(struct transfer_request *request)
                    request->http_code != 416) {
                        if (stat(request->tmpfile, &st) == 0) {
                                if (st.st_size == 0)
-                                       unlink(request->tmpfile);
+                                       unlink_or_warn(request->tmpfile);
                        }
                } else {
                        if (request->http_code == 416)
@@ -793,9 +793,9 @@ static void finish_request(struct transfer_request *request)
                        git_inflate_end(&request->stream);
                        git_SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
-                               unlink(request->tmpfile);
+                               unlink_or_warn(request->tmpfile);
                        } else if (hashcmp(request->obj->sha1, request->real_sha1)) {
-                               unlink(request->tmpfile);
+                               unlink_or_warn(request->tmpfile);
                        } else {
                                request->rename =
                                        move_temp_to_file(
@@ -1415,8 +1415,9 @@ static void remove_locks(void)
 
        fprintf(stderr, "Removing remote locks...\n");
        while (lock) {
+               struct remote_lock *next = lock->next;
                unlock_remote(lock);
-               lock = lock->next;
+               lock = next;
        }
 }
 
@@ -1883,17 +1884,6 @@ static void get_dav_remote_heads(void)
        remote_ls("refs/", (PROCESS_FILES | PROCESS_DIRS | RECURSIVE), process_ls_ref, NULL);
 }
 
-static int is_zero_sha1(const unsigned char *sha1)
-{
-       int i;
-
-       for (i = 0; i < 20; i++) {
-               if (*sha1++)
-                       return 0;
-       }
-       return 1;
-}
-
 static void add_remote_info_ref(struct remote_ls_ctx *ls)
 {
        struct strbuf *buf = (struct strbuf *)ls->userData;
@@ -2119,13 +2109,13 @@ static int delete_remote_branch(char *pattern, int force)
                /* Remote HEAD must resolve to a known object */
                if (symref)
                        return error("Remote HEAD symrefs too deep");
-               if (is_zero_sha1(head_sha1))
+               if (is_null_sha1(head_sha1))
                        return error("Unable to resolve remote HEAD");
                if (!has_sha1_file(head_sha1))
                        return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", sha1_to_hex(head_sha1));
 
                /* Remote branch must resolve to a known object */
-               if (is_zero_sha1(remote_ref->old_sha1))
+               if (is_null_sha1(remote_ref->old_sha1))
                        return error("Unable to resolve remote branch %s",
                                     remote_ref->name);
                if (!has_sha1_file(remote_ref->old_sha1))
@@ -2326,14 +2316,14 @@ int main(int argc, char **argv)
        new_refs = 0;
        for (ref = remote_refs; ref; ref = ref->next) {
                char old_hex[60], *new_hex;
-               const char *commit_argv[4];
+               const char *commit_argv[5];
                int commit_argc;
                char *new_sha1_hex, *old_sha1_hex;
 
                if (!ref->peer_ref)
                        continue;
 
-               if (is_zero_sha1(ref->peer_ref->new_sha1)) {
+               if (is_null_sha1(ref->peer_ref->new_sha1)) {
                        if (delete_remote_branch(ref->name, 1) == -1) {
                                error("Could not remove %s", ref->name);
                                rc = -4;
@@ -2349,7 +2339,7 @@ int main(int argc, char **argv)
                }
 
                if (!force_all &&
-                   !is_zero_sha1(ref->old_sha1) &&
+                   !is_null_sha1(ref->old_sha1) &&
                    !ref->force) {
                        if (!has_sha1_file(ref->old_sha1) ||
                            !ref_newer(ref->peer_ref->new_sha1,
@@ -2399,13 +2389,14 @@ int main(int argc, char **argv)
                old_sha1_hex = NULL;
                commit_argv[1] = "--objects";
                commit_argv[2] = new_sha1_hex;
-               if (!push_all && !is_zero_sha1(ref->old_sha1)) {
+               if (!push_all && !is_null_sha1(ref->old_sha1)) {
                        old_sha1_hex = xmalloc(42);
                        sprintf(old_sha1_hex, "^%s",
                                sha1_to_hex(ref->old_sha1));
                        commit_argv[3] = old_sha1_hex;
                        commit_argc++;
                }
+               commit_argv[commit_argc] = NULL;
                init_revisions(&revs, setup_git_directory());
                setup_revisions(commit_argc, commit_argv, &revs, NULL);
                revs.edge_hint = 0; /* just in case */
index c5a3ea3b31045be9407579a9d1aba222ee3e9914..7321ccc9fe751a1e608c6620bcce401eac7ff98c 100644 (file)
@@ -111,9 +111,9 @@ static void start_object_request(struct walker *walker,
        struct walker_data *data = walker->data;
 
        snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename);
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
        rename(obj_req->tmpfile, prevfile);
-       unlink(obj_req->tmpfile);
+       unlink_or_warn(obj_req->tmpfile);
 
        if (obj_req->local != -1)
                error("fd leakage in start: %d", obj_req->local);
@@ -177,7 +177,7 @@ static void start_object_request(struct walker *walker,
                } while (prev_read > 0);
                close(prevlocal);
        }
-       unlink(prevfile);
+       unlink_or_warn(prevfile);
 
        /* Reset inflate/SHA1 if there was an error reading the previous temp
           file; also rewind to the beginning of the local file. */
@@ -238,18 +238,18 @@ static void finish_object_request(struct object_request *obj_req)
        } else if (obj_req->curl_result != CURLE_OK) {
                if (stat(obj_req->tmpfile, &st) == 0)
                        if (st.st_size == 0)
-                               unlink(obj_req->tmpfile);
+                               unlink_or_warn(obj_req->tmpfile);
                return;
        }
 
        git_inflate_end(&obj_req->stream);
        git_SHA1_Final(obj_req->real_sha1, &obj_req->c);
        if (obj_req->zret != Z_STREAM_END) {
-               unlink(obj_req->tmpfile);
+               unlink_or_warn(obj_req->tmpfile);
                return;
        }
        if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
-               unlink(obj_req->tmpfile);
+               unlink_or_warn(obj_req->tmpfile);
                return;
        }
        obj_req->rename =
@@ -809,7 +809,7 @@ static void abort_object_request(struct object_request *obj_req)
                close(obj_req->local);
                obj_req->local = -1;
        }
-       unlink(obj_req->tmpfile);
+       unlink_or_warn(obj_req->tmpfile);
        if (obj_req->slot) {
                release_active_slot(obj_req->slot);
                obj_req->slot = NULL;
index 8154cb2116da9257ecf286c46f77fc1ed2a62afc..e4c83b9d5b989671c1accc573235479ad77a5ab7 100644 (file)
@@ -982,9 +982,7 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
        struct imap_store *ctx;
        struct imap *imap;
        char *arg, *rsp;
-       struct hostent *he;
-       struct sockaddr_in addr;
-       int s, a[2], preauth;
+       int s = -1, a[2], preauth;
        pid_t pid;
 
        ctx = xcalloc(sizeof(*ctx), 1);
@@ -1021,6 +1019,51 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
 
                imap_info("ok\n");
        } else {
+#ifndef NO_IPV6
+               struct addrinfo hints, *ai0, *ai;
+               int gai;
+               char portstr[6];
+
+               snprintf(portstr, sizeof(portstr), "%hu", srvc->port);
+
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_socktype = SOCK_STREAM;
+               hints.ai_protocol = IPPROTO_TCP;
+
+               imap_info("Resolving %s... ", srvc->host);
+               gai = getaddrinfo(srvc->host, portstr, &hints, &ai);
+               if (gai) {
+                       fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai));
+                       goto bail;
+               }
+               imap_info("ok\n");
+
+               for (ai0 = ai; ai; ai = ai->ai_next) {
+                       char addr[NI_MAXHOST];
+
+                       s = socket(ai->ai_family, ai->ai_socktype,
+                                  ai->ai_protocol);
+                       if (s < 0)
+                               continue;
+
+                       getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
+                                   sizeof(addr), NULL, 0, NI_NUMERICHOST);
+                       imap_info("Connecting to [%s]:%s... ", addr, portstr);
+
+                       if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+                               close(s);
+                               s = -1;
+                               perror("connect");
+                               continue;
+                       }
+
+                       break;
+               }
+               freeaddrinfo(ai0);
+#else /* NO_IPV6 */
+               struct hostent *he;
+               struct sockaddr_in addr;
+
                memset(&addr, 0, sizeof(addr));
                addr.sin_port = htons(srvc->port);
                addr.sin_family = AF_INET;
@@ -1040,7 +1083,12 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
                imap_info("Connecting to %s:%hu... ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
                if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) {
                        close(s);
+                       s = -1;
                        perror("connect");
+               }
+#endif
+               if (s < 0) {
+                       fputs("Error: unable to connect to server.\n", stderr);
                        goto bail;
                }
 
index a32f4cdc458f823f7e8754742d2f8e21b2aabff3..fc281597fd2fd5ad2299eab0848da99355e383fc 100644 (file)
@@ -27,7 +27,7 @@
  *
  * It does so by calculating the costs of the path ending in characters
  * i (in string1) and j (in string2), respectively, given that the last
- * operation is a substition, a swap, a deletion, or an insertion.
+ * operation is a substitution, a swap, a deletion, or an insertion.
  *
  * This implementation allows the costs to be weighted:
  *
index 433394a107fe682b6adfcb122ef182321c4f5947..8953548c07bb36f20798c7ca344d07960c22618c 100644 (file)
@@ -10,7 +10,7 @@
 
 static void process_blob(struct rev_info *revs,
                         struct blob *blob,
-                        struct object_array *p,
+                        show_object_fn show,
                         struct name_path *path,
                         const char *name)
 {
@@ -23,7 +23,7 @@ static void process_blob(struct rev_info *revs,
        if (obj->flags & (UNINTERESTING | SEEN))
                return;
        obj->flags |= SEEN;
-       add_object(obj, p, path, name);
+       show(obj, path, name);
 }
 
 /*
@@ -50,7 +50,7 @@ static void process_blob(struct rev_info *revs,
  */
 static void process_gitlink(struct rev_info *revs,
                            const unsigned char *sha1,
-                           struct object_array *p,
+                           show_object_fn show,
                            struct name_path *path,
                            const char *name)
 {
@@ -59,7 +59,7 @@ static void process_gitlink(struct rev_info *revs,
 
 static void process_tree(struct rev_info *revs,
                         struct tree *tree,
-                        struct object_array *p,
+                        show_object_fn show,
                         struct name_path *path,
                         const char *name)
 {
@@ -77,7 +77,7 @@ static void process_tree(struct rev_info *revs,
        if (parse_tree(tree) < 0)
                die("bad tree object %s", sha1_to_hex(obj->sha1));
        obj->flags |= SEEN;
-       add_object(obj, p, path, name);
+       show(obj, path, name);
        me.up = path;
        me.elem = name;
        me.elem_len = strlen(name);
@@ -88,14 +88,14 @@ static void process_tree(struct rev_info *revs,
                if (S_ISDIR(entry.mode))
                        process_tree(revs,
                                     lookup_tree(entry.sha1),
-                                    p, &me, entry.path);
+                                    show, &me, entry.path);
                else if (S_ISGITLINK(entry.mode))
                        process_gitlink(revs, entry.sha1,
-                                       p, &me, entry.path);
+                                       show, &me, entry.path);
                else
                        process_blob(revs,
                                     lookup_blob(entry.sha1),
-                                    p, &me, entry.path);
+                                    show, &me, entry.path);
        }
        free(tree->buffer);
        tree->buffer = NULL;
@@ -134,6 +134,11 @@ void mark_edges_uninteresting(struct commit_list *list,
        }
 }
 
+static void add_pending_tree(struct rev_info *revs, struct tree *tree)
+{
+       add_pending_object(revs, &tree->object, "");
+}
+
 void traverse_commit_list(struct rev_info *revs,
                          show_commit_fn show_commit,
                          show_object_fn show_object,
@@ -141,10 +146,9 @@ void traverse_commit_list(struct rev_info *revs,
 {
        int i;
        struct commit *commit;
-       struct object_array objects = { 0, 0, NULL };
 
        while ((commit = get_revision(revs)) != NULL) {
-               process_tree(revs, commit->tree, &objects, NULL, "");
+               add_pending_tree(revs, commit->tree);
                show_commit(commit, data);
        }
        for (i = 0; i < revs->pending.nr; i++) {
@@ -155,25 +159,22 @@ void traverse_commit_list(struct rev_info *revs,
                        continue;
                if (obj->type == OBJ_TAG) {
                        obj->flags |= SEEN;
-                       add_object_array(obj, name, &objects);
+                       show_object(obj, NULL, name);
                        continue;
                }
                if (obj->type == OBJ_TREE) {
-                       process_tree(revs, (struct tree *)obj, &objects,
+                       process_tree(revs, (struct tree *)obj, show_object,
                                     NULL, name);
                        continue;
                }
                if (obj->type == OBJ_BLOB) {
-                       process_blob(revs, (struct blob *)obj, &objects,
+                       process_blob(revs, (struct blob *)obj, show_object,
                                     NULL, name);
                        continue;
                }
                die("unknown pending object %s (%s)",
                    sha1_to_hex(obj->sha1), name);
        }
-       for (i = 0; i < objects.nr; i++)
-               show_object(&objects.objects[i], data);
-       free(objects.objects);
        if (revs->pending.nr) {
                free(revs->pending.objects);
                revs->pending.nr = 0;
index 47fae2e4683e604b81c530a80494033a2e36ca35..d65dbf03e657facb29a2846144eda2fa3687bc2f 100644 (file)
@@ -2,7 +2,7 @@
 #define LIST_OBJECTS_H
 
 typedef void (*show_commit_fn)(struct commit *, void *);
-typedef void (*show_object_fn)(struct object_array_entry *, void *);
+typedef void (*show_object_fn)(struct object *, const struct name_path *, const char *);
 typedef void (*show_edge_fn)(struct commit *);
 
 void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
index fa2ca5250c75a0d335570a3a3c71b20ebd0b42fa..81c02ad0531e98379d8cd11dc7c2d70214d67fb4 100644 (file)
@@ -219,7 +219,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
        close(fd);
  bad:
        for (i = 0; i < 3; i++)
-               unlink(temp[i]);
+               unlink_or_warn(temp[i]);
        strbuf_release(&cmd);
        return status;
 }
index 3dbb2d1ff9407a7417be294adedc5312e7421a96..eb931eded5a6ed20f1d80dadf08cbb8009d85767 100644 (file)
@@ -16,7 +16,7 @@ static void remove_lock_file(void)
                    lock_file_list->filename[0]) {
                        if (lock_file_list->fd >= 0)
                                close(lock_file_list->fd);
-                       unlink(lock_file_list->filename);
+                       unlink_or_warn(lock_file_list->filename);
                }
                lock_file_list = lock_file_list->next;
        }
@@ -109,7 +109,7 @@ static char *resolve_symlink(char *p, size_t s)
                         * link is a relative path, so I must replace the
                         * last element of p with it.
                         */
-                       char *r = (char*)last_path_elm(p);
+                       char *r = (char *)last_path_elm(p);
                        if (r - p + link_len < s)
                                strcpy(r, link);
                        else {
@@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk)
        if (lk->filename[0]) {
                if (lk->fd >= 0)
                        close(lk->fd);
-               unlink(lk->filename);
+               unlink_or_warn(lk->filename);
        }
        lk->filename[0] = 0;
 }
index 5bd29e6994c92268ec576671bb8564b57d1a5c9d..59d63eb67e57ab55bdca6493fa8b28b0c870ff21 100644 (file)
@@ -25,6 +25,7 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
        struct object *obj = parse_object(sha1);
        if (!obj)
                return 0;
+       refname = prettify_refname(refname);
        add_name_decoration("", refname, obj);
        while (obj->type == OBJ_TAG) {
                obj = ((struct tag *)obj)->tagged;
index d6f0582238cac037a9779c905b7ece55b9d21ac1..f5df9b961b2999e4824b900d61d28c254b2ef858 100644 (file)
@@ -520,8 +520,12 @@ static void update_file_flags(struct merge_options *o,
                unsigned long size;
 
                if (S_ISGITLINK(mode))
-                       die("cannot read object %s '%s': It is a submodule!",
-                           sha1_to_hex(sha), path);
+                       /*
+                        * We may later decide to recursively descend into
+                        * the submodule directory and update its index
+                        * and/or work tree, but we do not do that now.
+                        */
+                       goto update_index;
 
                buf = read_sha1_file(sha, &type, &size);
                if (!buf)
@@ -929,11 +933,12 @@ static int process_renames(struct merge_options *o,
                                       ren1_src, ren1_dst, branch1,
                                       branch2);
                                update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
-                               update_stages(ren1_dst, NULL,
-                                               branch1 == o->branch1 ?
-                                               ren1->pair->two : NULL,
-                                               branch1 == o->branch1 ?
-                                               NULL : ren1->pair->two, 1);
+                               if (!o->call_depth)
+                                       update_stages(ren1_dst, NULL,
+                                                       branch1 == o->branch1 ?
+                                                       ren1->pair->two : NULL,
+                                                       branch1 == o->branch1 ?
+                                                       NULL : ren1->pair->two, 1);
                        } else if (!sha_eq(dst_other.sha1, null_sha1)) {
                                const char *new_path;
                                clean_merge = 0;
index 7e6a92c88e7b139ec03e0ff26e97e1559a06a220..a6ef439192c1083e367f0a86cb10d93564fc9481 100644 (file)
--- a/object.c
+++ b/object.c
@@ -45,13 +45,14 @@ int type_from_string(const char *str)
 
 static unsigned int hash_obj(struct object *obj, unsigned int n)
 {
-       unsigned int hash = *(unsigned int *)obj->sha1;
+       unsigned int hash;
+       memcpy(&hash, obj->sha1, sizeof(unsigned int));
        return hash % n;
 }
 
 static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size)
 {
-       int j = hash_obj(obj, size);
+       unsigned int j = hash_obj(obj, size);
 
        while (hash[j]) {
                j++;
@@ -61,16 +62,16 @@ static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i
        hash[j] = obj;
 }
 
-static int hashtable_index(const unsigned char *sha1)
+static unsigned int hashtable_index(const unsigned char *sha1)
 {
        unsigned int i;
        memcpy(&i, sha1, sizeof(unsigned int));
-       return (int)(i % obj_hash_size);
+       return i % obj_hash_size;
 }
 
 struct object *lookup_object(const unsigned char *sha1)
 {
-       int i;
+       unsigned int i;
        struct object *obj;
 
        if (!obj_hash)
index 2c76fb181f64e10c65517224b0c09cb648db81ac..301fc60eae1ad53721851a272a0fbd0192881801 100644 (file)
@@ -66,7 +66,7 @@ static void prune_ref(struct ref_to_prune *r)
        struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
 
        if (lock) {
-               unlink(git_path("%s", r->name));
+               unlink_or_warn(git_path("%s", r->name));
                unlock_ref(lock);
        }
 }
index cf71bcffd2e1e9aeacb44df488b0825f09d54255..c52b8ccf59a4848be6f3f810e01029f7c6625c78 100644 (file)
@@ -50,6 +50,7 @@ static int get_value(struct parse_opt_ctx_t *p,
                        /* FALLTHROUGH */
                case OPTION_BOOLEAN:
                case OPTION_BIT:
+               case OPTION_NEGBIT:
                case OPTION_SET_INT:
                case OPTION_SET_PTR:
                        return opterror(opt, "takes no value", flags);
@@ -66,6 +67,13 @@ static int get_value(struct parse_opt_ctx_t *p,
                        *(int *)opt->value |= opt->defval;
                return 0;
 
+       case OPTION_NEGBIT:
+               if (unset)
+                       *(int *)opt->value |= opt->defval;
+               else
+                       *(int *)opt->value &= ~opt->defval;
+               return 0;
+
        case OPTION_BOOLEAN:
                *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
                return 0;
@@ -121,11 +129,33 @@ static int get_value(struct parse_opt_ctx_t *p,
 
 static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
 {
+       const struct option *numopt = NULL;
+
        for (; options->type != OPTION_END; options++) {
                if (options->short_name == *p->opt) {
                        p->opt = p->opt[1] ? p->opt + 1 : NULL;
                        return get_value(p, options, OPT_SHORT);
                }
+
+               /*
+                * Handle the numerical option later, explicit one-digit
+                * options take precedence over it.
+                */
+               if (options->type == OPTION_NUMBER)
+                       numopt = options;
+       }
+       if (numopt && isdigit(*p->opt)) {
+               size_t len = 1;
+               char *arg;
+               int rc;
+
+               while (isdigit(p->opt[len]))
+                       len++;
+               arg = xmemdupz(p->opt, len);
+               p->opt = p->opt[len] ? p->opt + len : NULL;
+               rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
+               free(arg);
+               return rc;
        }
        return -2;
 }
@@ -215,6 +245,25 @@ is_abbreviated:
        return -2;
 }
 
+static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
+                           const struct option *options)
+{
+       for (; options->type != OPTION_END; options++) {
+               if (!(options->flags & PARSE_OPT_NODASH))
+                       continue;
+               if ((options->flags & PARSE_OPT_OPTARG) ||
+                   !(options->flags & PARSE_OPT_NOARG))
+                       die("BUG: dashless options don't support arguments");
+               if (!(options->flags & PARSE_OPT_NONEG))
+                       die("BUG: dashless options don't support negation");
+               if (options->long_name)
+                       die("BUG: dashless options can't be long");
+               if (options->short_name == arg[0] && arg[1] == '\0')
+                       return get_value(p, options, OPT_SHORT);
+       }
+       return -2;
+}
+
 static void check_typos(const char *arg, const struct option *options)
 {
        if (strlen(arg) < 3)
@@ -265,6 +314,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                const char *arg = ctx->argv[0];
 
                if (*arg != '-' || !arg[1]) {
+                       if (parse_nodash_opt(ctx, arg, options) == 0)
+                               continue;
                        if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
                                break;
                        ctx->out[ctx->cpidx++] = ctx->argv[0];
@@ -397,12 +448,18 @@ int usage_with_options_internal(const char * const *usagestr,
                        continue;
 
                pos = fprintf(stderr, "    ");
-               if (opts->short_name)
-                       pos += fprintf(stderr, "-%c", opts->short_name);
+               if (opts->short_name) {
+                       if (opts->flags & PARSE_OPT_NODASH)
+                               pos += fprintf(stderr, "%c", opts->short_name);
+                       else
+                               pos += fprintf(stderr, "-%c", opts->short_name);
+               }
                if (opts->long_name && opts->short_name)
                        pos += fprintf(stderr, ", ");
                if (opts->long_name)
                        pos += fprintf(stderr, "--%s", opts->long_name);
+               if (opts->type == OPTION_NUMBER)
+                       pos += fprintf(stderr, "-NUM");
 
                switch (opts->type) {
                case OPTION_ARGUMENT:
@@ -439,7 +496,7 @@ int usage_with_options_internal(const char * const *usagestr,
                                        pos += fprintf(stderr, " ...");
                        }
                        break;
-               default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
+               default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */
                        break;
                }
 
index f8ef1db1289f85e0877b66d4573044d962df934e..919b9b441f97511695308287a2fdc6f3a45e383d 100644 (file)
@@ -6,8 +6,10 @@ enum parse_opt_type {
        OPTION_END,
        OPTION_ARGUMENT,
        OPTION_GROUP,
+       OPTION_NUMBER,
        /* options with no arguments */
        OPTION_BIT,
+       OPTION_NEGBIT,
        OPTION_BOOLEAN, /* _INCR would have been a better name */
        OPTION_SET_INT,
        OPTION_SET_PTR,
@@ -31,6 +33,7 @@ enum parse_opt_option_flags {
        PARSE_OPT_NONEG   = 4,
        PARSE_OPT_HIDDEN  = 8,
        PARSE_OPT_LASTARG_DEFAULT = 16,
+       PARSE_OPT_NODASH = 32,
 };
 
 struct option;
@@ -52,7 +55,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
  *
  * `argh`::
  *   token to explain the kind of argument this option wants. Keep it
- *   homogenous across the repository.
+ *   homogeneous across the repository.
  *
  * `help`::
  *   the short help associated to what the option does.
@@ -61,11 +64,14 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
  *
  * `flags`::
  *   mask of parse_opt_option_flags.
- *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
+ *   PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs)
  *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
  *   PARSE_OPT_NONEG: says that this option cannot be negated
- *   PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
- *                    the long one.
+ *   PARSE_OPT_HIDDEN: this option is skipped in the default usage, and
+ *                     shown only in the full usage.
+ *   PARSE_OPT_LASTARG_DEFAULT: if no argument is given, the default value
+ *                              is used.
+ *   PARSE_OPT_NODASH: this option doesn't start with a dash.
  *
  * `callback`::
  *   pointer to the callback to use for OPTION_CALLBACK.
@@ -93,6 +99,7 @@ struct option {
 #define OPT_ARGUMENT(l, h)          { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
 #define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
 #define OPT_BIT(s, l, v, h, b)      { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
+#define OPT_NEGBIT(s, l, v, h, b)   { OPTION_NEGBIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
 #define OPT_BOOLEAN(s, l, v, h)     { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
 #define OPT_SET_INT(s, l, v, h, i)  { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
 #define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
@@ -103,9 +110,12 @@ struct option {
          parse_opt_approxidate_cb }
 #define OPT_CALLBACK(s, l, v, a, h, f) \
        { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
+#define OPT_NUMBER_CALLBACK(v, h, f) \
+       { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
+         PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
 
 /* parse_options() will filter out the processed options and leave the
- * non-option argments in argv[].
+ * non-option arguments in argv[].
  * Returns the number of arguments left in argv[].
  */
 extern int parse_options(int argc, const char **argv,
@@ -115,7 +125,7 @@ extern int parse_options(int argc, const char **argv,
 extern NORETURN void usage_with_options(const char * const *usagestr,
                                         const struct option *options);
 
-/*----- incremantal advanced APIs -----*/
+/*----- incremental advanced APIs -----*/
 
 enum {
        PARSE_OPT_HELP = -1,
index 291ff5b53c1883ee8fce67fbb7e2b32393ef0800..e8df55d2f290210ba4cf7ae8c91639f2a34c834e 100644 (file)
@@ -185,7 +185,7 @@ sub repository {
 
                if ($dir) {
                        $dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir;
-                       $opts{Repository} = $dir;
+                       $opts{Repository} = abs_path($dir);
 
                        # If --git-dir went ok, this shouldn't die either.
                        my $prefix = $search->command_oneline('rev-parse', '--show-prefix');
@@ -1280,6 +1280,8 @@ sub _cmd_exec {
        my ($self, @args) = @_;
        if ($self) {
                $self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path();
+               $self->repo_path() and $self->wc_path()
+                       and $ENV{'GIT_WORK_TREE'} = $self->wc_path();
                $self->wc_path() and chdir($self->wc_path());
                $self->wc_subdir() and chdir($self->wc_subdir());
        }
index 55a8687ad15788f8ea5a5beb463d216908f618b2..621c34edc2a3a6a9bceb0f708ed5b0df05145fb5 100644 (file)
@@ -121,13 +121,13 @@ static void throughput_string(struct throughput *tp, off_t total,
                              (int)(total >> 30),
                              (int)(total & ((1 << 30) - 1)) / 10737419);
        } else if (total > 1 << 20) {
+               int x = total + 5243;  /* for rounding */
                l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
-                             (int)(total >> 20),
-                             ((int)(total & ((1 << 20) - 1)) * 100) >> 20);
+                             x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
        } else if (total > 1 << 10) {
+               int x = total + 5;  /* for rounding */
                l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
-                             (int)(total >> 10),
-                             ((int)(total & ((1 << 10) - 1)) * 100) >> 10);
+                             x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
        } else {
                l -= snprintf(tp->display, l, ", %u bytes", (int)total);
        }
index fd065f4e1a689176a3f3255b2d88270bce094ff0..5623ea6b48a2f355e8866eabb2805b51b4127a4a 100644 (file)
@@ -241,7 +241,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
        commit->object.flags &= ~(ADDED | SEEN | SHOWN);
 }
 
-void show_reflog_message(struct reflog_walk_infoinfo, int oneline,
+void show_reflog_message(struct reflog_walk_info *info, int oneline,
        enum date_mode dmode)
 {
        if (info && info->last_commit_reflog) {
diff --git a/refs.c b/refs.c
index 82afb8768473f605bdbce17698b219484890f4f9..24438c652fe4e09aaa1ba6dab283b8e59c24c1a7 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -682,12 +682,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
  * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
  * - it ends with a "/".
  * - it ends with ".lock"
+ * - it contains a "\" (backslash)
  */
 
 static inline int bad_ref_char(int ch)
 {
        if (((unsigned) ch) <= ' ' ||
-           ch == '~' || ch == '^' || ch == ':')
+           ch == '~' || ch == '^' || ch == ':' || ch == '\\')
                return 1;
        /* 2.13 Pattern Matching Notation */
        if (ch == '?' || ch == '[') /* Unsupported */
@@ -750,9 +751,8 @@ int check_ref_format(const char *ref)
        }
 }
 
-const char *prettify_ref(const struct ref *ref)
+const char *prettify_refname(const char *name)
 {
-       const char *name = ref->name;
        return name + (
                !prefixcmp(name, "refs/heads/") ? 11 :
                !prefixcmp(name, "refs/tags/") ? 10 :
@@ -893,8 +893,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
         * name is a proper prefix of our refname.
         */
        if (missing &&
-            !is_refname_available(ref, NULL, get_packed_refs(), 0))
+            !is_refname_available(ref, NULL, get_packed_refs(), 0)) {
+               last_errno = ENOTDIR;
                goto error_return;
+       }
 
        lock->lk = xcalloc(1, sizeof(struct lock_file));
 
@@ -1002,12 +1004,10 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
                } else {
                        path = git_path("%s", refname);
                }
-               err = unlink(path);
-               if (err && errno != ENOENT) {
+               err = unlink_or_warn(path);
+               if (err && errno != ENOENT)
                        ret = 1;
-                       error("unlink(%s) failed: %s",
-                             path, strerror(errno));
-               }
+
                if (!(delopt & REF_NODEREF))
                        lock->lk->filename[i] = '.';
        }
@@ -1017,10 +1017,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
         */
        ret |= repack_without_ref(refname);
 
-       err = unlink(git_path("logs/%s", lock->ref_name));
-       if (err && errno != ENOENT)
-               warning("unlink(%s) failed: %s",
-                       git_path("logs/%s", lock->ref_name), strerror(errno));
+       unlink_or_warn(git_path("logs/%s", lock->ref_name));
        invalidate_cached_refs();
        unlock_ref(lock);
        return ret;
@@ -1381,7 +1378,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
        if (adjust_shared_perm(git_HEAD)) {
                error("Unable to fix permissions on %s", lockpath);
        error_unlink_return:
-               unlink(lockpath);
+               unlink_or_warn(lockpath);
        error_free_return:
                free(git_HEAD);
                return -1;
@@ -1681,7 +1678,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
        return;
 }
 
-char *shorten_unambiguous_ref(const char *ref)
+char *shorten_unambiguous_ref(const char *ref, int strict)
 {
        int i;
        static char **scanf_fmts;
@@ -1718,6 +1715,7 @@ char *shorten_unambiguous_ref(const char *ref)
        /* skip first rule, it will always match */
        for (i = nr_rules - 1; i > 0 ; --i) {
                int j;
+               int rules_to_fail = i;
                int short_name_len;
 
                if (1 != sscanf(ref, scanf_fmts[i], short_name))
@@ -1725,15 +1723,26 @@ char *shorten_unambiguous_ref(const char *ref)
 
                short_name_len = strlen(short_name);
 
+               /*
+                * in strict mode, all (except the matched one) rules
+                * must fail to resolve to a valid non-ambiguous ref
+                */
+               if (strict)
+                       rules_to_fail = nr_rules;
+
                /*
                 * 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++) {
+               for (j = 0; j < rules_to_fail; j++) {
                        const char *rule = ref_rev_parse_rules[j];
                        unsigned char short_objectname[20];
                        char refname[PATH_MAX];
 
+                       /* skip matched rule */
+                       if (i == j)
+                               continue;
+
                        /*
                         * the short name is ambiguous, if it resolves
                         * (with this previous rule) to a valid ref
@@ -1749,7 +1758,7 @@ char *shorten_unambiguous_ref(const char *ref)
                 * short name is non-ambiguous if all previous rules
                 * haven't resolved to a valid ref
                 */
-               if (j == i)
+               if (j == rules_to_fail)
                        return short_name;
        }
 
diff --git a/refs.h b/refs.h
index 50abbbb2aafb5c6a514d3704001f60473b8b1bfa..c11f6a6d588d1bd737fa60241b9c67308f4c14cc 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -80,8 +80,8 @@ extern int for_each_reflog(each_ref_fn, void *);
 #define CHECK_REF_FORMAT_WILDCARD (-3)
 extern int check_ref_format(const char *target);
 
-extern const char *prettify_ref(const struct ref *ref);
-extern char *shorten_unambiguous_ref(const char *ref);
+extern const char *prettify_refname(const char *refname);
+extern char *shorten_unambiguous_ref(const char *ref, int strict);
 
 /** rename ref, return 0 on success **/
 extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
index a06761ace8a2566746a5ebeedf6b3075f625c47b..2c3e9053a492e0029eb1f98a8d2c649564888197 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -366,7 +366,7 @@ static int handle_config(const char *key, const char *value, void *cb)
        }
        subkey = strrchr(name, '.');
        if (!subkey)
-               return error("Config with no key for remote %s", name);
+               return 0;
        remote = make_remote(name, subkey - name);
        remote->origin = REMOTE_CONFIG;
        if (!strcmp(subkey, ".mirror"))
@@ -1399,13 +1399,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
        base = branch->merge[0]->dst;
        if (!resolve_ref(base, sha1, 1, NULL))
                return 0;
-       theirs = lookup_commit(sha1);
+       theirs = lookup_commit_reference(sha1);
        if (!theirs)
                return 0;
 
        if (!resolve_ref(branch->refname, sha1, 1, NULL))
                return 0;
-       ours = lookup_commit(sha1);
+       ours = lookup_commit_reference(sha1);
        if (!ours)
                return 0;
 
@@ -1413,10 +1413,9 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
        if (theirs == ours)
                return 0;
 
-       /* Run "rev-list --no-merges --left-right ours...theirs" internally... */
+       /* Run "rev-list --left-right ours...theirs" internally... */
        rev_argc = 0;
        rev_argv[rev_argc++] = NULL;
-       rev_argv[rev_argc++] = "--no-merges";
        rev_argv[rev_argc++] = "--left-right";
        rev_argv[rev_argc++] = symmetric;
        rev_argv[rev_argc++] = "--";
@@ -1461,11 +1460,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                return 0;
 
        base = branch->merge[0]->dst;
-       if (!prefixcmp(base, "refs/remotes/")) {
-               base += strlen("refs/remotes/");
-       } else if (!prefixcmp(base, "refs/heads/")) {
-               base += strlen("refs/heads/");
-       }
+       base = shorten_unambiguous_ref(base, 0);
        if (!num_theirs)
                strbuf_addf(sb, "Your branch is ahead of '%s' "
                            "by %d commit%s.\n",
@@ -1504,7 +1499,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla
 
 struct ref *get_local_heads(void)
 {
-       struct ref *local_refs, **local_tail = &local_refs;
+       struct ref *local_refs = NULL, **local_tail = &local_refs;
        for_each_ref(one_local_ref, &local_tail);
        return local_refs;
 }
index 713c6e16ac536eaa667cc9f22768670be129483c..87360dc23e54aabf47b3bda160e58058507d4a2f 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -173,7 +173,7 @@ static int handle_file(const char *path,
                git_SHA1_Final(sha1, &ctx);
        if (hunk != RR_CONTEXT) {
                if (output)
-                       unlink(output);
+                       unlink_or_warn(output);
                return error("Could not parse conflict hunks in %s", path);
        }
        if (wrerror)
index b6215cc72c77baa3f72d652e8457d3ace6e5f439..18b7ebbbd599417462b5c4275c2581b91ebeca6a 100644 (file)
@@ -15,9 +15,9 @@
 
 volatile show_early_output_fn_t show_early_output;
 
-static char *path_name(struct name_path *path, const char *name)
+char *path_name(const struct name_path *path, const char *name)
 {
-       struct name_path *p;
+       const struct name_path *p;
        char *n, *m;
        int nlen = strlen(name);
        int len = nlen + 1;
@@ -209,7 +209,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
        }
 
        /*
-        * Tree object? Either mark it uniniteresting, or add it
+        * Tree object? Either mark it uninteresting, or add it
         * to the list of objects to look at later..
         */
        if (object->type == OBJ_TREE) {
index 5adfc9140544429254bd67ff10504730c7424e1b..be39e7d38643817cced4e07a89b6db5201f2b747 100644 (file)
@@ -146,6 +146,8 @@ struct name_path {
        const char *elem;
 };
 
+char *path_name(const struct name_path *path, const char *name);
+
 extern void add_object(struct object *obj,
                       struct object_array *p,
                       struct name_path *path,
index b05c734d05e99cd009a0df26f0fc95fa13ae6f25..eb2efc33073512efd14b65e67db8cf814ca3fa33 100644 (file)
@@ -106,7 +106,7 @@ int start_command(struct child_process *cmd)
                if (cmd->env) {
                        for (; *cmd->env; cmd->env++) {
                                if (strchr(*cmd->env, '='))
-                                       putenv((char*)*cmd->env);
+                                       putenv((char *)*cmd->env);
                                else
                                        unsetenv(*cmd->env);
                        }
index 83d76c7e35183ded9eec5a56c59d4da549c0b584..1d7b1b3b4f41177dfd6637fcd98a0fc01f310c09 100644 (file)
@@ -6,6 +6,7 @@ struct send_pack_args {
                send_mirror:1,
                force_update:1,
                use_thin_pack:1,
+               use_ofs_delta:1,
                dry_run:1;
 };
 
index 66b0d9d878a011393582b837301eb1fd5caf2e40..4098ca2b5c166c32cfe4aea9d1bff2e6593e9a60 100644 (file)
@@ -132,8 +132,8 @@ static int read_pack_info_file(const char *infofile)
 
 static int compare_info(const void *a_, const void *b_)
 {
-       struct pack_info * const* a = a_;
-       struct pack_info * const* b = b_;
+       struct pack_info *const *a = a_;
+       struct pack_info *const *b = b_;
 
        if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
                /* Keep the order in the original */
@@ -246,7 +246,7 @@ int update_server_info(int force)
        errs = errs | update_info_packs(force);
 
        /* remove leftover rev-cache file if there is any */
-       unlink(git_path("info/rev-cache"));
+       unlink_or_warn(git_path("info/rev-cache"));
 
        return errs;
 }
index 8fe135dc61908103cf2d7de700794843f83db057..e73cd4fc0ba2daac14f604f1973d1b0658212b26 100644 (file)
@@ -720,6 +720,8 @@ static int open_packed_git_1(struct packed_git *p)
                return error("packfile %s index unavailable", p->pack_name);
 
        p->pack_fd = open(p->pack_name, O_RDONLY);
+       while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1))
+               p->pack_fd = open(p->pack_name, O_RDONLY);
        if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
                return -1;
 
@@ -791,7 +793,7 @@ static int in_window(struct pack_window *win, off_t offset)
                && (offset + 20) <= (win_off + win->len);
 }
 
-unsigned charuse_pack(struct packed_git *p,
+unsigned char *use_pack(struct packed_git *p,
                struct pack_window **w_cursor,
                off_t offset,
                unsigned int *left)
@@ -937,6 +939,8 @@ static void prepare_packed_git_one(char *objdir, int local)
        sprintf(path, "%s/pack", objdir);
        len = strlen(path);
        dir = opendir(path);
+       while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1))
+               dir = opendir(path);
        if (!dir) {
                if (errno != ENOENT)
                        error("unable to open object pack directory: %s: %s",
@@ -2225,7 +2229,9 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
 {
        int ret = 0;
 
-       if (link(tmpfile, filename))
+       if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
+               goto try_rename;
+       else if (link(tmpfile, filename))
                ret = errno;
 
        /*
@@ -2240,11 +2246,12 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
         * left to unlink.
         */
        if (ret && ret != EEXIST) {
+       try_rename:
                if (!rename(tmpfile, filename))
                        goto out;
                ret = errno;
        }
-       unlink(tmpfile);
+       unlink_or_warn(tmpfile);
        if (ret) {
                if (ret != EEXIST) {
                        return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
@@ -2336,6 +2343,8 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
 
        filename = sha1_file_name(sha1);
        fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
+       while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1))
+               fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
        if (fd < 0) {
                if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
diff --git a/shell.c b/shell.c
index e3393690dd3b79af80e6b95710583e744fd574d4..b968be79f487f8d93e205fd0a844a206e24f21f8 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -40,6 +40,7 @@ static struct commands {
 } cmd_list[] = {
        { "git-receive-pack", do_generic_cmd },
        { "git-upload-pack", do_generic_cmd },
+       { "git-upload-archive", do_generic_cmd },
        { "cvs", do_cvs_cmd },
        { NULL },
 };
index 9ee908a3ec5d4d5329385bc10cdd676f703c0c1f..eaa8704d5fa6e85d33953db77dd03de3cb462df4 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -11,7 +11,7 @@
  *    build complex strings/buffers whose final size isn't easily known.
  *
  *    It is NOT legal to copy the ->buf pointer away.
- *    `strbuf_detach' is the operation that detachs a buffer from its shell
+ *    `strbuf_detach' is the operation that detaches a buffer from its shell
  *    while keeping the shell valid wrt its invariants.
  *
  * 2. the ->buf member is a byte array that has at least ->len + 1 bytes
index cacb273afff1fbddf152bb440451fa141589cf33..396b9653a3ad80490cf360c86a910edff58862a2 100644 (file)
@@ -114,7 +114,10 @@ test_expect_success \
 test_expect_success \
     'some edit' \
     'mv file file.orig &&
-    sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" < file.orig > file &&
+    {
+       cat file.orig &&
+       echo
+    } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" > file &&
     echo "incomplete" | tr -d "\\012" >>file &&
     GIT_AUTHOR_NAME="D" git commit -a -m "edit"'
 
index 773d47cf3cb704d7976185738a2b9840c159a33c..56549623430ca6bea2de35bbae7d2d211720da3b 100644 (file)
@@ -26,6 +26,8 @@ fi
 
 svnrepo=$PWD/svnrepo
 export svnrepo
+svnconf=$PWD/svnconf
+export svnconf
 
 perl -w -e "
 use SVN::Core;
@@ -54,6 +56,19 @@ poke() {
        test-chmtime +1 "$1"
 }
 
+# We need this, because we should pass empty configuration directory to
+# the 'svn commit' to avoid automated property changes and other stuff
+# that could be set from user's configuration files in ~/.subversion.
+svn_cmd () {
+       [ -d "$svnconf" ] || mkdir "$svnconf"
+       orig_svncmd="$1"; shift
+       if [ -z "$orig_svncmd" ]; then
+               svn
+               return
+       fi
+       svn "$orig_svncmd" --config-dir "$svnconf" "$@"
+}
+
 for d in \
        "$SVN_HTTPD_PATH" \
        /usr/sbin/apache2 \
index 5ac0a273a94c033fbb7c48cb9a22e44c389e0f7d..e3d846420dc09e7b24876b291b9e546ac0628ed3 100755 (executable)
@@ -199,4 +199,13 @@ test_expect_success 'init honors global core.sharedRepository' '
        x`git config -f shared-honor-global/.git/config core.sharedRepository`
 '
 
+test_expect_success 'init rejects insanely long --template' '
+       (
+               insane=$(printf "x%09999dx" 1) &&
+               mkdir test &&
+               cd test &&
+               test_must_fail git init --template=$insane
+       )
+'
+
 test_done
index e38241c80a6625c9b5b89340b9d0c5a2667bf345..a40c1236c0862da4d77231bf9255b499ccddd99f 100755 (executable)
@@ -12,6 +12,7 @@ usage: test-parse-options <options>
 
     -b, --boolean         get a boolean
     -4, --or4             bitwise-or boolean with ...0100
+    --neg-or4             same as --no-or4
 
     -i, --integer <n>     get a integer
     -j <n>                get a integer, too
@@ -29,6 +30,8 @@ String options
 
 Magic arguments
     --quux                means --quux
+    -NUM                  set integer to NUM
+    +                     same as -b
 
 Standard options
     --abbrev[=<n>]        use <n> digits to display SHA-1s
@@ -245,7 +248,56 @@ test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
        test_cmp expect output
 '
 
-# --or4
-# --no-or4
+test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' '
+       test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err &&
+       test ! -s output.err &&
+       test_cmp expect output
+'
+
+cat > expect <<EOF
+boolean: 6
+integer: 0
+timestamp: 0
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_BIT() works' '
+       test-parse-options -bb --or4 > output 2> output.err &&
+       test ! -s output.err &&
+       test_cmp expect output
+'
+
+test_expect_success 'OPT_NEGBIT() works' '
+       test-parse-options -bb --no-neg-or4 > output 2> output.err &&
+       test ! -s output.err &&
+       test_cmp expect output
+'
+
+test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' '
+       test-parse-options + + + + + + > output 2> output.err &&
+       test ! -s output.err &&
+       test_cmp expect output
+'
+
+cat > expect <<EOF
+boolean: 0
+integer: 12345
+timestamp: 0
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_NUMBER_CALLBACK() works' '
+       test-parse-options -12345 > output 2> output.err &&
+       test ! -s output.err &&
+       test_cmp expect output
+'
 
 test_done
index 750fbb32e87e0eb8f7a95928f9b407036822c7ad..de42d21c922045415abedf3c81163682d0754eb5 100755 (executable)
@@ -126,7 +126,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
        esac
 '
 
-test_expect_success 'forced modes' '
+test_expect_success POSIXPERM 'forced modes' '
        mkdir -p templates/hooks &&
        echo update-server-info >templates/hooks/post-update &&
        chmod +x templates/hooks/post-update &&
@@ -141,11 +141,14 @@ test_expect_success 'forced modes' '
                git commit -a -m initial &&
                git repack
        ) &&
-       find new/.git -print |
+       # List repository files meant to be protected; note that
+       # COMMIT_EDITMSG does not matter---0mode is not about a
+       # repository with a work tree.
+       find new/.git -type f -name COMMIT_EDITMSG -prune -o -print |
        xargs ls -ld >actual &&
 
        # Everything must be unaccessible to others
-       test -z "$(sed -n -e "/^.......---/d" actual)" &&
+       test -z "$(sed -e "/^.......---/d" actual)" &&
 
        # All directories must have either 2770 or 770
        test -z "$(sed -n -e "/^drwxrw[sx]---/d" -e "/^d/p" actual)" &&
@@ -156,10 +159,11 @@ test_expect_success 'forced modes' '
                p
        }" actual)" &&
 
-       # All files inside objects must be 0440
+       # All files inside objects must be accessible by us
        test -z "$(sed -n -e "/objects\//{
                /^d/d
-               /^-r--r-----/d
+               /^-r.-r.----/d
+               p
        }" actual)"
 '
 
index 1983076c753ea12a4f69d2a98eda3c1621daed59..080117c6bcbb61078539f36011ecd62780bae305 100755 (executable)
@@ -10,7 +10,7 @@ setup() {
 
 check() {
        echo "$2" >expected
-       git config --get "$1" >actual
+       git config --get "$1" >actual 2>&1
        test_cmp actual expected
 }
 
@@ -40,4 +40,11 @@ test_expect_success 'make sure git config escapes section names properly' '
        check "$SECTION" bar
 '
 
+LONG_VALUE=$(printf "x%01021dx a" 7)
+test_expect_success 'do not crash on special long config line' '
+       setup &&
+       git config section.key "$LONG_VALUE" &&
+       check section.key "fatal: bad config file line 2 in .git/config"
+'
+
 test_done
diff --git a/t/t2014-switch.sh b/t/t2014-switch.sh
new file mode 100755 (executable)
index 0000000..ccfb147
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+test_description='Peter MacMillan'
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo Hello >file &&
+       git add file &&
+       test_tick &&
+       git commit -m V1 &&
+       echo Hello world >file &&
+       git add file &&
+       git checkout -b other
+'
+
+test_expect_success 'check all changes are staged' '
+       git diff --exit-code
+'
+
+test_expect_success 'second commit' '
+       git commit -m V2
+'
+
+test_expect_success 'check' '
+       git diff --cached --exit-code
+'
+
+test_done
diff --git a/t/t3031-merge-criscross.sh b/t/t3031-merge-criscross.sh
new file mode 100755 (executable)
index 0000000..7f41607
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+#         A      <- create some files
+#        / \
+#       B   C    <- cause rename/delete conflicts between B and C
+#      /     \
+#     |\     /|
+#     | D   E |
+#     |  \ /  |
+#     |   X   |
+#     |  / \  |
+#     | /   \ |
+#     |/     \|
+#     F       G  <- merge E into B, D into C
+#      \     /
+#       \   /
+#        \ /
+#         H      <- recursive merge crashes
+#
+
+# initialize
+test_expect_success 'setup repo with criss-cross history' '
+       mkdir data &&
+
+       # create a bunch of files
+       n=1 &&
+       while test $n -le 10
+       do
+               echo $n > data/$n &&
+               n=$(($n+1)) ||
+               break
+       done &&
+
+       # check them in
+       git add data &&
+       git commit -m A &&
+       git branch A &&
+
+       # a file in one branch
+       git checkout -b B A &&
+       git rm data/9 &&
+       git add data &&
+       git commit -m B &&
+
+       # with a branch off of it
+       git branch D &&
+
+       # put some commits on D
+       git checkout D &&
+       echo testD > data/testD &&
+       git add data &&
+       git commit -m D &&
+
+       # back up to the top, create another branch and cause
+       # a rename conflict with the file we deleted earlier
+       git checkout -b C A &&
+       git mv data/9 data/new-9 &&
+       git add data &&
+       git commit -m C &&
+
+       # with a branch off of it
+       git branch E &&
+
+       # put a commit on E
+       git checkout E &&
+       echo testE > data/testE &&
+       git add data &&
+       git commit -m E &&
+
+       # now, merge E into B
+       git checkout B &&
+       test_must_fail git merge E &&
+       # force-resolve
+       git add data &&
+       git commit -m F &&
+       git branch F &&
+
+       # and merge D into C
+       git checkout C &&
+       test_must_fail git merge D &&
+       # force-resolve
+       git add data &&
+       git commit -m G &&
+       git branch G
+'
+
+test_expect_success 'recursive merge between F and G, causes segfault' '
+       git merge F
+'
+
+test_done
index 6e391a370208c9a0a6e73facc87f6a0e5081b929..7f62bfb9ddbc4b28017be529d73c7ece29424fec 100755 (executable)
@@ -41,9 +41,40 @@ test_expect_success \
      git tag topic
 '
 
+test_expect_success 'rebase on dirty worktree' '
+     echo dirty >> A &&
+     test_must_fail git rebase master'
+
+test_expect_success 'rebase on dirty cache' '
+     git add A &&
+     test_must_fail git rebase master'
+
 test_expect_success 'rebase against master' '
+     git reset --hard HEAD &&
      git rebase master'
 
+test_expect_success 'rebase against master twice' '
+     git rebase master 2>err &&
+     grep "Current branch my-topic-branch is up to date" err
+'
+
+test_expect_success 'rebase against master twice with --force' '
+     git rebase --force-rebase master >out &&
+     grep "Current branch my-topic-branch is up to date, rebase forced" out
+'
+
+test_expect_success 'rebase against master twice from another branch' '
+     git checkout my-topic-branch^ &&
+     git rebase master my-topic-branch 2>err &&
+     grep "Current branch my-topic-branch is up to date" err
+'
+
+test_expect_success 'rebase fast-forward to master' '
+     git checkout my-topic-branch^ &&
+     git rebase my-topic-branch 2>err &&
+     grep "Fast-forwarded HEAD to my-topic-branch" err
+'
+
 test_expect_success \
     'the rebase operation should not have destroyed author information' \
     '! (git log | grep "Author:" | grep "<>")'
index 050de42ef4148a730c30520ccaad5e9871e536bd..6ce8256a17bb7c775eed301b3af8a88497a12c09 100755 (executable)
@@ -230,4 +230,16 @@ test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" '
        ! ( git ls-files foobar | grep foobar )
 '
 
+test_expect_success 'git add to resolve conflicts on otherwise ignored path' '
+       git reset --hard &&
+       H=$(git rev-parse :1/2/a) &&
+       (
+               echo "100644 $H 1       track-this"
+               echo "100644 $H 3       track-this"
+       ) | git update-index --index-info &&
+       echo track-this >>.gitignore &&
+       echo resolved >track-this &&
+       git add track-this
+'
+
 test_done
index dfc65601aa2171bfc9321753a3d90db112d81f72..fd2a55a5c23247c010a02513af73a93641cfb067 100755 (executable)
@@ -165,4 +165,42 @@ test_expect_success FILEMODE 'stage mode but not hunk' '
 
 # end of tests disabled when filemode is not usable
 
+test_expect_success 'setup again' '
+       git reset --hard &&
+       test_chmod +x file &&
+       echo content >>file
+'
+
+# Write the patch file with a new line at the top and bottom
+cat >patch <<EOF
+index 180b47c..b6f2c08 100644
+--- a/file
++++ b/file
+@@ -1,2 +1,4 @@
++firstline
+ baseline
+ content
++lastline
+EOF
+# Expected output, similar to the patch but w/ diff at the top
+cat >expected <<EOF
+diff --git a/file b/file
+index b6f2c08..61b9053 100755
+--- a/file
++++ b/file
+@@ -1,2 +1,4 @@
++firstline
+ baseline
+ content
++lastline
+EOF
+# Test splitting the first patch, then adding both
+test_expect_success 'add first line works' '
+       git commit -am "clear local changes" &&
+       git apply patch &&
+       (echo s; echo y; echo y) | git add -p file &&
+       git diff --cached > diff &&
+       test_cmp expected diff
+'
+
 test_done
diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh
new file mode 100755 (executable)
index 0000000..4ee47cc
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='add -e basic tests'
+. ./test-lib.sh
+
+
+cat > file << EOF
+LO, praise of the prowess of people-kings
+of spear-armed Danes, in days long sped,
+we have heard, and what honor the athelings won!
+Oft Scyld the Scefing from squadroned foes,
+from many a tribe, the mead-bench tore,
+awing the earls. Since erst he lay
+friendless, a foundling, fate repaid him:
+for he waxed under welkin, in wealth he throve,
+till before him the folk, both far and near,
+who house by the whale-path, heard his mandate,
+gave him gifts:  a good king he!
+EOF
+
+cat > second-part << EOF
+To him an heir was afterward born,
+a son in his halls, whom heaven sent
+to favor the folk, feeling their woe
+that erst they had lacked an earl for leader
+so long a while; the Lord endowed him,
+the Wielder of Wonder, with world's renown.
+EOF
+
+test_expect_success 'setup' '
+
+       git add file &&
+       test_tick &&
+       git commit -m initial file
+
+'
+
+cat > expected-patch << EOF
+diff --git a/file b/file
+index b9834b5..9020acb 100644
+--- a/file
++++ b/file
+@@ -1,11 +1,6 @@
+-LO, praise of the prowess of people-kings
+-of spear-armed Danes, in days long sped,
+-we have heard, and what honor the athelings won!
+-Oft Scyld the Scefing from squadroned foes,
+-from many a tribe, the mead-bench tore,
+-awing the earls. Since erst he lay
+-friendless, a foundling, fate repaid him:
+-for he waxed under welkin, in wealth he throve,
+-till before him the folk, both far and near,
+-who house by the whale-path, heard his mandate,
+-gave him gifts:  a good king he!
++To him an heir was afterward born,
++a son in his halls, whom heaven sent
++to favor the folk, feeling their woe
++that erst they had lacked an earl for leader
++so long a while; the Lord endowed him,
++the Wielder of Wonder, with world's renown.
+EOF
+
+cat > patch << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+@@ -2,7 +1,5 @@ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+EOF
+
+cat > expected << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -1,10 +1,12 @@
+ LO, praise of the prowess of people-kings
+ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+ from many a tribe, the mead-bench tore,
+ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+ till before him the folk, both far and near,
+ who house by the whale-path, heard his mandate,
+EOF
+
+echo "#!$SHELL_PATH" >fake-editor.sh
+cat >> fake-editor.sh <<\EOF
+mv -f "$1" orig-patch &&
+mv -f patch "$1"
+EOF
+
+test_set_editor "$(pwd)/fake-editor.sh"
+chmod a+x fake-editor.sh
+
+test_expect_success 'add -e' '
+
+       cp second-part file &&
+       git add -e &&
+       test_cmp second-part file &&
+       test_cmp orig-patch expected-patch &&
+       git diff --cached > out &&
+       test_cmp out expected
+
+'
+
+test_done
index 784c31aec99d90b69186079ddb66350d9f4a8827..b4ec2b53de2662a5ba40602d4b7a4fde984c4013 100755 (executable)
@@ -9,7 +9,15 @@ test_description='commit and log output encodings'
 
 compare_with () {
        git show -s $1 | sed -e '1,/^$/d' -e 's/^    //' >current &&
-       test_cmp current "$2"
+       case "$3" in
+       '')
+               test_cmp "$2" current ;;
+       ?*)
+               iconv -f "$3" -t UTF-8 >current.utf8 <current &&
+               iconv -f "$3" -t UTF-8 >expect.utf8 <"$2" &&
+               test_cmp expect.utf8 current.utf8
+               ;;
+       esac
 }
 
 test_expect_success setup '
@@ -103,11 +111,17 @@ done
 
 for J in EUCJP ISO-2022-JP
 do
+       if test "$J" = ISO-2022-JP
+       then
+               ICONV=$J
+       else
+               ICONV=
+       fi
        git config i18n.logoutputencoding $J
        for H in EUCJP ISO-2022-JP
        do
                test_expect_success "$H should be shown in $J now" '
-                       compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt
+                       compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt $ICONV
                '
        done
 done
index 12da8ac07de4423cf4736aced96bab8150f83ef0..954210ea907cb04f6113d82194c0753019270d8a 100644 (file)
@@ -1,12 +1,12 @@
 $ git log --decorate --all
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
     Merge branch 'side'
 
-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:03:00 2006 +0000
 
@@ -26,7 +26,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 
-commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (initial)
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:00:00 2006 +0000
 
index 11061ddd5bd122a1e180509c018e1b8bea42ddc3..922a8941ed4720e2ad6dcd500a3759187aace969 100755 (executable)
@@ -505,4 +505,15 @@ test_expect_success 'format-patch from a subdirectory (3)' '
        test -f "$basename"
 '
 
+test_expect_success 'format-patch --in-reply-to' '
+       git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
+       grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
+       grep "^References: <baz@foo.bar>" patch8
+'
+
+test_expect_success 'format-patch --signoff' '
+       git format-patch -1 --signoff --stdout |
+       grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+'
+
 test_done
index be541348c6f8d469428e2fcc7abaf6d25168c08f..5b10e976a3fd0c554ff2fa14004e69343a9ec634 100755 (executable)
@@ -32,7 +32,7 @@ EOF
 
 sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
 
-builtin_patterns="bibtex html java objc pascal php python ruby tex"
+builtin_patterns="bibtex cpp html java objc pascal php python ruby tex"
 for p in $builtin_patterns
 do
        test_expect_success "builtin $p pattern compiles" '
index 390af2389f3b9559fcfebe1e21a24317562ab7af..709b3231ca8d9da631727b4aadfb2f46049d37e9 100755 (executable)
@@ -86,6 +86,13 @@ test_expect_success 'format.numbered && --no-numbered' '
 
 '
 
+test_expect_success 'format.numbered && --keep-subject' '
+
+       git format-patch --keep-subject --stdout HEAD^ >patch4a &&
+       grep "^Subject: Third" patch4a
+
+'
+
 test_expect_success 'format.numbered = auto' '
 
        git config format.numbered auto
@@ -108,4 +115,10 @@ test_expect_success 'format.numbered = auto && --no-numbered' '
 
 '
 
+test_expect_success '--start-number && --numbered' '
+
+       git format-patch --start-number 3 --numbered --stdout HEAD~1 > patch8 &&
+       grep "^Subject: \[PATCH 3/3\]" patch8
+'
+
 test_done
index 1c2edebb09bd6e1d7581365011c8500da57942c5..5cf8924b2163ec55328ce270911a23cdcf52634a 100755 (executable)
@@ -57,4 +57,43 @@ test_expect_success 'git diff (empty submodule dir)' '
        test_cmp empty actual.empty
 '
 
+test_expect_success 'conflicted submodule setup' '
+
+       # 39 efs
+       c=fffffffffffffffffffffffffffffffffffffff
+       (
+               echo "000000 $_z40 0    sub"
+               echo "160000 1$c 1      sub"
+               echo "160000 2$c 2      sub"
+               echo "160000 3$c 3      sub"
+       ) | git update-index --index-info &&
+       echo >expect.nosub '\''diff --cc sub
+index 2ffffff,3ffffff..0000000
+--- a/sub
++++ b/sub
+@@@ -1,1 -1,1 +1,1 @@@
+- Subproject commit 2fffffffffffffffffffffffffffffffffffffff
+ -Subproject commit 3fffffffffffffffffffffffffffffffffffffff
+++Subproject commit 0000000000000000000000000000000000000000'\'' &&
+
+       hh=$(git rev-parse HEAD) &&
+       sed -e "s/$_z40/$hh/" expect.nosub >expect.withsub
+
+'
+
+test_expect_success 'combined (empty submodule)' '
+       rm -fr sub && mkdir sub &&
+       git diff >actual &&
+       test_cmp expect.nosub actual
+'
+
+test_expect_success 'combined (with submodule)' '
+       rm -fr sub &&
+       git clone --no-checkout . sub &&
+       git diff >actual &&
+       test_cmp expect.withsub actual
+'
+
+
+
 test_done
index 9ddbbcde57489e266e2f229314ebac5dbfeb3be6..3ccc237a8d4443bfc8763fbb9cb51033f846b0e8 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 #
 # Copyright (c) Jim Meyering
 #
index f92e259cc6f251ec6f89edee3fc16720f264d82f..65f2e4c3efb9ae5b5459e15df337e07201d78c38 100755 (executable)
@@ -20,10 +20,10 @@ test_expect_success setup '
                cat file1 &&
                echo Q | tr -d "\\012"
        } >file2 &&
-       cat file2 >file2.orig
+       cat file2 >file2.orig &&
        git add file1 file2 &&
        sed -e "/^B/d" <file1.orig >file1 &&
-       sed -e "/^[BQ]/d" <file2.orig >file2 &&
+       cat file1 > file2 &&
        echo Q | tr -d "\\012" >>file2 &&
        cat file1 >file1.mods &&
        cat file2 >file2.mods &&
diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
new file mode 100755 (executable)
index 0000000..7cfa2d6
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='git apply handling criss-cross rename patch.'
+. ./test-lib.sh
+
+create_file() {
+       cnt=0
+       while test $cnt -le 100
+       do
+               cnt=$(($cnt + 1))
+               echo "$2" >> "$1"
+       done
+}
+
+test_expect_success 'setup' '
+       create_file file1 "File1 contents" &&
+       create_file file2 "File2 contents" &&
+       create_file file3 "File3 contents" &&
+       git add file1 file2 file3 &&
+       git commit -m 1
+'
+
+test_expect_success 'criss-cross rename' '
+       mv file1 tmp &&
+       mv file2 file1 &&
+       mv tmp file2 &&
+       cp file1 file1-swapped &&
+       cp file2 file2-swapped
+'
+
+test_expect_success 'diff -M -B' '
+       git diff -M -B > diff &&
+       git reset --hard
+
+'
+
+test_expect_success 'apply' '
+       git apply diff &&
+       test_cmp file1 file1-swapped &&
+       test_cmp file2 file2-swapped
+'
+
+test_expect_success 'criss-cross rename' '
+       git reset --hard &&
+       mv file1 tmp &&
+       mv file2 file1 &&
+       mv file3 file2
+       mv tmp file3 &&
+       cp file1 file1-swapped &&
+       cp file2 file2-swapped &&
+       cp file3 file3-swapped
+'
+
+test_expect_success 'diff -M -B' '
+       git diff -M -B > diff &&
+       git reset --hard
+'
+
+test_expect_success 'apply' '
+       git apply diff &&
+       test_cmp file1 file1-swapped &&
+       test_cmp file2 file2-swapped &&
+       test_cmp file3 file3-swapped
+'
+
+test_done
diff --git a/t/t4131-apply-fake-ancestor.sh b/t/t4131-apply-fake-ancestor.sh
new file mode 100755 (executable)
index 0000000..94373ca
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Stephen Boyd
+#
+
+test_description='git apply --build-fake-ancestor handling.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit 1 &&
+       test_commit 2 &&
+       mkdir sub &&
+       test_commit 3 sub/3 &&
+       test_commit 4
+'
+
+test_expect_success 'apply --build-fake-ancestor' '
+       git checkout 2 &&
+       echo "A" > 1.t &&
+       git diff > 1.patch &&
+       git reset --hard &&
+       git checkout 1 &&
+       git apply --build-fake-ancestor 1.ancestor 1.patch
+'
+
+test_expect_success 'apply --build-fake-ancestor in a subdirectory' '
+       git checkout 3 &&
+       echo "C" > sub/3.t &&
+       git diff > 3.patch &&
+       git reset --hard &&
+       git checkout 4 &&
+       (
+               cd sub &&
+               git apply --build-fake-ancestor 3.ancestor ../3.patch &&
+               test -f 3.ancestor
+       ) &&
+       git apply --build-fake-ancestor 3.ancestor 3.patch &&
+       test_cmp sub/3.ancestor 3.ancestor
+'
+
+test_done
index 5e65afa0c10d02e50c79b550a3c142d8ff1f0674..d6ebbaebe2c258a4694cfb709809e13d24084231 100755 (executable)
@@ -290,4 +290,19 @@ test_expect_success 'am --ignore-date' '
        echo "$at" | grep "+0000"
 '
 
+test_expect_success 'am into an unborn branch' '
+       rm -fr subdir &&
+       mkdir -p subdir &&
+       git format-patch --numbered-files -o subdir -1 first &&
+       (
+               cd subdir &&
+               git init &&
+               git am 1
+       ) &&
+       result=$(
+               cd subdir && git rev-parse HEAD^{tree}
+       ) &&
+       test "z$result" = "z$(git rev-parse first^{tree})"
+'
+
 test_done
index b68ab11f2915789cd04ac6bd43363aeab2079198..a6bc028a57115729d38e4b228cd259880d0bf6f8 100755 (executable)
@@ -57,7 +57,7 @@ test_expect_success 'conflicting merge' '
        test_must_fail git merge first
 '
 
-sha1=$(sed -e 's/      .*//' .git/MERGE_RR)
+sha1=$(perl -pe 's/    .*//' .git/MERGE_RR)
 rr=.git/rr-cache/$sha1
 test_expect_success 'recorded preimage' "grep ^=======$ $rr/preimage"
 
@@ -190,8 +190,6 @@ test_expect_success 'file2 added differently in two branches' '
        git add file2 &&
        git commit -m version2 &&
        test_must_fail git merge fourth &&
-       sha1=$(sed -e "s/       .*//" .git/MERGE_RR) &&
-       rr=.git/rr-cache/$sha1 &&
        echo Cello > file2 &&
        git add file2 &&
        git commit -m resolution
index b98619035c58d1b5c617c6e9998e7ae07ab3f27f..aad3894ad4c542d4ab894c2d57a035a89eb88258 100755 (executable)
@@ -284,10 +284,36 @@ test_expect_success 'set up more tangled history' '
        git merge master~3 &&
        git merge side~1 &&
        git checkout master &&
-       git merge tangle
+       git merge tangle &&
+       git checkout -b reach &&
+       test_commit reach &&
+       git checkout master &&
+       git checkout -b octopus-a &&
+       test_commit octopus-a &&
+       git checkout master &&
+       git checkout -b octopus-b &&
+       test_commit octopus-b &&
+       git checkout master &&
+       test_commit seventh &&
+       git merge octopus-a octopus-b
+       git merge reach
 '
 
 cat > expect <<\EOF
+*   Merge branch 'reach'
+|\
+| \
+|  \
+*-. \   Merge branches 'octopus-a' and 'octopus-b'
+|\ \ \
+* | | | seventh
+| | * | octopus-b
+| |/ /
+|/| |
+| * | octopus-a
+|/ /
+| * reach
+|/
 *   Merge branch 'tangle'
 |\
 | *   Merge branch 'side' (early part) into tangle
@@ -298,14 +324,12 @@ cat > expect <<\EOF
 * | | |   Merge branch 'side'
 |\ \ \ \
 | * | | | side-2
-| | | |/
-| | |/|
+| | |_|/
 | |/| |
 | * | | side-1
 * | | | Second
 * | | | sixth
-| | |/
-| |/|
+| |_|/
 |/| |
 * | | fifth
 * | | fourth
index 7641e0dd46cc4f33231817664843787c90a01802..abb41b07ef1985d53c2186617e6b2fcf7e7fe033 100755 (executable)
@@ -50,7 +50,7 @@ test_expect_success \
 test_expect_success \
     'add ignored file' \
     'echo ignore me >a/ignored &&
-     echo ignored export-ignore >.gitattributes'
+     echo ignored export-ignore >.git/info/attributes'
 
 test_expect_success \
     'add files to repository' \
@@ -64,7 +64,7 @@ test_expect_success \
 test_expect_success \
     'create bare clone' \
     'git clone --bare . bare.git &&
-     cp .gitattributes bare.git/info/attributes'
+     cp .git/info/attributes bare.git/info/attributes'
 
 test_expect_success \
     'remove ignored file' \
@@ -139,10 +139,11 @@ test_expect_success \
 
 test_expect_success \
     'create archives with substfiles' \
-    'echo "substfile?" export-subst >a/.gitattributes &&
+    'cp .git/info/attributes .git/info/attributes.before &&
+     echo "substfile?" export-subst >>.git/info/attributes &&
      git archive HEAD >f.tar &&
      git archive --prefix=prefix/ HEAD >g.tar &&
-     rm a/.gitattributes'
+     mv .git/info/attributes.before .git/info/attributes'
 
 test_expect_success \
     'extract substfiles' \
diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh
new file mode 100755 (executable)
index 0000000..426b319
--- /dev/null
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+test_description='git archive attribute tests'
+
+. ./test-lib.sh
+
+SUBSTFORMAT=%H%n
+
+test_expect_exists() {
+       test_expect_success " $1 exists" "test -e $1"
+}
+
+test_expect_missing() {
+       test_expect_success " $1 does not exist" "test ! -e $1"
+}
+
+test_expect_success 'setup' '
+       echo ignored >ignored &&
+       echo ignored export-ignore >>.git/info/attributes &&
+       git add ignored &&
+
+       echo ignored by tree >ignored-by-tree &&
+       echo ignored-by-tree export-ignore >.gitattributes &&
+       git add ignored-by-tree .gitattributes &&
+
+       echo ignored by worktree >ignored-by-worktree &&
+       echo ignored-by-worktree export-ignore >.gitattributes &&
+       git add ignored-by-worktree &&
+
+       printf "A\$Format:%s\$O" "$SUBSTFORMAT" >nosubstfile &&
+       printf "A\$Format:%s\$O" "$SUBSTFORMAT" >substfile1 &&
+       printf "A not substituted O" >substfile2 &&
+       echo "substfile?" export-subst >>.git/info/attributes &&
+       git add nosubstfile substfile1 substfile2 &&
+
+       git commit -m. &&
+
+       git clone --bare . bare &&
+       cp .git/info/attributes bare/info/attributes
+'
+
+test_expect_success 'git archive' '
+       git archive HEAD >archive.tar &&
+       (mkdir archive && cd archive && "$TAR" xf -) <archive.tar
+'
+
+test_expect_missing    archive/ignored
+test_expect_missing    archive/ignored-by-tree
+test_expect_exists     archive/ignored-by-worktree
+
+test_expect_success 'git archive with worktree attributes' '
+       git archive --worktree-attributes HEAD >worktree.tar &&
+       (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar
+'
+
+test_expect_missing    worktree/ignored
+test_expect_exists     worktree/ignored-by-tree
+test_expect_missing    worktree/ignored-by-worktree
+
+test_expect_success 'git archive vs. bare' '
+       (cd bare && git archive HEAD) >bare-archive.tar &&
+       test_cmp archive.tar bare-archive.tar
+'
+
+test_expect_success 'git archive with worktree attributes, bare' '
+       (cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar &&
+       (mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar
+'
+
+test_expect_missing    bare-worktree/ignored
+test_expect_exists     bare-worktree/ignored-by-tree
+test_expect_exists     bare-worktree/ignored-by-worktree
+
+test_expect_success 'export-subst' '
+       git log "--pretty=format:A${SUBSTFORMAT}O" HEAD >substfile1.expected &&
+       test_cmp nosubstfile archive/nosubstfile &&
+       test_cmp substfile1.expected archive/substfile1 &&
+       test_cmp substfile2 archive/substfile2
+'
+
+test_expect_success 'git tar-tree vs. git archive with worktree attributes' '
+       git tar-tree HEAD >tar-tree.tar &&
+       test_cmp worktree.tar tar-tree.tar
+'
+
+test_expect_success 'git tar-tree vs. git archive with worktree attrs, bare' '
+       (cd bare && git tar-tree HEAD) >bare-tar-tree.tar &&
+       test_cmp bare-worktree.tar bare-tar-tree.tar
+'
+
+test_done
index c450f33f333e6f1c367f8f350dfd78f8f44a0fee..a8c2ca2a78dd54f69230cb443eff1d6e82336f0a 100755 (executable)
@@ -3,9 +3,8 @@
 # Copyright (c) 2005 Johannes Schindelin
 #
 
-test_description='Testing multi_ack pack fetching
+test_description='Testing multi_ack pack fetching'
 
-'
 . ./test-lib.sh
 
 # Test fetch-pack/upload-pack pair.
@@ -13,77 +12,60 @@ test_description='Testing multi_ack pack fetching
 # Some convenience functions
 
 add () {
-       name=$1
-       text="$@"
-       branch=`echo $name | sed -e 's/^\(.\).*$/\1/'`
-       parents=""
+       name=$1 &&
+       text="$@" &&
+       branch=`echo $name | sed -e 's/^\(.\).*$/\1/'` &&
+       parents="" &&
 
-       shift
+       shift &&
        while test $1; do
-               parents="$parents -p $1"
+               parents="$parents -p $1" &&
                shift
-       done
+       done &&
 
-       echo "$text" > test.txt
-       git update-index --add test.txt
-       tree=$(git write-tree)
+       echo "$text" > test.txt &&
+       git update-index --add test.txt &&
+       tree=$(git write-tree) &&
        # make sure timestamps are in correct order
-       sec=$(($sec+1))
-       commit=$(echo "$text" | GIT_AUTHOR_DATE=$sec \
-               git commit-tree $tree $parents 2>>log2.txt)
-       eval "$name=$commit; export $name"
-       echo $commit > .git/refs/heads/$branch
+       test_tick &&
+       commit=$(echo "$text" | git commit-tree $tree $parents) &&
+       eval "$name=$commit; export $name" &&
+       echo $commit > .git/refs/heads/$branch &&
        eval ${branch}TIP=$commit
 }
 
-count_objects () {
-       ls .git/objects/??/* 2>>log2.txt | wc -l | tr -d " "
-}
-
-test_expect_object_count () {
-       message=$1
-       count=$2
-
-       output="$(count_objects)"
-       test_expect_success \
-               "new object count $message" \
-               "test $count = $output"
-}
-
 pull_to_client () {
-       number=$1
-       heads=$2
-       count=$3
-       no_strict_count_check=$4
-
-       cd client
-       test_expect_success "$number pull" \
-               "git fetch-pack -k -v .. $heads"
-       case "$heads" in *A*) echo $ATIP > .git/refs/heads/A;; esac
-       case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac
-       git symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'`
-
-       test_expect_success "fsck" 'git fsck --full > fsck.txt 2>&1'
-
-       test_expect_success 'check downloaded results' \
-       'mv .git/objects/pack/pack-* . &&
-        p=`ls -1 pack-*.pack` &&
-        git unpack-objects <$p &&
-        git fsck --full'
-
-       test_expect_success "new object count after $number pull" \
-       'idx=`echo pack-*.idx` &&
-        pack_count=`git show-index <$idx | wc -l` &&
-        test $pack_count = $count'
-       test -z "$pack_count" && pack_count=0
-       if [ -z "$no_strict_count_check" ]; then
-               test_expect_success "minimal count" "test $count = $pack_count"
-       else
-               test $count != $pack_count && \
-                       echo "WARNING: $pack_count objects transmitted, only $count of which were needed"
-       fi
-       rm -f pack-*
-       cd ..
+       number=$1 &&
+       heads=$2 &&
+       count=$3 &&
+       test_expect_success "$number pull" '
+               (
+                       cd client &&
+                       git fetch-pack -k -v .. $heads &&
+
+                       case "$heads" in
+                           *A*)
+                                   echo $ATIP > .git/refs/heads/A;;
+                       esac &&
+                       case "$heads" in *B*)
+                           echo $BTIP > .git/refs/heads/B;;
+                       esac &&
+                       git symbolic-ref HEAD refs/heads/`echo $heads \
+                               | sed -e "s/^\(.\).*$/\1/"` &&
+
+                       git fsck --full &&
+
+                       mv .git/objects/pack/pack-* . &&
+                       p=`ls -1 pack-*.pack` &&
+                       git unpack-objects <$p &&
+                       git fsck --full &&
+
+                       idx=`echo pack-*.idx` &&
+                       pack_count=`git show-index <$idx | wc -l` &&
+                       test $pack_count = $count &&
+                       rm -f pack-*
+               )
+       '
 }
 
 # Here begins the actual testing
@@ -94,89 +76,129 @@ pull_to_client () {
 
 # client pulls A20, B1. Then tracks only B. Then pulls A.
 
-(
+test_expect_success 'setup' '
        mkdir client &&
-       cd client &&
-       git init 2>> log2.txt &&
-       git config transfer.unpacklimit 0
-)
-
-add A1
-
-prev=1; cur=2; while [ $cur -le 10 ]; do
-       add A$cur $(eval echo \$A$prev)
-       prev=$cur
-       cur=$(($cur+1))
-done
-
-add B1 $A1
-
-echo $ATIP > .git/refs/heads/A
-echo $BTIP > .git/refs/heads/B
-git symbolic-ref HEAD refs/heads/B
+       (
+               cd client &&
+               git init &&
+               git config transfer.unpacklimit 0
+       ) &&
+       add A1 &&
+       prev=1 &&
+       cur=2 &&
+       while [ $cur -le 10 ]; do
+               add A$cur $(eval echo \$A$prev) &&
+               prev=$cur &&
+               cur=$(($cur+1))
+       done &&
+       add B1 $A1
+       echo $ATIP > .git/refs/heads/A &&
+       echo $BTIP > .git/refs/heads/B &&
+       git symbolic-ref HEAD refs/heads/B
+'
 
 pull_to_client 1st "B A" $((11*3))
 
-add A11 $A10
-
-prev=1; cur=2; while [ $cur -le 65 ]; do
-       add B$cur $(eval echo \$B$prev)
-       prev=$cur
-       cur=$(($cur+1))
-done
+test_expect_success 'post 1st pull setup' '
+       add A11 $A10 &&
+       prev=1 &&
+       cur=2 &&
+       while [ $cur -le 65 ]; do
+               add B$cur $(eval echo \$B$prev) &&
+               prev=$cur &&
+               cur=$(($cur+1))
+       done
+'
 
 pull_to_client 2nd "B" $((64*3))
 
-pull_to_client 3rd "A" $((1*3)) # old fails
-
-test_expect_success "clone shallow" 'git clone --depth 2 "file://$(pwd)/." shallow'
+pull_to_client 3rd "A" $((1*3))
 
-(cd shallow; git count-objects -v) > count.shallow
-
-test_expect_success "clone shallow object count" \
-       "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\""
-
-count_output () {
-       sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/^size-pack:/d' -e '/: 0$/d' "$1"
-}
+test_expect_success 'clone shallow' '
+       git clone --depth 2 "file://$(pwd)/." shallow
+'
 
-test_expect_success "clone shallow object count (part 2)" '
-       test -z "$(count_output count.shallow)"
+test_expect_success 'clone shallow object count' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow &&
+       grep "^in-pack: 18" count.shallow
 '
 
-test_expect_success "fsck in shallow repo" \
-       "(cd shallow; git fsck --full)"
+test_expect_success 'clone shallow object count (part 2)' '
+       sed -e "/^in-pack:/d" -e "/^packs:/d" -e "/^size-pack:/d" \
+           -e "/: 0$/d" count.shallow > count_output &&
+       ! test -s count_output
+'
 
-#test_done; exit
+test_expect_success 'fsck in shallow repo' '
+       (
+               cd shallow &&
+               git fsck --full
+       )
+'
 
-add B66 $B65
-add B67 $B66
+test_expect_success 'add two more' '
+       add B66 $B65 &&
+       add B67 $B66
+'
 
-test_expect_success "pull in shallow repo" \
-       "(cd shallow; git pull .. B)"
+test_expect_success 'pull in shallow repo' '
+       (
+               cd shallow &&
+               git pull .. B
+       )
+'
 
-(cd shallow; git count-objects -v) > count.shallow
-test_expect_success "clone shallow object count" \
-       "test \"count: 6\" = \"$(grep count count.shallow)\""
+test_expect_success 'clone shallow object count' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow &&
+       grep "^count: 6" count.shallow
+'
 
-add B68 $B67
-add B69 $B68
+test_expect_success 'add two more (part 2)' '
+       add B68 $B67 &&
+       add B69 $B68
+'
 
-test_expect_success "deepening pull in shallow repo" \
-       "(cd shallow; git pull --depth 4 .. B)"
+test_expect_success 'deepening pull in shallow repo' '
+       (
+               cd shallow &&
+               git pull --depth 4 .. B
+       )
+'
 
-(cd shallow; git count-objects -v) > count.shallow
-test_expect_success "clone shallow object count" \
-       "test \"count: 12\" = \"$(grep count count.shallow)\""
+test_expect_success 'clone shallow object count' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow &&
+       grep "^count: 12" count.shallow
+'
 
-test_expect_success "deepening fetch in shallow repo" \
-       "(cd shallow; git fetch --depth 4 .. A:A)"
+test_expect_success 'deepening fetch in shallow repo' '
+       (
+               cd shallow &&
+               git fetch --depth 4 .. A:A
+       )
+'
 
-(cd shallow; git count-objects -v) > count.shallow
-test_expect_success "clone shallow object count" \
-       "test \"count: 18\" = \"$(grep count count.shallow)\""
+test_expect_success 'clone shallow object count' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow &&
+       grep "^count: 18" count.shallow
+'
 
-test_expect_success "pull in shallow repo with missing merge base" \
-       "(cd shallow && test_must_fail git pull --depth 4 .. A)"
+test_expect_success 'pull in shallow repo with missing merge base' '
+       (
+               cd shallow &&
+               test_must_fail git pull --depth 4 .. A
+       )
+'
 
 test_done
index 5ec668d6d8ac22f161549e5592a49bfdb0f11081..e70246b3fb5f0040a65db953b0adee7ada2d51ed 100755 (executable)
@@ -494,5 +494,15 @@ test_expect_success 'remote prune to cause a dangling symref' '
        grep "dangling symref" err
 '
 
+test_expect_success 'show empty remote' '
+
+       test_create_repo empty &&
+       git clone empty empty-clone &&
+       (
+               cd empty-clone &&
+               git remote show origin
+       )
+'
+
 test_done
 
index 3559d179647035a6ad8783aabfbecb8edcd4c254..19b5c0d552fa8b4665b5e396833264e258365b28 100755 (executable)
@@ -132,4 +132,14 @@ test_expect_success 'clone empty repository' '
         test $actual = $expected)
 '
 
+test_expect_success 'clone empty repository, and then push should not segfault.' '
+       cd "$D" &&
+       rm -fr empty/ empty-clone/ &&
+       mkdir empty &&
+       (cd empty && git init) &&
+       git clone empty empty-clone &&
+       (cd empty-clone &&
+       test_must_fail git push)
+'
+
 test_done
index 54b7ea6505d8c189c6c557cffd3d6518df06fb73..5254b23512a411e911090cc0473bbbfd025df484 100755 (executable)
@@ -482,28 +482,17 @@ test_expect_success 'good merge bases when good and bad are siblings' '
        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_must_fail test -f ".git/BISECT_ANCESTORS_OK"
 '
 
 # This creates another side branch called "parallel" with some files
index 3d6db4d386a0a009892fac490818294664d188fa..00e1de9627e8e20f4d28e3122502a494d21899e5 100755 (executable)
@@ -74,5 +74,19 @@ test_expect_success 'status' '
        grep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status when tracking lightweight tags' '
+       git checkout master &&
+       git tag light &&
+       git branch --track lighttrack light >actual &&
+       grep "set up to track" actual &&
+       git checkout lighttrack
+'
 
+test_expect_success 'status when tracking annotated tags' '
+       git checkout master &&
+       git tag -m heavy heavy &&
+       git branch --track heavytrack heavy >actual &&
+       grep "set up to track" actual &&
+       git checkout heavytrack
+'
 test_done
index 2049ab6cf844da233837b58857cfde8a2d563252..42f6fff373ba9707216279011b112c6c59af8780 100755 (executable)
@@ -208,4 +208,36 @@ test_expect_success 'merge-msg test #5-2' '
        test_cmp expected actual
 '
 
+test_expect_success 'merge-msg -F' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       setdate &&
+       git fetch . left right &&
+
+       git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'merge-msg -F in subdirectory' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       setdate &&
+       git fetch . left right &&
+       mkdir sub &&
+       cp .git/FETCH_HEAD sub/FETCH_HEAD &&
+       (
+               cd sub &&
+               git fmt-merge-msg -F FETCH_HEAD >../actual
+       ) &&
+       test_cmp expected actual
+'
+
 test_done
index daf02d5c103a55575edeefc53643a5b3794de121..8052c86ad3516505765ab214f4801940c8cc1684 100755 (executable)
@@ -301,10 +301,11 @@ test_expect_success 'Check for invalid refname format' '
 
 cat >expected <<\EOF
 heads/master
-master
+tags/master
 EOF
 
-test_expect_success 'Check ambiguous head and tag refs' '
+test_expect_success 'Check ambiguous head and tag refs (strict)' '
+       git config --bool core.warnambiguousrefs true &&
        git checkout -b newtag &&
        echo "Using $datestamp" > one &&
        git add one &&
@@ -315,12 +316,23 @@ test_expect_success 'Check ambiguous head and tag refs' '
        test_cmp expected actual
 '
 
+cat >expected <<\EOF
+heads/master
+master
+EOF
+
+test_expect_success 'Check ambiguous head and tag refs (loose)' '
+       git config --bool core.warnambiguousrefs false &&
+       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' '
+test_expect_success 'Check ambiguous head and tag refs II (loose)' '
        git checkout master &&
        git tag ambiguous testtag^0 &&
        git branch ambiguous testtag^0 &&
index c4938544d4ca7c5e7e886a59144c9b10b7971748..f275af82403dc0f1de4c584074c0eb63e61a6704 100755 (executable)
@@ -16,16 +16,21 @@ test_expect_success setup '
                echo foo mmap bar_mmap
                echo foo_mmap bar mmap baz
        } >file &&
+       echo ww w >w &&
        echo x x xx x >x &&
        echo y yy >y &&
        echo zzz > z &&
        mkdir t &&
        echo test >t/t &&
-       git add file x y z t/t &&
+       git add file x y z t/t &&
        test_tick &&
        git commit -m initial
 '
 
+test_expect_success 'grep should not segfault with a bad input' '
+       test_must_fail git grep "("
+'
+
 for H in HEAD ''
 do
        case "$H" in
@@ -44,6 +49,12 @@ do
                diff expected actual
        '
 
+       test_expect_success "grep -w $L (w)" '
+               : >expected &&
+               ! git grep -n -w -e "^w" >actual &&
+               test_cmp expected actual
+       '
+
        test_expect_success "grep -w $L (x)" '
                {
                        echo ${HC}x:1:x x xx x
index bdb808af1aefae97c297f7845a8cd3b595404e89..ebfd34df36068f8808406a98d371731fb85012c4 100755 (executable)
@@ -534,4 +534,12 @@ test_expect_success 'failing checkout -b should not break working tree' '
 
 '
 
+test_expect_success 'switch out of non-branch' '
+       git reset --hard master &&
+       git checkout master^0 &&
+       echo modified >one &&
+       test_must_fail git checkout renamer 2>error.log &&
+       ! grep "^Previous HEAD" error.log
+'
+
 test_done
index af690ec6c1f36871dbd0044d22ab78ab95103541..0f2ccc6cf0123951d9bdbb880931868f29de5b4e 100755 (executable)
@@ -64,6 +64,16 @@ test_expect_success 'submodule add' '
        )
 '
 
+test_expect_success 'submodule add --branch' '
+       (
+               cd addtest &&
+               git submodule add -b initial "$submodurl" submod-branch &&
+               git submodule init &&
+               cd submod-branch &&
+               git branch | grep initial
+       )
+'
+
 test_expect_success 'submodule add with ./ in path' '
        (
                cd addtest &&
index aa6c44ce4f5855bd4f18f737c7b1239407549eab..9a21f783d3a5fedaa56df26919ab8e0456872e90 100755 (executable)
@@ -54,13 +54,13 @@ test_expect_success setup '
        git merge -s ours a
 '
 
-test_expect_failure 'merging with modify/modify conflict' '
+test_expect_success 'merging with modify/modify conflict' '
 
        git checkout -b test1 a &&
        test_must_fail git merge b &&
        test -f .git/MERGE_MSG &&
-       git diff
-
+       git diff &&
+       test -n "$(git ls-files -u)"
 '
 
 test_expect_success 'merging with a modify/modify conflict between merge bases' '
diff --git a/t/t7406-submodule-reference.sh b/t/t7406-submodule-reference.sh
new file mode 100755 (executable)
index 0000000..cc16d3f
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+#
+# Copyright (c) 2009, Red Hat Inc, Author: Michael S. Tsirkin (mst@redhat.com)
+#
+
+test_description='test clone --reference'
+. ./test-lib.sh
+
+base_dir=`pwd`
+
+U=$base_dir/UPLOAD_LOG
+
+test_expect_success 'preparing first repository' \
+'test_create_repo A && cd A &&
+echo first > file1 &&
+git add file1 &&
+git commit -m A-initial'
+
+cd "$base_dir"
+
+test_expect_success 'preparing second repository' \
+'git clone A B && cd B &&
+echo second > file2 &&
+git add file2 &&
+git commit -m B-addition &&
+git repack -a -d &&
+git prune'
+
+cd "$base_dir"
+
+test_expect_success 'preparing supermodule' \
+'test_create_repo super && cd super &&
+echo file > file &&
+git add file &&
+git commit -m B-super-initial'
+
+cd "$base_dir"
+
+test_expect_success 'submodule add --reference' \
+'cd super && git submodule add --reference ../B "file://$base_dir/A" sub &&
+git commit -m B-super-added'
+
+cd "$base_dir"
+
+test_expect_success 'after add: existence of info/alternates' \
+'test `wc -l <super/sub/.git/objects/info/alternates` = 1'
+
+cd "$base_dir"
+
+test_expect_success 'that reference gets used with add' \
+'cd super/sub &&
+echo "0 objects, 0 kilobytes" > expected &&
+git count-objects > current &&
+diff expected current'
+
+cd "$base_dir"
+
+test_expect_success 'cloning supermodule' \
+'git clone super super-clone'
+
+cd "$base_dir"
+
+test_expect_success 'update with reference' \
+'cd super-clone && git submodule update --init --reference ../B'
+
+cd "$base_dir"
+
+test_expect_success 'after update: existence of info/alternates' \
+'test `wc -l <super-clone/sub/.git/objects/info/alternates` = 1'
+
+cd "$base_dir"
+
+test_expect_success 'that reference gets used with update' \
+'cd super-clone/sub &&
+echo "0 objects, 0 kilobytes" > expected &&
+git count-objects > current &&
+diff expected current'
+
+cd "$base_dir"
+
+test_done
index 5998baf27b5ad0fb32bf0fd42023d029a65d0e6b..8eec0fa9bc7278981b9a16571c588ede0a94d341 100755 (executable)
@@ -183,4 +183,14 @@ test_expect_success 'commit message from stdin' '
        commit_msg_is "Log with foo word"
 '
 
+test_expect_success 'commit -F overrides -t' '
+       (
+               cd subdir &&
+               echo "-F log" > f.log &&
+               echo "-t template" > t.template &&
+               git commit --allow-empty -F f.log -t t.template
+       ) &&
+       commit_msg_is "-F log"
+'
+
 test_done
index 6b29bff782f5a46bb6970d70598fd3be82c679fa..87c9b0e121db6c8ab7074e6c4968cd06d37851fe 100755 (executable)
@@ -69,7 +69,7 @@ test_expect_success 'packed obs in alt ODB are repacked even when local repo is
        done
 '
 
-test_expect_failure 'packed obs in alt ODB are repacked when local repo has packs' '
+test_expect_success 'packed obs in alt ODB are repacked when local repo has packs' '
        rm -f .git/objects/pack/* &&
        echo new_content >> file1 &&
        git add file1 &&
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
new file mode 100755 (executable)
index 0000000..ebdccf9
--- /dev/null
@@ -0,0 +1,216 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 David Aguilar
+#
+
+test_description='git-difftool
+
+Testing basic diff tool invocation
+'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PERL; then
+       say 'skipping difftool tests, perl not available'
+       test_done
+fi
+
+remove_config_vars()
+{
+       # Unset all config variables used by git-difftool
+       git config --unset diff.tool
+       git config --unset difftool.test-tool.cmd
+       git config --unset difftool.prompt
+       git config --unset merge.tool
+       git config --unset mergetool.test-tool.cmd
+       return 0
+}
+
+restore_test_defaults()
+{
+       # Restores the test defaults used by several tests
+       remove_config_vars
+       unset GIT_DIFF_TOOL
+       unset GIT_MERGE_TOOL
+       unset GIT_DIFFTOOL_PROMPT
+       unset GIT_DIFFTOOL_NO_PROMPT
+       git config diff.tool test-tool &&
+       git config difftool.test-tool.cmd 'cat $LOCAL'
+}
+
+prompt_given()
+{
+       prompt="$1"
+       test "$prompt" = "Hit return to launch 'test-tool': branch"
+}
+
+# Create a file on master and change it on branch
+test_expect_success 'setup' '
+       echo master >file &&
+       git add file &&
+       git commit -m "added file" &&
+
+       git checkout -b branch master &&
+       echo branch >file &&
+       git commit -a -m "branch changed file" &&
+       git checkout master
+'
+
+# Configure a custom difftool.<tool>.cmd and use it
+test_expect_success 'custom commands' '
+       restore_test_defaults &&
+       git config difftool.test-tool.cmd "cat \$REMOTE" &&
+
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "master" &&
+
+       restore_test_defaults &&
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "branch"
+'
+
+# Ensures that git-difftool ignores bogus --tool values
+test_expect_success 'difftool ignores bad --tool values' '
+       diff=$(git difftool --no-prompt --tool=bogus-tool branch)
+       test "$?" = 1 &&
+       test "$diff" = ""
+'
+
+# Specify the diff tool using $GIT_DIFF_TOOL
+test_expect_success 'GIT_DIFF_TOOL variable' '
+       git config --unset diff.tool
+       GIT_DIFF_TOOL=test-tool &&
+       export GIT_DIFF_TOOL &&
+
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
+# Test the $GIT_*_TOOL variables and ensure
+# that $GIT_DIFF_TOOL always wins unless --tool is specified
+test_expect_success 'GIT_DIFF_TOOL overrides' '
+       git config diff.tool bogus-tool &&
+       git config merge.tool bogus-tool &&
+
+       GIT_MERGE_TOOL=test-tool &&
+       export GIT_MERGE_TOOL &&
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "branch" &&
+       unset GIT_MERGE_TOOL &&
+
+       GIT_MERGE_TOOL=bogus-tool &&
+       GIT_DIFF_TOOL=test-tool &&
+       export GIT_MERGE_TOOL &&
+       export GIT_DIFF_TOOL &&
+
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "branch" &&
+
+       GIT_DIFF_TOOL=bogus-tool &&
+       export GIT_DIFF_TOOL &&
+
+       diff=$(git difftool --no-prompt --tool=test-tool branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
+# Test that we don't have to pass --no-prompt to difftool
+# when $GIT_DIFFTOOL_NO_PROMPT is true
+test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' '
+       GIT_DIFFTOOL_NO_PROMPT=true &&
+       export GIT_DIFFTOOL_NO_PROMPT &&
+
+       diff=$(git difftool branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
+# git-difftool supports the difftool.prompt variable.
+# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
+test_expect_success 'GIT_DIFFTOOL_PROMPT variable' '
+       git config difftool.prompt false &&
+       GIT_DIFFTOOL_PROMPT=true &&
+       export GIT_DIFFTOOL_PROMPT &&
+
+       prompt=$(echo | git difftool --prompt branch | tail -1) &&
+       prompt_given "$prompt" &&
+
+       restore_test_defaults
+'
+
+# Test that we don't have to pass --no-prompt when difftool.prompt is false
+test_expect_success 'difftool.prompt config variable is false' '
+       git config difftool.prompt false &&
+
+       diff=$(git difftool branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
+# Test that the -y flag can override difftool.prompt = true
+test_expect_success 'difftool.prompt can overridden with -y' '
+       git config difftool.prompt true &&
+
+       diff=$(git difftool -y branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
+# Test that the --prompt flag can override difftool.prompt = false
+test_expect_success 'difftool.prompt can overridden with --prompt' '
+       git config difftool.prompt false &&
+
+       prompt=$(echo | git difftool --prompt branch | tail -1) &&
+       prompt_given "$prompt" &&
+
+       restore_test_defaults
+'
+
+# Test that the last flag passed on the command-line wins
+test_expect_success 'difftool last flag wins' '
+       diff=$(git difftool --prompt --no-prompt branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults &&
+
+       prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) &&
+       prompt_given "$prompt" &&
+
+       restore_test_defaults
+'
+
+# git-difftool falls back to git-mergetool config variables
+# so test that behavior here
+test_expect_success 'difftool + mergetool config variables' '
+       remove_config_vars
+       git config merge.tool test-tool &&
+       git config mergetool.test-tool.cmd "cat \$LOCAL" &&
+
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "branch" &&
+
+       # set merge.tool to something bogus, diff.tool to test-tool
+       git config merge.tool bogus-tool &&
+       git config diff.tool test-tool &&
+
+       diff=$(git difftool --no-prompt branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
+test_expect_success 'difftool.<tool>.path' '
+       git config difftool.tkdiff.path echo &&
+       diff=$(git difftool --tool=tkdiff --no-prompt branch) &&
+       git config --unset difftool.tkdiff.path &&
+       lines=$(echo "$diff" | grep file | wc -l) &&
+       test "$lines" -eq 1
+'
+
+test_done
index 4470a92bb235420a2a0123eca5b57e06039ff011..fcd5c266754a2b5de3dbbf94c8ef25aebff061f2 100755 (executable)
@@ -36,7 +36,7 @@ EOF
 test_expect_success \
        'blame respects i18n.commitencoding' '
        git blame --incremental file | \
-               grep "^\(author\|summary\) " > actual &&
+               egrep "^(author|summary) " > actual &&
        test_cmp actual expected
 '
 
@@ -53,7 +53,7 @@ test_expect_success \
        'blame respects i18n.logoutputencoding' '
        git config i18n.logoutputencoding cp1251 &&
        git blame --incremental file | \
-               grep "^\(author\|summary\) " > actual &&
+               egrep "^(author|summary) " > actual &&
        test_cmp actual expected
 '
 
@@ -69,7 +69,7 @@ EOF
 test_expect_success \
        'blame respects --encoding=utf-8' '
        git blame --incremental --encoding=utf-8 file | \
-               grep "^\(author\|summary\) " > actual &&
+               egrep "^(author|summary) " > actual &&
        test_cmp actual expected
 '
 
@@ -85,7 +85,7 @@ EOF
 test_expect_success \
        'blame respects --encoding=none' '
        git blame --incremental --encoding=none file | \
-               grep "^\(author\|summary\) " > actual &&
+               egrep "^(author|summary) " > actual &&
        test_cmp actual expected
 '
 
index d9420e0a3b611c8aa8bb3a64d1bb21859d4a87ff..ce26ea4ac53a4608f6f8234b67868a9cc85be7f8 100755 (executable)
@@ -616,7 +616,7 @@ test_expect_success 'in-reply-to but no threading' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --in-reply-to="<in-reply-id@example.com>" \
-               --no-thread \
+               --nothread \
                $patches |
        grep "In-Reply-To: <in-reply-id@example.com>"
 '
index 4eee2e9fa6bacdc0d130a692f727885c5fa42e49..64aa7e2f104eba5f9f844c40d520163a8463cc8f 100755 (executable)
@@ -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_cmd import -m "import for git svn" . "$svnrepo" >/dev/null &&
        cd .. &&
        rm -rf import &&
        git svn init "$svnrepo"'
@@ -51,7 +51,7 @@ test_expect_success "$name" '
        git commit -m "$name" &&
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch &&
-       svn up "$SVN_TREE" &&
+       svn_cmd up "$SVN_TREE" &&
        test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a'
 
 
@@ -118,7 +118,7 @@ test_expect_success "$name" '
        git commit -m "$name" &&
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch5 &&
-       svn up "$SVN_TREE" &&
+       svn_cmd up "$SVN_TREE" &&
        test ! -x "$SVN_TREE"/exec.sh'
 
 
@@ -129,7 +129,7 @@ test_expect_success "$name" '
        git commit -m "$name" &&
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch5 &&
-       svn up "$SVN_TREE" &&
+       svn_cmd up "$SVN_TREE" &&
        test -x "$SVN_TREE"/exec.sh'
 
 
@@ -141,7 +141,7 @@ test_expect_success "$name" '
        git commit -m "$name" &&
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch5 &&
-       svn up "$SVN_TREE" &&
+       svn_cmd up "$SVN_TREE" &&
        test -L "$SVN_TREE"/exec.sh'
 
 name='new symlink is added to a file that was also just made executable'
@@ -153,7 +153,7 @@ test_expect_success "$name" '
        git commit -m "$name" &&
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch5 &&
-       svn up "$SVN_TREE" &&
+       svn_cmd up "$SVN_TREE" &&
        test -x "$SVN_TREE"/bar/zzz &&
        test -L "$SVN_TREE"/exec-2.sh'
 
@@ -166,7 +166,7 @@ test_expect_success "$name" '
        git commit -m "$name" &&
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch5 &&
-       svn up "$SVN_TREE" &&
+       svn_cmd up "$SVN_TREE" &&
        test -f "$SVN_TREE"/exec-2.sh &&
        test ! -L "$SVN_TREE"/exec-2.sh &&
        test_cmp help "$SVN_TREE"/exec-2.sh'
index 1e31d6ea7253ee4216347fd707d1408f97af32fa..9da4178c94f4bde62f69f32701b16ab3d04524e0 100755 (executable)
@@ -48,7 +48,7 @@ EOF
        printf "\r\n" > 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_cmd import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null
 cd ..
 
 rm -rf import
@@ -57,13 +57,13 @@ test_expect_success 'setup some commits to svn' \
        'cd test_wc &&
                echo Greetings >> kw.c &&
                poke kw.c &&
-               svn commit -m "Not yet an Id" &&
+               svn_cmd commit -m "Not yet an Id" &&
                echo Hello world >> kw.c &&
                poke kw.c &&
-               svn commit -m "Modified file, but still not yet an Id" &&
-               svn propset svn:keywords Id kw.c &&
+               svn_cmd commit -m "Modified file, but still not yet an Id" &&
+               svn_cmd propset svn:keywords Id kw.c &&
                poke kw.c &&
-               svn commit -m "Propset Id" &&
+               svn_cmd commit -m "Propset Id" &&
        cd ..'
 
 test_expect_success 'initialize git svn' 'git svn init "$svnrepo"'
@@ -83,16 +83,16 @@ test_expect_success 'raw $Id$ found in kw.c' "test '$expect' = '$got'"
 
 test_expect_success "propset CR on crlf files" \
        'cd test_wc &&
-               svn propset svn:eol-style CR empty &&
-               svn propset svn:eol-style CR crlf &&
-               svn propset svn:eol-style CR ne_crlf &&
-               svn commit -m "propset CR on crlf files" &&
+               svn_cmd propset svn:eol-style CR empty &&
+               svn_cmd propset svn:eol-style CR crlf &&
+               svn_cmd propset svn:eol-style CR ne_crlf &&
+               svn_cmd commit -m "propset CR on crlf files" &&
         cd ..'
 
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
        'git svn fetch &&
         git pull . ${remotes_git_svn} &&
-        svn co "$svnrepo" new_wc'
+        svn_cmd co "$svnrepo" new_wc'
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
@@ -106,11 +106,11 @@ cd test_wc
        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 &&
-        svn propset svn:keywords Id cr &&
-        svn propset svn:keywords Id ne_cr &&
-        svn commit -m "propset CRLF on cr files"'
+       'svn_cmd propset svn:eol-style CRLF cr &&
+        svn_cmd propset svn:eol-style CRLF ne_cr &&
+        svn_cmd propset svn:keywords Id cr &&
+        svn_cmd propset svn:keywords Id ne_cr &&
+        svn_cmd commit -m "propset CRLF on cr files"'
 cd ..
 test_expect_success 'fetch and pull latest from svn' \
        'git svn fetch && git pull . ${remotes_git_svn}'
@@ -140,10 +140,10 @@ test_expect_success 'test show-ignore' "
        cd test_wc &&
        mkdir -p deeply/nested/directory &&
        touch deeply/nested/directory/.keep &&
-       svn add deeply &&
-       svn up &&
-       svn propset -R svn:ignore 'no-such-file*' .
-       svn commit -m 'propset svn:ignore'
+       svn_cmd add deeply &&
+       svn_cmd up &&
+       svn_cmd propset -R svn:ignore 'no-such-file*' .
+       svn_cmd commit -m 'propset svn:ignore'
        cd .. &&
        git svn show-ignore > show-ignore.got &&
        cmp show-ignore.expect show-ignore.got
index e2232180158cfb0e523c8ffdd3ac10bf61c8f4ee..028fb19e09bbb9e2720e95a5e0b4ddb221f4a0e1 100755 (executable)
@@ -9,7 +9,7 @@ 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_cmd import -m "import for git svn" . "$svnrepo" &&
        cd ..
        '
 
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' '
        git rm -f deeply/nested/directory/number/2/another &&
        git commit -a -m "remove another" &&
        git svn set-tree --rmdir HEAD &&
-       svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
+       svn_cmd ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
        '
 
 
index 963dd95e4a71ccefa64b9500c490f44ea6d7c789..3413164cb127da9e8d601775769b3b049816173e 100755 (executable)
@@ -10,15 +10,15 @@ test_expect_success 'make history for tracking' '
        mkdir import &&
        mkdir import/trunk &&
        echo hello >> import/trunk/README &&
-       svn import -m initial import "$svnrepo" &&
+       svn_cmd import -m initial import "$svnrepo" &&
        rm -rf import &&
-       svn co "$svnrepo"/trunk trunk &&
+       svn_cmd co "$svnrepo"/trunk trunk &&
        echo bye bye >> trunk/README &&
-       svn rm -m "gone" "$svnrepo"/trunk &&
+       svn_cmd rm -m "gone" "$svnrepo"/trunk &&
        rm -rf trunk &&
        mkdir trunk &&
        echo "new" > trunk/FOLLOWME &&
-       svn import -m "new trunk" trunk "$svnrepo"/trunk
+       svn_cmd import -m "new trunk" trunk "$svnrepo"/trunk
 '
 
 test_expect_success 'clone repo with git' '
index ab9fa322200b333dd0222be6b712c6651f4419fb..78610b61e63596dad7e86a19a7e39deda3b19222 100755 (executable)
@@ -11,18 +11,18 @@ test_expect_success 'initialize repo' '
        cd import &&
        mkdir -p trunk &&
        echo hello > trunk/readme &&
-       svn import -m "initial" . "$svnrepo" &&
+       svn_cmd import -m "initial" . "$svnrepo" &&
        cd .. &&
-       svn co "$svnrepo" wc &&
+       svn_cmd co "$svnrepo" wc &&
        cd wc &&
        echo world >> trunk/readme &&
        poke trunk/readme &&
-       svn commit -m "another commit" &&
-       svn up &&
-       svn mv trunk thunk &&
+       svn_cmd commit -m "another commit" &&
+       svn_cmd up &&
+       svn_cmd mv trunk thunk &&
        echo goodbye >> thunk/readme &&
        poke thunk/readme &&
-       svn commit -m "bye now" &&
+       svn_cmd commit -m "bye now" &&
        cd ..
        '
 
@@ -51,7 +51,7 @@ test_expect_success 'init and fetch from one svn-remote' '
         '
 
 test_expect_success 'follow deleted parent' '
-        (svn cp -m "resurrecting trunk as junk" \
+        (svn_cmd cp -m "resurrecting trunk as junk" \
                "$svnrepo"/trunk@2 "$svnrepo"/junk ||
          svn cp -m "resurrecting trunk as junk" \
                -r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
@@ -97,8 +97,8 @@ test_expect_success 'follow higher-level parent' '
         '
 
 test_expect_success 'follow deleted directory' '
-       svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
-       svn rm -m "remove glob" "$svnrepo"/glob &&
+       svn_cmd mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
+       svn_cmd rm -m "remove glob" "$svnrepo"/glob &&
        git svn init --minimize-url -i glob "$svnrepo"/glob &&
        git svn fetch -i glob &&
        test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi &&
@@ -120,7 +120,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' '
        cd import &&
          svn import -m "r9270 test" . "$svnrepo"/r9270 &&
        cd .. &&
-       svn co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+       svn_cmd co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
        cd r9270 &&
          svn mkdir native &&
          svn mv t native/t &&
@@ -138,7 +138,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' '
        '
 
 test_expect_success "track initial change if it was only made to parent" '
-       svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
+       svn_cmd cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
        git svn init --minimize-url -i r9270-d \
          "$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
        git svn fetch -i r9270-d &&
@@ -152,20 +152,20 @@ test_expect_success "track initial change if it was only made to parent" '
 test_expect_success "follow-parent is atomic" '
        (
                cd wc &&
-               svn up &&
-               svn mkdir stunk &&
+               svn_cmd up &&
+               svn_cmd mkdir stunk &&
                echo "trunk stunk" > stunk/readme &&
-               svn add stunk/readme &&
-               svn ci -m "trunk stunk" &&
+               svn_cmd add stunk/readme &&
+               svn_cmd ci -m "trunk stunk" &&
                echo "stunk like junk" >> stunk/readme &&
-               svn ci -m "really stunk" &&
+               svn_cmd ci -m "really stunk" &&
                echo "stink stank stunk" >> stunk/readme &&
-               svn ci -m "even the grinch agrees"
+               svn_cmd ci -m "even the grinch agrees"
        ) &&
-       svn copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
+       svn_cmd copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
        { svn cp -m "early stunk flunked too" \
                "$svnrepo"/stunk@17 "$svnrepo"/flunked ||
-       svn cp -m "early stunk flunked too" \
+       svn_cmd cp -m "early stunk flunked too" \
                -r17 "$svnrepo"/stunk "$svnrepo"/flunked; } &&
        git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
        git svn fetch -i stunk &&
@@ -192,7 +192,7 @@ test_expect_success "follow-parent is atomic" '
        '
 
 test_expect_success "track multi-parent paths" '
-       svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
+       svn_cmd cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
        git svn multi-fetch &&
        test `git cat-file commit refs/remotes/glob | \
               grep "^parent " | wc -l` -eq 2
index ba99abb6d975351cf2725e757a588a26109a9723..dd48e9cba832a06a34fd1e2c895bb1b19792168f 100755 (executable)
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' '
        mkdir import &&
        cd import &&
        echo hello > readme &&
-       svn import -m "initial" . "$svnrepo" &&
+       svn_cmd import -m "initial" . "$svnrepo" &&
        cd .. &&
        echo hello > readme &&
        git update-index --add readme &&
@@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1`
 test_expect_success 'test the commit-diff command' '
        test -n "$prev" && test -n "$head" &&
        git svn commit-diff -r1 "$prev" "$head" "$svnrepo" &&
-       svn co "$svnrepo" wc &&
+       svn_cmd co "$svnrepo" wc &&
        cmp readme wc/readme
        '
 
 test_expect_success 'commit-diff to a sub-directory (with git svn config)' '
-       svn import -m "sub-directory" import "$svnrepo"/subdir &&
+       svn_cmd import -m "sub-directory" import "$svnrepo"/subdir &&
        git svn init --minimize-url "$svnrepo"/subdir &&
        git svn fetch &&
        git svn commit-diff -r3 "$prev" "$head" &&
-       svn cat "$svnrepo"/subdir/readme > readme.2 &&
+       svn_cmd cat "$svnrepo"/subdir/readme > readme.2 &&
        cmp readme readme.2
        '
 
index 6eb0fd85c86ec194062af7da8c7002f0819bcc07..12f21b700ec5216b6aeaa886f862d3e3b1f6682f 100755 (executable)
@@ -8,18 +8,18 @@ test_expect_success 'initialize repo' '
        mkdir import &&
        cd import &&
        echo initial > file &&
-       svn import -m "initial" . "$svnrepo" &&
+       svn_cmd import -m "initial" . "$svnrepo" &&
        cd .. &&
        echo initial > file &&
        git update-index --add file &&
        git commit -a -m "initial"
        '
 test_expect_success 'commit change from svn side' '
-       svn co "$svnrepo" t.svn &&
+       svn_cmd co "$svnrepo" t.svn &&
        cd t.svn &&
        echo second line from svn >> file &&
        poke file &&
-       svn commit -m "second line from svn" &&
+       svn_cmd commit -m "second line from svn" &&
        cd .. &&
        rm -rf t.svn
        '
@@ -43,11 +43,11 @@ test_expect_success 'dcommit fails to commit because of conflict' '
        git svn init "$svnrepo" &&
        git svn fetch &&
        git reset --hard refs/${remotes_git_svn} &&
-       svn co "$svnrepo" t.svn &&
+       svn_cmd co "$svnrepo" t.svn &&
        cd t.svn &&
        echo fourth line from svn >> file &&
        poke file &&
-       svn commit -m "fourth line from svn" &&
+       svn_cmd commit -m "fourth line from svn" &&
        cd .. &&
        rm -rf t.svn &&
        echo "fourth line from git" >> file &&
@@ -67,11 +67,11 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
        "
 
 test_expect_success 'commit another change from svn side' '
-       svn co "$svnrepo" t.svn &&
+       svn_cmd co "$svnrepo" t.svn &&
        cd t.svn &&
                echo third line from svn >> file &&
                poke file &&
-               svn commit -m "third line from svn" &&
+               svn_cmd commit -m "third line from svn" &&
        cd .. &&
        rm -rf t.svn
        '
index acad16a6f0f9b3b45b4766474e15ee5019ec2ce2..3a9e07768d8e6bebd7a4c4156ace6c5746d7d440 100755 (executable)
@@ -12,7 +12,7 @@ test_expect_success 'setup old-looking metadata' '
                        mkdir -p $i && \
                        echo hello >> $i/README || exit 1
                done && \
-               svn import -m test . "$svnrepo"
+               svn_cmd import -m test . "$svnrepo"
                cd .. &&
        git svn init "$svnrepo" &&
        git svn fetch &&
index d8582b1aa5d178778623bfb4386a66f58e165c17..d732d3130299e964359784949fc97805a2888e39 100755 (executable)
@@ -14,30 +14,30 @@ test_expect_success 'test refspec globbing' '
        mkdir -p trunk/src/a trunk/src/b trunk/doc &&
        echo "hello world" > trunk/src/a/readme &&
        echo "goodbye world" > trunk/src/b/readme &&
-       svn import -m "initial" trunk "$svnrepo"/trunk &&
-       svn co "$svnrepo" tmp &&
+       svn_cmd import -m "initial" trunk "$svnrepo"/trunk &&
+       svn_cmd co "$svnrepo" tmp &&
        (
                cd tmp &&
                mkdir branches tags &&
-               svn add branches tags &&
-               svn cp trunk branches/start &&
-               svn commit -m "start a new branch" &&
-               svn up &&
+               svn_cmd add branches tags &&
+               svn_cmd cp trunk branches/start &&
+               svn_cmd commit -m "start a new branch" &&
+               svn_cmd up &&
                echo "hi" >> branches/start/src/b/readme &&
                poke branches/start/src/b/readme &&
                echo "hey" >> branches/start/src/a/readme &&
                poke branches/start/src/a/readme &&
-               svn commit -m "hi" &&
-               svn up &&
-               svn cp branches/start tags/end &&
+               svn_cmd commit -m "hi" &&
+               svn_cmd up &&
+               svn_cmd cp branches/start tags/end &&
                echo "bye" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
                echo "aye" >> tags/end/src/a/readme &&
                poke tags/end/src/a/readme &&
-               svn commit -m "the end" &&
+               svn_cmd commit -m "the end" &&
                echo "byebye" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
-               svn commit -m "nothing to see here"
+               svn_cmd commit -m "nothing to see here"
        ) &&
        git config --add svn-remote.svn.url "$svnrepo" &&
        git config --add svn-remote.svn.fetch \
@@ -72,7 +72,7 @@ test_expect_success 'test left-hand-side only globbing' '
                cd tmp &&
                echo "try try" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
-               svn commit -m "try to try"
+               svn_cmd commit -m "try to try"
        ) &&
        git svn fetch two &&
        test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
@@ -102,7 +102,7 @@ test_expect_success 'test disallow multi-globs' '
                cd tmp &&
                echo "try try" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
-               svn commit -m "try to try"
+               svn_cmd commit -m "try to try"
        ) &&
        test_must_fail git svn fetch three 2> stderr.three &&
        test_cmp expect.three stderr.three
index 8f79c3f251aed240e0ba59244a8cfd91db2369d2..c318f9f946a35f0d13b90f67dd00a6817d77d989 100755 (executable)
@@ -14,30 +14,30 @@ test_expect_success 'test refspec globbing' '
        mkdir -p trunk/src/a trunk/src/b trunk/doc &&
        echo "hello world" > trunk/src/a/readme &&
        echo "goodbye world" > trunk/src/b/readme &&
-       svn import -m "initial" trunk "$svnrepo"/trunk &&
-       svn co "$svnrepo" tmp &&
+       svn_cmd import -m "initial" trunk "$svnrepo"/trunk &&
+       svn_cmd co "$svnrepo" tmp &&
        (
                cd tmp &&
                mkdir branches branches/v1 tags &&
-               svn add branches tags &&
-               svn cp trunk branches/v1/start &&
-               svn commit -m "start a new branch" &&
-               svn up &&
+               svn_cmd add branches tags &&
+               svn_cmd cp trunk branches/v1/start &&
+               svn_cmd commit -m "start a new branch" &&
+               svn_cmd up &&
                echo "hi" >> branches/v1/start/src/b/readme &&
                poke branches/v1/start/src/b/readme &&
                echo "hey" >> branches/v1/start/src/a/readme &&
                poke branches/v1/start/src/a/readme &&
-               svn commit -m "hi" &&
-               svn up &&
-               svn cp branches/v1/start tags/end &&
+               svn_cmd commit -m "hi" &&
+               svn_cmd up &&
+               svn_cmd cp branches/v1/start tags/end &&
                echo "bye" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
                echo "aye" >> tags/end/src/a/readme &&
                poke tags/end/src/a/readme &&
-               svn commit -m "the end" &&
+               svn_cmd commit -m "the end" &&
                echo "byebye" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
-               svn commit -m "nothing to see here"
+               svn_cmd commit -m "nothing to see here"
        ) &&
        git config --add svn-remote.svn.url "$svnrepo" &&
        git config --add svn-remote.svn.fetch \
@@ -72,7 +72,7 @@ test_expect_success 'test left-hand-side only globbing' '
                cd tmp &&
                echo "try try" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
-               svn commit -m "try to try"
+               svn_cmd commit -m "try to try"
        ) &&
        git svn fetch two &&
        test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
@@ -97,25 +97,25 @@ test_expect_success 'test another branch' '
        (
                cd tmp &&
                mkdir branches/v2 &&
-               svn add branches/v2 &&
-               svn cp trunk branches/v2/start &&
-               svn commit -m "Another versioned branch" &&
-               svn up &&
+               svn_cmd add branches/v2 &&
+               svn_cmd cp trunk branches/v2/start &&
+               svn_cmd commit -m "Another versioned branch" &&
+               svn_cmd up &&
                echo "hello" >> branches/v2/start/src/b/readme &&
                poke branches/v2/start/src/b/readme &&
                echo "howdy" >> branches/v2/start/src/a/readme &&
                poke branches/v2/start/src/a/readme &&
-               svn commit -m "Changed 2 in v2/start" &&
-               svn up &&
-               svn cp branches/v2/start tags/next &&
+               svn_cmd commit -m "Changed 2 in v2/start" &&
+               svn_cmd up &&
+               svn_cmd cp branches/v2/start tags/next &&
                echo "bye" >> tags/next/src/b/readme &&
                poke tags/next/src/b/readme &&
                echo "aye" >> tags/next/src/a/readme &&
                poke tags/next/src/a/readme &&
-               svn commit -m "adding more" &&
+               svn_cmd commit -m "adding more" &&
                echo "byebye" >> tags/next/src/b/readme &&
                poke tags/next/src/b/readme &&
-               svn commit -m "adios"
+               svn_cmd commit -m "adios"
        ) &&
        git config --add svn-remote.four.url "$svnrepo" &&
        git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk &&
@@ -151,7 +151,7 @@ test_expect_success 'test disallow multiple globs' '
                cd tmp &&
                echo "try try" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
-               svn commit -m "try to try"
+               svn_cmd commit -m "try to try"
        ) &&
        test_must_fail git svn fetch three 2> stderr.three &&
        test_cmp expect.three stderr.three
index e9b6128b3fa5c3d0cbbe5abb7f3e55267263449d..e8479cec7abade29aec91b22bba69d4ab9804f21 100755 (executable)
@@ -15,7 +15,7 @@ test_description='git svn dcommit new files over svn:// test'
 require_svnserve
 
 test_expect_success 'start tracking an empty repo' '
-       svn mkdir -m "empty dir" "$svnrepo"/empty-dir &&
+       svn_cmd mkdir -m "empty dir" "$svnrepo"/empty-dir &&
        echo "[general]" > "$rawsvnrepo"/conf/svnserve.conf &&
        echo anon-access = write >> "$rawsvnrepo"/conf/svnserve.conf &&
        start_svnserve &&
index 17b2855c4f308d463ea239f355549120dab4f80f..84f7c9b4bb00931b57740be32ce7ee29bbb26694 100755 (executable)
@@ -35,12 +35,12 @@ EOF
 }
 
 test_expect_success 'setup svn repository' '
-       svn co "$svnrepo" mysvnwork &&
+       svn_cmd co "$svnrepo" mysvnwork &&
        mkdir -p mysvnwork/trunk &&
        cd mysvnwork &&
                big_text_block >> trunk/README &&
-               svn add trunk &&
-               svn ci -m "first commit" trunk &&
+               svn_cmd add trunk &&
+               svn_cmd ci -m "first commit" trunk &&
                cd ..
        '
 
index fd6d1d20463f2a4de1bd8ed739c0e977921e037c..0374a7476bcc5b254aa1464d468434ae3205f114 100755 (executable)
@@ -14,7 +14,7 @@ test_expect_success 'setup repository and import' '
                        mkdir -p $i && \
                        echo hello >> $i/README || exit 1
                done && \
-               svn import -m test . "$svnrepo"
+               svn_cmd import -m test . "$svnrepo"
                cd .. &&
        git svn init "$svnrepo" -T trunk -b branches -t tags &&
        git svn fetch &&
index dde46cd92fba24221393b15233ed248997161caf..b7ef9e25895550e8749952e2ed54d7827737242e 100755 (executable)
@@ -16,7 +16,7 @@ cd tmp
 test_expect_success 'setup svnrepo' '
        mkdir project project/trunk project/branches project/tags &&
        echo foo > project/trunk/foo &&
-       svn import -m "$test_description" project "$svnrepo"/project &&
+       svn_cmd import -m "$test_description" project "$svnrepo"/project &&
        rm -rf project
        '
 
index 7a7c12868758d6e3bd9d1f8ec4fe32c0663115f4..ac52bff0ef540bce48e4ee02a53adbbec3662939 100755 (executable)
@@ -13,13 +13,13 @@ scary_ref='Abo-Uebernahme%20(Bug%20#994)'
 test_expect_success 'setup svnrepo' '
        mkdir project project/trunk project/branches project/tags &&
        echo foo > project/trunk/foo &&
-       svn import -m "$test_description" project "$svnrepo/pr ject" &&
+       svn_cmd import -m "$test_description" project "$svnrepo/pr ject" &&
        rm -rf project &&
-       svn cp -m "fun" "$svnrepo/pr ject/trunk" \
+       svn_cmd cp -m "fun" "$svnrepo/pr ject/trunk" \
                        "$svnrepo/pr ject/branches/fun plugin" &&
-       svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
+       svn_cmd cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
                              "$svnrepo/pr ject/branches/more fun plugin!" &&
-       svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \
+       svn_cmd cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \
                      "$svnrepo/pr ject/branches/$scary_uri" &&
        start_httpd
        '
index 27dd7c273a4a1ae77a8e48b2e4b4ce1a3ae19a56..95741cbbac6bf2e59531bbe1f9527ce4596fa904 100755 (executable)
@@ -7,7 +7,7 @@ test_description='git svn info'
 . ./lib-git-svn.sh
 
 # Tested with: svn, version 1.4.4 (r25188)
-v=`svn --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'`
+v=`svn_cmd --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'`
 case $v in
 1.[45].*)
        ;;
@@ -31,7 +31,7 @@ ptouch() {
                        my $atime = $mtime;
                        utime $atime, $mtime, $git_file;
                }
-       ' "`svn info $2 | grep '^Text Last Updated:'`" "$1"
+       ' "`svn_cmd info $2 | grep '^Text Last Updated:'`" "$1"
 }
 
 quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
@@ -45,14 +45,14 @@ test_expect_success 'setup repository and import' '
                mkdir directory &&
                touch directory/.placeholder &&
                ln -s directory symlink-directory &&
-               svn import -m "initial" . "$svnrepo" &&
+               svn_cmd import -m "initial" . "$svnrepo" &&
        cd .. &&
-       svn co "$svnrepo" svnwc &&
+       svn_cmd co "$svnrepo" svnwc &&
        cd svnwc &&
                echo foo > foo &&
-               svn add foo &&
-               svn commit -m "change outside directory" &&
-               svn update &&
+               svn_cmd add foo &&
+               svn_cmd commit -m "change outside directory" &&
+               svn_cmd update &&
        cd .. &&
        mkdir gitwc &&
        cd gitwc &&
@@ -143,7 +143,7 @@ test_expect_success 'info added-file' "
        cp gitwc/added-file svnwc/added-file &&
        ptouch gitwc/added-file svnwc/added-file &&
        cd svnwc &&
-               svn add added-file > /dev/null &&
+               svn_cmd add added-file > /dev/null &&
        cd .. &&
        (cd svnwc; svn info added-file) > expected.info-added-file &&
        (cd gitwc; git svn info added-file) > actual.info-added-file &&
@@ -160,7 +160,7 @@ test_expect_success 'info added-directory' "
        ptouch gitwc/added-directory svnwc/added-directory &&
        touch gitwc/added-directory/.placeholder &&
        cd svnwc &&
-               svn add added-directory > /dev/null &&
+               svn_cmd add added-directory > /dev/null &&
        cd .. &&
        cd gitwc &&
                git add added-directory &&
@@ -184,7 +184,7 @@ test_expect_success 'info added-symlink-file' "
        cd .. &&
        cd svnwc &&
                ln -s added-file added-symlink-file &&
-               svn add added-symlink-file > /dev/null &&
+               svn_cmd add added-symlink-file > /dev/null &&
        cd .. &&
        ptouch gitwc/added-symlink-file svnwc/added-symlink-file &&
        (cd svnwc; svn info added-symlink-file) \
@@ -207,7 +207,7 @@ test_expect_success 'info added-symlink-directory' "
        cd .. &&
        cd svnwc &&
                ln -s added-directory added-symlink-directory &&
-               svn add added-symlink-directory > /dev/null &&
+               svn_cmd add added-symlink-directory > /dev/null &&
        cd .. &&
        ptouch gitwc/added-symlink-directory svnwc/added-symlink-directory &&
        (cd svnwc; svn info added-symlink-directory) \
@@ -233,7 +233,7 @@ test_expect_success 'info deleted-file' "
                git rm -f file > /dev/null &&
        cd .. &&
        cd svnwc &&
-               svn rm --force file > /dev/null &&
+               svn_cmd rm --force file > /dev/null &&
        cd .. &&
        (cd svnwc; svn info file) |
        sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
@@ -254,7 +254,7 @@ test_expect_success 'info deleted-directory' "
                git rm -r -f directory > /dev/null &&
        cd .. &&
        cd svnwc &&
-               svn rm --force directory > /dev/null &&
+               svn_cmd rm --force directory > /dev/null &&
        cd .. &&
        (cd svnwc; svn info directory) |
        sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
@@ -275,7 +275,7 @@ test_expect_success 'info deleted-symlink-file' "
                git rm -f symlink-file > /dev/null &&
        cd .. &&
        cd svnwc &&
-               svn rm --force symlink-file > /dev/null &&
+               svn_cmd rm --force symlink-file > /dev/null &&
        cd .. &&
        (cd svnwc; svn info symlink-file) |
        sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
@@ -297,7 +297,7 @@ test_expect_success 'info deleted-symlink-directory' "
                git rm -f symlink-directory > /dev/null &&
        cd .. &&
        cd svnwc &&
-               svn rm --force symlink-directory > /dev/null &&
+               svn_cmd rm --force symlink-directory > /dev/null &&
        cd .. &&
        (cd svnwc; svn info symlink-directory) |
        sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
index ef2c0523cd4566b3d1c4925ba608efc16524546a..f159ab689bd5f7dfba1b27adb9dc68d8b65b67fe 100755 (executable)
@@ -9,22 +9,17 @@ test_description='git svn clone with percent escapes'
 test_expect_success 'setup svnrepo' '
        mkdir project project/trunk project/branches project/tags &&
        echo foo > project/trunk/foo &&
-       svn import -m "$test_description" project "$svnrepo/pr ject" &&
+       svn_cmd import -m "$test_description" project "$svnrepo/pr ject" &&
        rm -rf project &&
        start_httpd
 '
 
-if test "$SVN_HTTPD_PORT" = ""
-then
-       test_expect_failure 'test clone with percent escapes - needs SVN_HTTPD_PORT set' 'false'
-else
-       test_expect_success 'test clone with percent escapes' '
-               git svn clone "$svnrepo/pr%20ject" clone &&
-               cd clone &&
-                       git rev-parse refs/${remotes_git_svn} &&
-               cd ..
-       '
-fi
+test_expect_success 'test clone with percent escapes' '
+       git svn clone "$svnrepo/pr%20ject" clone &&
+       cd clone &&
+               git rev-parse refs/${remotes_git_svn} &&
+       cd ..
+'
 
 stop_httpd
 
index 1b1cf47281d10c64ac57e96701c727f19f189948..30013b7bb948640869d5c5208b2feeb08c011b73 100755 (executable)
@@ -4,12 +4,12 @@ test_description='git svn authorship'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup svn repository' '
-       svn checkout "$svnrepo" work.svn &&
+       svn_cmd checkout "$svnrepo" work.svn &&
        (
                cd work.svn &&
                echo >file
-               svn add file
-               svn commit -m "first commit" file
+               svn_cmd add file
+               svn_cmd commit -m "first commit" file
        )
 '
 
@@ -74,10 +74,10 @@ test_expect_success 'interact with it via git svn' '
        # Make sure there are no svn commit messages with excess blank lines
        (
                cd work.svn &&
-               svn up &&
+               svn_cmd up &&
                
-               test $(svn log -r2:2 | wc -l) = 5 &&
-               test $(svn log -r4:4 | wc -l) = 7
+               test $(svn_cmd log -r2:2 | wc -l) = 5 &&
+               test $(svn_cmd log -r4:4 | wc -l) = 7
        )
 '
 
index cf0415274c2d2abae7a6850818f4de8063cb61a7..045521615c64d1ae938524b0424e1e4260ca8c54 100755 (executable)
@@ -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_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null
 cd ..
 rm -rf import
 
index 263dbf5fc276ffa052096810f59565a851245b7f..d6b076f6b7de148c8d548c7a977e4f09b4be8e3b 100755 (executable)
@@ -21,7 +21,7 @@ test_expect_success 'initialize git svn' '
        (
                cd import &&
                echo foo >foo &&
-               svn import -m "import for git svn" . "$svnrepo"
+               svn_cmd import -m "import for git svn" . "$svnrepo"
        ) &&
        rm -rf import &&
        git svn init "$svnrepo"
@@ -61,23 +61,23 @@ test_expect_success 'check resulting svn repository' '
 (
        mkdir work &&
        cd work &&
-       svn co "$svnrepo" &&
+       svn_cmd co "$svnrepo" &&
        cd svnrepo &&
 
        # Check properties from first commit.
-       test "x$(svn propget svn:executable exec1.sh)" = "x*" &&
-       test "x$(svn propget svn:mime-type exec1.sh)" = \
+       test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*" &&
+       test "x$(svn_cmd propget svn:mime-type exec1.sh)" = \
             "xapplication/x-shellscript" &&
-       test "x$(svn propget svn:mime-type hello.txt)" = "xtext/plain" &&
-       test "x$(svn propget svn:eol-style hello.txt)" = "xnative" &&
-       test "x$(svn propget svn:mime-type bar)" = "x" &&
+       test "x$(svn_cmd propget svn:mime-type hello.txt)" = "xtext/plain" &&
+       test "x$(svn_cmd propget svn:eol-style hello.txt)" = "xnative" &&
+       test "x$(svn_cmd propget svn:mime-type bar)" = "x" &&
 
        # Check properties from second commit.
-       test "x$(svn propget svn:executable exec2.sh)" = "x*" &&
-       test "x$(svn propget svn:mime-type exec2.sh)" = "x" &&
-       test "x$(svn propget svn:mime-type world.txt)" = "x" &&
-       test "x$(svn propget svn:eol-style world.txt)" = "x" &&
-       test "x$(svn propget svn:mime-type zot)" = "x"
+       test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*" &&
+       test "x$(svn_cmd propget svn:mime-type exec2.sh)" = "x" &&
+       test "x$(svn_cmd propget svn:mime-type world.txt)" = "x" &&
+       test "x$(svn_cmd propget svn:eol-style world.txt)" = "x" &&
+       test "x$(svn_cmd propget svn:mime-type zot)" = "x"
 )
 '
 
@@ -89,12 +89,12 @@ test_expect_success 'check renamed file' '
        git svn dcommit --config-dir=user &&
        (
                cd work/svnrepo &&
-               svn up &&
+               svn_cmd up &&
                test ! -e foo &&
                test -e foo.sh &&
-               test "x$(svn propget svn:mime-type foo.sh)" = \
+               test "x$(svn_cmd propget svn:mime-type foo.sh)" = \
                     "xapplication/x-shellscript" &&
-               test "x$(svn propget svn:eol-style foo.sh)" = "xLF"
+               test "x$(svn_cmd propget svn:eol-style foo.sh)" = "xLF"
        )
 '
 
index 475c751c1cb88ce92a18beb2f9c7362a29ae4a5b..c19418614fc8946b5be5f0014559e53fcc15c060 100755 (executable)
@@ -8,11 +8,11 @@ test_expect_success 'setup svnrepo' '
        mkdir project project/trunk project/branches \
                        project/branches/v14.1 project/tags &&
        echo foo > project/trunk/foo &&
-       svn import -m "$test_description" project "$svnrepo/project" &&
+       svn_cmd import -m "$test_description" project "$svnrepo/project" &&
        rm -rf project &&
-       svn cp -m "fun" "$svnrepo/project/trunk" \
+       svn_cmd cp -m "fun" "$svnrepo/project/trunk" \
                        "$svnrepo/project/branches/v14.1/beta" &&
-       svn cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \
+       svn_cmd cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \
                              "$svnrepo/project/branches/v14.1/gold"
        '
 
index 87696a92dc82fad38e89a97af4a74ede84057241..4aab8ecc142d9719fd83b064445fa297cc10a520 100755 (executable)
@@ -14,21 +14,21 @@ test_expect_success 'initialize svnrepo' '
                cd trunk &&
                echo foo > foo &&
                cd .. &&
-               svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
-               svn copy "$svnrepo"/trunk "$svnrepo"/branches/a \
+               svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null &&
+               svn_cmd copy "$svnrepo"/trunk "$svnrepo"/branches/a \
                        -m "created branch a" &&
                cd .. &&
                rm -rf import &&
-               svn co "$svnrepo"/trunk trunk &&
+               svn_cmd co "$svnrepo"/trunk trunk &&
                cd trunk &&
                echo bar >> foo &&
-               svn ci -m "updated trunk" &&
+               svn_cmd ci -m "updated trunk" &&
                cd .. &&
-               svn co "$svnrepo"/branches/a a &&
+               svn_cmd co "$svnrepo"/branches/a a &&
                cd a &&
                echo baz >> a &&
-               svn add a &&
-               svn ci -m "updated a" &&
+               svn_cmd add a &&
+               svn_cmd ci -m "updated a" &&
                cd .. &&
                git svn init --stdlayout "$svnrepo"
        )
index 252daa7e1aec3c40a31db9a12a9432fbb85ef1b0..807e494a3af4eb889711cbd7bb8d20c160557301 100755 (executable)
@@ -14,13 +14,13 @@ test_expect_success 'initialize svnrepo' '
                cd trunk &&
                echo foo > foo &&
                cd .. &&
-               svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
+               svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null &&
                cd .. &&
                rm -rf import &&
-               svn co "$svnrepo"/trunk trunk &&
+               svn_cmd co "$svnrepo"/trunk trunk &&
                cd trunk &&
                echo bar >> foo &&
-               svn ci -m "updated trunk" &&
+               svn_cmd ci -m "updated trunk" &&
                cd .. &&
                rm -rf trunk
        )
@@ -57,14 +57,14 @@ test_expect_success 'git svn branch tests' '
 '
 
 test_expect_success 'branch uses correct svn-remote' '
-       (svn co "$svnrepo" svn &&
+       (svn_cmd co "$svnrepo" svn &&
        cd svn &&
        mkdir mirror &&
-       svn add mirror &&
-       svn copy trunk mirror/ &&
-       svn copy tags mirror/ &&
-       svn copy branches mirror/ &&
-       svn ci -m "made mirror" ) &&
+       svn_cmd add mirror &&
+       svn_cmd copy trunk mirror/ &&
+       svn_cmd copy tags mirror/ &&
+       svn_cmd copy branches mirror/ &&
+       svn_cmd ci -m "made mirror" ) &&
        rm -rf svn &&
        git svn init -s -R mirror --prefix=mirror/ "$svnrepo"/mirror &&
        git svn fetch -R mirror &&
index 3200ab38efa03076b81b94713e74205d740e38e8..d45fb73016362827e647118eec028c8b85e5aeff 100755 (executable)
@@ -33,7 +33,7 @@ for H in ISO-8859-1 EUCJP ISO-2022-JP
 do
        test_expect_success "$H setup" '
                mkdir $H &&
-               svn import -m "$H test" $H "$svnrepo"/$H &&
+               svn_cmd import -m "$H test" $H "$svnrepo"/$H &&
                git svn clone "$svnrepo"/$H $H
        '
 done
index b8fb277562e7782cf538ba7011214b4cf9136484..f5abdb3c7fd24033f1538db51c957345ab86e341 100755 (executable)
@@ -15,7 +15,7 @@ EOF
 test_expect_success 'setup svnrepo' '
        for i in aa bb cc dd
        do
-               svn mkdir -m $i --username $i "$svnrepo"/$i
+               svn_cmd mkdir -m $i --username $i "$svnrepo"/$i
        done
        '
 
@@ -52,13 +52,13 @@ test_expect_success 'continues to import once authors have been added' '
        '
 
 test_expect_success 'authors-file against globs' '
-       svn mkdir -m globs --username aa \
+       svn_cmd mkdir -m globs --username aa \
          "$svnrepo"/aa/trunk "$svnrepo"/aa/branches "$svnrepo"/aa/tags &&
        git svn clone --authors-file=svn-authors -s "$svnrepo"/aa aa-work &&
        for i in bb ee cc
        do
                branch="aa/branches/$i"
-               svn mkdir -m "$branch" --username $i "$svnrepo/$branch"
+               svn_cmd mkdir -m "$branch" --username $i "$svnrepo/$branch"
        done
        '
 
index 893f57ef7370a5078cce39ef7f4136342451f655..f3c30e63b7f584cddb91793b0170f004d866530d 100755 (executable)
@@ -7,19 +7,19 @@ test_description='git svn property tests'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup repo with a git repo inside it' '
-       svn co "$svnrepo" s &&
+       svn_cmd co "$svnrepo" s &&
        (
                cd s &&
                git init &&
                test -f .git/HEAD &&
                > .git/a &&
                echo a > a &&
-               svn add .git a &&
-               svn commit -m "create a nested git repo" &&
-               svn up &&
+               svn_cmd add .git a &&
+               svn_cmd commit -m "create a nested git repo" &&
+               svn_cmd up &&
                echo hi >> .git/a &&
-               svn commit -m "modify .git/a" &&
-               svn up
+               svn_cmd commit -m "modify .git/a" &&
+               svn_cmd up
        )
 '
 
@@ -33,9 +33,9 @@ test_expect_success 'SVN-side change outside of .git' '
        (
                cd s &&
                echo b >> a &&
-               svn commit -m "SVN-side change outside of .git" &&
-               svn up &&
-               svn log -v | fgrep "SVN-side change outside of .git"
+               svn_cmd commit -m "SVN-side change outside of .git" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change outside of .git"
        )
 '
 
@@ -56,10 +56,10 @@ test_expect_success 'SVN-side change inside of .git' '
                git add a &&
                git commit -m "add a inside an SVN repo" &&
                git log &&
-               svn add --force .git &&
-               svn commit -m "SVN-side change inside of .git" &&
-               svn up &&
-               svn log -v | fgrep "SVN-side change inside of .git"
+               svn_cmd add --force .git &&
+               svn_cmd commit -m "SVN-side change inside of .git" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change inside of .git"
        )
 '
 
@@ -80,9 +80,9 @@ test_expect_success 'SVN-side change in and out of .git' '
                echo c >> a &&
                git add a &&
                git commit -m "add a inside an SVN repo" &&
-               svn commit -m "SVN-side change in and out of .git" &&
-               svn up &&
-               svn log -v | fgrep "SVN-side change in and out of .git"
+               svn_cmd commit -m "SVN-side change in and out of .git" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change in and out of .git"
        )
 '
 
index 71fdc4a69dde2ff0bfdb092d8e28aeba495a1dc0..09ff10cd9b0688522671cac9ee2c8886a8587947 100755 (executable)
@@ -8,19 +8,19 @@ test_description='git svn property tests'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup test repository' '
-       svn co "$svnrepo" s &&
+       svn_cmd co "$svnrepo" s &&
        (
                cd s &&
                mkdir qqq www &&
                echo test_qqq > qqq/test_qqq.txt &&
                echo test_www > www/test_www.txt &&
-               svn add qqq &&
-               svn add www &&
-               svn commit -m "create some files" &&
-               svn up &&
+               svn_cmd add qqq &&
+               svn_cmd add www &&
+               svn_cmd commit -m "create some files" &&
+               svn_cmd up &&
                echo hi >> www/test_www.txt &&
-               svn commit -m "modify www/test_www.txt" &&
-               svn up
+               svn_cmd commit -m "modify www/test_www.txt" &&
+               svn_cmd up
        )
 '
 
@@ -51,9 +51,9 @@ test_expect_success 'SVN-side change outside of www' '
        (
                cd s &&
                echo b >> qqq/test_qqq.txt &&
-               svn commit -m "SVN-side change outside of www" &&
-               svn up &&
-               svn log -v | fgrep "SVN-side change outside of www"
+               svn_cmd commit -m "SVN-side change outside of www" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change outside of www"
        )
 '
 
@@ -83,9 +83,9 @@ test_expect_success 'SVN-side change inside of ignored www' '
        (
                cd s &&
                echo zaq >> www/test_www.txt
-               svn commit -m "SVN-side change inside of www/test_www.txt" &&
-               svn up &&
-               svn log -v | fgrep "SVN-side change inside of www/test_www.txt"
+               svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
        )
 '
 
@@ -116,9 +116,9 @@ test_expect_success 'SVN-side change in and out of ignored www' '
                cd s &&
                echo cvf >> www/test_www.txt
                echo ygg >> qqq/test_qqq.txt
-               svn commit -m "SVN-side change in and out of ignored www" &&
-               svn up &&
-               svn log -v | fgrep "SVN-side change in and out of ignored www"
+               svn_cmd commit -m "SVN-side change in and out of ignored www" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
        )
 '
 
index fd185011b73a8e45b7863bc336f884dee8d4f980..636ca0abb965ad2462a2e1e1ebea2a4183aa19e6 100755 (executable)
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' '
        mkdir import &&
        cd import &&
        awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
-       svn import -m "initial" . "$svnrepo" &&
+       svn_cmd import -m "initial" . "$svnrepo" &&
        cd .. &&
        git svn init "$svnrepo" &&
        git svn fetch &&
@@ -18,14 +18,14 @@ test_expect_success 'initialize repo' '
 test_expect_success '(supposedly) non-conflicting change from SVN' '
        test x"`sed -n -e 58p < file`" = x58 &&
        test x"`sed -n -e 61p < file`" = x61 &&
-       svn co "$svnrepo" tmp &&
+       svn_cmd co "$svnrepo" tmp &&
        cd tmp &&
                perl -i.bak -p -e "s/^58$/5588/" file &&
                perl -i.bak -p -e "s/^61$/6611/" file &&
                poke file &&
                test x"`sed -n -e 58p < file`" = x5588 &&
                test x"`sed -n -e 61p < file`" = x6611 &&
-               svn commit -m "58 => 5588, 61 => 6611" &&
+               svn_cmd commit -m "58 => 5588, 61 => 6611" &&
                cd ..
        '
 
@@ -46,7 +46,7 @@ test_expect_success 'change file but in unrelated area' "
        test x\"\`sed -n -e 7p < file\`\" = x7777 &&
        git commit -m '4 => 4444, 7 => 7777' file &&
        git svn dcommit &&
-       svn up tmp &&
+       svn_cmd up tmp &&
        cd tmp &&
                test x\"\`sed -n -e 4p < file\`\" = x4444 &&
                test x\"\`sed -n -e 7p < file\`\" = x7777 &&
diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh
new file mode 100755 (executable)
index 0000000..a4b00f2
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Eric Wong, Mark Lodato
+#
+
+test_description='git svn authors prog tests'
+
+. ./lib-git-svn.sh
+
+cat > svn-authors-prog <<'EOF'
+#!/usr/bin/perl
+$_ = shift;
+if (s/-sub$//)  {
+       print "$_ <$_\@sub.example.com>\n";
+}
+else {
+       print "$_ <$_\@example.com>\n";
+}
+EOF
+chmod +x svn-authors-prog
+
+cat > svn-authors <<'EOF'
+ff = FFFFFFF FFFFFFF <fFf@other.example.com>
+EOF
+
+test_expect_success 'setup svnrepo' '
+       for i in aa bb cc-sub dd-sub ee-foo ff
+       do
+               svn mkdir -m $i --username $i "$svnrepo"/$i
+       done
+       '
+
+test_expect_success 'import authors with prog and file' '
+       git svn clone --authors-prog=./svn-authors-prog \
+           --authors-file=svn-authors "$svnrepo" x
+       '
+
+test_expect_success 'imported 6 revisions successfully' '
+       (
+               cd x
+               test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 6
+       )
+       '
+
+test_expect_success 'authors-prog ran correctly' '
+       (
+               cd x
+               git rev-list -1 --pretty=raw refs/remotes/git-svn~1 | \
+                 grep "^author ee-foo <ee-foo@example\.com> " &&
+               git rev-list -1 --pretty=raw refs/remotes/git-svn~2 | \
+                 grep "^author dd <dd@sub\.example\.com> " &&
+               git rev-list -1 --pretty=raw refs/remotes/git-svn~3 | \
+                 grep "^author cc <cc@sub\.example\.com> " &&
+               git rev-list -1 --pretty=raw refs/remotes/git-svn~4 | \
+                 grep "^author bb <bb@example\.com> " &&
+               git rev-list -1 --pretty=raw refs/remotes/git-svn~5 | \
+                 grep "^author aa <aa@example\.com> "
+       )
+       '
+
+test_expect_success 'authors-file overrode authors-prog' '
+       (
+               cd x
+               git rev-list -1 --pretty=raw refs/remotes/git-svn | \
+                 grep "^author FFFFFFF FFFFFFF <fFf@other\.example\.com> "
+       )
+       '
+
+test_done
diff --git a/t/t9139-git-svn-non-utf8-commitencoding.sh b/t/t9139-git-svn-non-utf8-commitencoding.sh
new file mode 100755 (executable)
index 0000000..2b1db97
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Eric Wong
+
+test_description='git svn refuses to dcommit non-UTF8 messages'
+
+. ./lib-git-svn.sh
+
+# ISO-2022-JP can pass for valid UTF-8, so skipping that in this test
+
+for H in ISO-8859-1 EUCJP
+do
+       test_expect_success "$H setup" '
+               mkdir $H &&
+               svn_cmd import -m "$H test" $H "$svnrepo"/$H &&
+               git svn clone "$svnrepo"/$H $H
+       '
+done
+
+for H in ISO-8859-1 EUCJP
+do
+       test_expect_success "$H commit on git side" '
+       (
+               cd $H &&
+               git config i18n.commitencoding $H &&
+               git checkout -b t refs/remotes/git-svn &&
+               echo $H >F &&
+               git add F &&
+               git commit -a -F "$TEST_DIRECTORY"/t3900/$H.txt &&
+               E=$(git cat-file commit HEAD | sed -ne "s/^encoding //p") &&
+               test "z$E" = "z$H"
+       )
+       '
+done
+
+for H in ISO-8859-1 EUCJP
+do
+       test_expect_success "$H dcommit to svn" '
+       (
+               cd $H &&
+               git config --unset i18n.commitencoding &&
+               ! git svn dcommit
+       )
+       '
+done
+
+test_done
index b4ca244626a6635faa2587722c26f4c17692af65..4eb7d3f7f042f896106f208a7f8bb91925352b2a 100755 (executable)
@@ -29,6 +29,10 @@ test_expect_success \
      git add . &&
      git commit -m "first commit" &&
 
+     echo "new file in subdir 2" > directory2/file2 &&
+     git add . &&
+     git commit -m "commit in directory2" &&
+
      echo "changed file 1" > file1 &&
      git commit -a -m "second commit" &&
 
index 697daf3ffd33c27654ce00f780acc2c6db5f9985..6c70aec020c9c6486ae984dc264edb1dd8b270cf 100755 (executable)
@@ -86,15 +86,22 @@ close TEMPFILE;
 unlink $tmpfile;
 
 # paths
-is($r->repo_path, "./.git", "repo_path");
+is($r->repo_path, $abs_repo_dir . "/.git", "repo_path");
 is($r->wc_path, $abs_repo_dir . "/", "wc_path");
 is($r->wc_subdir, "", "wc_subdir initial");
 $r->wc_chdir("directory1");
 is($r->wc_subdir, "directory1", "wc_subdir after wc_chdir");
-TODO: {
-       local $TODO = "commands do not work after wc_chdir";
-       # Failure output is active even in non-verbose mode and thus
-       # annoying.  Hence we skip these tests as long as they fail.
-       todo_skip 'config after wc_chdir', 1;
-       is($r->config("color.string"), "value", "config after wc_chdir");
-}
+is($r->config("test.string"), "value", "config after wc_chdir");
+
+# Object generation in sub directory
+chdir("directory2");
+my $r2 = Git->repository();
+is($r2->repo_path, $abs_repo_dir . "/.git", "repo_path (2)");
+is($r2->wc_path, $abs_repo_dir . "/", "wc_path (2)");
+is($r2->wc_subdir, "directory2/", "wc_subdir initial (2)");
+
+# commands in sub directory
+my $last_commit = $r2->command_oneline(qw(rev-parse --verify HEAD));
+like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash');
+my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.');
+isnt($last_commit, $dir_commit, 'log . does not show last commit');
index 4bd986f43091715432bb4b740cfe4f0e0701cf85..dad1437fa49596cf6f36b40b1ab18b008620a246 100644 (file)
@@ -491,7 +491,7 @@ test_create_repo () {
        repo="$1"
        mkdir -p "$repo"
        cd "$repo" || error "Cannot setup test environment"
-       "$GIT_EXEC_PATH/git-init" "--template=$owd/../templates/blt/" >&3 2>&4 ||
+       "$GIT_EXEC_PATH/git-init" "--template=$TEST_DIRECTORY/../templates/blt/" >&3 2>&4 ||
        error "cannot run git init -- have you built things yet?"
        mv .git/hooks .git/hooks-disabled
        cd "$owd"
index 0e49279c7f7b805c78f1bc4760a0d1c70a84a0d9..b11ad6a6fbab9242a2dac157ee1a55875954b95a 100755 (executable)
@@ -7,7 +7,32 @@
 #
 # To enable this hook, rename this file to "pre-commit".
 
-if git-rev-parse --verify HEAD 2>/dev/null
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+       test "$(git diff --cached --name-only --diff-filter=A -z |
+         LC_ALL=C tr -d '[ -~]\0')"
+then
+       echo "Error: Attempt to add a non-ascii filename."
+       echo
+       echo "This can cause problems if you want to work together"
+       echo "with people on other platforms than you."
+       echo
+       echo "To be portable it is adviseable to rename the file ..."
+       echo
+       echo "If you know what you are doing you can disable this"
+       echo "check using:"
+       echo
+       echo "  git config hooks.allownonascii true"
+       echo
+       exit 1
+fi
+
+if git-rev-parse --verify HEAD >/dev/null 2>&1
 then
        against=HEAD
 else
index a3f68ae3b4c2dbac2f5404a73eda3419532110cf..fd63b2d662dbcf98ec622a1ab754d041a559e3be 100755 (executable)
 # hooks.allowdeletetag
 #   This boolean sets whether deleting tags will be allowed in the
 #   repository.  By default they won't be.
+# hooks.allowmodifytag
+#   This boolean sets whether a tag may be modified after creation. By default
+#   it won't be.
 # hooks.allowdeletebranch
 #   This boolean sets whether deleting branches will be allowed in the
 #   repository.  By default they won't be.
+# hooks.denycreatebranch
+#   This boolean sets whether remotely creating branches will be denied
+#   in the repository.  By default this is allowed.
 #
 
 # --- Command line
@@ -39,7 +45,9 @@ fi
 # --- Config
 allowunannotated=$(git config --bool hooks.allowunannotated)
 allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
 allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
 
 # check for no description
 projectdesc=$(sed -e '1q' "$GIT_DIR/description")
@@ -52,7 +60,8 @@ esac
 
 # --- Check types
 # if $newrev is 0000...0000, it's a commit to delete a ref.
-if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
        newrev_type=delete
 else
        newrev_type=$(git-cat-file -t $newrev)
@@ -77,9 +86,19 @@ case "$refname","$newrev_type" in
                ;;
        refs/tags/*,tag)
                # annotated tag
+               if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+               then
+                       echo "*** Tag '$refname' already exists." >&2
+                       echo "*** Modifying a tag is not allowed in this repository." >&2
+                       exit 1
+               fi
                ;;
        refs/heads/*,commit)
                # branch
+               if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+                       echo "*** Creating a branch is not allowed in this repository" >&2
+                       exit 1
+               fi
                ;;
        refs/heads/*,delete)
                # delete branch
index 8cefe6cfed87c8fe0c11d1263dae01639d2bd0f0..8ad276d062d6b96e2d80d3fcb44e046287f34bf7 100644 (file)
@@ -13,7 +13,7 @@ int main(int argc, char *argv[])
        unsigned char *c;
 
        if (argc < 2 || argc > 3) {
-               fprintf( stderr, "Usage: %s <seed_string> [<size>]", argv[0]);
+               fprintf(stderr, "Usage: %s <seed_string> [<size>]\n", argv[0]);
                return 1;
        }
 
index 61d2c39814529bd0264e4c9e40241131d51d819c..e0669dcb41d1d779f274e1ff785352e284953b14 100644 (file)
@@ -19,6 +19,12 @@ int length_callback(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
+int number_callback(const struct option *opt, const char *arg, int unset)
+{
+       *(int *)opt->value = strtol(arg, NULL, 10);
+       return 0;
+}
+
 int main(int argc, const char **argv)
 {
        const char *usage[] = {
@@ -29,6 +35,7 @@ int main(int argc, const char **argv)
                OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
                OPT_BIT('4', "or4", &boolean,
                        "bitwise-or boolean with ...0100", 4),
+               OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4),
                OPT_GROUP(""),
                OPT_INTEGER('i', "integer", &integer, "get a integer"),
                OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
@@ -45,6 +52,10 @@ int main(int argc, const char **argv)
                        "set string to default", (unsigned long)"default"),
                OPT_GROUP("Magic arguments"),
                OPT_ARGUMENT("quux", "means --quux"),
+               OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
+                       number_callback),
+               { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b",
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH },
                OPT_GROUP("Standard options"),
                OPT__ABBREV(&abbrev),
                OPT__VERBOSE(&verbose),
index 3dfb03c06ed82102f60045d6889db97cf036651e..17891d5149aab99ce0ec5538a0e11b8e9c2398ec 100644 (file)
@@ -732,9 +732,9 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str
 {
        fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
        if (from)
-               fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
+               fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
        else
-               fputs(prettify_ref(to), stderr);
+               fputs(prettify_refname(to->name), stderr);
        if (msg) {
                fputs(" (", stderr);
                fputs(msg, stderr);
@@ -1069,7 +1069,7 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs)
 void transport_unlock_pack(struct transport *transport)
 {
        if (transport->pack_lockfile) {
-               unlink(transport->pack_lockfile);
+               unlink_or_warn(transport->pack_lockfile);
                free(transport->pack_lockfile);
                transport->pack_lockfile = NULL;
        }
@@ -1083,3 +1083,51 @@ int transport_disconnect(struct transport *transport)
        free(transport);
        return ret;
 }
+
+/*
+ * Strip username (and password) from an url and return
+ * it in a newly allocated string.
+ */
+char *transport_anonymize_url(const char *url)
+{
+       char *anon_url, *scheme_prefix, *anon_part;
+       size_t anon_len, prefix_len = 0;
+
+       anon_part = strchr(url, '@');
+       if (is_local(url) || !anon_part)
+               goto literal_copy;
+
+       anon_len = strlen(++anon_part);
+       scheme_prefix = strstr(url, "://");
+       if (!scheme_prefix) {
+               if (!strchr(anon_part, ':'))
+                       /* cannot be "me@there:/path/name" */
+                       goto literal_copy;
+       } else {
+               const char *cp;
+               /* make sure scheme is reasonable */
+               for (cp = url; cp < scheme_prefix; cp++) {
+                       switch (*cp) {
+                               /* RFC 1738 2.1 */
+                       case '+': case '.': case '-':
+                               break; /* ok */
+                       default:
+                               if (isalnum(*cp))
+                                       break;
+                               /* it isn't */
+                               goto literal_copy;
+                       }
+               }
+               /* @ past the first slash does not count */
+               cp = strchr(scheme_prefix + 3, '/');
+               if (cp && cp < anon_part)
+                       goto literal_copy;
+               prefix_len = scheme_prefix - url + 3;
+       }
+       anon_url = xcalloc(1, 1 + prefix_len + anon_len);
+       memcpy(anon_url, url, prefix_len);
+       memcpy(anon_url + prefix_len, anon_part, anon_len);
+       return anon_url;
+literal_copy:
+       return xstrdup(url);
+}
index b1c225276619c3bc4dda5dcd0469e242ab421ea0..27bfc528acb5b51006c7d61db0d1d7910adaf31c 100644 (file)
@@ -74,5 +74,6 @@ const struct ref *transport_get_remote_refs(struct transport *transport);
 int transport_fetch_refs(struct transport *transport, const struct ref *refs);
 void transport_unlock_pack(struct transport *transport);
 int transport_disconnect(struct transport *transport);
+char *transport_anonymize_url(const char *url);
 
 #endif
index b05d0f43555d28f872fd5225e6773eeb636ef302..edd83949bf0896bedff4cab8e2b037eba574a45e 100644 (file)
@@ -374,7 +374,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        }
 
        /*
-        * Then, discard all the non-relevane file pairs...
+        * Then, discard all the non-relevant file pairs...
         */
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
diff --git a/tree.c b/tree.c
index 0d703a0c473e65c60d9e130b4e1fd50b79e9462b..5ab90af256a664366f3f92b467f52634c0df3f79 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -62,6 +62,7 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns
                                continue;
                        /* pathspecs match only at the directory boundaries */
                        if (!matchlen ||
+                           baselen == matchlen ||
                            base[matchlen] == '/' ||
                            match[matchlen - 1] == '/')
                                return 1;
index 6847c2d966c5e1d0299b21682d6fef2637329071..aaacaf1015ccf1f353151982a3018ad349663d76 100644 (file)
@@ -61,7 +61,7 @@ static void unlink_entry(struct cache_entry *ce)
 {
        if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
                return;
-       if (unlink(ce->name))
+       if (unlink_or_warn(ce->name))
                return;
        schedule_dir_for_removal(ce->name, ce_namelen(ce));
 }
@@ -87,7 +87,8 @@ static int check_updates(struct unpack_trees_options *o)
                cnt = 0;
        }
 
-       git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
+       if (o->update)
+               git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
 
@@ -112,7 +113,8 @@ static int check_updates(struct unpack_trees_options *o)
                }
        }
        stop_progress(&progress);
-       git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
+       if (o->update)
+               git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
        return errs != 0;
 }
 
index 495c99f80a9de2e28f0875560d920e5bb4155d7c..edc78612289c5bd774e18fe5f8e1b9ea80378a5f 100644 (file)
@@ -78,20 +78,22 @@ static void show_commit(struct commit *commit, void *data)
        commit->buffer = NULL;
 }
 
-static void show_object(struct object_array_entry *p, void *data)
+static void show_object(struct object *obj, const struct name_path *path, const char *component)
 {
        /* An object with name "foo\n0000000..." can be used to
         * confuse downstream git-pack-objects very badly.
         */
-       const char *ep = strchr(p->name, '\n');
+       const char *name = path_name(path, component);
+       const char *ep = strchr(name, '\n');
        if (ep) {
-               fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(p->item->sha1),
-                      (int) (ep - p->name),
-                      p->name);
+               fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(obj->sha1),
+                      (int) (ep - name),
+                      name);
        }
        else
                fprintf(pack_pipe, "%s %s\n",
-                               sha1_to_hex(p->item->sha1), p->name);
+                               sha1_to_hex(obj->sha1), name);
+       free((char *)name);
 }
 
 static void show_edge(struct commit *commit)
index d8efb1365a01104db568633fa8f6aef0c67b4cd1..7eb3218ee995991881252e4bb599452d7214ae4f 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -289,3 +289,19 @@ int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)
        safe_create_leading_directories(name);
        return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
 }
+
+int unlink_or_warn(const char *file)
+{
+       int rc = unlink(file);
+
+       if (rc < 0) {
+               int err = errno;
+               if (ENOENT != err) {
+                       warning("unable to unlink %s: %s",
+                               file, strerror(errno));
+                       errno = err;
+               }
+       }
+       return rc;
+}
+
index 929b00f59285c21a07df98700c23171505f5cddb..1b6df45450c39c0f456df68485b5735950816ac8 100644 (file)
@@ -40,7 +40,7 @@ static int parse_status_slot(const char *var, int offset)
        die("bad config variable '%s'", var);
 }
 
-static const charcolor(int slot)
+static const char *color(int slot)
 {
        return wt_status_use_color > 0 ? wt_status_colors[slot] : "";
 }
index 02184d9cde2e27d14c8c2845d7e2c4eb7f0c9b09..1ebab687f77218d1520a4527214170eeab176d31 100644 (file)
@@ -456,7 +456,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
                        /*
                         * Record the end-of-group position in case we are matched
                         * with a group of changes in the other file (that is, the
-                        * change record before the enf-of-group index in the other
+                        * change record before the end-of-group index in the other
                         * file is set).
                         */
                        ixref = rchgo[ixo - 1] ? ix: nrec;