summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore12
-rw-r--r--.mailmap8
-rw-r--r--Documentation/Makefile28
-rw-r--r--Documentation/RelNotes/1.7.10.1.txt78
-rw-r--r--Documentation/RelNotes/1.7.10.2.txt85
-rw-r--r--Documentation/RelNotes/1.7.10.3.txt43
-rw-r--r--Documentation/RelNotes/1.7.10.4.txt29
-rw-r--r--Documentation/RelNotes/1.7.10.5.txt12
-rw-r--r--Documentation/RelNotes/1.7.10.txt219
-rw-r--r--Documentation/RelNotes/1.7.11.1.txt9
-rw-r--r--Documentation/RelNotes/1.7.11.2.txt53
-rw-r--r--Documentation/RelNotes/1.7.11.txt139
-rw-r--r--Documentation/RelNotes/1.7.12.txt138
-rw-r--r--Documentation/asciidoc.conf4
-rw-r--r--Documentation/config.txt163
-rw-r--r--Documentation/diff-config.txt4
-rw-r--r--Documentation/diff-generate-patch.txt2
-rw-r--r--Documentation/diff-options.txt31
-rw-r--r--Documentation/everyday.txt4
-rw-r--r--Documentation/git-am.txt6
-rw-r--r--Documentation/git-apply.txt11
-rw-r--r--Documentation/git-archive.txt2
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--Documentation/git-branch.txt33
-rw-r--r--Documentation/git-bundle.txt8
-rw-r--r--Documentation/git-check-ref-format.txt12
-rw-r--r--Documentation/git-checkout.txt8
-rw-r--r--Documentation/git-cherry-pick.txt36
-rw-r--r--Documentation/git-clone.txt35
-rw-r--r--Documentation/git-column.txt53
-rw-r--r--Documentation/git-commit-tree.txt13
-rw-r--r--Documentation/git-commit.txt25
-rw-r--r--Documentation/git-config.txt40
-rw-r--r--Documentation/git-credential.txt144
-rw-r--r--Documentation/git-cvsserver.txt2
-rw-r--r--Documentation/git-difftool.txt16
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-fast-import.txt48
-rw-r--r--Documentation/git-fetch-pack.txt10
-rw-r--r--Documentation/git-filter-branch.txt34
-rw-r--r--Documentation/git-format-patch.txt4
-rw-r--r--Documentation/git-fsck.txt7
-rw-r--r--Documentation/git-gc.txt2
-rw-r--r--Documentation/git-grep.txt8
-rw-r--r--Documentation/git-index-pack.txt10
-rw-r--r--Documentation/git-log.txt2
-rw-r--r--Documentation/git-merge.txt2
-rw-r--r--Documentation/git-notes.txt2
-rw-r--r--Documentation/git-p4.txt82
-rw-r--r--Documentation/git-pack-refs.txt2
-rw-r--r--Documentation/git-pull.txt2
-rw-r--r--Documentation/git-push.txt36
-rw-r--r--Documentation/git-rebase.txt66
-rw-r--r--Documentation/git-reflog.txt6
-rw-r--r--Documentation/git-remote-helpers.txt8
-rw-r--r--Documentation/git-remote.txt6
-rw-r--r--Documentation/git-repack.txt2
-rw-r--r--Documentation/git-rerere.txt6
-rw-r--r--Documentation/git-reset.txt2
-rw-r--r--Documentation/git-rev-parse.txt10
-rw-r--r--Documentation/git-revert.txt4
-rw-r--r--Documentation/git-rm.txt3
-rw-r--r--Documentation/git-send-email.txt4
-rw-r--r--Documentation/git-sh-i18n--envsubst.txt2
-rw-r--r--Documentation/git-shortlog.txt2
-rw-r--r--Documentation/git-show-ref.txt2
-rw-r--r--Documentation/git-show.txt4
-rw-r--r--Documentation/git-stash.txt18
-rw-r--r--Documentation/git-status.txt13
-rw-r--r--Documentation/git-submodule.txt15
-rw-r--r--Documentation/git-svn.txt41
-rw-r--r--Documentation/git-symbolic-ref.txt7
-rw-r--r--Documentation/git-tag.txt15
-rw-r--r--Documentation/git-tar-tree.txt2
-rw-r--r--Documentation/git-update-index.txt6
-rw-r--r--Documentation/git-var.txt21
-rw-r--r--Documentation/git-whatchanged.txt2
-rw-r--r--Documentation/git.txt19
-rw-r--r--Documentation/gitattributes.txt41
-rw-r--r--Documentation/gitcli.txt12
-rw-r--r--Documentation/gitcore-tutorial.txt32
-rw-r--r--Documentation/gitcredentials.txt4
-rw-r--r--Documentation/gitdiffcore.txt10
-rw-r--r--Documentation/githooks.txt8
-rw-r--r--Documentation/gitignore.txt4
-rw-r--r--Documentation/gitmodules.txt9
-rw-r--r--Documentation/gitweb.conf.txt21
-rw-r--r--Documentation/gitworkflows.txt4
-rw-r--r--Documentation/howto/using-merge-subtree.txt2
-rw-r--r--Documentation/merge-options.txt17
-rw-r--r--Documentation/pretty-formats.txt6
-rw-r--r--Documentation/pull-fetch-param.txt2
-rw-r--r--Documentation/rev-list-options.txt7
-rw-r--r--Documentation/technical/api-argv-array.txt5
-rw-r--r--Documentation/technical/api-config.txt140
-rw-r--r--Documentation/technical/api-credentials.txt107
-rw-r--r--Documentation/technical/api-parse-options.txt37
-rw-r--r--Documentation/technical/api-revision-walking.txt5
-rw-r--r--Documentation/technical/index-format.txt13
-rw-r--r--Documentation/technical/pack-protocol.txt4
-rw-r--r--Documentation/technical/protocol-common.txt2
-rw-r--r--Documentation/user-manual.txt23
-rwxr-xr-xGIT-VERSION-GEN4
-rw-r--r--INSTALL9
-rw-r--r--Makefile345
l---------RelNotes2
-rw-r--r--advice.c20
-rw-r--r--advice.h4
-rw-r--r--archive-tar.c213
-rw-r--r--archive-zip.c200
-rw-r--r--archive.c45
-rw-r--r--archive.h10
-rw-r--r--argv-array.c14
-rw-r--r--argv-array.h3
-rw-r--r--attr.c17
-rw-r--r--attr.h2
-rw-r--r--bisect.c8
-rw-r--r--branch.c47
-rw-r--r--branch.h2
-rw-r--r--builtin.h8
-rw-r--r--builtin/add.c8
-rw-r--r--builtin/apply.c1010
-rw-r--r--builtin/blame.c99
-rw-r--r--builtin/branch.c102
-rw-r--r--builtin/cat-file.c33
-rw-r--r--builtin/checkout.c38
-rw-r--r--builtin/clone.c364
-rw-r--r--builtin/column.c59
-rw-r--r--builtin/commit.c297
-rw-r--r--builtin/config.c121
-rw-r--r--builtin/credential.c31
-rw-r--r--builtin/diff.c30
-rw-r--r--builtin/fast-export.c8
-rw-r--r--builtin/fetch-pack.c238
-rw-r--r--builtin/fetch.c29
-rw-r--r--builtin/fmt-merge-msg.c250
-rw-r--r--builtin/fsck.c15
-rw-r--r--builtin/gc.c89
-rw-r--r--builtin/grep.c21
-rw-r--r--builtin/help.c76
-rw-r--r--builtin/index-pack.c798
-rw-r--r--builtin/init-db.c1
-rw-r--r--builtin/log.c88
-rw-r--r--builtin/ls-files.c23
-rw-r--r--builtin/mailinfo.c11
-rw-r--r--builtin/merge-file.c4
-rw-r--r--builtin/merge.c159
-rw-r--r--builtin/pack-objects.c736
-rw-r--r--builtin/prune-packed.c4
-rw-r--r--builtin/prune.c2
-rw-r--r--builtin/push.c145
-rw-r--r--builtin/reflog.c6
-rw-r--r--builtin/remote.c233
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-list.c1
-rw-r--r--builtin/rev-parse.c6
-rw-r--r--builtin/revert.c967
-rw-r--r--builtin/send-pack.c13
-rw-r--r--builtin/symbolic-ref.c11
-rw-r--r--builtin/tag.c79
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-index.c20
-rw-r--r--builtin/update-server-info.c1
-rw-r--r--builtin/var.c4
-rw-r--r--builtin/verify-tag.c10
-rw-r--r--bundle.c46
-rw-r--r--cache-tree.c27
-rw-r--r--cache-tree.h4
-rw-r--r--cache.h130
-rw-r--r--column.c434
-rw-r--r--column.h45
-rw-r--r--combine-diff.c2
-rw-r--r--command-list.txt2
-rw-r--r--commit.c73
-rw-r--r--commit.h3
-rw-r--r--compat/mingw.c6
-rw-r--r--compat/mingw.h11
-rw-r--r--compat/nedmalloc/Readme.txt2
-rw-r--r--compat/precompose_utf8.c190
-rw-r--r--compat/precompose_utf8.h45
-rw-r--r--compat/win32/pthread.h5
-rw-r--r--compat/win32mmap.c2
-rw-r--r--config.c209
-rw-r--r--config.mak.in1
-rw-r--r--configure.ac221
-rw-r--r--connect.c20
-rw-r--r--[-rwxr-xr-x]contrib/completion/git-completion.bash406
-rw-r--r--contrib/completion/git-prompt.sh289
-rw-r--r--contrib/credential/osxkeychain/Makefile7
-rw-r--r--contrib/diff-highlight/README109
-rwxr-xr-xcontrib/diff-highlight/diff-highlight109
-rw-r--r--contrib/diffall/README31
-rwxr-xr-xcontrib/diffall/git-diffall257
-rw-r--r--contrib/emacs/git-blame.el75
-rw-r--r--contrib/examples/builtin-fetch--tool.c4
-rw-r--r--contrib/fast-import/git-p4.README12
-rw-r--r--contrib/fast-import/git-p4.bat1
-rw-r--r--contrib/mw-to-git/Makefile47
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki708
-rw-r--r--contrib/mw-to-git/t/.gitignore4
-rw-r--r--contrib/mw-to-git/t/Makefile31
-rw-r--r--contrib/mw-to-git/t/README124
-rwxr-xr-xcontrib/mw-to-git/t/install-wiki.sh45
-rw-r--r--contrib/mw-to-git/t/install-wiki/.gitignore1
-rw-r--r--contrib/mw-to-git/t/install-wiki/LocalSettings.php129
-rw-r--r--contrib/mw-to-git/t/install-wiki/db_install.php120
-rw-r--r--contrib/mw-to-git/t/push-pull-tests.sh144
-rwxr-xr-xcontrib/mw-to-git/t/t9360-mw-to-git-clone.sh257
-rwxr-xr-xcontrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh24
-rwxr-xr-xcontrib/mw-to-git/t/t9362-mw-to-git-utf8.sh301
-rwxr-xr-xcontrib/mw-to-git/t/t9363-mw-to-git-export-import.sh198
-rwxr-xr-xcontrib/mw-to-git/t/t9364-pull-by-rev.sh17
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh435
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw.pl225
-rw-r--r--contrib/mw-to-git/t/test.config35
-rw-r--r--contrib/persistent-https/LICENSE202
-rw-r--r--contrib/persistent-https/Makefile38
-rw-r--r--contrib/persistent-https/README62
-rw-r--r--contrib/persistent-https/client.go189
-rw-r--r--contrib/persistent-https/main.go82
-rw-r--r--contrib/persistent-https/proxy.go190
-rw-r--r--contrib/persistent-https/socket.go97
-rwxr-xr-xcontrib/rerere-train.sh2
-rw-r--r--contrib/subtree/.gitignore5
-rw-r--r--contrib/subtree/COPYING339
-rw-r--r--contrib/subtree/INSTALL28
-rw-r--r--contrib/subtree/Makefile52
-rw-r--r--contrib/subtree/README8
-rwxr-xr-xcontrib/subtree/git-subtree.sh712
-rw-r--r--contrib/subtree/git-subtree.txt366
-rw-r--r--contrib/subtree/t/Makefile69
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh508
-rw-r--r--contrib/subtree/todo50
-rw-r--r--contrib/svn-fe/svn-fe.txt10
-rw-r--r--convert.c28
-rw-r--r--credential.c2
-rw-r--r--credential.h1
-rw-r--r--ctype.c36
-rw-r--r--daemon.c6
-rw-r--r--date.c95
-rw-r--r--diff-no-index.c161
-rw-r--r--diff.c364
-rw-r--r--diff.h7
-rw-r--r--diffcore-pickaxe.c9
-rw-r--r--diffcore-rename.c6
-rw-r--r--diffcore.h1
-rw-r--r--dir.c342
-rw-r--r--dir.h21
-rw-r--r--entry.c53
-rw-r--r--environment.c6
-rw-r--r--exec_cmd.c2
-rw-r--r--fast-import.c110
-rw-r--r--fetch-pack.h1
-rw-r--r--fsck.c2
-rwxr-xr-xgenerate-cmdlist.sh2
-rwxr-xr-xgit-add--interactive.perl27
-rwxr-xr-xgit-am.sh81
-rw-r--r--git-compat-util.h15
-rwxr-xr-xgit-difftool--helper.sh19
-rwxr-xr-xgit-difftool.perl392
-rwxr-xr-xgit-p4.py (renamed from contrib/fast-import/git-p4)875
-rw-r--r--git-parse-remote.sh43
-rwxr-xr-xgit-pull.sh10
-rw-r--r--git-rebase--am.sh21
-rw-r--r--git-rebase--interactive.sh98
-rw-r--r--git-rebase--merge.sh2
-rwxr-xr-xgit-rebase.sh48
-rwxr-xr-xgit-relink.perl2
-rw-r--r--git-remote-testgit.py7
-rwxr-xr-xgit-repack.sh10
-rwxr-xr-xgit-request-pull.sh29
-rw-r--r--git-sh-i18n.sh106
-rw-r--r--git-sh-setup.sh45
-rwxr-xr-xgit-stash.sh4
-rwxr-xr-xgit-submodule.sh279
-rwxr-xr-xgit-svn.perl1847
-rw-r--r--git.c6
-rw-r--r--git.spec.in1
-rwxr-xr-xgitk-git/gitk415
-rwxr-xr-xgitweb/gitweb.perl681
-rw-r--r--gitweb/static/gitweb.css15
-rw-r--r--gitweb/static/js/lib/cookies.js2
-rw-r--r--gpg-interface.c2
-rw-r--r--graph.c3
-rw-r--r--grep.c87
-rw-r--r--grep.h2
-rw-r--r--help.c89
-rw-r--r--help.h4
-rw-r--r--http-backend.c22
-rw-r--r--http-push.c6
-rw-r--r--http.c32
-rw-r--r--http.h2
-rw-r--r--ident.c311
-rw-r--r--imap-send.c2
-rw-r--r--ll-merge.c2
-rw-r--r--log-tree.c38
-rw-r--r--log-tree.h4
-rw-r--r--merge-recursive.c9
-rw-r--r--mergesort.c73
-rw-r--r--mergesort.h17
-rw-r--r--mergetools/deltawalker21
-rw-r--r--notes-merge.c69
-rw-r--r--object.c35
-rw-r--r--object.h2
-rw-r--r--pack-refs.c3
-rw-r--r--pager.c14
-rw-r--r--parse-options.c55
-rw-r--r--parse-options.h31
-rw-r--r--path.c41
-rw-r--r--perl/Git.pm2
-rw-r--r--perl/Git/I18N.pm11
-rw-r--r--perl/Git/SVN/Editor.pm536
-rw-r--r--perl/Git/SVN/Fetcher.pm603
-rw-r--r--perl/Git/SVN/Memoize/YAML.pm93
-rw-r--r--perl/Git/SVN/Prompt.pm202
-rw-r--r--perl/Git/SVN/Ra.pm658
-rw-r--r--perl/Makefile42
-rw-r--r--perl/Makefile.PL9
-rw-r--r--pkt-line.c32
-rw-r--r--pkt-line.h1
-rw-r--r--po/.gitignore1
-rw-r--r--po/README109
-rw-r--r--po/TEAMS47
-rw-r--r--po/da.po3503
-rw-r--r--po/de.po5776
-rw-r--r--po/git.pot5334
-rw-r--r--po/it.po5367
-rw-r--r--po/nl.po3493
-rw-r--r--po/pt_PT.po4980
-rw-r--r--po/sv.po5738
-rw-r--r--po/vi.po5698
-rw-r--r--po/zh_CN.po5607
-rw-r--r--pretty.c72
-rw-r--r--read-cache.c279
-rw-r--r--reflog-walk.c22
-rw-r--r--reflog-walk.h4
-rw-r--r--refs.c1327
-rw-r--r--refs.h17
-rw-r--r--remote-curl.c19
-rw-r--r--remote.c132
-rw-r--r--remote.h5
-rw-r--r--rerere.c14
-rw-r--r--revision.c122
-rw-r--r--revision.h2
-rw-r--r--run-command.c74
-rw-r--r--sequencer.c995
-rw-r--r--sequencer.h39
-rw-r--r--setup.c73
-rw-r--r--sha1_file.c51
-rw-r--r--sha1_name.c22
-rw-r--r--strbuf.c33
-rw-r--r--strbuf.h7
-rw-r--r--streaming.c59
-rw-r--r--streaming.h4
-rw-r--r--submodule.c76
-rw-r--r--submodule.h6
-rw-r--r--symlinks.c28
-rw-r--r--t/Makefile49
-rw-r--r--t/README38
-rw-r--r--t/gitweb-lib.sh2
-rw-r--r--t/lib-bash.sh18
-rwxr-xr-xt/lib-credential.sh39
-rw-r--r--t/lib-git-daemon.sh69
-rw-r--r--t/lib-git-p4.sh69
-rw-r--r--t/lib-httpd.sh2
-rw-r--r--t/lib-httpd/apache.conf7
-rw-r--r--t/perf/.gitignore2
-rw-r--r--t/perf/Makefile15
-rw-r--r--t/perf/README146
-rwxr-xr-xt/perf/aggregate.perl166
-rwxr-xr-xt/perf/min_time.perl21
-rwxr-xr-xt/perf/p0000-perf-lib-sanity.sh55
-rwxr-xr-xt/perf/p0001-rev-list.sh17
-rwxr-xr-xt/perf/p4000-diff-algorithms.sh29
-rwxr-xr-xt/perf/p5302-pack-index.sh40
-rwxr-xr-xt/perf/p7810-grep.sh23
-rw-r--r--t/perf/perf-lib.sh202
-rwxr-xr-xt/perf/run82
-rwxr-xr-xt/t0000-basic.sh563
-rwxr-xr-xt/t0021-conversion.sh37
-rwxr-xr-xt/t0023-crlf-am.sh2
-rwxr-xr-xt/t0040-parse-options.sh70
-rwxr-xr-xt/t0061-run-command.sh13
-rwxr-xr-xt/t0062-revision-walking.sh33
-rwxr-xr-xt/t0080-vcs-svn.sh117
-rwxr-xr-xt/t0204-gettext-reencode-sanity.sh37
-rwxr-xr-xt/t0300-credentials.sh22
-rwxr-xr-xt/t0303-credential-external.sh69
-rwxr-xr-xt/t1010-mktree.sh4
-rwxr-xr-xt/t1050-large.sh67
-rwxr-xr-xt/t1200-tutorial.sh4
-rwxr-xr-xt/t1300-repo-config.sh35
-rwxr-xr-xt/t1304-default-acl.sh19
-rwxr-xr-xt/t1305-config-include.sh142
-rwxr-xr-xt/t1306-xdg-files.sh158
-rwxr-xr-xt/t1410-reflog.sh26
-rwxr-xr-xt/t1411-reflog-show.sh61
-rwxr-xr-xt/t1450-fsck.sh6
-rwxr-xr-xt/t1501-worktree.sh2
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh11
-rwxr-xr-xt/t1507-rev-parse-upstream.sh81
-rwxr-xr-xt/t2004-checkout-cache-temp.sh20
-rwxr-xr-xt/t2015-checkout-unborn.sh11
-rwxr-xr-xt/t2017-checkout-orphan.sh6
-rwxr-xr-xt/t2020-checkout-detach.sh23
-rwxr-xr-xt/t2030-unresolve-info.sh2
-rwxr-xr-xt/t3200-branch.sh77
-rwxr-xr-xt/t3300-funny-names.sh356
-rwxr-xr-xt/t3310-notes-merge-manual-resolve.sh27
-rwxr-xr-xt/t3400-rebase.sh6
-rwxr-xr-xt/t3401-rebase-partial.sh8
-rwxr-xr-xt/t3404-rebase-interactive.sh181
-rwxr-xr-xt/t3405-rebase-malformed.sh32
-rwxr-xr-xt/t3406-rebase-message.sh5
-rwxr-xr-xt/t3411-rebase-preserve-around-merges.sh1
-rwxr-xr-xt/t3412-rebase-root.sh7
-rwxr-xr-xt/t3415-rebase-autosquash.sh16
-rwxr-xr-xt/t3505-cherry-pick-empty.sh55
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh14
-rwxr-xr-xt/t3508-cherry-pick-many-commits.sh30
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh2
-rwxr-xr-xt/t3701-add-interactive.sh26
-rwxr-xr-xt/t3900-i18n-commit.sh2
-rwxr-xr-xt/t3903-stash.sh26
-rwxr-xr-xt/t3910-mac-os-precompose.sh164
-rwxr-xr-xt/t4006-diff-mode.sh65
-rwxr-xr-xt/t4012-diff-binary.sh60
-rwxr-xr-xt/t4013-diff-various.sh7
-rw-r--r--t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master4
-rw-r--r--t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side6
-rw-r--r--t/t4013/diff.diff-tree_--cc_--patch-with-stat_master4
-rw-r--r--t/t4013/diff.diff-tree_--cc_--stat_--summary_master4
-rw-r--r--t/t4013/diff.diff-tree_--cc_--stat_--summary_side6
-rw-r--r--t/t4013/diff.diff-tree_--cc_--stat_master4
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial6
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side6
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial6
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial6
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--stat_initial6
-rw-r--r--t/t4013/diff.diff-tree_--root_--patch-with-stat_initial6
-rw-r--r--t/t4013/diff.diff-tree_-c_--stat_--summary_master4
-rw-r--r--t/t4013/diff.diff-tree_-c_--stat_--summary_side6
-rw-r--r--t/t4013/diff.diff-tree_-c_--stat_master4
-rw-r--r--t/t4013/diff.diff_--patch-with-stat_-r_initial..side6
-rw-r--r--t/t4013/diff.diff_--patch-with-stat_initial..side6
-rw-r--r--t/t4013/diff.diff_--stat_initial..side6
-rw-r--r--t/t4013/diff.diff_-r_--stat_initial..side6
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side6
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_initial..master^10
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_initial..side6
-rw-r--r--t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--inline_--stdout_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--inline_--stdout_initial..master^10
-rw-r--r--t/t4013/diff.format-patch_--inline_--stdout_initial..master^^6
-rw-r--r--t/t4013/diff.format-patch_--inline_--stdout_initial..side6
-rw-r--r--t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^18
-rw-r--r--t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--stdout_--numbered_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--stdout_initial..master16
-rw-r--r--t/t4013/diff.format-patch_--stdout_initial..master^10
-rw-r--r--t/t4013/diff.format-patch_--stdout_initial..side6
-rw-r--r--t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_6
-rw-r--r--t/t4013/diff.log_--patch-with-stat_master16
-rw-r--r--t/t4013/diff.log_--patch-with-stat_master_--_dir_6
-rw-r--r--t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master26
-rw-r--r--t/t4013/diff.log_--root_--patch-with-stat_--summary_master22
-rw-r--r--t/t4013/diff.log_--root_--patch-with-stat_master22
-rw-r--r--t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master26
-rw-r--r--t/t4013/diff.show_--patch-with-stat_--summary_side6
-rw-r--r--t/t4013/diff.show_--patch-with-stat_side6
-rw-r--r--t/t4013/diff.show_--stat_--summary_side6
-rw-r--r--t/t4013/diff.show_--stat_side6
-rw-r--r--t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_6
-rw-r--r--t/t4013/diff.whatchanged_--patch-with-stat_master16
-rw-r--r--t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_6
-rw-r--r--t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master26
-rw-r--r--t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master22
-rw-r--r--t/t4013/diff.whatchanged_--root_--patch-with-stat_master22
-rw-r--r--t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master26
-rwxr-xr-xt/t4014-format-patch.sh11
-rwxr-xr-xt/t4015-diff-whitespace.sh14
-rwxr-xr-xt/t4016-diff-quote.sh35
-rwxr-xr-xt/t4020-diff-external.sh2
-rwxr-xr-xt/t4029-diff-trailing-space.sh2
-rwxr-xr-xt/t4030-diff-textconv.sh10
-rwxr-xr-xt/t4031-diff-rewrite-binary.sh12
-rwxr-xr-xt/t4034-diff-words.sh36
-rwxr-xr-xt/t4035-diff-quiet.sh99
-rwxr-xr-xt/t4041-diff-submodule-option.sh34
-rwxr-xr-xt/t4043-diff-rename-binary.sh8
-rwxr-xr-xt/t4045-diff-relative.sh18
-rwxr-xr-xt/t4047-diff-dirstat.sh69
-rwxr-xr-xt/t4049-diff-stat-count.sh6
-rwxr-xr-xt/t4052-stat-output.sh336
-rwxr-xr-xt/t4053-diff-no-index.sh32
-rwxr-xr-xt/t4100-apply-stat.sh4
-rwxr-xr-xt/t4103-apply-binary.sh4
-rwxr-xr-xt/t4108-apply-threeway.sh157
-rwxr-xr-xt/t4116-apply-reverse.sh4
-rwxr-xr-xt/t4117-apply-reject.sh8
-rwxr-xr-xt/t4150-am.sh18
-rwxr-xr-xt/t4200-rerere.sh8
-rwxr-xr-xt/t4202-log.sh290
-rwxr-xr-xt/t4205-log-pretty-formats.sh28
-rwxr-xr-xt/t4209-log-pickaxe.sh119
-rwxr-xr-xt/t4253-am-keep-cr-dos.sh4
-rwxr-xr-xt/t5000-tar-tree.sh78
-rwxr-xr-xt/t5100-mailinfo.sh2
-rw-r--r--t/t5100/patch00012
-rw-r--r--t/t5100/patch00022
-rw-r--r--t/t5100/patch00032
-rw-r--r--t/t5100/patch00054
-rw-r--r--t/t5100/patch00062
-rw-r--r--t/t5100/patch00102
-rw-r--r--t/t5100/patch00112
-rw-r--r--t/t5100/patch00142
-rw-r--r--t/t5100/patch0014--scissors2
-rw-r--r--t/t5100/sample.mbox18
-rwxr-xr-xt/t5150-request-pull.sh2
-rwxr-xr-xt/t5300-pack-object.sh17
-rwxr-xr-xt/t5302-pack-index.sh4
-rwxr-xr-xt/t5303-pack-corruption-resilience.sh4
-rwxr-xr-xt/t5500-fetch-pack.sh151
-rwxr-xr-xt/t5510-fetch.sh30
-rwxr-xr-xt/t5512-ls-remote.sh16
-rwxr-xr-xt/t5516-fetch-push.sh16
-rwxr-xr-xt/t5528-push-default.sh118
-rwxr-xr-xt/t5531-deep-submodule-push.sh94
-rwxr-xr-xt/t5532-fetch-proxy.sh2
-rwxr-xr-xt/t5541-http-push.sh50
-rwxr-xr-xt/t5550-http-fetch.sh15
-rwxr-xr-xt/t5551-http-fetch.sh31
-rwxr-xr-xt/t5570-git-daemon.sh146
-rwxr-xr-xt/t5601-clone.sh40
-rwxr-xr-xt/t5700-clone-reference.sh38
-rwxr-xr-xt/t5701-clone-local.sh83
-rwxr-xr-xt/t5706-clone-branch.sh8
-rwxr-xr-xt/t5710-info-alternate.sh2
-rwxr-xr-xt/t5800-remote-helpers.sh13
-rwxr-xr-xt/t6006-rev-list-format.sh20
-rwxr-xr-xt/t6011-rev-list-with-bad-commit.sh2
-rwxr-xr-xt/t6013-rev-list-reverse-parents.sh4
-rwxr-xr-xt/t6022-merge-rename.sh16
-rwxr-xr-xt/t6028-merge-up-to-date.sh17
-rwxr-xr-xt/t6030-bisect-porcelain.sh2
-rwxr-xr-xt/t6032-merge-large-rename.sh2
-rwxr-xr-xt/t6040-tracking-info.sh10
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh2
-rwxr-xr-xt/t6200-fmt-merge-msg.sh27
-rwxr-xr-xt/t7004-tag.sh83
-rwxr-xr-xt/t7007-show.sh91
-rwxr-xr-xt/t7060-wtstatus.sh96
-rwxr-xr-xt/t7201-co.sh4
-rwxr-xr-xt/t7300-clean.sh27
-rwxr-xr-xt/t7400-submodule-basic.sh173
-rwxr-xr-xt/t7403-submodule-sync.sh90
-rwxr-xr-xt/t7406-submodule-update.sh17
-rwxr-xr-xt/t7408-submodule-reference.sh8
-rwxr-xr-xt/t7501-commit.sh26
-rwxr-xr-xt/t7502-commit.sh2
-rwxr-xr-xt/t7503-pre-commit-hook.sh18
-rwxr-xr-xt/t7508-status.sh42
-rwxr-xr-xt/t7512-status-help.sh649
-rwxr-xr-xt/t7602-merge-octopus-many.sh26
-rwxr-xr-xt/t7603-merge-reduce-heads.sh50
-rwxr-xr-xt/t7607-merge-overwrite.sh9
-rwxr-xr-xt/t7701-repack-unpack-unreachable.sh14
-rwxr-xr-xt/t7800-difftool.sh68
-rwxr-xr-xt/t7810-grep.sh28
-rwxr-xr-xt/t8006-blame-textconv.sh2
-rwxr-xr-xt/t9002-column.sh180
-rwxr-xr-xt/t9010-svn-fe.sh365
-rwxr-xr-xt/t9011-svn-da.sh248
-rwxr-xr-xt/t9100-git-svn-basic.sh45
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh2
-rwxr-xr-xt/t9137-git-svn-dcommit-clobber-series.sh8
-rwxr-xr-xt/t9300-fast-import.sh381
-rwxr-xr-xt/t9350-fast-export.sh8
-rwxr-xr-xt/t9400-git-cvsserver-server.sh8
-rwxr-xr-xt/t9501-gitweb-standalone-http-status.sh67
-rwxr-xr-xt/t9800-git-p4-basic.sh343
-rwxr-xr-xt/t9801-git-p4-branch.sh222
-rwxr-xr-xt/t9802-git-p4-filetype.sh10
-rwxr-xr-xt/t9803-git-p4-shell-metachars.sh58
-rwxr-xr-xt/t9804-git-p4-label.sh115
-rwxr-xr-xt/t9805-git-p4-skip-submit-edit.sh29
-rwxr-xr-xt/t9806-git-p4-options.sh45
-rwxr-xr-xt/t9807-git-p4-submit.sh278
-rwxr-xr-xt/t9808-git-p4-chdir.sh10
-rwxr-xr-xt/t9809-git-p4-client-view.sh497
-rwxr-xr-xt/t9810-git-p4-rcs.sh388
-rwxr-xr-xt/t9811-git-p4-label-import.sh222
-rwxr-xr-xt/t9812-git-p4-wildcards.sh147
-rwxr-xr-xt/t9813-git-p4-preserve-users.sh153
-rwxr-xr-xt/t9814-git-p4-rename.sh206
-rwxr-xr-xt/t9902-completion.sh231
-rwxr-xr-xt/t9903-bash-prompt.sh456
-rw-r--r--t/test-lib-functions.sh565
-rw-r--r--t/test-lib.sh569
-rw-r--r--tag.c12
-rw-r--r--tag.h1
-rw-r--r--test-credential.c38
-rw-r--r--test-date.c7
-rw-r--r--test-dump-cache-tree.c2
-rw-r--r--test-line-buffer.c1
-rw-r--r--test-mergesort.c52
-rw-r--r--test-obj-pool.c116
-rw-r--r--test-parse-options.c12
-rw-r--r--test-revision-walking.c66
-rw-r--r--test-string-pool.c31
-rw-r--r--test-subprocess.c6
-rw-r--r--test-svn-fe.c48
-rw-r--r--test-treap.c70
-rw-r--r--transport-helper.c4
-rw-r--r--transport.c58
-rw-r--r--transport.h4
-rw-r--r--unpack-trees.c45
-rw-r--r--unpack-trees.h1
-rw-r--r--upload-pack.c11
-rw-r--r--userdiff.c19
-rw-r--r--utf8.c26
-rw-r--r--utf8.h1
-rw-r--r--varint.c29
-rw-r--r--varint.h9
-rw-r--r--vcs-svn/LICENSE3
-rw-r--r--vcs-svn/fast_export.c251
-rw-r--r--vcs-svn/fast_export.h25
-rw-r--r--vcs-svn/line_buffer.c10
-rw-r--r--vcs-svn/line_buffer.h3
-rw-r--r--vcs-svn/obj_pool.h61
-rw-r--r--vcs-svn/repo_tree.c330
-rw-r--r--vcs-svn/repo_tree.h12
-rw-r--r--vcs-svn/sliding_window.c79
-rw-r--r--vcs-svn/sliding_window.h18
-rw-r--r--vcs-svn/string_pool.c102
-rw-r--r--vcs-svn/string_pool.h11
-rw-r--r--vcs-svn/string_pool.txt43
-rw-r--r--vcs-svn/svndiff.c309
-rw-r--r--vcs-svn/svndiff.h10
-rw-r--r--vcs-svn/svndump.c161
-rw-r--r--vcs-svn/trp.h237
-rw-r--r--vcs-svn/trp.txt109
-rw-r--r--version.c17
-rw-r--r--version.h8
-rw-r--r--wrapper.c39
-rw-r--r--wt-status.c308
-rw-r--r--wt-status.h18
-rw-r--r--xdiff-interface.c44
-rw-r--r--xdiff-interface.h4
-rw-r--r--xdiff/xdiff.h16
-rw-r--r--xdiff/xdiffi.c21
-rw-r--r--xdiff/xemit.c12
-rw-r--r--xdiff/xhistogram.c2
-rw-r--r--xdiff/xpatience.c2
-rw-r--r--xdiff/xprepare.c21
-rw-r--r--xdiff/xutils.c149
-rw-r--r--xdiff/xutils.h3
659 files changed, 82195 insertions, 12247 deletions
diff --git a/.gitignore b/.gitignore
index 3b7680e..bb5c91e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,9 @@
/GIT-CFLAGS
/GIT-LDFLAGS
/GIT-GUI-VARS
+/GIT-PREFIX
+/GIT-SCRIPT-DEFINES
+/GIT-USER-AGENT
/GIT-VERSION-FILE
/bin-wrappers/
/git
@@ -26,10 +29,12 @@
/git-cherry-pick
/git-clean
/git-clone
+/git-column
/git-commit
/git-commit-tree
/git-config
/git-count-objects
+/git-credential
/git-credential-cache
/git-credential-cache--daemon
/git-credential-store
@@ -92,6 +97,7 @@
/git-name-rev
/git-mv
/git-notes
+/git-p4
/git-pack-redundant
/git-pack-objects
/git-pack-refs
@@ -170,7 +176,6 @@
/gitweb/static/gitweb.js
/gitweb/static/gitweb.min.*
/test-chmtime
-/test-credential
/test-ctype
/test-date
/test-delta
@@ -180,17 +185,16 @@
/test-index-version
/test-line-buffer
/test-match-trees
+/test-mergesort
/test-mktemp
-/test-obj-pool
/test-parse-options
/test-path-utils
+/test-revision-walking
/test-run-command
/test-sha1
/test-sigchain
-/test-string-pool
/test-subprocess
/test-svn-fe
-/test-treap
/common-cmds.h
*.tar.gz
*.dsc
diff --git a/.mailmap b/.mailmap
index 19c8726..6303782 100644
--- a/.mailmap
+++ b/.mailmap
@@ -29,7 +29,13 @@ Joachim Berdal Haga <cjhaga@fys.uio.no>
Jon Loeliger <jdl@freescale.com>
Jon Seymour <jon@blackcubes.dyndns.org>
Jonathan Nieder <jrnieder@uchicago.edu>
-Junio C Hamano <junio@twinsun.com>
+Junio C Hamano <gitster@pobox.com> <gitster@pobox.com>
+Junio C Hamano <gitster@pobox.com> <junio@pobox.com>
+Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
+Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
+Junio C Hamano <gitster@pobox.com> <junio@hera.kernel.org>
+Junio C Hamano <gitster@pobox.com> <junio@kernel.org>
+Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
Karl Hasselström <kha@treskal.com>
Kent Engstrom <kent@lysator.liu.se>
Lars Doelle <lars.doelle@on-line ! de>
diff --git a/Documentation/Makefile b/Documentation/Makefile
index d40e211..063fa69 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -66,12 +66,6 @@ endif
-include ../config.mak
#
-# For asciidoc ...
-# -7.1.2, set ASCIIDOC7
-# 8.0-, no extra settings are needed
-#
-
-#
# For docbook-xsl ...
# -1.68.1, no extra settings are needed?
# 1.69.0, set ASCIIDOC_ROFF?
@@ -81,9 +75,6 @@ endif
# 1.73.0-, no extra settings are needed
#
-ifndef ASCIIDOC7
-ASCIIDOC_EXTRA += -a asciidoc7compatible -a no-inline-literal
-endif
ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
MANPAGE_XSL = manpage-1.72.xsl
@@ -124,14 +115,15 @@ SHELL_PATH ?= $(SHELL)
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
-#
-# Please note that there is a minor bug in asciidoc.
-# The version after 6.0.3 _will_ include the patch found here:
-# http://marc.theaimsgroup.com/?l=git&m=111558757202243&w=2
-#
-# Until that version is released you may have to apply the patch
-# yourself - yes, all 6 characters of it!
-#
+ifdef DEFAULT_PAGER
+DEFAULT_PAGER_SQ = $(subst ','\'',$(DEFAULT_PAGER))
+ASCIIDOC_EXTRA += -a 'git-default-pager=$(DEFAULT_PAGER_SQ)'
+endif
+
+ifdef DEFAULT_EDITOR
+DEFAULT_EDITOR_SQ = $(subst ','\'',$(DEFAULT_EDITOR))
+ASCIIDOC_EXTRA += -a 'git-default-editor=$(DEFAULT_EDITOR_SQ)'
+endif
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
@@ -270,6 +262,7 @@ technical/api-index.txt: technical/api-index-skel.txt \
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
$(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh
+technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt
$(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt
@@ -323,6 +316,7 @@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
WEBDOC_DEST = /pub/software/scm/git/docs
+howto/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
sed -e '1,/^$$/d' $< | $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 - >$@+ && \
diff --git a/Documentation/RelNotes/1.7.10.1.txt b/Documentation/RelNotes/1.7.10.1.txt
new file mode 100644
index 0000000..806a965
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.1.txt
@@ -0,0 +1,78 @@
+Git v1.7.10.1 Release Notes
+===========================
+
+Additions since v1.7.10
+-----------------------
+
+Localization message files for Danish and German have been added.
+
+
+Fixes since v1.7.10
+-------------------
+
+ * "git add -p" is not designed to deal with unmerged paths but did
+ not exclude them and tried to apply funny patches only to fail.
+
+ * "git blame" started missing quite a few changes from the origin
+ since we stopped using the diff minimalization by default in v1.7.2
+ era.
+
+ * When PATH contains an unreadable directory, alias expansion code
+ did not kick in, and failed with an error that said "git-subcmd"
+ was not found.
+
+ * "git clean -d -f" (not "-d -f -f") is supposed to protect nested
+ working trees of independent git repositories that exist in the
+ current project working tree from getting removed, but the
+ protection applied only to such working trees that are at the
+ top-level of the current project by mistake.
+
+ * "git commit --author=$name" did not tell the name that was being
+ recorded in the resulting commit to hooks, even though it does do
+ so when the end user overrode the authorship via the
+ "GIT_AUTHOR_NAME" environment variable.
+
+ * When "git commit --template F" errors out because the user did not
+ touch the message, it claimed that it aborts due to "empty
+ message", which was utterly wrong.
+
+ * The regexp configured with diff.wordregex was incorrectly reused
+ across files.
+
+ * An age-old corner case bug in combine diff (only triggered with -U0
+ and the hunk at the beginning of the file needs to be shown) has
+ been fixed.
+
+ * Rename detection logic used to match two empty files as renames
+ during merge-recursive, leading to unnatural mismerges.
+
+ * The parser in "fast-import" did not diagnose ":9" style references
+ that is not followed by required SP/LF as an error.
+
+ * When "git fetch" encounters repositories with too many references,
+ the command line of "fetch-pack" that is run by a helper
+ e.g. remote-curl, may fail to hold all of them. Now such an
+ internal invocation can feed the references through the standard
+ input of "fetch-pack".
+
+ * "git fetch" that recurses into submodules on demand did not check
+ if it needs to go into submodules when non branches (most notably,
+ tags) are fetched.
+
+ * "log -p --graph" used with "--stat" had a few formatting error.
+
+ * Running "notes merge --commit" failed to perform correctly when run
+ from any directory inside $GIT_DIR/. When "notes merge" stops with
+ conflicts, $GIT_DIR/NOTES_MERGE_WORKTREE is the place a user edits
+ to resolve it.
+
+ * The 'push to upstream' implementation was broken in some corner
+ cases. "git push $there" without refspec, when the current branch
+ is set to push to a remote different from $there, used to push to
+ $there using the upstream information to a remote unreleated to
+ $there.
+
+ * Giving "--continue" to a conflicted "rebase -i" session skipped a
+ commit that only results in changes to submodules.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.2.txt b/Documentation/RelNotes/1.7.10.2.txt
new file mode 100644
index 0000000..7a7e9d6
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.2.txt
@@ -0,0 +1,85 @@
+Git v1.7.10.2 Release Notes
+===========================
+
+Fixes since v1.7.10.1
+---------------------
+
+ * The test scaffolding for git-daemon was flaky.
+
+ * The test scaffolding for fast-import was flaky.
+
+ * The filesystem boundary was not correctly reported when .git directory
+ discovery stopped at a mount point.
+
+ * HTTP transport that requires authentication did not work correctly when
+ multiple connections are used simultaneously.
+
+ * Minor memory leak during unpack_trees (hence "merge" and "checkout"
+ to check out another branch) has been plugged.
+
+ * In the older days, the header "Conflicts:" in "cherry-pick" and "merge"
+ was separated by a blank line from the list of paths that follow for
+ readability, but when "merge" was rewritten in C, we lost it by
+ mistake. Remove the newline from "cherry-pick" to make them match
+ again.
+
+ * The command line parser choked "git cherry-pick $name" when $name can
+ be both revision name and a pathname, even though $name can never be a
+ path in the context of the command.
+
+ * The "include.path" facility in the configuration mechanism added in
+ 1.7.10 forgot to interpret "~/path" and "~user/path" as it should.
+
+ * "git config --rename-section" to rename an existing section into a
+ bogus one did not check the new name.
+
+ * The "diff --no-index" codepath used limited-length buffers, risking
+ pathnames getting truncated. Update it to use the strbuf API.
+
+ * The report from "git fetch" said "new branch" even for a non branch
+ ref.
+
+ * The http-backend (the server side of the smart http transfer) used
+ to overwrite GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL with the
+ value obtained from REMOTE_USER unconditionally, making it
+ impossible for the server side site-specific customization to use
+ different identity sources to affect the names logged. It now uses
+ REMOTE_USER only as a fallback value.
+
+ * "log --graph" was not very friendly with "--stat" option and its
+ output had line breaks at wrong places.
+
+ * Octopus merge strategy did not reduce heads that are recorded in the
+ final commit correctly.
+
+ * "git push" over smart-http lost progress output a few releases ago;
+ this release resurrects it.
+
+ * The error and advice messages given by "git push" when it fails due
+ to non-ff were not very helpful to new users; it has been broken
+ into three cases, and each is given a separate advice message.
+
+ * The insn sheet given by "rebase -i" did not make it clear that the
+ insn lines can be re-ordered to affect the order of the commits in
+ the resulting history.
+
+ * "git repack" used to write out unreachable objects as loose objects
+ when repacking, even if such loose objects will immediately pruned
+ due to its age.
+
+ * A contrib script "rerere-train" did not work out of the box unless
+ user futzed with her $PATH.
+
+ * "git rev-parse --show-prefix" used to emit nothing when run at the
+ top-level of the working tree, but now it gives a blank line.
+
+ * The i18n of error message "git stash save" was not properly done.
+
+ * "git submodule" used a sed script that some platforms mishandled.
+
+ * When using a Perl script on a system where "perl" found on user's
+ $PATH could be ancient or otherwise broken, we allow builders to
+ specify the path to a good copy of Perl with $PERL_PATH. The
+ gitweb test forgot to use that Perl when running its test.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.3.txt b/Documentation/RelNotes/1.7.10.3.txt
new file mode 100644
index 0000000..703fbf1
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.3.txt
@@ -0,0 +1,43 @@
+Git v1.7.10.3 Release Notes
+===========================
+
+Fixes since v1.7.10.2
+---------------------
+
+ * The message file for German translation has been updated a bit.
+
+ * Running "git checkout" on an unborn branch used to corrupt HEAD.
+
+ * When checking out another commit from an already detached state, we
+ used to report all commits that are not reachable from any of the
+ refs as lossage, but some of them might be reachable from the new
+ HEAD, and there is no need to warn about them.
+
+ * Some time ago, "git clone" lost the progress output for its
+ "checkout" phase; when run without any "--quiet" option, it should
+ give progress to the lengthy operation.
+
+ * The directory path used in "git diff --no-index", when it recurses
+ down, was broken with a recent update after v1.7.10.1 release.
+
+ * "log -z --pretty=tformat:..." did not terminate each record with
+ NUL. The fix is not entirely correct when the output also asks for
+ --patch and/or --stat, though.
+
+ * The DWIM behaviour for "log --pretty=format:%gd -g" was somewhat
+ broken and gave undue precedence to configured log.date, causing
+ "git stash list" to show "stash@{time stamp string}".
+
+ * "git status --porcelain" ignored "--branch" option by mistake. The
+ output for "git status --branch -z" was also incorrect and did not
+ terminate the record for the current branch name with NUL as asked.
+
+ * When a submodule repository uses alternate object store mechanism,
+ some commands that were started from the superproject did not
+ notice it and failed with "No such object" errors. The subcommands
+ of "git submodule" command that recursed into the submodule in a
+ separate process were OK; only the ones that cheated and peeked
+ directly into the submodule's repository from the primary process
+ were affected.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.4.txt b/Documentation/RelNotes/1.7.10.4.txt
new file mode 100644
index 0000000..326670d
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.4.txt
@@ -0,0 +1,29 @@
+Git v1.7.10.4 Release Notes
+===========================
+
+Fixes since v1.7.10.3
+---------------------
+
+ * The message file for Swedish translation has been updated a bit.
+
+ * A name taken from mailmap was copied into an internal buffer
+ incorrectly and could overun the buffer if it is too long.
+
+ * A malformed commit object that has a header line chomped in the
+ middle could kill git with a NULL pointer dereference.
+
+ * An author/committer name that is a single character was mishandled
+ as an invalid name by mistake.
+
+ * The progress indicator for a large "git checkout" was sent to
+ stderr even if it is not a terminal.
+
+ * "git grep -e '$pattern'", unlike the case where the patterns are
+ read from a file, did not treat individual lines in the given
+ pattern argument as separate regular expressions as it should.
+
+ * When "git rebase" was given a bad commit to replay the history on,
+ its error message did not correctly give the command line argument
+ it had trouble parsing.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.5.txt b/Documentation/RelNotes/1.7.10.5.txt
new file mode 100644
index 0000000..4db1770
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.5.txt
@@ -0,0 +1,12 @@
+Git v1.7.10.5 Release Notes
+===========================
+
+Fixes since v1.7.10.4
+---------------------
+
+ * "git fast-export" did not give a readable error message when the
+ same mark erroneously appeared twice in the --import-marks input.
+
+ * "git rebase -p" used to pay attention to rebase.autosquash which
+ was wrong. "git rebase -p -i" should, but "git rebase -p" by
+ itself should not.
diff --git a/Documentation/RelNotes/1.7.10.txt b/Documentation/RelNotes/1.7.10.txt
new file mode 100644
index 0000000..58100bf
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.txt
@@ -0,0 +1,219 @@
+Git v1.7.10 Release Notes
+=========================
+
+Compatibility Notes
+-------------------
+
+ * From this release on, the "git merge" command in an interactive
+ session will start an editor when it automatically resolves the
+ merge for the user to explain the resulting commit, just like the
+ "git commit" command does when it wasn't given a commit message.
+
+ If you have a script that runs "git merge" and keeps its standard
+ input and output attached to the user's terminal, and if you do not
+ want the user to explain the resulting merge commits, you can
+ export GIT_MERGE_AUTOEDIT environment variable set to "no", like
+ this:
+
+ #!/bin/sh
+ GIT_MERGE_AUTOEDIT=no
+ export GIT_MERGE_AUTOEDIT
+
+ to disable this behavior (if you want your users to explain their
+ merge commits, you do not have to do anything). Alternatively, you
+ can give the "--no-edit" option to individual invocations of the
+ "git merge" command if you know everybody who uses your script has
+ Git v1.7.8 or newer.
+
+ * The "--binary/-b" options to "git am" have been a no-op for quite a
+ while and were deprecated in mid 2008 (v1.6.0). When you give these
+ options to "git am", it will now warn and ask you not to use them.
+
+ * When you do not tell which branches and tags to push to the "git
+ push" command in any way, the command used "matching refs" rule to
+ update remote branches and tags with branches and tags with the
+ same name you locally have. In future versions of Git, this will
+ change to push out only your current branch according to either the
+ "upstream" or the "current" rule. Although "upstream" may be more
+ powerful once the user understands Git better, the semantics
+ "current" gives is simpler and easier to understand for beginners
+ and may be a safer and better default option. We haven't decided
+ yet which one to switch to.
+
+
+Updates since v1.7.9
+--------------------
+
+UI, Workflows & Features
+
+ * various "gitk" updates.
+ - show the path to the top level directory in the window title
+ - update preference edit dialog
+ - display file list correctly when directories are given on command line
+ - make "git-describe" output in the log message into a clickable link
+ - avoid matching the UNIX timestamp part when searching all fields
+ - give preference to symbolic font names like sans & monospace
+ - allow comparing two commits using a mark
+ - "gitk" honors log.showroot configuration.
+
+ * Teams for localizing the messages from the Porcelain layer of
+ commands are starting to form, thanks to Jiang Xin who volunteered
+ to be the localization coordinator. Translated messages for
+ simplified Chinese, Swedish and Portuguese are available.
+
+ * The configuration mechanism learned an "include" facility; an
+ assignment to the include.path pseudo-variable causes the named
+ file to be included in-place when Git looks up configuration
+ variables.
+
+ * A content filter (clean/smudge) used to be just a way to make the
+ recorded contents "more useful", and allowed to fail; a filter can
+ now optionally be marked as "required".
+
+ * Options whose names begin with "--no-" (e.g. the "--no-verify"
+ option of the "git commit" command) can be negated by omitting
+ "no-" from its name, e.g. "git commit --verify".
+
+ * "git am" learned to pass "-b" option to underlying "git mailinfo", so
+ that a bracketed string other than "PATCH" at the beginning can be kept.
+
+ * "git clone" learned "--single-branch" option to limit cloning to a
+ single branch (surprise!); tags that do not point into the history
+ of the branch are not fetched.
+
+ * "git clone" learned to detach the HEAD in the resulting repository
+ when the user specifies a tag with "--branch" (e.g., "--branch=v1.0").
+ Clone also learned to print the usual "detached HEAD" advice in such
+ a case, similar to "git checkout v1.0".
+
+ * When showing a patch while ignoring whitespace changes, the context
+ lines are taken from the postimage, in order to make it easier to
+ view the output.
+
+ * "git diff --stat" learned to adjust the width of the output on
+ wider terminals, and give more columns to pathnames as needed.
+
+ * "diff-highlight" filter (in contrib/) was updated to produce more
+ aesthetically pleasing output.
+
+ * "fsck" learned "--no-dangling" option to omit dangling object
+ information.
+
+ * "git log -G" and "git log -S" learned to pay attention to the "-i"
+ option. With "-i", "log -G" ignores the case when finding patch
+ hunks that introduce or remove a string that matches the given
+ pattern. Similarly with "-i", "log -S" ignores the case when
+ finding the commit the given block of text appears or disappears
+ from the file.
+
+ * "git merge" in an interactive session learned to spawn the editor
+ by default to let the user edit the auto-generated merge message,
+ to encourage people to explain their merges better. Legacy scripts
+ can export GIT_MERGE_AUTOEDIT=no to retain the historical behavior.
+ Both "git merge" and "git pull" can be given --no-edit from the
+ command line to accept the auto-generated merge message.
+
+ * The advice message given when the user didn't give enough clue on
+ what to merge to "git pull" and "git merge" has been updated to
+ be more concise and easier to understand.
+
+ * "git push" learned the "--prune" option, similar to "git fetch".
+
+ * The whole directory that houses a top-level superproject managed by
+ "git submodule" can be moved to another place.
+
+ * "git symbolic-ref" learned the "--short" option to abbreviate the
+ refname it shows unambiguously.
+
+ * "git tag --list" can be given "--points-at <object>" to limit its
+ output to those that point at the given object.
+
+ * "gitweb" allows intermediate entries in the directory hierarchy
+ that leads to a project to be clicked, which in turn shows the
+ list of projects inside that directory.
+
+ * "gitweb" learned to read various pieces of information for the
+ repositories lazily, instead of reading everything that could be
+ needed (including the ones that are not necessary for a specific
+ task).
+
+ * Project search in "gitweb" shows the substring that matched in the
+ project name and description highlighted.
+
+ * HTTP transport learned to authenticate with a proxy if needed.
+
+ * A new script "diffall" is added to contrib/; it drives an
+ external tool to perform a directory diff of two Git revisions
+ in one go, unlike "difftool" that compares one file at a time.
+
+Foreign Interface
+
+ * Improved handling of views, labels and branches in "git-p4" (in contrib).
+
+ * "git-p4" (in contrib) suffered from unnecessary merge conflicts when
+ p4 expanded the embedded $RCS$-like keywords; it can be now told to
+ unexpand them.
+
+ * Some "git-svn" updates.
+
+ * "vcs-svn"/"svn-fe" learned to read dumps with svn-deltas and
+ support incremental imports.
+
+ * "git difftool/mergetool" learned to drive DeltaWalker.
+
+Performance
+
+ * Unnecessary calls to parse_object() "git upload-pack" makes in
+ response to "git fetch", have been eliminated, to help performance
+ in repositories with excessive number of refs.
+
+Internal Implementation (please report possible regressions)
+
+ * Recursive call chains in "git index-pack" to deal with long delta
+ chains have been flattened, to reduce the stack footprint.
+
+ * Use of add_extra_ref() API is now gone, to make it possible to
+ cleanly restructure the overall refs API.
+
+ * The command line parser of "git pack-objects" now uses parse-options
+ API.
+
+ * The test suite supports the new "test_pause" helper function.
+
+ * Parallel to the test suite, there is a beginning of performance
+ benchmarking framework.
+
+ * t/Makefile is adjusted to prevent newer versions of GNU make from
+ running tests in seemingly random order.
+
+ * The code to check if a path points at a file beyond a symbolic link
+ has been restructured to be thread-safe.
+
+ * When pruning directories that has become empty during "git prune"
+ and "git prune-packed", call closedir() that iterates over a
+ directory before rmdir() it.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.9
+------------------
+
+Unless otherwise noted, all the fixes since v1.7.9 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * Build with NO_PERL_MAKEMAKER was broken and Git::I18N did not work
+ with versions of Perl older than 5.8.3.
+ (merge 5eb660e ab/perl-i18n later to maint).
+
+ * "git tag -s" honored "gpg.program" configuration variable since
+ 1.7.9, but "git tag -v" and "git verify-tag" didn't.
+ (merge a2c2506 az/verify-tag-use-gpg-config later to maint).
+
+ * "configure" script learned to take "--with-sane-tool-path" from the
+ command line to record SANE_TOOL_PATH (used to avoid broken platform
+ tools in /usr/bin) in config.mak.autogen. This may be useful for
+ people on Solaris who have saner tools outside /usr/xpg[46]/bin.
+
+ * zsh port of bash completion script needed another workaround.
diff --git a/Documentation/RelNotes/1.7.11.1.txt b/Documentation/RelNotes/1.7.11.1.txt
new file mode 100644
index 0000000..577ecca
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.1.txt
@@ -0,0 +1,9 @@
+Git v1.7.11.1 Release Notes
+===========================
+
+Fixes since v1.7.11
+-------------------
+
+ * The cross links in the HTML version of manual pages were broken.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.2.txt b/Documentation/RelNotes/1.7.11.2.txt
new file mode 100644
index 0000000..a0d24d1
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.2.txt
@@ -0,0 +1,53 @@
+Git v1.7.11.2 Release Notes
+===========================
+
+Fixes since v1.7.11.1
+---------------------
+
+ * On Cygwin, the platform pread(2) is not thread safe, just like our
+ own compat/ emulation, and cannot be used in the index-pack
+ program. Makefile variable NO_THREAD_SAFE_PREAD can be defined to
+ avoid use of this function in a threaded program.
+
+ * "git add" allows adding a regular file to the path where a
+ submodule used to exist, but "git update-index" does not allow an
+ equivalent operation to Porcelain writers.
+
+ * "git archive" incorrectly computed the header checksum; the symptom
+ was observed only when using pathnames with hi-bit set.
+
+ * "git blame" did not try to make sure that the abbreviated commit
+ object names in its output are unique.
+
+ * Running "git bundle verify" on a bundle that records a complete
+ history said "it requires these 0 commits".
+
+ * "git clone --single-branch" to clone a single branch did not limit
+ the cloning to the specified branch.
+
+ * "git diff --no-index" did not correctly handle relative paths and
+ did not correctly give exit codes when run under "--quiet" option.
+
+ * "git diff --no-index" did not work with pagers correctly.
+
+ * "git diff COPYING HEAD:COPYING" gave a nonsense error message that
+ claimed that the treeish HEAD did not have COPYING in it.
+
+ * When "git log" gets "--simplify-merges/by-decoration" together with
+ "--first-parent", the combination of these options makes the
+ simplification logic to use in-core commit objects that haven't
+ been examined for relevance, either producing incorrect result or
+ taking too long to produce any output. Teach the simplification
+ logic to ignore commits that the first-parent traversal logic
+ ignored when both are in effect to work around the issue.
+
+ * "git ls-files --exclude=t -i" did not consider anything under t/ as
+ excluded, as it did not pay attention to exclusion of leading paths
+ while walking the index. Other two users of excluded() are also
+ updated.
+
+ * "git request-pull $url dev" when the tip of "dev" branch was tagged
+ with "ext4-for-linus" used the contents from the tag in the output
+ but still asked the "dev" branch to be pulled, not the tag.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.txt b/Documentation/RelNotes/1.7.11.txt
new file mode 100644
index 0000000..15b954c
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.txt
@@ -0,0 +1,139 @@
+Git v1.7.11 Release Notes
+=========================
+
+Updates since v1.7.10
+---------------------
+
+UI, Workflows & Features
+
+ * A new mode for push, "simple", which is a cross between "current"
+ and "upstream", has been introduced. "git push" without any refspec
+ will push the current branch out to the same name at the remote
+ repository only when it is set to track the branch with the same
+ name over there. The plan is to make this mode the new default
+ value when push.default is not configured.
+
+ * A couple of commands learned the "--column" option to produce
+ columnar output.
+
+ * A third-party tool "git subtree" is distributed in contrib/
+
+ * A remote helper that acts as a proxy and caches ssl session for the
+ https:// transport is added to the contrib/ area.
+
+ * Error messages given when @{u} is used for a branch without its
+ upstream configured have been clarified.
+
+ * Even with the "-q"uiet option, "checkout" used to report setting up
+ tracking. Also "branch" learned the "-q"uiet option to squelch
+ informational message.
+
+ * Your build platform may support hardlinks but you may prefer not to
+ use them, e.g. when installing to DESTDIR to make a tarball and
+ untarring on a filesystem that has poor support for hardlinks.
+ There is a Makefile option NO_INSTALL_HARDLINKS for you.
+
+ * The smart-http backend used to always override GIT_COMMITTER_*
+ variables with REMOTE_USER and REMOTE_ADDR, but these variables are
+ now preserved when set.
+
+ * "git am" learned the "--include" option, which is an opposite of
+ existing the "--exclude" option.
+
+ * When "git am -3" needs to fall back to an application of the patch
+ to a synthesized preimage followed by a 3-way merge, the paths that
+ needed such treatment are now reported to the end user, so that the
+ result in them can be eyeballed with extra care.
+
+ * The output from "diff/log --stat" used to always allocate 4 columns
+ to show the number of modified lines, but not anymore.
+
+ * "git difftool" learned the "--dir-diff" option to spawn external
+ diff tools that can compare two directory hierarchies at a time
+ after populating two temporary directories, instead of running an
+ instance of the external tool once per a file pair.
+
+ * The "fmt-merge-msg" command learned to list the primary contributors
+ involved in the side topic you are merging in a comment in the merge
+ commit template.
+
+ * "git rebase" learned to optionally keep commits that do not
+ introduce any change in the original history.
+
+ * "git push --recurse-submodules" learned to optionally look into the
+ histories of submodules bound to the superproject and push them
+ out.
+
+ * A 'snapshot' request to "gitweb" honors If-Modified-Since: header,
+ based on the commit date.
+
+ * "gitweb" learned to highlight the patch it outputs even more.
+
+Foreign Interface
+
+ * "git svn" used to die with unwanted SIGPIPE when talking with an HTTP
+ server that uses keep-alive.
+
+ * "git svn" learned to use platform specific authentication
+ providers, e.g. gnome-keyring, kwallet, etc.
+
+ * "git p4" has been moved out of the contrib/ area and has seen more
+ work on importing labels as tags from (and exporting tags as labels
+ to) p4.
+
+Performance and Internal Implementation (please report possible regressions)
+
+ * Bash completion script (in contrib/) have been cleaned up to make
+ future work on it simpler.
+
+ * An experimental "version 4" format of the index file has been
+ introduced to reduce on-disk footprint and I/O overhead.
+
+ * "git archive" learned to produce its output without reading the
+ blob object it writes out in memory in its entirety.
+
+ * "git index-pack" that runs when fetching or pushing objects to
+ complete the packfile on the receiving end learned to use multiple
+ threads to do its job when available.
+
+ * The code to compute hash values for lines used by the internal diff
+ engine was optimized on little-endian machines, using the same
+ trick the kernel folks came up with.
+
+ * "git apply" had some memory leaks plugged.
+
+ * Setting up a revision traversal with many starting points was
+ inefficient as these were placed in a date-order priority queue
+ one-by-one. Now they are collected in the queue unordered first,
+ and sorted immediately before getting used.
+
+ * More lower-level commands learned to use the streaming API to read
+ from the object store without keeping everything in core.
+
+ * The weighting parameters to suggestion command name typo have been
+ tweaked, so that "git tags" will suggest "tag?" and not "stage?".
+
+ * Because "sh" on the user's PATH may be utterly broken on some
+ systems, run-command API now uses SHELL_PATH, not /bin/sh, when
+ spawning an external command (not applicable to Windows port).
+
+ * The API to iterate over the refs/ hierarchy has been tweaked to
+ allow walking only a subset of it more efficiently.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.10
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.10 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * "git submodule init" used to report "registered for path ..."
+ even for submodules that were registered earlier.
+ (cherry-pick c1c259e jl/submodule-report-new-path-once later to maint).
+
+ * "git diff --stat" used to fully count a binary file with modified
+ execution bits whose contents is unmodified, which was not quite
+ right.
diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.txt
new file mode 100644
index 0000000..067c476
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.txt
@@ -0,0 +1,138 @@
+Git v1.7.12 Release Notes
+=========================
+
+Updates since v1.7.11
+---------------------
+
+UI, Workflows & Features
+
+ * Git can be told to normalize pathnames it read from readdir(3) and
+ all arguments it got from the command line into precomposed UTF-8
+ (assuming that they come as decomposed UTF-8), in order to work
+ around issues on Mac OS.
+
+ I think there still are other places that need conversion
+ (e.g. paths that are read from stdin for some commands), but this
+ should be a good first step in the right direction.
+
+ * Per-user $HOME/.gitconfig file can optionally be stored in
+ $HOME/.config/git/config instead, which is in line with XDG.
+
+ * The value of core.attributesfile and core.excludesfile default to
+ $HOME/.config/attributes and $HOME/.config/ignore respectively when
+ these files exist.
+
+ * Scripted Porcelain writers now have access to the credential API via
+ the "git credential" plumbing command.
+
+ * "git help" used to always default to "man" format even on platforms
+ where "man" viewer is not widely available.
+
+ * "git clone --local $path" started its life as an experiment to
+ optionally use link/copy when cloning a repository on the disk, but
+ we didn't deprecate it after we made the option a no-op to always
+ use the optimization. The command learned "--no-local" option to
+ turn this off, as a more explicit alternative over use of file://
+ URL.
+
+ * "git fetch" and friends used to say "remote side hung up
+ unexpectedly" when they failed to get response they expect from the
+ other side, but one common reason why they don't get expected
+ response is that the remote repository does not exist or cannot be
+ read. The error message in this case was updated to give better
+ hints to the user.
+
+ * git native protocol agents learned to show software version over
+ the wire, so that the server log can be examined to see the vintage
+ distribution of clients.
+
+ * "git help -w $cmd" can show HTML version of documentation for
+ "git-$cmd" by setting help.htmlpath to somewhere other than the
+ default location where the build procedure installs them locally;
+ the variable can even point at a http:// URL.
+
+ * "git rebase -i" learned "-x <cmd>" to insert "exec <cmd>" after
+ each commit in the resulting history.
+
+ * "git status" gives finer classification to various states of paths
+ in conflicted state and offer advice messages in its output.
+
+ * "git submodule" learned to deal with nested submodule structure
+ where a module is contained within a module whose origin is
+ specified as a relative URL to its superproject's origin.
+
+ * A rather heavy-ish "git completion" script has been split to create
+ a separate "git prompting" script, to help lazy-autoloading of the
+ completion part while making prompting part always available.
+
+
+Foreign Interface
+
+ * "mediawiki" remote helper (in contrib/) learned to handle file
+ attachments.
+
+ * vcs-svn has been updated to clean-up compilation, lift 32-bit
+ limitations, etc.
+
+
+Performance, Internal Implementation, etc. (please report possible regressions)
+
+ * Some tests showed false failures caused by a bug in ecryptofs.
+
+ * We no longer use AsciiDoc7 syntax in our documentation and favor a
+ more modern style.
+
+ * "git am --rebasing" codepath was taught to grab authorship, log
+ message and the patch text directly out of existing commits. This
+ will help rebasing commits that have confusing "diff" output in
+ their log messages.
+
+ * "git index-pack" and "git pack-objects" use streaming API to read
+ from the object store to avoid having to hold a large blob object
+ in-core while they are doing their thing.
+
+ * Code to match paths with exclude patterns learned to avoid calling
+ fnmatch() by comparing fixed leading substring literally when
+ possible.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.11
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.11 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * "git show"'s auto-walking behaviour was an unreliable and
+ unpredictable hack; it now behaves just like "git log" does when it
+ walks.
+ (merge c5941f1 tr/maint-show-walk later to maint).
+
+ * "git diff", "git status" and anything that internally uses the
+ comparison machinery was utterly broken when the difference
+ involved a file with "-" as its name. This was due to the way "git
+ diff --no-index" was incorrectly bolted on to the system, making
+ any comparison that involves a file "-" at the root level
+ incorrectly read from the standard input.
+ (merge 4682d85 jc/refactor-diff-stdin later to maint).
+
+ * We did not have test to make sure "git rebase" without extra options
+ filters out an empty commit in the original history.
+ (merge 2b5ba7b mz/empty-rebase-test later to maint).
+
+ * "git fast-export" produced an input stream for fast-import without
+ properly quoting pathnames when they contain SPs in them.
+ (merge ff59f6d js/fast-export-paths-with-spaces later to maint).
+
+ * "git checkout --detach", when you are still on an unborn branch,
+ should be forbidden, but it wasn't.
+ (merge 8ced1aa cw/no-detaching-an-unborn later to maint).
+
+ * Some implementations of Perl terminates "lines" with CRLF even when
+ the script is operating on just a sequence of bytes. Make sure to
+ use "$PERL_PATH", the version of Perl the user told Git to use, in
+ our tests to avoid unnecessary breakages in tests.
+ (merge ad78585 vr/use-our-perl-in-tests later to maint).
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index aea8627..a26d245 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -90,6 +90,8 @@ endif::backend-docbook[]
endif::doctype-manpage[]
ifdef::backend-xhtml11[]
+[attributes]
+git-relative-html-prefix=
[linkgit-inlinemacro]
-<a href="{target}.html">{target}{0?({0})}</a>
+<a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
endif::backend-xhtml11[]
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0e1168c..7bc0e53 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -86,6 +86,19 @@ customary UNIX fashion.
Some variables may require a special value format.
+Includes
+~~~~~~~~
+
+You can include one config file from another by setting the special
+`include.path` variable to the name of the file to be included. The
+included file is expanded immediately, as if its contents had been
+found at the location of the include directive. If the value of the
+`include.path` variable is a relative path, the path is considered to be
+relative to the configuration file in which the include directive was
+found. The value of `include.path` is subject to tilde expansion: `~/`
+is expanded to the value of `$HOME`, and `~user/` to the specified
+user's home directory. See below for examples.
+
Example
~~~~~~~
@@ -108,6 +121,11 @@ Example
gitProxy="ssh" for "kernel.org"
gitProxy=default-proxy ; for the rest
+ [include]
+ path = /path/to/foo.inc ; include by absolute path
+ path = foo ; expand "foo" relative to the current file
+ path = ~/foo ; expand "foo" in your $HOME directory
+
Variables
~~~~~~~~~
@@ -123,12 +141,28 @@ advice.*::
+
--
pushNonFastForward::
- Advice shown when linkgit:git-push[1] refuses
- non-fast-forward refs.
+ Set this variable to 'false' if you want to disable
+ 'pushNonFFCurrent', 'pushNonFFDefault', and
+ 'pushNonFFMatching' simultaneously.
+ pushNonFFCurrent::
+ Advice shown when linkgit:git-push[1] fails due to a
+ non-fast-forward update to the current branch.
+ pushNonFFDefault::
+ Advice to set 'push.default' to 'upstream' or 'current'
+ when you ran linkgit:git-push[1] and pushed 'matching
+ refs' by default (i.e. you did not provide an explicit
+ refspec, and no 'push.default' configuration was set)
+ and it resulted in a non-fast-forward error.
+ pushNonFFMatching::
+ Advice shown when you ran linkgit:git-push[1] and pushed
+ 'matching refs' explicitly (i.e. you used ':', or
+ specified a refspec that isn't your current branch) and
+ it resulted in a non-fast-forward error.
statusHints::
- Directions on how to stage/unstage/add shown in the
- output of linkgit:git-status[1] and the template shown
- when writing commit messages.
+ Show directions on how to proceed from the current
+ state in the output of linkgit:git-status[1] and in
+ the template shown when writing commit messages in
+ linkgit:git-commit[1].
commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
@@ -177,6 +211,15 @@ The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
will probe and set core.ignorecase true if appropriate when the repository
is created.
+core.precomposeunicode::
+ This option is only used by Mac OS implementation of git.
+ When core.precomposeunicode=true, git reverts the unicode decomposition
+ of filenames done by Mac OS. This is useful when sharing a repository
+ between Mac OS and Linux or Windows.
+ (Git for Windows 1.7.10 or higher is needed, or git under cygwin 1.7).
+ When false, file names are handled fully transparent by git,
+ which is backward compatible with older versions of git.
+
core.trustctime::
If false, the ctime differences between the index and the
working tree are ignored; useful when the inode change time
@@ -448,9 +491,11 @@ Common unit suffixes of 'k', 'm', or 'g' are supported.
core.excludesfile::
In addition to '.gitignore' (per-directory) and
'.git/info/exclude', git looks into this file for patterns
- of files which are not meant to be tracked. "{tilde}/" is expanded
- to the value of `$HOME` and "{tilde}user/" to the specified user's
- home directory. See linkgit:gitignore[5].
+ of files which are not meant to be tracked. "`~/`" is expanded
+ to the value of `$HOME` and "`~user/`" to the specified user's
+ home directory. Its default value is $XDG_CONFIG_HOME/git/ignore.
+ If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
+ is used instead. See linkgit:gitignore[5].
core.askpass::
Some commands (e.g. svn and http interfaces) that interactively
@@ -465,7 +510,9 @@ core.attributesfile::
In addition to '.gitattributes' (per-directory) and
'.git/info/attributes', git looks into this file for attributes
(see linkgit:gitattributes[5]). Path expansions are made the same
- way as for `core.excludesfile`.
+ way as for `core.excludesfile`. Its default value is
+ $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
+ set or empty, $HOME/.config/git/attributes is used instead.
core.editor::
Commands such as `commit` and `tag` that lets you edit
@@ -823,6 +870,44 @@ color.ui::
`never` if you prefer git commands not to use color unless enabled
explicitly with some other configuration or the `--color` option.
+column.ui::
+ Specify whether supported commands should output in columns.
+ This variable consists of a list of tokens separated by spaces
+ or commas:
++
+--
+`always`;;
+ always show in columns
+`never`;;
+ never show in columns
+`auto`;;
+ show in columns if the output is to the terminal
+`column`;;
+ fill columns before rows (default)
+`row`;;
+ fill rows before columns
+`plain`;;
+ show in one column
+`dense`;;
+ make unequal size columns to utilize more space
+`nodense`;;
+ make equal size columns
+--
++
+This option defaults to 'never'.
+
+column.branch::
+ Specify whether to output branch listing in `git branch` in columns.
+ See `column.ui` for details.
+
+column.status::
+ Specify whether to output untracked files in `git status` in columns.
+ See `column.ui` for details.
+
+column.tag::
+ Specify whether to output tag listing in `git tag` in columns.
+ See `column.ui` for details.
+
commit.status::
A boolean to enable/disable inclusion of status information in the
commit message template when using an editor to prepare the commit
@@ -830,7 +915,7 @@ commit.status::
commit.template::
Specify a file to use as the template for new commit messages.
- "{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
+ "`~/`" is expanded to the value of `$HOME` and "`~user/`" to the
specified user's home directory.
credential.helper::
@@ -955,7 +1040,7 @@ format.thread::
a boolean value, or `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.
+ `--in-reply-to`, and the first patch mail, in this order.
`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.
@@ -1386,7 +1471,7 @@ instaweb.port::
interactive.singlekey::
In interactive commands, allow the user to provide one-letter
input with a single key (i.e., without hitting enter).
- Currently this is used by the `\--patch` mode of
+ Currently this is used by the `--patch` mode of
linkgit:git-add[1], linkgit:git-checkout[1], linkgit:git-commit[1],
linkgit:git-reset[1], and linkgit:git-stash[1]. Note that this
setting is silently ignored if portable keystroke input
@@ -1394,13 +1479,13 @@ interactive.singlekey::
log.abbrevCommit::
If true, makes linkgit:git-log[1], linkgit:git-show[1], and
- linkgit:git-whatchanged[1] assume `\--abbrev-commit`. You may
- override this option with `\--no-abbrev-commit`.
+ linkgit:git-whatchanged[1] assume `--abbrev-commit`. You may
+ override this option with `--no-abbrev-commit`.
log.date::
Set the default date-time mode for the 'log' command.
Setting a value for log.date is similar to using 'git log''s
- `\--date` option. Possible values are `relative`, `local`,
+ `--date` option. Possible values are `relative`, `local`,
`default`, `iso`, `rfc`, and `short`; see linkgit:git-log[1]
for details.
@@ -1590,18 +1675,18 @@ pack.indexVersion::
and this config option ignored whenever the corresponding pack is
larger than 2 GB.
+
-If you have an old git that does not understand the version 2 `{asterisk}.idx` file,
+If you have an old git that does not understand the version 2 `*.idx` file,
cloning or fetching over a non native protocol (e.g. "http" and "rsync")
-that will copy both `{asterisk}.pack` file and corresponding `{asterisk}.idx` file from the
+that will copy both `*.pack` file and corresponding `*.idx` file from the
other side may give you a repository that cannot be accessed with your
-older version of git. If the `{asterisk}.pack` file is smaller than 2 GB, however,
+older version of git. If the `*.pack` file is smaller than 2 GB, however,
you can use linkgit:git-index-pack[1] on the *.pack file to regenerate
-the `{asterisk}.idx` file.
+the `*.idx` file.
pack.packSizeLimit::
The maximum size of a pack. This setting only affects
packing to a file when repacking, i.e. the git:// protocol
- is unaffected. It can be overridden by the `\--max-pack-size`
+ is unaffected. It can be overridden by the `--max-pack-size`
option of linkgit:git-repack[1]. The minimum size allowed is
limited to 1 MiB. The default is unlimited.
Common unit suffixes of 'k', 'm', or 'g' are
@@ -1611,8 +1696,8 @@ pager.<cmd>::
If the value is boolean, turns on or off pagination of the
output of a particular git subcommand when writing to a tty.
Otherwise, turns on pagination for the subcommand using the
- pager specified by the value of `pager.<cmd>`. If `\--paginate`
- or `\--no-pager` is specified on the command line, it takes
+ pager specified by the value of `pager.<cmd>`. If `--paginate`
+ or `--no-pager` is specified on the command line, it takes
precedence over this option. To disable pagination for all
commands, set `core.pager` or `GIT_PAGER` to `cat`.
@@ -1620,9 +1705,9 @@ pretty.<name>::
Alias for a --pretty= format string, as specified in
linkgit:git-log[1]. Any aliases defined here can be used just
as the built-in pretty formats could. For example,
- running `git config pretty.changelog "format:{asterisk} %H %s"`
+ running `git config pretty.changelog "format:* %H %s"`
would cause the invocation `git log --pretty=changelog`
- to be equivalent to running `git log "--pretty=format:{asterisk} %H %s"`.
+ to be equivalent to running `git log "--pretty=format:* %H %s"`.
Note that an alias with the same name as a built-in format
will be silently ignored.
@@ -1649,13 +1734,33 @@ push.default::
no refspec is implied by any of the options given on the command
line. Possible values are:
+
+--
* `nothing` - do not push anything.
-* `matching` - push all matching branches.
- All branches having the same name in both ends are considered to be
- matching. This is the default.
+* `matching` - push all branches having the same name in both ends.
+ This is for those who prepare all the branches into a publishable
+ shape and then push them out with a single command. It is not
+ appropriate for pushing into a repository shared by multiple users,
+ since locally stalled branches will attempt a non-fast forward push
+ if other users updated the branch.
+ +
+ This is currently the default, but Git 2.0 will change the default
+ to `simple`.
* `upstream` - push the current branch to its upstream branch.
-* `tracking` - deprecated synonym for `upstream`.
+ With this, `git push` will update the same remote ref as the one which
+ is merged by `git pull`, making `push` and `pull` symmetrical.
+ See "branch.<name>.merge" for how to configure the upstream branch.
+* `simple` - like `upstream`, but refuses to push if the upstream
+ branch's name is different from the local one. This is the safest
+ option and is well-suited for beginners. It will become the default
+ in Git 2.0.
* `current` - push the current branch to a branch of the same name.
+--
++
+The `simple`, `current` and `upstream` modes are for those who want to
+push out a single branch after finishing work, even when the other
+branches are not yet ready to be pushed out. If you are working with
+other people to push into the same shared repository, you would want
+to use one of these.
rebase.stat::
Whether to show a diffstat of what changed upstream since the last
@@ -1735,7 +1840,7 @@ remote.<name>.push::
remote.<name>.mirror::
If true, pushing to this remote will automatically behave
- as if the `\--mirror` option was given on the command line.
+ as if the `--mirror` option was given on the command line.
remote.<name>.skipDefaultUpdate::
If true, this remote will be skipped by default when updating
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
index 1aed79e..67a90a8 100644
--- a/Documentation/diff-config.txt
+++ b/Documentation/diff-config.txt
@@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files,
and accumulating child directory counts in the parent directories:
`files,10,cumulative`.
+diff.statGraphWidth::
+ Limit the width of the graph part in --stat output. If set, applies
+ to all commands generating --stat output except format-patch.
+
diff.external::
If this config variable is set, diff generation is not
performed using the internal diff machinery, but using the
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index c57460c..55f499a 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -175,7 +175,7 @@ In the above example output, the function signature was changed
from both files (hence two `-` removals from both file1 and
file2, plus `++` to mean one line that was added does not appear
in either file1 nor file2). Also eight other lines are the same
-from file1 but do not appear in file2 (hence prefixed with `{plus}`).
+from file1 but do not appear in file2 (hence prefixed with `+`).
When shown by `git diff-tree -c`, it compares the parents of a
merge commit with the merge result (i.e. file1..fileN are the
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index ba7cd13..cf4b216 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -56,19 +56,25 @@ endif::git-format-patch[]
Generate a diff using the "histogram diff" algorithm.
--stat[=<width>[,<name-width>[,<count>]]]::
- Generate a diffstat. You can override the default
- output width for 80-column terminal by `--stat=<width>`.
- The width of the filename part can be controlled by
- giving another width to it separated by a comma.
+ Generate a diffstat. By default, as much space as necessary
+ will be used for the filename part, and the rest for the graph
+ part. Maximum width defaults to terminal width, or 80 columns
+ if not connected to a terminal, and can be overridden by
+ `<width>`. The width of the filename part can be limited by
+ giving another width `<name-width>` after a comma. The width
+ of the graph part can be limited by using
+ `--stat-graph-width=<width>` (affects all commands generating
+ a stat graph) or by setting `diff.statGraphWidth=<width>`
+ (does not affect `git format-patch`).
By giving a third parameter `<count>`, you can limit the
- output to the first `<count>` lines, followed by
- `...` if there are more.
+ output to the first `<count>` lines, followed by `...` if
+ there are more.
+
These parameters can also be set individually with `--stat-width=<width>`,
`--stat-name-width=<name-width>` and `--stat-count=<count>`.
--numstat::
- Similar to `\--stat`, but shows number of added and
+ Similar to `--stat`, but shows number of added and
deleted lines in decimal notation and pathname without
abbreviation, to make it more machine friendly. For
binary files, outputs two `-` instead of saying
@@ -159,11 +165,12 @@ any of those replacements occurred.
of the `--diff-filter` option on what the status letters mean.
--submodule[=<format>]::
- Chose the output format for submodule differences. <format> can be one of
- 'short' and 'log'. 'short' just shows pairs of commit names, this format
- is used when this option is not given. 'log' is the default value for this
- option and lists the commits in that commit range like the 'summary'
- option of linkgit:git-submodule[1] does.
+ Specify how differences in submodules are shown. When `--submodule`
+ or `--submodule=log` is given, the 'log' format is used. This format lists
+ the commits in the range like linkgit:git-submodule[1] `summary` does.
+ Omitting the `--submodule` option or specifying `--submodule=short`,
+ uses the 'short' format. This format just shows the names of the commits
+ at the beginning and end of the range.
--color[=<when>]::
Show colored diff.
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index ae413e5..048337b 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -98,8 +98,8 @@ you originally wrote.
<9> switch to the master branch.
<10> merge a topic branch into your master branch.
<11> review commit logs; other forms to limit output can be
-combined and include `\--max-count=10` (show 10 commits),
-`\--until=2005-12-10`, etc.
+combined and include `--max-count=10` (show 10 commits),
+`--until=2005-12-10`, etc.
<12> view only the changes that touch what's in `curses/`
directory, since `v2.43` tag.
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 887466d..19d57a8 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[--3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
- [--exclude=<path>] [--reject] [-q | --quiet]
+ [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
[--scissors | --no-scissors]
[(<mbox> | <Maildir>)...]
'git am' (--continue | --skip | --abort)
@@ -40,6 +40,9 @@ OPTIONS
--keep::
Pass `-k` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+--keep-non-patch::
+ Pass `-b` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
--keep-cr::
--no-keep-cr::
With `--keep-cr`, call 'git mailsplit' (see linkgit:git-mailsplit[1])
@@ -89,6 +92,7 @@ default. You can use `--no-utf8` to override this.
-p<n>::
--directory=<dir>::
--exclude=<path>::
+--include=<path>::
--reject::
These flags are passed to the 'git apply' (see linkgit:git-apply[1])
program that applies
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index afd2c9a..634b84e 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index
SYNOPSIS
--------
[verse]
-'git apply' [--stat] [--numstat] [--summary] [--check] [--index]
+'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way]
[--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z]
[-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -72,6 +72,15 @@ OPTIONS
cached data, apply the patch, and store the result in the index
without using the working tree. This implies `--index`.
+-3::
+--3way::
+ When the patch does not apply cleanly, fall back on 3-way merge if
+ the patch records the identity of blobs it is supposed to apply to,
+ and we have those blobs available locally, possibly leaving the
+ conflict markers in the files in the working tree for the user to
+ resolve. This option implies the `--index` option, and is incompatible
+ with the `--reject` and the `--cached` options.
+
--build-fake-ancestor=<file>::
Newer 'git diff' output has embedded 'index information'
for each blob to help identify the original version that
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index ac7006e..59d73e5 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -160,7 +160,7 @@ EXAMPLES
Same as above, but the format is inferred from the output file.
-`git archive --format=tar --prefix=git-1.4.0/ v1.4.0{caret}\{tree\} | gzip >git-1.4.0.tar.gz`::
+`git archive --format=tar --prefix=git-1.4.0/ v1.4.0^{tree} | gzip >git-1.4.0.tar.gz`::
Create a compressed tarball for v1.4.0 release, but without a
global extended pax header.
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 9516914..7ee9236 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -160,7 +160,7 @@ introduced the file with:
git log --diff-filter=A --pretty=short -- foo
and then annotate the change between the commit and its
-parents, using `commit{caret}!` notation:
+parents, using `commit^!` notation:
git blame -C -C -f $commit^! -- foo
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0427e80..47235be 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'git branch' [--color[=<when>] | --no-color] [-r | -a]
[--list] [-v [--abbrev=<length> | --no-abbrev]]
+ [--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (-m | -M) [<oldbranch>] <newbranch>
@@ -24,8 +25,8 @@ be highlighted with an asterisk. Option `-r` causes the remote-tracking
branches to be listed, and option `-a` shows both. This list mode is also
activated by the `--list` option (see below).
<pattern> restricts the output to matching branches, the pattern is a shell
-wildcard (i.e., matched using fnmatch(3))
-Multiple patterns may be given; if any of them matches, the tag is shown.
+wildcard (i.e., matched using fnmatch(3)).
+Multiple patterns may be given; if any of them matches, the branch is shown.
With `--contains`, shows only the branches that contain the named commit
(in other words, the branches whose tip commits are descendants of the
@@ -49,7 +50,7 @@ the remote-tracking branch. This behavior may be changed via the global
overridden by using the `--track` and `--no-track` options, and
changed later using `git branch --set-upstream`.
-With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
+With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match
<newbranch>, and a reflog entry is created to remember the branch
renaming. If <newbranch> exists, -M must be used to force the rename
@@ -59,7 +60,7 @@ With a `-d` or `-D` option, `<branchname>` will be deleted. You may
specify more than one branch for deletion. If the branch currently
has a reflog then the reflog will also be deleted.
-Use -r together with -d to delete remote-tracking branches. Note, that it
+Use `-r` together with `-d` to delete remote-tracking branches. Note, that it
only makes sense to delete remote-tracking branches if they no longer exist
in the remote repository or if 'git fetch' was configured not to fetch
them again. See also the 'prune' subcommand of linkgit:git-remote[1] for a
@@ -107,6 +108,14 @@ OPTIONS
default to color output.
Same as `--color=never`.
+--column[=<options>]::
+--no-column::
+ Display branch listing in columns. See configuration variable
+ column.branch for option syntax.`--column` and `--no-column`
+ without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable in non-verbose mode.
+
-r::
--remotes::
List or delete (if used with -d) the remote-tracking branches.
@@ -126,6 +135,11 @@ OPTIONS
relationship to upstream branch (if any). If given twice, print
the name of the upstream branch, as well.
+-q::
+--quiet::
+ Be more quiet when creating or deleting a branch, suppressing
+ non-error messages.
+
--abbrev=<length>::
Alter the sha1's minimum display length in the output listing.
The default value is 7 and can be overridden by the `core.abbrev`
@@ -154,17 +168,18 @@ start-point is either a local or remote-tracking branch.
branch.autosetupmerge configuration variable is true.
--set-upstream::
- If specified branch does not exist yet or if '--force' has been
- given, acts exactly like '--track'. Otherwise sets up configuration
- like '--track' would when creating the branch, except that where
+ If specified branch does not exist yet or if `--force` has been
+ given, acts exactly like `--track`. Otherwise sets up configuration
+ like `--track` would when creating the branch, except that where
branch points to is not changed.
--edit-description::
Open an editor and edit the text to explain what the branch is
for, to be used by various other commands (e.g. `request-pull`).
---contains <commit>::
- Only list branches which contain the specified commit.
+--contains [<commit>]::
+ Only list branches which contain the specified commit (HEAD
+ if not specified).
--merged [<commit>]::
Only list branches whose tips are reachable from the
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 92b01ec2..16a6b0a 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -61,7 +61,7 @@ unbundle <file>::
A list of arguments, acceptable to 'git rev-parse' and
'git rev-list' (and containing a named ref, see SPECIFYING REFERENCES
below), that specifies the specific objects and references
- to transport. For example, `master{tilde}10..master` causes the
+ to transport. For example, `master~10..master` causes the
current master reference to be packaged along with all objects
added since its 10th ancestor commit. There is no explicit
limit to the number of references and objects that may be
@@ -80,12 +80,12 @@ SPECIFYING REFERENCES
'git bundle' will only package references that are shown by
'git show-ref': this includes heads, tags, and remote heads. References
-such as `master{tilde}1` cannot be packaged, but are perfectly suitable for
+such as `master~1` cannot be packaged, but are perfectly suitable for
defining the basis. More than one reference may be packaged, and more
than one basis can be specified. The objects packaged are those not
contained in the union of the given bases. Each basis can be
-specified explicitly (e.g. `^master{tilde}10`), or implicitly (e.g.
-`master{tilde}10..master`, `--since=10.days.ago master`).
+specified explicitly (e.g. `^master~10`), or implicitly (e.g.
+`master~10..master`, `--since=10.days.ago master`).
It is very important that the basis used be held by the destination.
It is okay to err on the side of caution, causing the bundle file
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 103e7b1..98009d1 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -40,9 +40,9 @@ git imposes the following rules on how references are named:
. They cannot have ASCII control characters (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`,
- caret `{caret}`, or colon `:` anywhere.
+ caret `^`, or colon `:` anywhere.
-. They cannot have question-mark `?`, asterisk `{asterisk}`, or open
+. They cannot have question-mark `?`, asterisk `*`, or open
bracket `[` anywhere. See the `--refspec-pattern` option below for
an exception to this rule.
@@ -62,10 +62,10 @@ unquoted (by mistake), and also avoids ambiguities in certain
reference name expressions (see linkgit:gitrevisions[7]):
. A double-dot `..` is often used as in `ref1..ref2`, and in some
- contexts this notation means `{caret}ref1 ref2` (i.e. not in
+ contexts this notation means `^ref1 ref2` (i.e. not in
`ref1` and in `ref2`).
-. A tilde `~` and caret `{caret}` are used to introduce the postfix
+. A tilde `~` and caret `^` are used to introduce the postfix
'nth parent' and 'peel onion' operation.
. A colon `:` is used as in `srcref:dstref` to mean "use srcref\'s
@@ -92,9 +92,9 @@ OPTIONS
--refspec-pattern::
Interpret <refname> as a reference name pattern for a refspec
(as used with remote repositories). If this option is
- enabled, <refname> is allowed to contain a single `{asterisk}`
+ enabled, <refname> is allowed to contain a single `*`
in place of a one full pathname component (e.g.,
- `foo/{asterisk}/bar` but not `foo/bar{asterisk}`).
+ `foo/*/bar` but not `foo/bar*`).
--normalize::
Normalize 'refname' by removing any leading slash (`/`)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index c0a96e6..63a2516 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -184,7 +184,7 @@ the conflicted merge in the specified paths.
+
This means that you can use `git checkout -p` to selectively discard
edits from your current working tree. See the ``Interactive Mode''
-section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
+section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
<branch>::
Branch to checkout; if it refers to a branch (i.e., a name that,
@@ -193,11 +193,11 @@ section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
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
+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\}"`.
+`-` which is synonymous with `"@{-1}"`.
+
-As a further special case, you may use `"A\...B"` as a shortcut for the
+As a further special case, you may use `"A...B"` as a shortcut for the
merge base of `A` and `B` if there is exactly one merge base. You can
leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..0e170a5 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -47,7 +47,9 @@ OPTIONS
linkgit:gitrevisions[7].
Sets of commits can be passed but no traversal is done by
default, as if the '--no-walk' option was specified, see
- linkgit:git-rev-list[1].
+ linkgit:git-rev-list[1]. Note that specifying a range will
+ feed all <commit>... arguments to a single revision walk
+ (see a later example that uses 'maint master..next').
-e::
--edit::
@@ -103,6 +105,25 @@ effect to your index in a row.
cherry-pick'ed commit, then a fast forward to this commit will
be performed.
+--allow-empty::
+ By default, cherry-picking an empty commit will fail,
+ indicating that an explicit invocation of `git commit
+ --allow-empty` is required. This option overrides that
+ behavior, allowing empty commits to be preserved automatically
+ in a cherry-pick. Note that when "--ff" is in effect, empty
+ commits that meet the "fast-forward" requirement will be kept
+ even without this option. Note also, that use of this option only
+ keeps commits that were initially empty (i.e. the commit recorded the
+ same tree as its parent). Commits which are made empty due to a
+ previous commit are dropped. To force the inclusion of those commits
+ use `--keep-redundant-commits`.
+
+--keep-redundant-commits::
+ If a commit being cherry picked duplicates a commit already in the
+ current history, it will become empty. By default these
+ redundant commits are ignored. This option overrides that behavior and
+ creates an empty commit object. Implies `--allow-empty`.
+
--strategy=<strategy>::
Use the given merge strategy. Should only be used once.
See the MERGE STRATEGIES section in linkgit:git-merge[1]
@@ -130,7 +151,16 @@ EXAMPLES
Apply the changes introduced by all commits that are ancestors
of master but not of HEAD to produce new commits.
-`git cherry-pick master{tilde}4 master{tilde}2`::
+`git cherry-pick maint next ^master`::
+`git cherry-pick maint master..next`::
+
+ Apply the changes introduced by all commits that are
+ ancestors of maint or next, but not master or any of its
+ ancestors. Note that the latter does not mean `maint` and
+ everything between `master` and `next`; specifically,
+ `maint` will not be used if it is included in `master`.
+
+`git cherry-pick master~4 master~2`::
Apply the changes introduced by the fifth and third last
commits pointed to by master and create 2 new commits with
@@ -151,7 +181,7 @@ EXAMPLES
are in next but not HEAD to the current branch, creating a new
commit for each new change.
-`git rev-list --reverse master \-- README | git cherry-pick -n --stdin`::
+`git rev-list --reverse master -- README | git cherry-pick -n --stdin`::
Apply the changes introduced by all commits on the master
branch that touched README to the working tree and index,
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 4b8b26b..c1ddd4c 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -13,7 +13,8 @@ SYNOPSIS
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--separate-git-dir <git dir>]
- [--depth <depth>] [--recursive|--recurse-submodules] [--] <repository>
+ [--depth <depth>] [--[no-]single-branch]
+ [--recursive|--recurse-submodules] [--] <repository>
[<directory>]
DESCRIPTION
@@ -45,13 +46,18 @@ OPTIONS
mechanism and clones the repository by making a copy of
HEAD and everything under objects and refs directories.
The files under `.git/objects/` directory are hardlinked
- to save space when possible. This is now the default when
- the source repository is specified with `/path/to/repo`
- syntax, so it essentially is a no-op option. To force
- copying instead of hardlinking (which may be desirable
- if you are trying to make a back-up of your repository),
- but still avoid the usual "git aware" transport
- mechanism, `--no-hardlinks` can be used.
+ to save space when possible.
++
+If the repository is specified as a local path (e.g., `/path/to/repo`),
+this is the default, and --local is essentially a no-op. If the
+repository is specified as a URL, then this flag is ignored (and we
+never use the local optimizations). Specifying `--no-local` will
+override the default when `/path/to/repo` is given, using the regular
+git transport instead.
++
+To force copying instead of hardlinking (which may be desirable if you
+are trying to make a back-up of your repository), but still avoid the
+usual "git aware" transport mechanism, `--no-hardlinks` can be used.
--no-hardlinks::
Optimize the cloning process from a repository on a
@@ -146,8 +152,9 @@ objects from the source repository into a pack in the cloned repository.
-b <name>::
Instead of pointing the newly created HEAD to the branch pointed
to by the cloned repository's HEAD, point to `<name>` branch
- instead. In a non-bare repository, this is the branch that will
- be checked out.
+ instead. `--branch` can also take tags and treat them like
+ detached HEAD. In a non-bare repository, this is the branch
+ that will be checked out.
--upload-pack <upload-pack>::
-u <upload-pack>::
@@ -179,6 +186,14 @@ objects from the source repository into a pack in the cloned repository.
with a long history, and would want to send in fixes
as patches.
+--single-branch::
+ Clone only the history leading to the tip of a single branch,
+ either specified by the `--branch` option or the primary
+ branch remote's `HEAD` points at. When creating a shallow
+ clone with the `--depth` option, this is the default, unless
+ `--no-single-branch` is given to fetch the histories near the
+ tips of all branches.
+
--recursive::
--recurse-submodules::
After the clone is created, initialize all submodules within,
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
new file mode 100644
index 0000000..5d6f1cc
--- /dev/null
+++ b/Documentation/git-column.txt
@@ -0,0 +1,53 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Display data in columns
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--command=<name>] [--[raw-]mode=<mode>] [--width=<width>]
+ [--indent=<string>] [--nl=<string>] [--padding=<n>]
+
+DESCRIPTION
+-----------
+This command formats its input into multiple columns.
+
+OPTIONS
+-------
+--command=<name>::
+ Look up layout mode using configuration variable column.<name> and
+ column.ui.
+
+--mode=<mode>::
+ Specify layout mode. See configuration variable column.ui for option
+ syntax.
+
+--raw-mode=<n>::
+ Same as --mode but take mode encoded as a number. This is mainly used
+ by other commands that have already parsed layout mode.
+
+--width=<width>::
+ Specify the terminal width. By default 'git column' will detect the
+ terminal width, or fall back to 80 if it is unable to do so.
+
+--indent=<string>::
+ String to be printed at the beginning of each line.
+
+--nl=<N>::
+ String to be printed at the end of each line,
+ including newline character.
+
+--padding=<N>::
+ The number of spaces between columns. One space by default.
+
+
+Author
+------
+Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index cfb9906..ff73286 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git commit-tree' <tree> [(-p <parent>)...] < changelog
-'git commit-tree' [(-p <parent>)...] [(-m <message>)...] [(-F <file>)...] <tree>
+'git commit-tree' <tree> [(-p <parent>)...] [(-m <message>)...] [(-F <file>)...]
DESCRIPTION
-----------
@@ -45,7 +45,7 @@ OPTIONS
Each '-p' indicates the id of a parent commit object.
-m <message>::
- A paragraph in the commig log message. This can be given more than
+ A paragraph in the commit log message. This can be given more than
once and each <message> becomes its own paragraph.
-F <file>::
@@ -88,15 +88,6 @@ for one to be entered and terminated with ^D.
include::date-formats.txt[]
-Diagnostics
------------
-You don't exist. Go away!::
- The passwd(5) gecos field couldn't be read
-Your parents must have hated you!::
- The passwd(5) gecos field is longer than a giant static buffer.
-Your sysadmin must hate you!::
- The passwd(5) name field is longer than a giant static buffer.
-
Discussion
----------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 5cc84a1..f400835 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -42,7 +42,7 @@ The content to be added can be specified in several ways:
5. by using the --interactive or --patch switches with the 'commit' command
to decide one by one which files or hunks should be part of the commit,
- before finalizing the operation. See the ``Interactive Mode`` section of
+ before finalizing the operation. See the ``Interactive Mode'' section of
linkgit:git-add[1] to learn how to operate these modes.
The `--dry-run` option can be used to obtain a
@@ -101,12 +101,16 @@ OPTIONS
When doing a dry-run, give the output in the short-format. See
linkgit:git-status[1] for details. Implies `--dry-run`.
+--branch::
+ Show the branch and tracking info even in short-format.
+
--porcelain::
When doing a dry-run, give the output in a porcelain-ready
format. See linkgit:git-status[1] for details. Implies
`--dry-run`.
-z::
+--null::
When showing `short` or `porcelain` status output, terminate
entries in the status output with NUL, instead of LF. If no
format is given, implies the `--porcelain` output format.
@@ -132,11 +136,14 @@ OPTIONS
-t <file>::
--template=<file>::
- Use the contents of the given file as the initial version
- of the commit message. The editor is invoked and you can
- make subsequent changes. If a message is specified using
- the `-m` or `-F` options, this option has no effect. This
- overrides the `commit.template` configuration variable.
+ When editing the commit message, start the editor with the
+ contents in the given file. The `commit.template` configuration
+ variable is often used to give this option implicitly to the
+ command. This mechanism can be used by projects that want to
+ guide participants with some hints on what to write in the message
+ in what order. If the user exits the editor without editing the
+ message, the commit is aborted. This has no effect when a message
+ is given by other means, e.g. with the `-m` or `-F` options.
-s::
--signoff::
@@ -186,6 +193,10 @@ OPTIONS
current tip -- if it was a merge, it will have the parents of
the current tip as parents -- so the current top commit is
discarded.
+
+--no-post-rewrite::
+ Bypass the post-rewrite hook.
+
+
--
It is a rough equivalent for:
@@ -284,7 +295,7 @@ When recording your own work, the contents of modified files in
your working tree are temporarily stored to a staging area
called the "index" with 'git add'. A file can be
reverted back, only in the index but not in the working tree,
-to that of the last commit with `git reset HEAD \-- <file>`,
+to that of the last commit with `git reset HEAD -- <file>`,
which effectively reverts 'git add' and prevents the changes to
this file from participating in the next commit. After building
the state to be committed incrementally with these commands,
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 7617d9e..2d6ef32 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -44,11 +44,15 @@ a "true" or "false" string for bool), or '--path', which does some
path expansion (see '--path' below). If no type specifier is passed, no
checks or transformations are performed on the value.
-The file-option can be one of '--system', '--global' or '--file'
-which specify where the values will be read from or written to.
-The default is to assume the config file of the current repository,
-.git/config unless defined otherwise with GIT_DIR and GIT_CONFIG
-(see <<FILES>>).
+When reading, the values are read from the system, global and
+repository local configuration files by default, and options
+'--system', '--global', '--local' and '--file <filename>' can be
+used to tell the command to read from only that location (see <<FILES>>).
+
+When writing, the new value is written to the repository local
+configuration file by default, and options '--system', '--global',
+'--file <filename>' can be used to tell the command to write to
+that location (you can say '--local' but that is the default).
This command will fail (with exit code ret) if:
@@ -93,10 +97,11 @@ OPTIONS
--global::
For writing options: write to global ~/.gitconfig file rather than
- the repository .git/config.
+ the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
+ if this file exists and the ~/.gitconfig file doesn't.
+
-For reading options: read only from global ~/.gitconfig rather than
-from all available files.
+For reading options: read only from global ~/.gitconfig and from
+$XDG_CONFIG_HOME/git/config rather than from all available files.
+
See also <<FILES>>.
@@ -181,22 +186,33 @@ See also <<FILES>>.
Opens an editor to modify the specified config file; either
'--system', '--global', or repository (default).
+--includes::
+--no-includes::
+ Respect `include.*` directives in config files when looking up
+ values. Defaults to on.
+
[[FILES]]
FILES
-----
-If not set explicitly with '--file', there are three files where
+If not set explicitly with '--file', there are four files where
'git config' will search for configuration options:
$GIT_DIR/config::
- Repository specific configuration file. (The filename is
- of course relative to the repository root, not the working
- directory.)
+ Repository specific configuration file.
~/.gitconfig::
User-specific configuration file. Also called "global"
configuration file.
+$XDG_CONFIG_HOME/git/config::
+ Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
+ or empty, $HOME/.config/git/config will be used. Any single-valued
+ variable set in this file will be overwritten by whatever is in
+ ~/.gitconfig. It is a good idea not to create this file if
+ you sometimes use older versions of Git, as support for this
+ file was added fairly recently.
+
$(prefix)/etc/gitconfig::
System-wide configuration file.
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
new file mode 100644
index 0000000..a81684e
--- /dev/null
+++ b/Documentation/git-credential.txt
@@ -0,0 +1,144 @@
+git-credential(1)
+=================
+
+NAME
+----
+git-credential - retrieve and store user credentials
+
+SYNOPSIS
+--------
+------------------
+git credential <fill|approve|reject>
+------------------
+
+DESCRIPTION
+-----------
+
+Git has an internal interface for storing and retrieving credentials
+from system-specific helpers, as well as prompting the user for
+usernames and passwords. The git-credential command exposes this
+interface to scripts which may want to retrieve, store, or prompt for
+credentials in the same manner as git. The design of this scriptable
+interface models the internal C API; see
+link:technical/api-credentials.txt[the git credential API] for more
+background on the concepts.
+
+git-credential takes an "action" option on the command-line (one of
+`fill`, `approve`, or `reject`) and reads a credential description
+on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>).
+
+If the action is `fill`, git-credential will attempt to add "username"
+and "password" attributes to the description by reading config files,
+by contacting any configured credential helpers, or by prompting the
+user. The username and password attributes of the credential
+description are then printed to stdout together with the attributes
+already provided.
+
+If the action is `approve`, git-credential will send the description
+to any configured credential helpers, which may store the credential
+for later use.
+
+If the action is `reject`, git-credential will send the description to
+any configured credential helpers, which may erase any stored
+credential matching the description.
+
+If the action is `approve` or `reject`, no output should be emitted.
+
+TYPICAL USE OF GIT CREDENTIAL
+-----------------------------
+
+An application using git-credential will typically use `git
+credential` following these steps:
+
+ 1. Generate a credential description based on the context.
++
+For example, if we want a password for
+`https://example.com/foo.git`, we might generate the following
+credential description (don't forget the blank line at the end; it
+tells `git credential` that the application finished feeding all the
+infomation it has):
+
+ protocol=https
+ host=example.com
+ path=foo.git
+
+ 2. Ask git-credential to give us a username and password for this
+ description. This is done by running `git credential fill`,
+ feeding the description from step (1) to its standard input. The complete
+ credential description (including the credential per se, i.e. the
+ login and password) will be produced on standard output, like:
+
+ protocol=https
+ host=example.com
+ username=bob
+ password=secr3t
++
+In most cases, this means the attributes given in the input will be
+repeated in the output, but git may also modify the credential
+description, for example by removing the `path` attribute when the
+protocol is HTTP(s) and `credential.useHttpPath` is false.
++
+If the `git credential` knew about the password, this step may
+not have involved the user actually typing this password (the
+user may have typed a password to unlock the keychain instead,
+or no user interaction was done if the keychain was already
+unlocked) before it returned `password=secr3t`.
+
+ 3. Use the credential (e.g., access the URL with the username and
+ password from step (2)), and see if it's accepted.
+
+ 4. Report on the success or failure of the password. If the
+ credential allowed the operation to complete successfully, then
+ it can be marked with an "approve" action to tell `git
+ credential` to reuse it in its next invocation. If the credential
+ was rejected during the operation, use the "reject" action so
+ that `git credential` will ask for a new password in its next
+ invocation. In either case, `git credential` should be fed with
+ the credential description obtained from step (2) (which also
+ contain the ones provided in step (1)).
+
+[[IOFMT]]
+INPUT/OUTPUT FORMAT
+-------------------
+
+`git credential` reads and/or writes (depending on the action used)
+credential information in its standard input/output. These information
+can correspond either to keys for which `git credential` will obtain
+the login/password information (e.g. host, protocol, path), or to the
+actual credential data to be obtained (login/password).
+
+The credential is split into a set of named attributes.
+Attributes are provided to the helper, one per line. Each attribute is
+specified by a key-value pair, separated by an `=` (equals) sign,
+followed by a newline. The key may contain any bytes except `=`,
+newline, or NUL. The value may contain any bytes except newline or NUL.
+In both cases, all bytes are treated as-is (i.e., there is no quoting,
+and one cannot transmit a value with newline or NUL in it). The list of
+attributes is terminated by a blank line or end-of-file.
+Git will send the following attributes (but may not send all of
+them for a given credential; for example, a `host` attribute makes no
+sense when dealing with a non-network protocol):
+
+`protocol`::
+
+ The protocol over which the credential will be used (e.g.,
+ `https`).
+
+`host`::
+
+ The remote hostname for a network credential.
+
+`path`::
+
+ The path with which the credential will be used. E.g., for
+ accessing a remote https repository, this will be the
+ repository's path on the server.
+
+`username`::
+
+ The credential's username, if we already have one (e.g., from a
+ URL, from the user, or from a previously run helper).
+
+`password`::
+
+ The credential's password, if we are asking it to be stored.
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index 827bc98..88d814a 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -252,7 +252,7 @@ Configuring database backend
'git-cvsserver' uses the Perl DBI module. Please also read
its documentation if changing these variables, especially
-about `DBI\->connect()`.
+about `DBI->connect()`.
gitcvs.dbname::
Database name. The exact meaning depends on the
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 19d473c..31fc2e3 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -19,6 +19,12 @@ linkgit:git-diff[1].
OPTIONS
-------
+-d::
+--dir-diff::
+ Copy the modified files to a temporary location and perform
+ a directory diff on them. This mode never prompts before
+ launching the diff tool.
+
-y::
--no-prompt::
Do not prompt before launching a diff tool.
@@ -30,10 +36,9 @@ OPTIONS
-t <tool>::
--tool=<tool>::
- Use the diff tool specified by <tool>.
- Valid diff tools are:
- araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3,
- kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff.
+ Use the diff tool specified by <tool>. Valid values include
+ emerge, kompare, meld, and vimdiff. Run `git difftool --tool-help`
+ for the list of valid <tool> settings.
+
If a diff tool is not specified, 'git difftool'
will use the configuration variable `diff.tool`. If the
@@ -61,6 +66,9 @@ of the diff post-image. `$MERGED` is the name of the file which is
being compared. `$BASE` is provided for compatibility
with custom merge tool commands and has the same value as `$MERGED`.
+--tool-help::
+ Print a list of diff tools that may be used with `--tool`.
+
-x <command>::
--extcmd=<command>::
Specify a custom command for viewing diffs.
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index f37eada..d6487e1 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -104,7 +104,7 @@ marks the same across runs.
[<git-rev-list-args>...]::
A list of arguments, acceptable to 'git rev-parse' and
'git rev-list', that specifies the specific objects and references
- to export. For example, `master{tilde}10..master` causes the
+ to export. For example, `master~10..master` causes the
current master reference to be exported along with all objects
added since its 10th ancestor commit.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index ec6ef31..2620d28 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -98,9 +98,10 @@ OPTIONS
options.
--cat-blob-fd=<fd>::
- Specify the file descriptor that will be written to
- when the `cat-blob` command is encountered in the stream.
- The default behaviour is to write to `stdout`.
+ Write responses to `cat-blob` and `ls` queries to the
+ file descriptor <fd> instead of `stdout`. Allows `progress`
+ output intended for the end-user to be separated from other
+ output.
--done::
Require a `done` command at the end of the stream.
@@ -478,9 +479,9 @@ current branch value should be written as:
----
from refs/heads/branch^0
----
-The `{caret}0` suffix is necessary as fast-import does not permit a branch to
+The `^0` suffix is necessary as fast-import does not permit a branch to
start from itself, and the branch is created in memory before the
-`from` command is even read from the input. Adding `{caret}0` will force
+`from` command is even read from the input. Adding `^0` will force
fast-import to resolve the commit through Git's revision parsing library,
rather than its internal branch table, thereby loading in the
existing value of the branch.
@@ -942,6 +943,9 @@ This command can be used anywhere in the stream that comments are
accepted. In particular, the `cat-blob` command can be used in the
middle of a commit but not in the middle of a `data` command.
+See ``Responses To Commands'' below for details about how to read
+this output safely.
+
`ls`
~~~~
Prints information about the object at a path to a file descriptor
@@ -975,7 +979,7 @@ Reading from a named tree::
See `filemodify` above for a detailed description of `<path>`.
-Output uses the same format as `git ls-tree <tree> {litdd} <path>`:
+Output uses the same format as `git ls-tree <tree> -- <path>`:
====
<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
@@ -991,6 +995,9 @@ instead report
missing SP <path> LF
====
+See ``Responses To Commands'' below for details about how to read
+this output safely.
+
`feature`
~~~~~~~~~
Require that fast-import supports the specified feature, or abort if
@@ -1079,6 +1086,35 @@ If the `--done` command line option or `feature done` command is
in use, the `done` command is mandatory and marks the end of the
stream.
+Responses To Commands
+---------------------
+New objects written by fast-import are not available immediately.
+Most fast-import commands have no visible effect until the next
+checkpoint (or completion). The frontend can send commands to
+fill fast-import's input pipe without worrying about how quickly
+they will take effect, which improves performance by simplifying
+scheduling.
+
+For some frontends, though, it is useful to be able to read back
+data from the current repository as it is being updated (for
+example when the source material describes objects in terms of
+patches to be applied to previously imported objects). This can
+be accomplished by connecting the frontend and fast-import via
+bidirectional pipes:
+
+====
+ mkfifo fast-import-output
+ frontend <fast-import-output |
+ git fast-import >fast-import-output
+====
+
+A frontend set up this way can use `progress`, `ls`, and `cat-blob`
+commands to read information from the import in progress.
+
+To avoid deadlock, such frontends must completely consume any
+pending output from `progress`, `ls`, and `cat-blob` before
+performing writes to fast-import that might block.
+
Crash Reports
-------------
If fast-import is supplied invalid input it will terminate with a
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index ed1bdaa..474fa30 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -32,6 +32,16 @@ OPTIONS
--all::
Fetch all remote refs.
+--stdin::
+ Take the list of refs from stdin, one per line. If there
+ are refs specified on the command line in addition to this
+ option, then the refs from stdin are processed after those
+ on the command line.
++
+If '--stateless-rpc' is specified together with this option then
+the list of refs must be in packet format (pkt-line). Each ref must
+be in a separate packet, and the list must end with a flush packet.
+
-q::
--quiet::
Pass '-q' flag to 'git unpack-objects'; this makes the
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 0f2f117..81f5823 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -96,8 +96,8 @@ OPTIONS
--index-filter <command>::
This is the filter for rewriting the index. It is similar to the
tree filter but does not check out the tree, which makes it much
- faster. Frequently used with `git rm \--cached
- \--ignore-unmatch ...`, see EXAMPLES below. For hairy
+ faster. Frequently used with `git rm --cached
+ --ignore-unmatch ...`, see EXAMPLES below. For hairy
cases, see linkgit:git-update-index[1].
--parent-filter <command>::
@@ -222,11 +222,11 @@ However, if the file is absent from the tree of some commit,
a simple `rm filename` will fail for that tree and commit.
Thus you may instead want to use `rm -f filename` as the script.
-Using `\--index-filter` with 'git rm' yields a significantly faster
+Using `--index-filter` with 'git rm' yields a significantly faster
version. Like with using `rm filename`, `git rm --cached filename`
will fail if the file is absent from the tree of a commit. If you
want to "completely forget" a file, it does not matter when it entered
-history, so we also add `\--ignore-unmatch`:
+history, so we also add `--ignore-unmatch`:
--------------------------------------------------------------------------
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
@@ -242,8 +242,8 @@ git filter-branch --subdirectory-filter foodir -- --all
-------------------------------------------------------
Thus you can, e.g., turn a library subdirectory into a repository of
-its own. Note the `\--` that separates 'filter-branch' options from
-revision options, and the `\--all` to rewrite all branches and tags.
+its own. Note the `--` that separates 'filter-branch' options from
+revision options, and the `--all` to rewrite all branches and tags.
To set a commit (which typically is at the tip of another
history) to be the parent of the current initial commit, in
@@ -371,23 +371,23 @@ Checklist for Shrinking a Repository
------------------------------------
git-filter-branch is often used to get rid of a subset of files,
-usually with some combination of `\--index-filter` and
-`\--subdirectory-filter`. People expect the resulting repository to
+usually with some combination of `--index-filter` and
+`--subdirectory-filter`. People expect the resulting repository to
be smaller than the original, but you need a few more steps to
actually make it smaller, because git tries hard not to lose your
objects until you tell it to. First make sure that:
* You really removed all variants of a filename, if a blob was moved
- over its lifetime. `git log \--name-only \--follow \--all \--
- filename` can help you find renames.
+ over its lifetime. `git log --name-only --follow --all -- filename`
+ can help you find renames.
-* You really filtered all refs: use `\--tag-name-filter cat \--
- \--all` when calling git-filter-branch.
+* You really filtered all refs: use `--tag-name-filter cat -- --all`
+ when calling git-filter-branch.
Then there are two ways to get a smaller repository. A safer way is
to clone, that keeps your original intact.
-* Clone it with `git clone +++file:///path/to/repo+++`. The clone
+* Clone it with `git clone file:///path/to/repo`. The clone
will not have the removed objects. See linkgit:git-clone[1]. (Note
that cloning with a plain path just hardlinks everything!)
@@ -397,14 +397,14 @@ approach, so *make a backup* or go back to cloning it. You have been
warned.
* Remove the original refs backed up by git-filter-branch: say `git
- for-each-ref \--format="%(refname)" refs/original/ | xargs -n 1 git
+ for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git
update-ref -d`.
-* Expire all reflogs with `git reflog expire \--expire=now \--all`.
+* Expire all reflogs with `git reflog expire --expire=now --all`.
-* Garbage collect all unreferenced objects with `git gc \--prune=now`
+* Garbage collect all unreferenced objects with `git gc --prune=now`
(or if your git-gc is not new enough to support arguments to
- `\--prune`, use `git repack -ad; git prune` instead).
+ `--prune`, use `git repack -ad; git prune` instead).
GIT
---
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 6ea9be7..04c7346 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -45,7 +45,7 @@ There are two ways to specify which commits to operate on.
The first rule takes precedence in the case of a single <commit>. To
apply the second rule, i.e., format everything since the beginning of
history up until <commit>, use the '\--root' option: `git format-patch
-\--root <commit>`. If you want to format only <commit> itself, you
+--root <commit>`. If you want to format only <commit> itself, you
can do this with `git format-patch -1 <commit>`.
By default, each output file is numbered sequentially from 1, and uses the
@@ -134,7 +134,7 @@ include::diff-options.txt[]
The optional <style> argument can be either `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'
+`--in-reply-to`, and the first patch mail, in this order. 'deep'
threading makes every mail a reply to the previous one.
+
The default is `--no-thread`, unless the 'format.thread' configuration
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index 6c47395..bbb25da 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
[--[no-]full] [--strict] [--verbose] [--lost-found]
- [--[no-]progress] [<object>*]
+ [--[no-]dangling] [--[no-]progress] [<object>*]
DESCRIPTION
-----------
@@ -30,6 +30,11 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless
Print out objects that exist but that aren't reachable from any
of the reference nodes.
+--dangling::
+--no-dangling::
+ Print objects that exist but that are never 'directly' used (default).
+ `--no-dangling` can be used to omit this information from the output.
+
--root::
Report root nodes.
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 815afcb..b370b02 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -84,7 +84,7 @@ The optional configuration variable 'gc.reflogExpireUnreachable'
can be set to indicate how long historical reflog entries which
are not part of the current branch should remain available in
this repository. These types of entries are generally created as
-a result of using `git commit \--amend` or `git rebase` and are the
+a result of using `git commit --amend` or `git rebase` and are the
commits prior to the amend or rebase occurring. Since these changes
are not part of the current project most users will want to expire
them sooner. This option defaults to '30 days'.
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 343eadd..3bec036 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -31,7 +31,9 @@ SYNOPSIS
DESCRIPTION
-----------
Look for specified patterns in the tracked files in the work tree, blobs
-registered in the index file, or blobs in given tree objects.
+registered in the index file, or blobs in given tree objects. Patterns
+are lists of one or more search expressions separated by newline
+characters. An empty string as search expression matches all lines.
CONFIGURATION
@@ -247,11 +249,11 @@ OPTIONS
Examples
--------
-`git grep {apostrophe}time_t{apostrophe} \-- {apostrophe}*.[ch]{apostrophe}`::
+`git grep 'time_t' -- '*.[ch]'`::
Looks for `time_t` in all tracked .c and .h files in the working
directory and its subdirectories.
-`git grep -e {apostrophe}#define{apostrophe} --and \( -e MAX_PATH -e PATH_MAX \)`::
+`git grep -e '#define' --and \( -e MAX_PATH -e PATH_MAX \)`::
Looks for a line that has `#define` and either `MAX_PATH` or
`PATH_MAX`.
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 909687f..39e6d0d 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -74,6 +74,16 @@ OPTIONS
--strict::
Die, if the pack contains broken objects or links.
+--threads=<n>::
+ Specifies the number of threads to spawn when resolving
+ deltas. This requires that index-pack be compiled with
+ pthreads otherwise this option is ignored with a warning.
+ This is meant to reduce packing time on multiprocessor
+ machines. The required amount of memory for the delta search
+ window is however multiplied by the number of threads.
+ Specifying 0 will cause git to auto-detect the number of CPU's
+ and use maximum 3 threads.
+
Note
----
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 249fc87..1f90620 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -100,7 +100,7 @@ Examples
Show all commits since version 'v2.6.12' that changed any file
in the include/scsi or drivers/scsi subdirectories
-`git log --since="2 weeks ago" \-- gitk`::
+`git log --since="2 weeks ago" -- gitk`::
Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index e2e6aba..3ceefb8 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -9,7 +9,7 @@ git-merge - Join two or more development histories together
SYNOPSIS
--------
[verse]
-'git merge' [-n] [--stat] [--no-commit] [--squash]
+'git merge' [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
[-s <strategy>] [-X <strategy-option>]
[--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]
'git merge' <msg> HEAD <commit>...
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index e8319ea..b95aafa 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -70,7 +70,7 @@ copy::
second object). This subcommand is equivalent to:
`git notes add [-f] -C $(git notes list <from-object>) <to-object>`
+
-In `\--stdin` mode, take lines in the format
+In `--stdin` mode, take lines in the format
+
----------
<from-object> SP <to-object> [ SP <rest> ] LF
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index ed82790..8228f33 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -31,13 +31,6 @@ the updated p4 remote branch.
EXAMPLE
-------
-* Create an alias for 'git p4', using the full path to the 'git-p4'
- script if needed:
-+
-------------
-$ git config --global alias.p4 '!git-p4'
-------------
-
* Clone a repository:
+
------------
@@ -165,11 +158,14 @@ OPTIONS
General options
~~~~~~~~~~~~~~~
-All commands except clone accept this option.
+All commands except clone accept these options.
--git-dir <dir>::
Set the 'GIT_DIR' environment variable. See linkgit:git[1].
+--verbose::
+ Provide more progress information.
+
Sync options
~~~~~~~~~~~~
These options can be used in the initial 'clone' as well as in
@@ -183,6 +179,7 @@ subsequent 'sync' operations.
+
This example imports a new remote "p4/proj2" into an existing
git repository:
++
----
$ git init
$ git p4 sync --branch=refs/remotes/p4/proj2 //depot/proj2
@@ -200,12 +197,13 @@ git repository:
--silent::
Do not print any progress information.
---verbose::
- Provide more progress information.
-
--detect-labels::
Query p4 for labels associated with the depot paths, and add
- them as tags in git.
+ them as tags in git. Limited usefulness as only imports labels
+ associated with new changelists. Deprecated.
+
+--import-labels::
+ Import labels from p4 into git.
--import-local::
By default, p4 branches are stored in 'refs/remotes/p4/',
@@ -252,15 +250,12 @@ Submit options
~~~~~~~~~~~~~~
These options can be used to modify 'git p4 submit' behavior.
---verbose::
- Provide more progress information.
-
--origin <commit>::
Upstream location from which commits are identified to submit to
p4. By default, this is the most recent p4 commit reachable
from 'HEAD'.
--M[<n>]::
+-M::
Detect renames. See linkgit:git-diff[1]. Renames will be
represented in p4 using explicit 'move' operations. There
is no corresponding option to detect copies, but there are
@@ -270,6 +265,16 @@ These options can be used to modify 'git p4 submit' behavior.
Re-author p4 changes before submitting to p4. This option
requires p4 admin privileges.
+--export-labels::
+ Export tags from git as p4 labels. Tags found in git are applied
+ to the perforce working directory.
+
+Rebase options
+~~~~~~~~~~~~~~
+These options can be used to modify 'git p4 rebase' behavior.
+
+--import-labels::
+ Import p4 labels.
DEPOT PATH SYNTAX
-----------------
@@ -311,14 +316,19 @@ configuration file. This allows future 'git p4 submit' commands to
work properly; the submit command looks only at the variable and does
not have a command-line option.
-The full syntax for a p4 view is documented in 'p4 help views'. Git-p4
+The full syntax for a p4 view is documented in 'p4 help views'. 'Git p4'
knows only a subset of the view syntax. It understands multi-line
mappings, overlays with '+', exclusions with '-' and double-quotes
-around whitespace. Of the possible wildcards, git-p4 only handles
-'...', and only when it is at the end of the path. Git-p4 will complain
+around whitespace. Of the possible wildcards, 'git p4' only handles
+'...', and only when it is at the end of the path. 'Git p4' will complain
if it encounters an unhandled wildcard.
-The name of the client can be given to git-p4 in multiple ways. The
+Bugs in the implementation of overlap mappings exist. If multiple depot
+paths map through overlays to the same location in the repository,
+'git p4' can choose the wrong one. This is hard to solve without
+dedicating a client spec just for 'git p4'.
+
+The name of the client can be given to 'git p4' in multiple ways. The
variable 'git-p4.client' takes precedence if it exists. Otherwise,
normal p4 mechanisms of determining the client are used: environment
variable P4CLIENT, a file referenced by P4CONFIG, or the local host name.
@@ -429,11 +439,23 @@ git-p4.branchList::
enabled. Each entry should be a pair of branch names separated
by a colon (:). This example declares that both branchA and
branchB were created from main:
++
-------------
git config git-p4.branchList main:branchA
git config --add git-p4.branchList main:branchB
-------------
+git-p4.ignoredP4Labels::
+ List of p4 labels to ignore. This is built automatically as
+ unimportable labels are discovered.
+
+git-p4.importLabels::
+ Import p4 labels into git, as per --import-labels.
+
+git-p4.labelImportRegexp::
+ Only p4 labels matching this regular expression will be imported. The
+ default value is '[a-zA-Z0-9_\-.]+$'.
+
git-p4.useClientSpec::
Specify that the p4 client spec should be used to identify p4
depot paths of interest. This is equivalent to specifying the
@@ -443,13 +465,15 @@ git-p4.useClientSpec::
Submit variables
~~~~~~~~~~~~~~~~
git-p4.detectRenames::
- Detect renames. See linkgit:git-diff[1].
+ Detect renames. See linkgit:git-diff[1]. This can be true,
+ false, or a score as expected by 'git diff -M'.
git-p4.detectCopies::
- Detect copies. See linkgit:git-diff[1].
+ Detect copies. See linkgit:git-diff[1]. This can be true,
+ false, or a score as expected by 'git diff -C'.
git-p4.detectCopiesHarder::
- Detect copies harder. See linkgit:git-diff[1].
+ Detect copies harder. See linkgit:git-diff[1]. A boolean.
git-p4.preserveUser::
On submit, re-author changes to reflect the git author,
@@ -482,6 +506,18 @@ git-p4.skipUserNameCheck::
user map, 'git p4' exits. This option can be used to force
submission regardless.
+git-p4.attemptRCSCleanup::
+ If enabled, 'git p4 submit' will attempt to cleanup RCS keywords
+ ($Header$, etc). These would otherwise cause merge conflicts and prevent
+ the submit going ahead. This option should be considered experimental at
+ present.
+
+git-p4.exportLabels::
+ Export git tags to p4 labels, as per --export-labels.
+
+git-p4.labelExportRegexp::
+ Only p4 labels matching this regular expression will be exported. The
+ default value is '[a-zA-Z0-9_\-.]+$'.
IMPLEMENTATION DETAILS
----------------------
diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt
index a3c6677..10afd4e 100644
--- a/Documentation/git-pack-refs.txt
+++ b/Documentation/git-pack-refs.txt
@@ -32,7 +32,7 @@ Subsequent updates to branches always create new files under
A recommended practice to deal with a repository with too many
refs is to pack its refs with `--all --prune` once, and
-occasionally run `git pack-refs \--prune`. Tags are by
+occasionally run `git pack-refs --prune`. Tags are by
definition stationary and are not expected to change. Branch
heads will be packed with the initial `pack-refs --all`, but
only the currently active branch heads will become unpacked,
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec8..defb544 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -110,7 +110,7 @@ include::merge-options.txt[]
+
See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
linkgit:git-config[1] if you want to make `git pull` always use
-`{litdd}rebase` instead of merging.
+`--rebase` instead of merging.
+
[NOTE]
This is a potentially _dangerous_ mode of operation.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index aede488..cb97cc1 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
- [--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream]
+ [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream]
[<repository> [<refspec>...]]
DESCRIPTION
@@ -34,7 +34,7 @@ OPTIONS[[OPTIONS]]
<refspec>...::
The format of a <refspec> parameter is an optional plus
- `{plus}`, followed by the source ref <src>, followed
+ `+`, followed by the source ref <src>, followed
by a colon `:`, followed by the destination ref <dst>.
It is used to specify with what <src> object the <dst> ref
in the remote repository is to be updated.
@@ -50,7 +50,7 @@ updated.
+
The object referenced by <src> is used to update the <dst> reference
on the remote side, but by default this is only allowed if the
-update can fast-forward <dst>. By having the optional leading `{plus}`,
+update can fast-forward <dst>. By having the optional leading `+`,
you can tell git to update the <dst> ref even when the update is not a
fast-forward. This does *not* attempt to merge <src> into <dst>. See
EXAMPLES below for details.
@@ -60,7 +60,7 @@ EXAMPLES below for details.
Pushing an empty <src> allows you to delete the <dst> ref from
the remote repository.
+
-The special refspec `:` (or `{plus}:` to allow non-fast-forward updates)
+The special refspec `:` (or `+:` to allow non-fast-forward updates)
directs git to push "matching" branches: for every branch that exists on
the local side, the remote side is updated if a branch of the same name
already exists on the remote side. This is the default operation mode
@@ -71,6 +71,14 @@ nor in any Push line of the corresponding remotes file---see below).
Instead of naming each ref to push, specifies that all
refs under `refs/heads/` be pushed.
+--prune::
+ Remove remote branches that don't have a local counterpart. For example
+ a remote branch `tmp` will be removed if a local branch with the same
+ name doesn't exist any more. This also respects refspecs, e.g.
+ `git push --prune remote refs/heads/*:refs/tmp/*` would
+ make sure that remote `refs/tmp/foo` will be removed if `refs/heads/foo`
+ doesn't exist.
+
--mirror::
Instead of naming each ref to push, specifies that all
refs under `refs/` (which includes but is not
@@ -162,10 +170,16 @@ useful if you write an alias or script around 'git push'.
is specified. This flag forces progress status even if the
standard error stream is not directed to a terminal.
---recurse-submodules=check::
- Check whether all submodule commits used by the revisions to be
- pushed are available on a remote tracking branch. Otherwise the
- push will be aborted and the command will exit with non-zero status.
+--recurse-submodules=check|on-demand::
+ Make sure all submodule commits used by the revisions to be
+ pushed are available on a remote tracking branch. If 'check' is
+ used git will verify that all submodule commits that changed in
+ the revisions to be pushed are available on at least one remote
+ of the submodule. If any commits are missing the push will be
+ aborted and exit with non-zero status. If 'on-demand' is used
+ all submodules that changed in the revisions to be pushed will
+ be pushed. If on-demand was not able to push all necessary
+ revisions it will also be aborted and exit with non-zero status.
include::urls-remotes.txt[]
@@ -196,7 +210,7 @@ option is used.
flag::
A single character indicating the status of the ref:
(space);; for a successfully pushed fast-forward;
-`{plus}`;; for a successful forced update;
+`+`;; for a successful forced update;
`-`;; for a successfully deleted ref;
`*`;; for a successfully pushed new ref;
`!`;; for a ref that was rejected or failed to push; and
@@ -206,7 +220,7 @@ summary::
For a successfully pushed ref, the summary shows the old and new
values of the ref in a form suitable for using as an argument to
`git log` (this is `<old>..<new>` in most cases, and
- `<old>\...<new>` for forced non-fast-forward updates).
+ `<old>...<new>` for forced non-fast-forward updates).
+
For a failed update, more details are given:
+
@@ -388,7 +402,7 @@ the ones in the examples below) can be configured as the default for
Find a ref that matches `experimental` in the `origin` repository
(e.g. `refs/heads/experimental`), and delete it.
-`git push origin {plus}dev:master`::
+`git push origin +dev:master`::
Update the origin repository's master branch with the dev branch,
allowing non-fast-forward updates. *This can leave unreferenced
commits dangling in the origin repository.* Consider the
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 520aaa9..b30ed35 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -8,9 +8,9 @@ git-rebase - Forward-port local commits to the updated upstream head
SYNOPSIS
--------
[verse]
-'git rebase' [-i | --interactive] [options] [--onto <newbase>]
+'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
[<upstream>] [<branch>]
-'git rebase' [-i | --interactive] [options] --onto <newbase>
+'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
'git rebase' --continue | --skip | --abort
@@ -210,7 +210,7 @@ rebase.autosquash::
OPTIONS
-------
-<newbase>::
+--onto <newbase>::
Starting point at which to create the new commits. If the
--onto option is not specified, the starting point is
<upstream>. May be any valid commit, and not just an
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
will be reset to where it was when the rebase operation was
started.
+--keep-empty::
+ Keep the commits that do not change anything from its
+ parents in the result.
+
--skip::
Restart the rebasing process by skipping the current patch.
@@ -267,7 +271,7 @@ which makes little sense.
-X <strategy-option>::
--strategy-option=<strategy-option>::
Pass the <strategy-option> through to the merge strategy.
- This implies `\--merge` and, if no strategy has been
+ This implies `--merge` and, if no strategy has been
specified, `-s recursive`. Note the reversal of 'ours' and
'theirs' as noted in above for the `-m` option.
@@ -340,14 +344,36 @@ This uses the `--interactive` machinery internally, but combining it
with the `--interactive` option explicitly is generally not a good
idea unless you know what you are doing (see BUGS below).
+-x <cmd>::
+--exec <cmd>::
+ Append "exec <cmd>" after each line creating a commit in the
+ final history. <cmd> will be interpreted as one or more shell
+ commands.
++
+This option can only be used with the `--interactive` option
+(see INTERACTIVE MODE below).
++
+You may execute several commands by either using one instance of `--exec`
+with several commands:
++
+ git rebase -i --exec "cmd1 && cmd2 && ..."
++
+or by giving more than one `--exec`:
++
+ git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
++
+If `--autosquash` is used, "exec" lines will not be appended for
+the intermediate commits, and will only appear at the end of each
+squash/fixup series.
--root::
Rebase all commits reachable from <branch>, instead of
limiting them with an <upstream>. This allows you to rebase
- the root commit(s) on a branch. Must be used with --onto, and
+ the root commit(s) on a branch. When used with --onto, it
will skip changes already contained in <newbase> (instead of
- <upstream>). When used together with --preserve-merges, 'all'
- root commits will be rewritten to have <newbase> as parent
+ <upstream>) whereas without --onto it will operate on every change.
+ When used together with both --onto and --preserve-merges,
+ 'all' root commits will be rewritten to have <newbase> as parent
instead.
--autosquash::
@@ -517,6 +543,24 @@ in `$SHELL`, or the default shell if `$SHELL` is not set), so you can
use shell features (like "cd", ">", ";" ...). The command is run from
the root of the working tree.
+----------------------------------
+$ git rebase -i --exec "make test"
+----------------------------------
+
+This command lets you check that intermediate commits are compilable.
+The todo list becomes like that:
+
+--------------------
+pick 5928aea one
+exec make test
+pick 04d0fda two
+exec make test
+pick ba46169 three
+exec make test
+pick f4593f9 four
+exec make test
+--------------------
+
SPLITTING COMMITS
-----------------
@@ -611,8 +655,8 @@ Easy case: The changes are literally the same.::
Hard case: The changes are not the same.::
This happens if the 'subsystem' rebase had conflicts, or used
- `\--interactive` to omit, edit, squash, or fixup commits; or
- if the upstream used one of `commit \--amend`, `reset`, or
+ `--interactive` to omit, edit, squash, or fixup commits; or
+ if the upstream used one of `commit --amend`, `reset`, or
`filter-branch`.
@@ -648,7 +692,7 @@ correspond to the ones before the rebase.
NOTE: While an "easy case recovery" sometimes appears to be successful
even in the hard case, it may have unintended consequences. For
example, a commit that was removed via `git rebase
- \--interactive` will be **resurrected**!
+ --interactive` will be **resurrected**!
The idea is to manually tell 'git rebase' "where the old 'subsystem'
ended and your 'topic' began", that is, what the old merge-base
@@ -656,7 +700,7 @@ between them was. You will have to find a way to name the last commit
of the old 'subsystem', for example:
* With the 'subsystem' reflog: after 'git fetch', the old tip of
- 'subsystem' is at `subsystem@\{1}`. Subsequent fetches will
+ 'subsystem' is at `subsystem@{1}`. Subsequent fetches will
increase the number. (See linkgit:git-reflog[1].)
* Relative to the tip of 'topic': knowing that your 'topic' has three
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index 976dc14..7fe2d22 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -39,13 +39,13 @@ as well). It is an alias for `git log -g --abbrev-commit --pretty=oneline`;
see linkgit:git-log[1].
The reflog is useful in various git commands, to specify the old value
-of a reference. For example, `HEAD@\{2\}` means "where HEAD used to be
-two moves ago", `master@\{one.week.ago\}` means "where master used to
+of a reference. For example, `HEAD@{2}` means "where HEAD used to be
+two moves ago", `master@{one.week.ago}` means "where master used to
point to one week ago", and so on. See linkgit:gitrevisions[7] for
more details.
To delete single entries from the reflog, use the subcommand "delete"
-and specify the _exact_ entry (e.g. "`git reflog delete master@\{2\}`").
+and specify the _exact_ entry (e.g. "`git reflog delete master@{2}`").
OPTIONS
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index 674797c..f5836e4 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/git-remote-helpers.txt
@@ -87,7 +87,7 @@ to the `capabilities` command (see COMMANDS, below).
capability use this.
+
A helper advertising the capability
-`refspec refs/heads/{asterisk}:refs/svn/origin/branches/{asterisk}`
+`refspec refs/heads/*:refs/svn/origin/branches/*`
is saying that, when it is asked to `import refs/heads/topic`, the
stream it outputs will update the `refs/svn/origin/branches/topic`
ref.
@@ -96,7 +96,7 @@ This capability can be advertised multiple times. The first
applicable refspec takes precedence. The left-hand of refspecs
advertised with this capability must cover all refs reported by
the list command. If no 'refspec' capability is advertised,
-there is an implied `refspec {asterisk}:{asterisk}`.
+there is an implied `refspec *:*`.
Capabilities for Pushing
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -148,7 +148,7 @@ Other frontends may have some other order of preference.
This modifies the 'import' capability.
+
A helper advertising
-`refspec refs/heads/{asterisk}:refs/svn/origin/branches/{asterisk}`
+`refspec refs/heads/*:refs/svn/origin/branches/*`
in its capabilities is saying that, when it handles
`import refs/heads/topic`, the stream it outputs will update the
`refs/svn/origin/branches/topic` ref.
@@ -157,7 +157,7 @@ This capability can be advertised multiple times. The first
applicable refspec takes precedence. The left-hand of refspecs
advertised with this capability must cover all refs reported by
the list command. If no 'refspec' capability is advertised,
-there is an implied `refspec {asterisk}:{asterisk}`.
+there is an implied `refspec *:*`.
INVOCATION
----------
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index d376d19..a308f4c 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -67,14 +67,14 @@ multiple branches without grabbing all branches.
With `-m <master>` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch. See also the set-head command.
+
-When a fetch mirror is created with `\--mirror=fetch`, the refs will not
+When a fetch mirror is created with `--mirror=fetch`, the refs will not
be stored in the 'refs/remotes/' namespace, but rather everything in
'refs/' on the remote will be directly mirrored into 'refs/' in the
local repository. This option only makes sense in bare repositories,
because a fetch would overwrite any local commits.
+
-When a push mirror is created with `\--mirror=push`, then `git push`
-will always behave as if `\--mirror` was passed.
+When a push mirror is created with `--mirror=push`, then `git push`
+will always behave as if `--mirror` was passed.
'rename'::
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 40af321..4c1aff6 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -34,7 +34,7 @@ OPTIONS
Especially useful when packing a repository that is used
for private development. Use
with '-d'. This will clean up the objects that `git prune`
- leaves behind, but `git fsck --full` shows as
+ leaves behind, but `git fsck --full --dangling` shows as
dangling.
+
Note that users fetching over dumb protocols will have to fetch the
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index b43b7c8..a62227f 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -101,15 +101,15 @@ One way to do it is to pull master into the topic branch:
The commits marked with `*` touch the same area in the same
file; you need to resolve the conflicts when creating the commit
-marked with `{plus}`. Then you can test the result to make sure your
+marked with `+`. Then you can test the result to make sure your
work-in-progress still works with what is in the latest master.
After this test merge, there are two ways to continue your work
on the topic. The easiest is to build on top of the test merge
-commit `{plus}`, and when your work in the topic branch is finally
+commit `+`, and when your work in the topic branch is finally
ready, pull the topic branch into master, and/or ask the
upstream to pull from you. By that time, however, the master or
-the upstream might have been advanced since the test merge `{plus}`,
+the upstream might have been advanced since the test merge `+`,
in which case the final commit graph would look like this:
------------
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index b674866..117e374 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -41,7 +41,7 @@ working tree in one go.
+
This means that `git reset -p` is the opposite of `git add -p`, i.e.
you can use it to selectively reset hunks. See the ``Interactive Mode''
-section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
+section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
'git reset' --<mode> [<commit>]::
This form resets the current branch head to <commit> and
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 8023dc0..4cc3e95 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -113,15 +113,14 @@ OPTIONS
+
If a `pattern` is given, only refs matching the given shell glob are
shown. If the pattern does not contain a globbing character (`?`,
-`{asterisk}`, or `[`), it is turned into a prefix match by
-appending `/{asterisk}`.
+`*`, or `[`), it is turned into a prefix match by appending `/*`.
--glob=pattern::
Show all refs matching the shell glob pattern `pattern`. If
the pattern does not start with `refs/`, this is automatically
prepended. If the pattern does not contain a globbing
- character (`?`, `{asterisk}`, or `[`), it is turned into a prefix
- match by appending `/{asterisk}`.
+ character (`?`, `*`, or `[`), it is turned into a prefix
+ match by appending `/*`.
--show-toplevel::
Show the absolute path of the top-level directory.
@@ -138,7 +137,8 @@ appending `/{asterisk}`.
--git-dir::
Show `$GIT_DIR` if defined. Otherwise show the path to
- the .git directory, relative to the current directory.
+ the .git directory. The path shown, when relative, is
+ relative to the current working directory.
+
If `$GIT_DIR` is not defined and the current directory
is not detected to lie in a git repository or work tree
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index b699a34..70152e8 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -27,7 +27,7 @@ throw away all uncommitted changes in your working directory, you
should see linkgit:git-reset[1], particularly the '--hard' option. If
you want to extract specific files as they were in another commit, you
should see linkgit:git-checkout[1], specifically the `git checkout
-<commit> \-- <filename>` syntax. Take care with these alternatives as
+<commit> -- <filename>` syntax. Take care with these alternatives as
both will discard uncommitted changes in your working directory.
OPTIONS
@@ -105,7 +105,7 @@ EXAMPLES
Revert the changes specified by the fourth last commit in HEAD
and create a new commit with the reverted changes.
-`git revert -n master{tilde}5..master{tilde}2`::
+`git revert -n master~5..master~2`::
Revert the changes done by commits from the fifth last commit
in master (included) to the third last commit in master
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 665ad4d..5d31860 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -79,8 +79,7 @@ a file that you have not told git about does not remove that file.
File globbing matches across directory boundaries. Thus, given
two directories `d` and `d2`, there is a difference between
-using `git rm {apostrophe}d{asterisk}{apostrophe}` and
-`git rm {apostrophe}d/{asterisk}{apostrophe}`, as the former will
+using `git rm 'd*'` and `git rm 'd/*'`, as the former will
also remove all of directory `d2`.
REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 327233c..3241170 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -198,6 +198,10 @@ must be used for each option.
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
then authentication is not attempted.
+--smtp-debug=0|1::
+ Enable (1) or disable (0) debug output. If enabled, SMTP
+ commands and replies will be printed. Useful to debug TLS
+ connection and authentication problems.
Automating
~~~~~~~~~~
diff --git a/Documentation/git-sh-i18n--envsubst.txt b/Documentation/git-sh-i18n--envsubst.txt
index 5c3ec32..2ffaf93 100644
--- a/Documentation/git-sh-i18n--envsubst.txt
+++ b/Documentation/git-sh-i18n--envsubst.txt
@@ -25,7 +25,7 @@ plumbing scripts and/or are writing new ones.
'git sh-i18n{litdd}envsubst' is Git's stripped-down copy of the GNU
`envsubst(1)` program that comes with the GNU gettext package. It's
used internally by linkgit:git-sh-i18n[1] to interpolate the variables
-passed to the the `eval_gettext` function.
+passed to the `eval_gettext` function.
No promises are made about the interface, or that this
program won't disappear without warning in the next version
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index ff3755b..01d8417 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -47,7 +47,7 @@ OPTIONS
--format[=<format>]::
Instead of the commit subject, use some other information to
describe each commit. '<format>' can be any string accepted
- by the `--format` option of 'git log', such as '{asterisk} [%h] %s'.
+ by the `--format` option of 'git log', such as '* [%h] %s'.
(See the "PRETTY FORMATS" section of linkgit:git-log[1].)
Each pretty-printed commit will be rewrapped before it is shown.
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index fcee000..5dbcd47 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -73,7 +73,7 @@ OPTIONS
--exclude-existing[=<pattern>]::
Make 'git show-ref' act as a filter that reads refs from stdin of the
- form "`{caret}(?:<anything>\s)?<refname>(?:{backslash}{caret}{})?$`"
+ form "`^(?:<anything>\s)?<refname>(?:\^{})?$`"
and performs the following actions on each:
(1) strip "{caret}{}" at the end of line if any;
(2) ignore if pattern is provided and does not head-match refname;
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 1e38819..ae4edcc 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -52,10 +52,10 @@ EXAMPLES
Shows the tag `v1.0.0`, along with the object the tags
points at.
-`git show v1.0.0^\{tree\}`::
+`git show v1.0.0^{tree}`::
Shows the tree pointed to by the tag `v1.0.0`.
-`git show -s --format=%s v1.0.0^\{commit\}`::
+`git show -s --format=%s v1.0.0^{commit}`::
Shows the subject of the commit pointed to by the
tag `v1.0.0`.
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 43af38a..0aa4e20 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -36,8 +36,8 @@ you create one.
The latest stash you created is stored in `refs/stash`; older
stashes are found in the reflog of this reference and can be named using
-the usual reflog syntax (e.g. `stash@\{0}` is the most recently
-created stash, `stash@\{1}` is the one before it, `stash@\{2.hours.ago}`
+the usual reflog syntax (e.g. `stash@{0}` is the most recently
+created stash, `stash@{1}` is the one before it, `stash@{2.hours.ago}`
is also possible).
OPTIONS
@@ -66,7 +66,7 @@ constructed such that its index state is the same as the index state
of your repository, and its worktree contains only the changes you
selected interactively. The selected changes are then rolled back
from your worktree. See the ``Interactive Mode'' section of
-linkgit:git-add[1] to learn how to operate the `\--patch` mode.
+linkgit:git-add[1] to learn how to operate the `--patch` mode.
+
The `--patch` option implies `--keep-index`. You can use
`--no-keep-index` to override this.
@@ -74,7 +74,7 @@ The `--patch` option implies `--keep-index`. You can use
list [<options>]::
List the stashes that you currently have. Each 'stash' is listed
- with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1}` is
+ with its name (e.g. `stash@{0}` is the latest stash, `stash@{1}` is
the one before, etc.), the name of the branch that was current when the
stash was made, and a short description of the commit the stash was
based on.
@@ -93,7 +93,7 @@ show [<stash>]::
stashed state and its original parent. When no `<stash>` is given,
shows the latest one. By default, the command shows the diffstat, but
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).
+ -p stash@{1}` to view the second most recent stash in patch form).
pop [--index] [-q|--quiet] [<stash>]::
@@ -111,8 +111,8 @@ tree's changes, but also the index's ones. However, this can fail, when you
have conflicts (which are stored in the index, where you therefore can no
longer apply the changes as they were originally).
+
-When no `<stash>` is given, `stash@\{0}` is assumed, otherwise `<stash>` must
-be a reference of the form `stash@\{<revision>}`.
+When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must
+be a reference of the form `stash@{<revision>}`.
apply [--index] [-q|--quiet] [<stash>]::
@@ -143,9 +143,9 @@ clear::
drop [-q|--quiet] [<stash>]::
Remove a single stashed state from the stash list. When no `<stash>`
- is given, it removes the latest one. i.e. `stash@\{0}`, otherwise
+ is given, it removes the latest one. i.e. `stash@{0}`, otherwise
`<stash>` must a valid stash log reference of the form
- `stash@\{<revision>}`.
+ `stash@{<revision>}`.
create::
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3d51717..67e5f53 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -77,6 +77,13 @@ configuration variable documented in linkgit:git-config[1].
Terminate entries with NUL, instead of LF. This implies
the `--porcelain` output format if no other format is given.
+--column[=<options>]::
+--no-column::
+ Display untracked files in columns. See configuration variable
+ column.status for option syntax.`--column` and `--no-column`
+ without options are equivalent to 'always' and 'never'
+ respectively.
+
OUTPUT
------
@@ -98,12 +105,12 @@ In the short-format, the status of each path is shown as
XY PATH1 -> PATH2
-where `PATH1` is the path in the `HEAD`, and the ` \-> PATH2` part is
+where `PATH1` is the path in the `HEAD`, and the " `-> PATH2`" part is
shown only when `PATH1` corresponds to a different path in the
index/worktree (i.e. the file is renamed). The 'XY' is a two-letter
status code.
-The fields (including the `\->`) are separated from each other by a
+The fields (including the `->`) are separated from each other by a
single space. If a filename contains whitespace or other nonprintable
characters, that field will be quoted in the manner of a C string
literal: surrounded by ASCII double quote (34) characters, and with
@@ -177,7 +184,7 @@ order is reversed (e.g 'from \-> to' becomes 'to from'). Second, a NUL
and the terminating newline (but a space still separates the status
field from the first filename). Third, filenames containing special
characters are not specially formatted; no quoting or
-backslash-escaping is performed. Fourth, there is no branch line.
+backslash-escaping is performed.
CONFIGURATION
-------------
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index b729649..fbbbcb2 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -43,9 +43,9 @@ if you choose to go that route.
Submodules are composed from a so-called `gitlink` tree entry
in the main repository that refers to a particular commit object
within the inner repository that is completely separate.
-A record in the `.gitmodules` file at the root of the source
-tree assigns a logical name to the submodule and describes
-the default URL the submodule shall be cloned from.
+A record in the `.gitmodules` (see linkgit:gitmodules[5]) file at the
+root of the source tree assigns a logical name to the submodule and
+describes the default URL the submodule shall be cloned from.
The logical name can be used for overriding this URL within your
local repository configuration (see 'submodule init').
@@ -140,7 +140,8 @@ update::
checkout the commit specified in the index of the containing repository.
This will make the submodules HEAD be detached unless `--rebase` or
`--merge` is specified or the key `submodule.$name.update` is set to
- `rebase`, `merge` or `none`.
+ `rebase`, `merge` or `none`. `none` can be overridden by specifying
+ `--checkout`.
+
If the submodule is not yet initialized, and you just want to use the
setting as stored in .gitmodules, you can automatically initialize the
@@ -148,10 +149,6 @@ submodule with the `--init` option.
+
If `--recursive` is specified, this command will recurse into the
registered submodules, and update any nested submodules within.
-+
-If the configuration key `submodule.$name.update` is set to `none` the
-submodule with name `$name` will not be updated by default. This can be
-overriden by adding `--checkout` to the command.
summary::
Show commit summary between the given commit (defaults to HEAD) and
@@ -190,7 +187,7 @@ commit for each submodule.
sync::
Synchronizes submodules' remote URL configuration setting
to the value specified in .gitmodules. It will only affect those
- submodules which already have an url entry in .git/config (that is the
+ submodules which already have a URL entry in .git/config (that is the
case when they are initialized or freshly added). This is useful when
submodule URLs change upstream and you need to update your local
repositories accordingly.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 34ee785..cfe8d2b 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -189,18 +189,16 @@ and have no uncommitted changes.
last fetched commit from the upstream SVN.
'dcommit'::
- Commit each diff from a specified head directly to the SVN
+ Commit each diff from the current branch directly to the SVN
repository, and then rebase or reset (depending on whether or
not there is a diff between SVN and head). This will create
a revision in SVN for each commit in git.
- It is recommended that you run 'git svn' fetch and rebase (not
- pull or merge) your commits against the latest changes in the
- SVN repository.
- An optional revision or branch argument may be specified, and
- causes 'git svn' to do all work on that revision/branch
- instead of HEAD.
- This is advantageous over 'set-tree' (below) because it produces
- cleaner, more linear history.
++
+When an optional git branch name (or a git commit object name)
+is specified as an argument, the subcommand works on the specified
+branch, not on the current branch.
++
+Use of 'dcommit' is preferred to 'set-tree' (below).
+
--no-rebase;;
After committing, do not rebase or reset.
@@ -572,6 +570,8 @@ config key: svn.repackflags
--merge::
-s<strategy>::
--strategy=<strategy>::
+-p::
+--preserve-merges::
These are only used with the 'dcommit' and 'rebase' commands.
+
Passed directly to 'git rebase' when using 'dcommit' if a
@@ -800,18 +800,19 @@ have each person clone that repository with 'git clone':
REBASE VS. PULL/MERGE
---------------------
-
-Originally, 'git svn' recommended that the 'remotes/git-svn' branch be
-pulled or merged from. This is because the author favored
+Prefer to use 'git svn rebase' or 'git rebase', rather than
+'git pull' or 'git merge' to synchronize unintegrated commits with a 'git svn'
+branch. Doing so will keep the history of unintegrated commits linear with
+respect to the upstream SVN repository and allow the use of the preferred
+'git svn dcommit' subcommand to push unintegrated commits back into SVN.
+
+Originally, 'git svn' recommended that developers pulled or merged from
+the 'git svn' branch. This was because the author favored
`git svn set-tree B` to commit a single head rather than the
-`git svn set-tree A..B` notation to commit multiple commits.
-
-If you use `git svn set-tree A..B` to commit several diffs and you do
-not have the latest remotes/git-svn merged into my-branch, you should
-use `git svn rebase` to update your work branch instead of `git pull` or
-`git merge`. `pull`/`merge` can cause non-linear history to be flattened
-when committing into SVN, which can lead to merge commits reversing
-previous commits in SVN.
+`git svn set-tree A..B` notation to commit multiple commits. Use of
+'git pull' or 'git merge' with `git svn set-tree A..B` will cause non-linear
+history to be flattened when committing into SVN and this can lead to merge
+commits unexpectedly reversing previous commits in SVN.
MERGE TRACKING
--------------
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index a45d4c4..981d3a8 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -8,7 +8,8 @@ git-symbolic-ref - Read and modify symbolic refs
SYNOPSIS
--------
[verse]
-'git symbolic-ref' [-q] [-m <reason>] <name> [<ref>]
+'git symbolic-ref' [-m <reason>] <name> <ref>
+'git symbolic-ref' [-q] [--short] <name>
DESCRIPTION
-----------
@@ -33,6 +34,10 @@ OPTIONS
symbolic ref but a detached HEAD; instead exit with
non-zero status silently.
+--short::
+ When showing the value of <name> as a symbolic ref, try to shorten the
+ value, e.g. from `refs/heads/master` to `master`.
+
-m::
Update the reflog for <name> with <reason>. This is valid only
when creating or updating a symbolic ref.
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 53ff5f6..e36a7c3 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -12,7 +12,9 @@ SYNOPSIS
'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
-'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]
+'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
+ [--column[=<options>] | --no-column] [<pattern>...]
+ [<pattern>...]
'git tag' -v <tagname>...
DESCRIPTION
@@ -83,9 +85,20 @@ OPTIONS
using fnmatch(3)). Multiple patterns may be given; if any of
them matches, the tag is shown.
+--column[=<options>]::
+--no-column::
+ Display tag listing in columns. See configuration variable
+ column.tag for option syntax.`--column` and `--no-column`
+ without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable when listing tags without annotation lines.
+
--contains <commit>::
Only list tags which contain the specified commit.
+--points-at <object>::
+ Only list tags of the given object.
+
-m <msg>::
--message=<msg>::
Use the given tag message (instead of prompting).
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 346e7a2..f7362dc 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -63,7 +63,7 @@ EXAMPLES
Create a tarball for v1.4.0 release.
-`git tar-tree v1.4.0{caret}\{tree\} git-1.4.0 | gzip >git-1.4.0.tar.gz`::
+`git tar-tree v1.4.0^{tree} git-1.4.0 | gzip >git-1.4.0.tar.gz`::
Create a tarball for v1.4.0 release, but without a
global extended pax header.
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index a3081f4..9d0b151 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -19,7 +19,7 @@ SYNOPSIS
[--ignore-submodules]
[--really-refresh] [--unresolve] [--again | -g]
[--info-only] [--index-info]
- [-z] [--stdin]
+ [-z] [--stdin] [--index-version <n>]
[--verbose]
[--] [<file>...]
@@ -143,6 +143,10 @@ you will need to handle the situation manually.
--verbose::
Report what is being added and removed from index.
+--index-version <n>::
+ Write the resulting index out in the named on-disk format version.
+ The current default version is 2.
+
-z::
Only meaningful with `--stdin` or `--index-info`; paths are
separated with NUL character instead of LF.
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 5317cc2..67edf58 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -43,22 +43,21 @@ GIT_EDITOR::
`$SOME_ENVIRONMENT_VARIABLE`, `"C:\Program Files\Vim\gvim.exe"
--nofork`. The order of preference is the `$GIT_EDITOR`
environment variable, then `core.editor` configuration, then
- `$VISUAL`, then `$EDITOR`, and then finally 'vi'.
+ `$VISUAL`, then `$EDITOR`, and then the default chosen at compile
+ time, which is usually 'vi'.
+ifdef::git-default-editor[]
+ The build you are using chose '{git-default-editor}' as the default.
+endif::git-default-editor[]
GIT_PAGER::
Text viewer for use by git commands (e.g., 'less'). The value
is meant to be interpreted by the shell. The order of preference
is the `$GIT_PAGER` environment variable, then `core.pager`
- configuration, then `$PAGER`, and then finally 'less'.
-
-Diagnostics
------------
-You don't exist. Go away!::
- The passwd(5) gecos field couldn't be read
-Your parents must have hated you!::
- The passwd(5) gecos field is longer than a giant static buffer.
-Your sysadmin must hate you!::
- The passwd(5) name field is longer than a giant static buffer.
+ configuration, then `$PAGER`, and then the default chosen at
+ compile time (usually 'less').
+ifdef::git-default-pager[]
+ The build you are using chose '{git-default-pager}' as the default.
+endif::git-default-pager[]
SEE ALSO
--------
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index 76c7f7e..6c8f510 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -58,7 +58,7 @@ Examples
Show as patches the commits since version 'v2.6.12' that changed
any file in the include/scsi or drivers/scsi subdirectories
-`git whatchanged --since="2 weeks ago" \-- gitk`::
+`git whatchanged --since="2 weeks ago" -- gitk`::
Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 8f31675..43f9a1b 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -44,6 +44,23 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
+* link:v1.7.11.2/git.html[documentation for release 1.7.11.2]
+
+* release notes for
+ link:RelNotes/1.7.11.2.txt[1.7.11.2],
+ link:RelNotes/1.7.11.1.txt[1.7.11.1],
+ link:RelNotes/1.7.11.txt[1.7.11].
+
+* link:v1.7.10.5/git.html[documentation for release 1.7.10.5]
+
+* release notes for
+ link:RelNotes/1.7.10.5.txt[1.7.10.5],
+ link:RelNotes/1.7.10.4.txt[1.7.10.4],
+ link:RelNotes/1.7.10.3.txt[1.7.10.3],
+ link:RelNotes/1.7.10.2.txt[1.7.10.2],
+ link:RelNotes/1.7.10.1.txt[1.7.10.1],
+ link:RelNotes/1.7.10.txt[1.7.10].
+
* link:v1.7.9.7/git.html[documentation for release 1.7.9.7]
* release notes for
@@ -719,7 +736,7 @@ other
'GIT_EDITOR'::
This environment variable overrides `$EDITOR` and `$VISUAL`.
- It is used by several git comands when, on interactive mode,
+ It is used by several git commands when, on interactive mode,
an editor is to be launched. See also linkgit:git-var[1]
and the `core.editor` option in linkgit:git-config[1].
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a85b187..e16f3e1 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -75,6 +75,8 @@ repositories (i.e., attributes of interest to all users) should go into
`.gitattributes` files. Attributes that should affect all repositories
for a single user should be placed in a file specified by the
`core.attributesfile` configuration option (see linkgit:git-config[1]).
+Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
+is either not set or empty, $HOME/.config/git/attributes is used instead.
Attributes for all users on a system should be placed in the
`$(prefix)/etc/gitattributes` file.
@@ -294,16 +296,27 @@ output is used to update the worktree file. Similarly, the
`clean` command is used to convert the contents of worktree file
upon checkin.
-A missing filter driver definition in the config is not an error
-but makes the filter a no-op passthru.
+One use of the content filtering is to massage the content into a shape
+that is more convenient for the platform, filesystem, and the user to use.
+For this mode of operation, the key phrase here is "more convenient" and
+not "turning something unusable into usable". In other words, the intent
+is that if someone unsets the filter driver definition, or does not have
+the appropriate filter program, the project should still be usable.
-The content filtering is done to massage the content into a
-shape that is more convenient for the platform, filesystem, and
-the user to use. The key phrase here is "more convenient" and not
-"turning something unusable into usable". In other words, the
-intent is that if someone unsets the filter driver definition,
-or does not have the appropriate filter program, the project
-should still be usable.
+Another use of the content filtering is to store the content that cannot
+be directly used in the repository (e.g. a UUID that refers to the true
+content stored outside git, or an encrypted content) and turn it into a
+usable form upon checkout (e.g. download the external content, or decrypt
+the encrypted content).
+
+These two filters behave differently, and by default, a filter is taken as
+the former, massaging the contents into more convenient shape. A missing
+filter driver definition in the config, or a filter driver that exits with
+a non-zero status, is not an error but makes the filter a no-op passthru.
+
+You can declare that a filter turns a content that by itself is unusable
+into a usable content by setting the filter.<driver>.required configuration
+variable to `true`.
For example, in .gitattributes, you would assign the `filter`
attribute for paths.
@@ -335,6 +348,16 @@ input that is already correctly indented. In this case, the lack of a
smudge filter means that the clean filter _must_ accept its own output
without modifying it.
+If a filter _must_ succeed in order to make the stored contents usable,
+you can declare that the filter is `required`, in the configuration:
+
+------------------------
+[filter "crypt"]
+ clean = openssl enc ...
+ smudge = openssl enc -d ...
+ required
+------------------------
+
Sequence "%f" on the filter command line is replaced with the name of
the file the filter is working on. A filter might use this in keyword
substitution. For example:
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index f734f97..ea17f7a 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -25,22 +25,22 @@ arguments. Here are the rules:
are paths.
* When an argument can be misunderstood as either a revision or a path,
- they can be disambiguated by placing `\--` between them.
- E.g. `git diff \-- HEAD` is, "I have a file called HEAD in my work
+ they can be disambiguated by placing `--` between them.
+ E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
tree. Please show changes between the version I staged in the index
and what I have in the work tree for that file". not "show difference
between the HEAD commit and the work tree as a whole". You can say
- `git diff HEAD \--` to ask for the latter.
+ `git diff HEAD --` to ask for the latter.
- * Without disambiguating `\--`, git makes a reasonable guess, but errors
+ * Without disambiguating `--`, git makes a reasonable guess, but errors
out and asking you to disambiguate when ambiguous. E.g. if you have a
file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
- you have to say either `git diff HEAD \--` or `git diff \-- HEAD` to
+ you have to say either `git diff HEAD --` or `git diff -- HEAD` to
disambiguate.
When writing a script that is expected to handle random user-input, it is
a good practice to make it explicit which arguments are which by placing
-disambiguating `\--` at appropriate places.
+disambiguating `--` at appropriate places.
Here are the rules regarding the "flags" that you should follow when you are
scripting git:
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index fb0d569..9d89336 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -151,8 +151,8 @@ to your working tree, you use the 'git update-index' program. That
program normally just takes a list of filenames you want to update, but
to avoid trivial mistakes, it refuses to add new entries to the index
(or remove existing ones) unless you explicitly tell it that you're
-adding a new entry with the `\--add` flag (or removing an entry with the
-`\--remove`) flag.
+adding a new entry with the `--add` flag (or removing an entry with the
+`--remove`) flag.
So to populate the index with the two files you just created, you can do
@@ -399,10 +399,10 @@ $ git diff HEAD
which ends up doing the above for you.
In other words, 'git diff-index' normally compares a tree against the
-working tree, but when given the `\--cached` flag, it is told to
+working tree, but when given the `--cached` flag, it is told to
instead compare against just the index cache contents, and ignore the
current working tree state entirely. Since we just wrote the index
-file to HEAD, doing `git diff-index \--cached -p HEAD` should thus return
+file to HEAD, doing `git diff-index --cached -p HEAD` should thus return
an empty set of differences, and that's exactly what it does.
[NOTE]
@@ -411,7 +411,7 @@ an empty set of differences, and that's exactly what it does.
comparisons, and saying that it compares a tree against the working
tree is thus not strictly accurate. In particular, the list of
files to compare (the "meta-data") *always* comes from the index file,
-regardless of whether the `\--cached` flag is used or not. The `\--cached`
+regardless of whether the `--cached` flag is used or not. The `--cached`
flag really only determines whether the file *contents* to be compared
come from the working tree or not.
@@ -433,7 +433,7 @@ update the index cache:
$ git update-index hello
------------------------------------------------
-(note how we didn't need the `\--add` flag this time, since git knew
+(note how we didn't need the `--add` flag this time, since git knew
about the file already).
Note what happens to the different 'git diff-{asterisk}' versions here.
@@ -560,7 +560,7 @@ short history.
When using the above two commands, the initial commit will be shown.
If this is a problem because it is huge, you can hide it by setting
the log.showroot configuration variable to false. Having this, you
-can still show it for each command just adding the `\--root` option,
+can still show it for each command just adding the `--root` option,
which is a flag for 'git diff-tree' accepted by both commands.
With that, you should now be having some inkling of what git does, and
@@ -881,7 +881,7 @@ helps you view what's going on:
$ gitk --all
----------------
-will show you graphically both of your branches (that's what the `\--all`
+will show you graphically both of your branches (that's what the `--all`
means: normally it will just show you your current `HEAD`) and their
histories. You can also see exactly how they came to be from a common
source.
@@ -935,7 +935,7 @@ which will very loudly warn you that you're now committing a merge
(which is correct, so never mind), and you can write a small merge
message about your adventures in 'git merge'-land.
-After you're done, start up `gitk \--all` to see graphically what the
+After you're done, start up `gitk --all` to see graphically what the
history looks like. Notice that `mybranch` still exists, and you can
switch to it, and continue to work with it if you want to. The
`mybranch` branch will not contain the merge, but next time you merge it
@@ -958,11 +958,11 @@ $ git show-branch --topo-order --more=1 master mybranch
The first two lines indicate that it is showing the two branches
and the first line of the commit log message from their
top-of-the-tree commits, you are currently on `master` branch
-(notice the asterisk `{asterisk}` character), and the first column for
+(notice the asterisk `*` character), and the first column for
the later output lines is used to show commits contained in the
`master` branch, and the second column for the `mybranch`
branch. Three commits are shown along with their log messages.
-All of them have non blank characters in the first column (`{asterisk}`
+All of them have non blank characters in the first column (`*`
shows an ordinary commit on the current branch, `-` is a merge commit), which
means they are now part of the `master` branch. Only the "Some
work" commit has the plus `+` character in the second column,
@@ -1002,8 +1002,8 @@ would be different)
----------------
Updating from ae3a2da... to a80b4aa....
Fast-forward (no commit created; -m option ignored)
- example | 1 +
- hello | 1 +
+ example | 1 +
+ hello | 1 +
2 files changed, 2 insertions(+)
----------------
@@ -1013,7 +1013,7 @@ not actually do a merge. Instead, it just updated the top of
the tree of your branch to that of the `master` branch. This is
often called 'fast-forward' merge.
-You can run `gitk \--all` again to see how the commit ancestry
+You can run `gitk --all` again to see how the commit ancestry
looks like, or run 'show-branch', which tells you this.
------------------------------------------------
@@ -1257,7 +1257,7 @@ this 'collapsing' tends to trivially merge most of the paths
fairly quickly, leaving only a handful of real changes in non-zero
stages.
-To look at only non-zero stages, use `\--unmerged` flag:
+To look at only non-zero stages, use `--unmerged` flag:
------------
$ git ls-files --unmerged
@@ -1420,7 +1420,7 @@ packed, and stores the packed file in `.git/objects/pack`
directory.
[NOTE]
-You will see two files, `pack-{asterisk}.pack` and `pack-{asterisk}.idx`,
+You will see two files, `pack-*.pack` and `pack-*.idx`,
in `.git/objects/pack` directory. They are closely related to
each other, and if you ever copy them by hand to a different
repository for whatever reason, you should make sure you copy
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 066f825..7dfffc0 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -143,8 +143,8 @@ CONFIGURATION OPTIONS
---------------------
Options for a credential context can be configured either in
-`credential.\*` (which applies to all credentials), or
-`credential.<url>.\*`, where <url> matches the context as described
+`credential.*` (which applies to all credentials), or
+`credential.<url>.*`, where <url> matches the context as described
above.
The following options are available in either location:
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 370624c..daf1782 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -168,11 +168,11 @@ a similarity score different from the default of 50% by giving a
number after the "-M" or "-C" option (e.g. "-M8" to tell it to use
8/10 = 80%).
-Note. When the "-C" option is used with `\--find-copies-harder`
+Note. When the "-C" option is used with `--find-copies-harder`
option, 'git diff-{asterisk}' commands feed unmodified filepairs to
diffcore mechanism as well as modified ones. This lets the copy
detector consider unmodified files as copy source candidates at
-the expense of making it slower. Without `\--find-copies-harder`,
+the expense of making it slower. Without `--find-copies-harder`,
'git diff-{asterisk}' commands can detect copies only if the file that was
copied happened to have been modified in the same changeset.
@@ -224,7 +224,7 @@ diffcore-pickaxe: For Detecting Addition/Deletion of Specified String
This transformation is used to find filepairs that represent
changes that touch a specified string, and is controlled by the
--S option and the `\--pickaxe-all` option to the 'git diff-{asterisk}'
+-S option and the `--pickaxe-all` option to the 'git diff-*'
commands.
When diffcore-pickaxe is in use, it checks if there are
@@ -233,9 +233,9 @@ different number of specified string. Such a filepair represents
"the string appeared in this changeset". It also checks for the
opposite case that loses the specified string.
-When `\--pickaxe-all` is not in effect, diffcore-pickaxe leaves
+When `--pickaxe-all` is not in effect, diffcore-pickaxe leaves
only such filepairs that touch the specified string in its
-output. When `\--pickaxe-all` is used, diffcore-pickaxe leaves all
+output. When `--pickaxe-all` is used, diffcore-pickaxe leaves all
filepairs intact if there is such a filepair, or makes the
output empty otherwise. The latter behaviour is designed to
make reviewing of the changes in the context of the whole
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 28edefa..b9003fe 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -73,7 +73,7 @@ pre-commit
~~~~~~~~~~
This hook is invoked by 'git commit', and can be bypassed
-with `\--no-verify` option. It takes no parameter, and is
+with `--no-verify` option. It takes no parameter, and is
invoked before obtaining the proposed commit log message and
making a commit. Exiting with non-zero status from this script
causes the 'git commit' to abort.
@@ -99,12 +99,12 @@ given); `template` (if a `-t` option was given or the
configuration option `commit.template` is set); `merge` (if the
commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
-a commit SHA1 (if a `-c`, `-C` or `\--amend` option was given).
+a commit SHA1 (if a `-c`, `-C` or `--amend` option was given).
If the exit status is non-zero, 'git commit' will abort.
The purpose of the hook is to edit the message file in place, and
-it is not suppressed by the `\--no-verify` option. A non-zero exit
+it is not suppressed by the `--no-verify` option. A non-zero exit
means a failure of the hook and aborts the commit. It should not
be used as replacement for pre-commit hook.
@@ -115,7 +115,7 @@ commit-msg
~~~~~~~~~~
This hook is invoked by 'git commit', and can be bypassed
-with `\--no-verify` option. It takes a single parameter, the
+with `--no-verify` option. It takes a single parameter, the
name of the file that holds the proposed commit log message.
Exiting with non-zero status causes the 'git commit' to
abort.
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 2e7328b..c1f692a 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -50,7 +50,9 @@ the repository but are specific to one user's workflow) should go into
the `$GIT_DIR/info/exclude` file. Patterns which a user wants git to
ignore in all situations (e.g., backup or temporary files generated by
the user's editor of choice) generally go into a file specified by
-`core.excludesfile` in the user's `~/.gitconfig`.
+`core.excludesfile` in the user's `~/.gitconfig`. Its default value is
+$XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or empty,
+$HOME/.config/git/ignore is used instead.
The underlying git plumbing tools, such as
'git ls-files' and 'git read-tree', read
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 4040941..4effd78 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -28,7 +28,7 @@ submodule.<name>.path::
be unique within the .gitmodules file.
submodule.<name>.url::
- Defines an url from where the submodule repository can be cloned.
+ Defines a URL from which the submodule repository can be cloned.
This may be either an absolute URL ready to be passed to
linkgit:git-clone[1] or (if it begins with ./ or ../) a location
relative to the superproject's origin repository.
@@ -41,8 +41,11 @@ submodule.<name>.update::
the commit specified in the superproject. If 'merge', the commit
specified in the superproject will be merged into the current branch
in the submodule.
+ If 'none', the submodule with name `$name` will not be updated
+ by default.
+
This config option is overridden if 'git submodule update' is given
- the '--merge' or '--rebase' options.
+ the '--merge', '--rebase' or '--checkout' options.
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
@@ -84,7 +87,7 @@ Consider the following .gitmodules file:
This defines two submodules, `libfoo` and `libbar`. These are expected to
be checked out in the paths 'include/foo' and 'include/bar', and for both
-submodules an url is specified which can be used for cloning the submodules.
+submodules a URL is specified which can be used for cloning the submodules.
SEE ALSO
--------
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index 7aba497..4947455 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -244,7 +244,7 @@ $highlight_bin::
By default set to 'highlight'; set it to full path to highlight
executable if it is not installed on your web server's PATH.
Note that 'highlight' feature must be set for gitweb to actually
- use syntax hightlighting.
+ use syntax highlighting.
+
*NOTE*: if you want to add support for new file type (supported by
"highlight" but not used by gitweb), you need to modify `%highlight_ext`
@@ -499,6 +499,13 @@ $maxload::
Set `$maxload` to undefined value (`undef`) to turn this feature off.
The default value is 300.
+$omit_age_column::
+ If true, omit the column with date of the most current commit on the
+ projects list page. It can save a bit of I/O and a fork per repository.
+
+$omit_owner::
+ If true prevents displaying information about repository owner.
+
$per_request_config::
If this is set to code reference, it will be run once for each request.
You can set parts of configuration that change per session this way.
@@ -749,14 +756,14 @@ Project specific override is not supported.
forks::
If this feature is enabled, gitweb considers projects in
subdirectories of project root (basename) to be forks of existing
- projects. For each project `$projname.git`, projects in the
- `$projname/` directory and its subdirectories will not be
- shown in the main projects list. Instead, a \'+' mark is shown
- next to `$projname`, which links to a "forks" view that lists all
- the forks (all projects in `$projname/` subdirectory). Additionally
+ projects. For each project +$projname.git+, projects in the
+ +$projname/+ directory and its subdirectories will not be
+ shown in the main projects list. Instead, a \'\+' mark is shown
+ next to +$projname+, which links to a "forks" view that lists all
+ the forks (all projects in +$projname/+ subdirectory). Additionally
a "forks" view for a project is linked from project summary page.
+
-If the project list is taken from a file (`$projects_list` points to a
+If the project list is taken from a file (+$projects_list+ points to a
file), forks are only recognized if they are listed after the main project
in that file.
+
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt
index 5e4f362..8b8c6ae 100644
--- a/Documentation/gitworkflows.txt
+++ b/Documentation/gitworkflows.txt
@@ -39,8 +39,8 @@ To achieve this, try to split your work into small steps from the very
beginning. It is always easier to squash a few commits together than
to split one big commit into several. Don't be afraid of making too
small or imperfect steps along the way. You can always go back later
-and edit the commits with `git rebase \--interactive` before you
-publish them. You can use `git stash save \--keep-index` to run the
+and edit the commits with `git rebase --interactive` before you
+publish them. You can use `git stash save --keep-index` to run the
test suite independent of other uncommitted changes; see the EXAMPLES
section of linkgit:git-stash[1].
diff --git a/Documentation/howto/using-merge-subtree.txt b/Documentation/howto/using-merge-subtree.txt
index 2933056..1ae8d12 100644
--- a/Documentation/howto/using-merge-subtree.txt
+++ b/Documentation/howto/using-merge-subtree.txt
@@ -25,7 +25,7 @@ What you want is the 'subtree' merge strategy, which helps you in such a
situation.
In this example, let's say you have the repository at `/path/to/B` (but
-it can be an URL as well, if you want). You want to merge the 'master'
+it can be a URL as well, if you want). You want to merge the 'master'
branch of that repository to the `dir-B` subdirectory in your current
branch.
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 5afc99f..0bcbe0a 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -9,18 +9,19 @@ inspect and further tweak the merge result before committing.
--edit::
--no-edit::
- Invoke editor before committing successful merge to further
- edit the default merge message. The `--no-edit` option can be
+ Invoke an editor before committing successful mechanical merge to
+ further edit the auto-generated merge message, so that the user
+ can explain and justify the merge. The `--no-edit` option can be
used to accept the auto-generated message (this is generally
- discouraged) when merging an annotated tag, in which case
- `git merge` automatically spawns the editor so that the result
- of the GPG verification of the tag can be seen.
+ discouraged). The `--edit` option is still useful if you are
+ giving a draft message with the `-m` option from the command line
+ and want to edit it in the editor.
+
Older scripts may depend on the historical behaviour of not allowing the
user to edit the merge log message. They will see an editor opened when
-they run `git merge` to merge an annotated tag. To make it easier to adjust
-such scripts to the updated behaviour, the environment variable
-`GIT_MERGE_AUTOEDIT` can be set to `no` at the beginning of them.
+they run `git merge`. To make it easier to adjust such scripts to the
+updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
+set to `no` at the beginning of them.
--ff::
When the merge resolves as a fast-forward, only update the branch
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 880b6f2..e3d8a83 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -130,8 +130,8 @@ The placeholders are:
- '%b': body
- '%B': raw body (unwrapped subject and body)
- '%N': commit notes
-- '%gD': reflog selector, e.g., `refs/stash@\{1\}`
-- '%gd': shortened reflog selector, e.g., `stash@\{1\}`
+- '%gD': reflog selector, e.g., `refs/stash@{1}`
+- '%gd': shortened reflog selector, e.g., `stash@{1}`
- '%gn': reflog identity name
- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ge': reflog identity email
@@ -155,7 +155,7 @@ insert an empty string unless we are traversing reflog entries (e.g., by
`git log -g`). The `%d` placeholder will use the "short" decoration
format if `--decorate` was not already provided on the command line.
-If you add a `{plus}` (plus sign) after '%' of a placeholder, a line-feed
+If you add a `+` (plus sign) after '%' of a placeholder, a line-feed
is inserted immediately before the expansion if and only if the
placeholder expands to a non-empty string.
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index 5dd6e5a..94a9d32 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -13,7 +13,7 @@ endif::git-pull[]
<refspec>::
The format of a <refspec> parameter is an optional plus
- `{plus}`, followed by the source ref <src>, followed
+ `+`, followed by the source ref <src>, followed
by a colon `:`, followed by the destination ref <dst>.
+
The remote ref that matches <src>
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 6a4b635..84e34b1 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -198,7 +198,7 @@ excluded from the output.
+
For example, `--cherry-pick --right-only A...B` omits those
commits from `B` which are in `A` or are patch-equivalent to a commit in
-`A`. In other words, this lists the `{plus}` commits from `git cherry A B`.
+`A`. In other words, this lists the `+` commits from `git cherry A B`.
More precisely, `--cherry-pick --right-only --no-merges` gives the exact
list.
@@ -455,7 +455,7 @@ The effect of this is best shown by way of comparing to
`---------'
-----------------------------------------------------------------------
+
-Note the major differences in `N` and `P` over '\--full-history':
+Note the major differences in `N` and `P` over '--full-history':
+
--
* `N`'s parent list had `I` removed, because it is an ancestor of the
@@ -494,7 +494,7 @@ of course).
When we want to find out what commits in `M` are contaminated with the
bug introduced by `D` and need fixing, however, we might want to view
only the subset of 'D..M' that are actually descendants of `D`, i.e.
-excluding `C` and `K`. This is exactly what the '\--ancestry-path'
+excluding `C` and `K`. This is exactly what the '--ancestry-path'
option does. Applied to the 'D..M' range, it results in:
+
-----------------------------------------------------------------------
@@ -622,6 +622,7 @@ These options are mostly targeted for packing of git repositories.
--no-walk::
Only show the given revs, but do not traverse their ancestors.
+ This has no effect if a range is specified.
--do-walk::
diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt
index 49b3d52..1b7d8f1 100644
--- a/Documentation/technical/api-argv-array.txt
+++ b/Documentation/technical/api-argv-array.txt
@@ -37,6 +37,11 @@ Functions
`argv_array_push`::
Push a copy of a string onto the end of the array.
+`argv_array_pushl`::
+ Push a list of strings onto the end of the array. The arguments
+ should be a list of `const char *` strings, terminated by a NULL
+ argument.
+
`argv_array_pushf`::
Format a string and push it onto the end of the array. This is a
convenience wrapper combining `strbuf_addf` and `argv_array_push`.
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
new file mode 100644
index 0000000..edf8dfb
--- /dev/null
+++ b/Documentation/technical/api-config.txt
@@ -0,0 +1,140 @@
+config API
+==========
+
+The config API gives callers a way to access git configuration files
+(and files which have the same syntax). See linkgit:git-config[1] for a
+discussion of the config file syntax.
+
+General Usage
+-------------
+
+Config files are parsed linearly, and each variable found is passed to a
+caller-provided callback function. The callback function is responsible
+for any actions to be taken on the config option, and is free to ignore
+some options. It is not uncommon for the configuration to be parsed
+several times during the run of a git program, with different callbacks
+picking out different variables useful to themselves.
+
+A config callback function takes three parameters:
+
+- the name of the parsed variable. This is in canonical "flat" form: the
+ section, subsection, and variable segments will be separated by dots,
+ and the section and variable segments will be all lowercase. E.g.,
+ `core.ignorecase`, `diff.SomeType.textconv`.
+
+- the value of the found variable, as a string. If the variable had no
+ value specified, the value will be NULL (typically this means it
+ should be interpreted as boolean true).
+
+- a void pointer passed in by the caller of the config API; this can
+ contain callback-specific data
+
+A config callback should return 0 for success, or -1 if the variable
+could not be parsed properly.
+
+Basic Config Querying
+---------------------
+
+Most programs will simply want to look up variables in all config files
+that git knows about, using the normal precedence rules. To do this,
+call `git_config` with a callback function and void data pointer.
+
+`git_config` will read all config sources in order of increasing
+priority. Thus a callback should typically overwrite previously-seen
+entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
+repo-specific `.git/config` contain `color.ui`, the config machinery
+will first feed the user-wide one to the callback, and then the
+repo-specific one; by overwriting, the higher-priority repo-specific
+value is left at the end).
+
+The `git_config_with_options` function lets the caller examine config
+while adjusting some of the default behavior of `git_config`. It should
+almost never be used by "regular" git code that is looking up
+configuration variables. It is intended for advanced callers like
+`git-config`, which are intentionally tweaking the normal config-lookup
+process. It takes two extra parameters:
+
+`filename`::
+If this parameter is non-NULL, it specifies the name of a file to
+parse for configuration, rather than looking in the usual files. Regular
+`git_config` defaults to `NULL`.
+
+`respect_includes`::
+Specify whether include directives should be followed in parsed files.
+Regular `git_config` defaults to `1`.
+
+There is a special version of `git_config` called `git_config_early`.
+This version takes an additional parameter to specify the repository
+config, instead of having it looked up via `git_path`. This is useful
+early in a git program before the repository has been found. Unless
+you're working with early setup code, you probably don't want to use
+this.
+
+Reading Specific Files
+----------------------
+
+To read a specific file in git-config format, use
+`git_config_from_file`. This takes the same callback and data parameters
+as `git_config`.
+
+Value Parsing Helpers
+---------------------
+
+To aid in parsing string values, the config API provides callbacks with
+a number of helper functions, including:
+
+`git_config_int`::
+Parse the string to an integer, including unit factors. Dies on error;
+otherwise, returns the parsed result.
+
+`git_config_ulong`::
+Identical to `git_config_int`, but for unsigned longs.
+
+`git_config_bool`::
+Parse a string into a boolean value, respecting keywords like "true" and
+"false". Integer values are converted into true/false values (when they
+are non-zero or zero, respectively). Other values cause a die(). If
+parsing is successful, the return value is the result.
+
+`git_config_bool_or_int`::
+Same as `git_config_bool`, except that integers are returned as-is, and
+an `is_bool` flag is unset.
+
+`git_config_maybe_bool`::
+Same as `git_config_bool`, except that it returns -1 on error rather
+than dying.
+
+`git_config_string`::
+Allocates and copies the value string into the `dest` parameter; if no
+string is given, prints an error message and returns -1.
+
+`git_config_pathname`::
+Similar to `git_config_string`, but expands `~` or `~user` into the
+user's home directory when found at the beginning of the path.
+
+Include Directives
+------------------
+
+By default, the config parser does not respect include directives.
+However, a caller can use the special `git_config_include` wrapper
+callback to support them. To do so, you simply wrap your "real" callback
+function and data pointer in a `struct config_include_data`, and pass
+the wrapper to the regular config-reading functions. For example:
+
+-------------------------------------------
+int read_file_with_include(const char *file, config_fn_t fn, void *data)
+{
+ struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ inc.fn = fn;
+ inc.data = data;
+ return git_config_from_file(git_config_include, file, &inc);
+}
+-------------------------------------------
+
+`git_config` respects includes automatically. The lower-level
+`git_config_from_file` does not.
+
+Writing Config Files
+--------------------
+
+TODO
diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt
index 21ca6a2..5977b58 100644
--- a/Documentation/technical/api-credentials.txt
+++ b/Documentation/technical/api-credentials.txt
@@ -6,8 +6,52 @@ password credentials from the user (even though credentials in the wider
world can take many forms, in this document the word "credential" always
refers to a username and password pair).
+This document describes two interfaces: the C API that the credential
+subsystem provides to the rest of git, and the protocol that git uses to
+communicate with system-specific "credential helpers". If you are
+writing git code that wants to look up or prompt for credentials, see
+the section "C API" below. If you want to write your own helper, see
+the section on "Credential Helpers" below.
+
+Typical setup
+-------------
+
+------------
++-----------------------+
+| git code (C) |--- to server requiring --->
+| | authentication
+|.......................|
+| C credential API |--- prompt ---> User
++-----------------------+
+ ^ |
+ | pipe |
+ | v
++-----------------------+
+| git credential helper |
++-----------------------+
+------------
+
+The git code (typically a remote-helper) will call the C API to obtain
+credential data like a login/password pair (credential_fill). The
+API will itself call a remote helper (e.g. "git credential-cache" or
+"git credential-store") that may retrieve credential data from a
+store. If the credential helper cannot find the information, the C API
+will prompt the user. Then, the caller of the API takes care of
+contacting the server, and does the actual authentication.
+
+C API
+-----
+
+The credential C API is meant to be called by git code which needs to
+acquire or store a credential. It is centered around an object
+representing a single credential and provides three basic operations:
+fill (acquire credentials by calling helpers and/or prompting the user),
+approve (mark a credential as successfully used so that it can be stored
+for later use), and reject (mark a credential as unsuccessful so that it
+can be erased from any persistent storage).
+
Data Structures
----------------
+~~~~~~~~~~~~~~~
`struct credential`::
@@ -21,14 +65,17 @@ Data Structures
The `helpers` member of the struct is a `string_list` of helpers. Each
string specifies an external helper which will be run, in order, to
either acquire or store credentials. See the section on credential
-helpers below.
+helpers below. This list is filled-in by the API functions
+according to the corresponding configuration variables before
+consulting helpers, so there usually is no need for a caller to
+modify the helpers field at all.
+
This struct should always be initialized with `CREDENTIAL_INIT` or
`credential_init`.
Functions
----------
+~~~~~~~~~
`credential_init`::
@@ -72,7 +119,7 @@ Functions
Parse a URL into broken-down credential fields.
Example
--------
+~~~~~~~
The example below shows how the functions of the credential API could be
used to login to a fictitious "foo" service on a remote host:
@@ -135,8 +182,10 @@ credentials from and to long-term storage (where "long-term" is simply
longer than a single git process; e.g., credentials may be stored
in-memory for a few minutes, or indefinitely on disk).
-Each helper is specified by a single string. The string is transformed
-by git into a command to be executed using these rules:
+Each helper is specified by a single string in the configuration
+variable `credential.helper` (and others, see linkgit:git-config[1]).
+The string is transformed by git into a command to be executed using
+these rules:
1. If the helper string begins with "!", it is considered a shell
snippet, and everything after the "!" becomes the command.
@@ -192,42 +241,9 @@ appended to its command line, which is one of:
Remove a matching credential, if any, from the helper's storage.
The details of the credential will be provided on the helper's stdin
-stream. The credential is split into a set of named attributes.
-Attributes are provided to the helper, one per line. Each attribute is
-specified by a key-value pair, separated by an `=` (equals) sign,
-followed by a newline. The key may contain any bytes except `=`,
-newline, or NUL. The value may contain any bytes except newline or NUL.
-In both cases, all bytes are treated as-is (i.e., there is no quoting,
-and one cannot transmit a value with newline or NUL in it). The list of
-attributes is terminated by a blank line or end-of-file.
-
-Git will send the following attributes (but may not send all of
-them for a given credential; for example, a `host` attribute makes no
-sense when dealing with a non-network protocol):
-
-`protocol`::
-
- The protocol over which the credential will be used (e.g.,
- `https`).
-
-`host`::
-
- The remote hostname for a network credential.
-
-`path`::
-
- The path with which the credential will be used. E.g., for
- accessing a remote https repository, this will be the
- repository's path on the server.
-
-`username`::
-
- The credential's username, if we already have one (e.g., from a
- URL, from the user, or from a previously run helper).
-
-`password`::
-
- The credential's password, if we are asking it to be stored.
+stream. The exact format is the same as the input/output format of the
+`git credential` plumbing command (see the section `INPUT/OUTPUT
+FORMAT` in linkgit:git-credential[7] for a detailed specification).
For a `get` operation, the helper should produce a list of attributes
on stdout in the same format. A helper is free to produce a subset, or
@@ -243,3 +259,10 @@ request.
If a helper receives any other operation, it should silently ignore the
request. This leaves room for future operations to be added (older
helpers will just ignore the new requests).
+
+See also
+--------
+
+linkgit:gitcredentials[7]
+
+linkgit:git-config[5] (See configuration variables `credential.*`)
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 4b92514..3062389 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -21,7 +21,7 @@ that allow to change the behavior of a command.
* There are basically two forms of options:
'Short options' consist of one dash (`-`) and one alphanumeric
character.
- 'Long options' begin with two dashes (`\--`) and some
+ 'Long options' begin with two dashes (`--`) and some
alphanumeric characters.
* Options are case-sensitive.
@@ -31,7 +31,7 @@ The parse-options API allows:
* 'sticked' and 'separate form' of options with arguments.
`-oArg` is sticked, `-o Arg` is separate form.
- `\--option=Arg` is sticked, `\--option Arg` is separate form.
+ `--option=Arg` is sticked, `--option Arg` is separate form.
* Long options may be 'abbreviated', as long as the abbreviation
is unambiguous.
@@ -39,11 +39,12 @@ The parse-options API allows:
* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
* Boolean long options can be 'negated' (or 'unset') by prepending
- `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
+ `no-`, e.g. `--no-abbrev` instead of `--abbrev`. Conversely,
+ options that begin with `no-` can be 'negated' by removing it.
-* Options and non-option arguments can clearly be separated using the `\--`
- option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that
- `\--this-is-a-file` must not be processed as an option.
+* Options and non-option arguments can clearly be separated using the `--`
+ option, e.g. `-a -b --option -- --this-is-a-file` indicates that
+ `--this-is-a-file` must not be processed as an option.
Steps to parse options
----------------------
@@ -75,7 +76,7 @@ before the full parser, which in turn shows the full help message.
Flags are the bitwise-or of:
`PARSE_OPT_KEEP_DASHDASH`::
- Keep the `\--` that usually separates options from
+ Keep the `--` that usually separates options from
non-option arguments.
`PARSE_OPT_STOP_AT_NON_OPTION`::
@@ -113,22 +114,22 @@ say `static struct option builtin_add_options[]`.
There are some macros to easily define options:
`OPT__ABBREV(&int_var)`::
- Add `\--abbrev[=<n>]`.
+ Add `--abbrev[=<n>]`.
`OPT__COLOR(&int_var, description)`::
- Add `\--color[=<when>]` and `--no-color`.
+ Add `--color[=<when>]` and `--no-color`.
`OPT__DRY_RUN(&int_var, description)`::
- Add `-n, \--dry-run`.
+ Add `-n, --dry-run`.
`OPT__FORCE(&int_var, description)`::
- Add `-f, \--force`.
+ Add `-f, --force`.
`OPT__QUIET(&int_var, description)`::
- Add `-q, \--quiet`.
+ Add `-q, --quiet`.
`OPT__VERBOSE(&int_var, description)`::
- Add `-v, \--verbose`.
+ Add `-v, --verbose`.
`OPT_GROUP(description)`::
Start an option group. `description` is a short string that
@@ -215,10 +216,10 @@ The last element of the array must be `OPT_END()`.
If not stated otherwise, interpret the arguments as follows:
* `short` is a character for the short option
- (e.g. `{apostrophe}e{apostrophe}` for `-e`, use `0` to omit),
+ (e.g. `'e'` for `-e`, use `0` to omit),
* `long` is a string for the long option
- (e.g. `"example"` for `\--example`, use `NULL` to omit),
+ (e.g. `"example"` for `--example`, use `NULL` to omit),
* `int_var` is an integer variable,
@@ -242,10 +243,10 @@ The function must be defined in this form:
The callback mechanism is as follows:
* 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
+ 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()`.
- For example, do `*(unsigned long *)opt\->value = 42;` to get 42
+ For example, do `*(unsigned long *)opt->value = 42;` to get 42
into an `unsigned long` variable.
* Return value `0` indicates success and non-zero return
diff --git a/Documentation/technical/api-revision-walking.txt b/Documentation/technical/api-revision-walking.txt
index 996da05..b7d0d9a 100644
--- a/Documentation/technical/api-revision-walking.txt
+++ b/Documentation/technical/api-revision-walking.txt
@@ -56,6 +56,11 @@ function.
returning a `struct commit *` each time you call it. The end of the
revision list is indicated by returning a NULL pointer.
+`reset_revision_walk`::
+
+ Reset the flags used by the revision walking api. You can use
+ this to do multiple sequencial revision walks.
+
Data structures
---------------
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 8930b3f..9d25b30 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -113,9 +113,22 @@ GIT index format
are encoded in 7-bit ASCII and the encoding cannot contain a NUL
byte (iow, this is a UNIX pathname).
+ (Version 4) In version 4, the entry path name is prefix-compressed
+ relative to the path name for the previous entry (the very first
+ entry is encoded as if the path name for the previous entry is an
+ empty string). At the beginning of an entry, an integer N in the
+ variable width encoding (the same encoding as the offset is encoded
+ for OFS_DELTA pack entries; see pack-format.txt) is stored, followed
+ by a NUL-terminated string S. Removing N bytes from the end of the
+ path name for the previous entry, and replacing it with the string S
+ yields the path name for this entry.
+
1-8 nul bytes as necessary to pad the entry to a multiple of eight bytes
while keeping the name NUL-terminated.
+ (Version 4) In version 4, the padding after the pathname does not
+ exist.
+
== Extensions
=== Cached tree
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index 546980c..49cdc57 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -351,7 +351,7 @@ Then the server will start sending its packfile data.
A simple clone may look like this (with no 'have' lines):
----
- C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+ C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
side-band-64k ofs-delta\n
C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
@@ -367,7 +367,7 @@ A simple clone may look like this (with no 'have' lines):
An incremental update (fetch) response might look like this:
----
- C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+ C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
side-band-64k ofs-delta\n
C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
diff --git a/Documentation/technical/protocol-common.txt b/Documentation/technical/protocol-common.txt
index d30a1b9..fb7ff08 100644
--- a/Documentation/technical/protocol-common.txt
+++ b/Documentation/technical/protocol-common.txt
@@ -36,7 +36,7 @@ More specifically, they:
. They cannot have ASCII control characters (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`,
- caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+ caret `^`, colon `:`, question-mark `?`, asterisk `*`,
or open bracket `[` anywhere.
. They cannot end with a slash `/` nor a dot `.`.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index f13a846..02ed566 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1582,7 +1582,7 @@ Checking the repository for corruption
The linkgit:git-fsck[1] command runs a number of self-consistency checks
on the repository, and reports on any problems. This may take some
-time. The most common warning by far is about "dangling" objects:
+time.
-------------------------------------------------
$ git fsck
@@ -1597,9 +1597,11 @@ dangling tree b24c2473f1fd3d91352a624795be026d64c8841f
...
-------------------------------------------------
-Dangling objects are not a problem. At worst they may take up a little
-extra disk space. They can sometimes provide a last-resort method for
-recovering lost work--see <<dangling-objects>> for details.
+You will see informational messages on dangling objects. They are objects
+that still exist in the repository but are no longer referenced by any of
+your branches, and can (and will) be removed after a while with "gc".
+You can run `git fsck --no-dangling` to suppress these messages, and still
+view real errors.
[[recovering-lost-changes]]
Recovering lost changes
@@ -1609,7 +1611,7 @@ Recovering lost changes
Reflogs
^^^^^^^
-Say you modify a branch with `linkgit:git-reset[1] --hard`, and then
+Say you modify a branch with +linkgit:git-reset[1] \--hard+, and then
realize that the branch was the only reference you had to that point in
history.
@@ -3295,15 +3297,12 @@ it is with linkgit:git-fsck[1]; this may be time-consuming.
Assume the output looks like this:
------------------------------------------------
-$ git fsck --full
+$ git fsck --full --no-dangling
broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
to blob 4b9458b3786228369c63936db65827de3cc06200
missing blob 4b9458b3786228369c63936db65827de3cc06200
------------------------------------------------
-(Typically there will be some "dangling object" messages too, but they
-aren't interesting.)
-
Now you know that blob 4b9458b3 is missing, and that the tree 2d9263c6
points to it. If you could find just one copy of that missing blob
object, possibly in some other repository, you could move it into
@@ -4208,7 +4207,7 @@ commits one by one with the function `get_revision()`.
If you are interested in more details of the revision walking process,
just have a look at the first implementation of `cmd_log()`; call
-`git show v1.3.0{tilde}155^2{tilde}4` and scroll down to that function (note that you
+`git show v1.3.0~155^2~4` and scroll down to that function (note that you
no longer need to call `setup_pager()` directly).
Nowadays, `git log` is a builtin, which means that it is _contained_ in the
@@ -4271,9 +4270,9 @@ Two things are interesting here:
negative numbers in case of different errors--and 0 on success.
- the variable `sha1` in the function signature of `get_sha1()` is `unsigned
- char {asterisk}`, but is actually expected to be a pointer to `unsigned
+ char *`, but is actually expected to be a pointer to `unsigned
char[20]`. This variable will contain the 160-bit SHA-1 of the given
- commit. Note that whenever a SHA-1 is passed as `unsigned char {asterisk}`, it
+ commit. Note that whenever a SHA-1 is passed as `unsigned char *`, it
is the binary representation, as opposed to the ASCII representation in
hex characters, which is passed as `char *`.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 5b54635..fde74a6 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.9.7
+DEF_VER=v1.7.11.GIT
LF='
'
@@ -12,7 +12,7 @@ if test -f version
then
VN=$(cat version) || VN="$DEF_VER"
elif test -d .git -o -f .git &&
- VN=$(git describe --match "v[0-9]*" --abbrev=4 HEAD 2>/dev/null) &&
+ VN=$(git describe --match "v[0-9]*" --abbrev=7 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
diff --git a/INSTALL b/INSTALL
index 58b2b86..28f34bd 100644
--- a/INSTALL
+++ b/INSTALL
@@ -131,6 +131,9 @@ Issues of note:
use English. Under autoconf the configure script will do this
automatically if it can't find libintl on the system.
+ - Python version 2.6 or later is needed to use the git-p4
+ interface to Perforce.
+
- Some platform specific issues are dealt with Makefile rules,
but depending on your specific installation, you may not
have all the libraries/tools needed, or you may have
@@ -158,11 +161,9 @@ Issues of note:
makeinfo and docbook2X. Version 0.8.3 is known to work.
Building and installing the pdf file additionally requires
- dblatex. Version 0.2.7 with asciidoc >= 8.2.7 is known to work.
+ dblatex. Version >= 0.2.7 is known to work.
- The documentation is written for AsciiDoc 7, but by default
- uses some compatibility wrappers to work on AsciiDoc 8. If you have
- AsciiDoc 7, try "make ASCIIDOC7=YesPlease".
+ All formats require at least asciidoc 8.4.1.
There are also "make quick-install-doc", "make quick-install-man"
and "make quick-install-html" which install preformatted man pages
diff --git a/Makefile b/Makefile
index e4f8e0e..285c660 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,9 @@ all::
# A translated Git requires GNU libintl or another gettext implementation,
# plus libintl-perl at runtime.
#
+# Define USE_GETTEXT_SCHEME and set it to 'fallthrough', if you don't trust
+# the installed gettext translation of the shell scripts output.
+#
# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't
# trust the langinfo.h's nl_langinfo(CODESET) function to return the
# current character set. GNU and Solaris have a nl_langinfo(CODESET),
@@ -155,6 +158,9 @@ all::
# Define NO_PREAD if you have a problem with pread() system call (e.g.
# cygwin1.dll before v1.5.22).
#
+# Define NO_THREAD_SAFE_PREAD if your pread() implementation is not
+# thread-safe. (e.g. compat/pread.c or cygwin)
+#
# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
# generally faster on your platform than accessing the working directory.
#
@@ -200,8 +206,6 @@ all::
# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
# field that counts the on-disk footprint in 512-byte blocks.
#
-# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7
-#
# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
# (not v1.73 or v1.71).
#
@@ -244,6 +248,9 @@ all::
# 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.
#
+# Define NO_INSTALL_HARDLINKS if you prefer to use either symbolic links or
+# copies to install built-in git commands e.g. git-cat-file.
+#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
#
@@ -285,6 +292,18 @@ all::
# dependency rules.
#
# Define NATIVE_CRLF if your platform uses CRLF for line endings.
+#
+# Define XDL_FAST_HASH to use an alternative line-hashing method in
+# the diff algorithm. It gives a nice speedup if your processor has
+# fast unaligned word loads. Does NOT work on big-endian systems!
+# Enabled by default on x86_64.
+#
+# Define GIT_USER_AGENT if you want to change how git identifies itself during
+# network interactions. The default is "git/$(GIT_VERSION)".
+#
+# Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
+# (defaults to "man") if you want to have a different default when
+# "git help" is called without a parameter specifying the format.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -378,6 +397,9 @@ BUILTIN_OBJS =
BUILT_INS =
COMPAT_CFLAGS =
COMPAT_OBJS =
+XDIFF_OBJS =
+VCSSVN_OBJS =
+GENERATED_H =
EXTRA_CPPFLAGS =
LIB_H =
LIB_OBJS =
@@ -432,6 +454,7 @@ SCRIPT_PERL += git-send-email.perl
SCRIPT_PERL += git-svn.perl
SCRIPT_PYTHON += git-remote-testgit.py
+SCRIPT_PYTHON += git-p4.py
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
@@ -446,15 +469,15 @@ EXTRA_PROGRAMS =
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
+PROGRAM_OBJS += credential-store.o
PROGRAM_OBJS += daemon.o
PROGRAM_OBJS += fast-import.o
+PROGRAM_OBJS += http-backend.o
PROGRAM_OBJS += imap-send.o
+PROGRAM_OBJS += sh-i18n--envsubst.o
PROGRAM_OBJS += shell.o
PROGRAM_OBJS += show-index.o
PROGRAM_OBJS += upload-pack.o
-PROGRAM_OBJS += http-backend.o
-PROGRAM_OBJS += sh-i18n--envsubst.o
-PROGRAM_OBJS += credential-store.o
# Binary suffix, set to .exe for Windows builds
X =
@@ -462,27 +485,25 @@ X =
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
TEST_PROGRAMS_NEED_X += test-chmtime
-TEST_PROGRAMS_NEED_X += test-credential
TEST_PROGRAMS_NEED_X += test-ctype
TEST_PROGRAMS_NEED_X += test-date
TEST_PROGRAMS_NEED_X += test-delta
TEST_PROGRAMS_NEED_X += test-dump-cache-tree
-TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
TEST_PROGRAMS_NEED_X += test-genrandom
TEST_PROGRAMS_NEED_X += test-index-version
TEST_PROGRAMS_NEED_X += test-line-buffer
TEST_PROGRAMS_NEED_X += test-match-trees
+TEST_PROGRAMS_NEED_X += test-mergesort
TEST_PROGRAMS_NEED_X += test-mktemp
-TEST_PROGRAMS_NEED_X += test-obj-pool
TEST_PROGRAMS_NEED_X += test-parse-options
TEST_PROGRAMS_NEED_X += test-path-utils
+TEST_PROGRAMS_NEED_X += test-revision-walking
TEST_PROGRAMS_NEED_X += test-run-command
+TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain
-TEST_PROGRAMS_NEED_X += test-string-pool
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
-TEST_PROGRAMS_NEED_X += test-treap
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
@@ -538,36 +559,60 @@ LIB_FILE=libgit.a
XDIFF_LIB=xdiff/lib.a
VCSSVN_LIB=vcs-svn/lib.a
+LIB_H += xdiff/xinclude.h
+LIB_H += xdiff/xmacros.h
+LIB_H += xdiff/xdiff.h
+LIB_H += xdiff/xtypes.h
+LIB_H += xdiff/xutils.h
+LIB_H += xdiff/xprepare.h
+LIB_H += xdiff/xdiffi.h
+LIB_H += xdiff/xemit.h
+
+LIB_H += vcs-svn/line_buffer.h
+LIB_H += vcs-svn/sliding_window.h
+LIB_H += vcs-svn/repo_tree.h
+LIB_H += vcs-svn/fast_export.h
+LIB_H += vcs-svn/svndiff.h
+LIB_H += vcs-svn/svndump.h
+
+GENERATED_H += common-cmds.h
+
LIB_H += advice.h
LIB_H += archive.h
LIB_H += argv-array.h
LIB_H += attr.h
+LIB_H += bisect.h
LIB_H += blob.h
+LIB_H += branch.h
LIB_H += builtin.h
LIB_H += bulk-checkin.h
-LIB_H += cache.h
+LIB_H += bundle.h
LIB_H += cache-tree.h
+LIB_H += cache.h
LIB_H += color.h
+LIB_H += column.h
LIB_H += commit.h
LIB_H += compat/bswap.h
LIB_H += compat/cygwin.h
LIB_H += compat/mingw.h
LIB_H += compat/obstack.h
+LIB_H += compat/precompose_utf8.h
LIB_H += compat/terminal.h
+LIB_H += compat/win32/dirent.h
+LIB_H += compat/win32/poll.h
LIB_H += compat/win32/pthread.h
LIB_H += compat/win32/syslog.h
-LIB_H += compat/win32/poll.h
-LIB_H += compat/win32/dirent.h
LIB_H += connected.h
LIB_H += convert.h
LIB_H += credential.h
LIB_H += csum-file.h
LIB_H += decorate.h
LIB_H += delta.h
-LIB_H += diffcore.h
LIB_H += diff.h
+LIB_H += diffcore.h
LIB_H += dir.h
LIB_H += exec_cmd.h
+LIB_H += fetch-pack.h
LIB_H += fmt-merge-msg.h
LIB_H += fsck.h
LIB_H += gettext.h
@@ -577,6 +622,7 @@ LIB_H += graph.h
LIB_H += grep.h
LIB_H += hash.h
LIB_H += help.h
+LIB_H += http.h
LIB_H += kwset.h
LIB_H += levenshtein.h
LIB_H += list-objects.h
@@ -585,19 +631,21 @@ LIB_H += log-tree.h
LIB_H += mailmap.h
LIB_H += merge-file.h
LIB_H += merge-recursive.h
-LIB_H += notes.h
+LIB_H += mergesort.h
LIB_H += notes-cache.h
LIB_H += notes-merge.h
+LIB_H += notes.h
LIB_H += object.h
-LIB_H += pack.h
LIB_H += pack-refs.h
LIB_H += pack-revindex.h
+LIB_H += pack.h
LIB_H += parse-options.h
LIB_H += patch-ids.h
LIB_H += pkt-line.h
LIB_H += progress.h
LIB_H += prompt.h
LIB_H += quote.h
+LIB_H += reachable.h
LIB_H += reflog-walk.h
LIB_H += refs.h
LIB_H += remote.h
@@ -605,9 +653,11 @@ LIB_H += rerere.h
LIB_H += resolve-undo.h
LIB_H += revision.h
LIB_H += run-command.h
+LIB_H += send-pack.h
LIB_H += sequencer.h
LIB_H += sha1-array.h
LIB_H += sha1-lookup.h
+LIB_H += shortlog.h
LIB_H += sideband.h
LIB_H += sigchain.h
LIB_H += strbuf.h
@@ -615,13 +665,18 @@ LIB_H += streaming.h
LIB_H += string-list.h
LIB_H += submodule.h
LIB_H += tag.h
+LIB_H += tar.h
LIB_H += thread-utils.h
LIB_H += transport.h
-LIB_H += tree.h
LIB_H += tree-walk.h
+LIB_H += tree.h
LIB_H += unpack-trees.h
+LIB_H += url.h
LIB_H += userdiff.h
LIB_H += utf8.h
+LIB_H += varint.h
+LIB_H += walker.h
+LIB_H += wt-status.h
LIB_H += xdiff-interface.h
LIB_H += xdiff/xdiff.h
@@ -642,6 +697,7 @@ LIB_OBJS += bulk-checkin.o
LIB_OBJS += bundle.o
LIB_OBJS += cache-tree.o
LIB_OBJS += color.o
+LIB_OBJS += column.o
LIB_OBJS += combine-diff.o
LIB_OBJS += commit.o
LIB_OBJS += compat/obstack.o
@@ -671,8 +727,8 @@ LIB_OBJS += entry.o
LIB_OBJS += environment.o
LIB_OBJS += exec_cmd.o
LIB_OBJS += fsck.o
-LIB_OBJS += gpg-interface.o
LIB_OBJS += gettext.o
+LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
LIB_OBJS += hash.o
@@ -689,6 +745,7 @@ LIB_OBJS += mailmap.o
LIB_OBJS += match-trees.o
LIB_OBJS += merge-file.o
LIB_OBJS += merge-recursive.o
+LIB_OBJS += mergesort.o
LIB_OBJS += name-hash.o
LIB_OBJS += notes.o
LIB_OBJS += notes-cache.o
@@ -720,9 +777,9 @@ LIB_OBJS += rerere.o
LIB_OBJS += resolve-undo.o
LIB_OBJS += revision.o
LIB_OBJS += run-command.o
+LIB_OBJS += sequencer.o
LIB_OBJS += server-info.o
LIB_OBJS += setup.o
-LIB_OBJS += sequencer.o
LIB_OBJS += sha1-array.o
LIB_OBJS += sha1-lookup.o
LIB_OBJS += sha1_file.o
@@ -747,6 +804,8 @@ LIB_OBJS += url.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
+LIB_OBJS += varint.o
+LIB_OBJS += version.o
LIB_OBJS += walker.o
LIB_OBJS += wrapper.o
LIB_OBJS += write_or_die.o
@@ -770,10 +829,12 @@ BUILTIN_OBJS += builtin/checkout-index.o
BUILTIN_OBJS += builtin/checkout.o
BUILTIN_OBJS += builtin/clean.o
BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/column.o
BUILTIN_OBJS += builtin/commit-tree.o
BUILTIN_OBJS += builtin/commit.o
BUILTIN_OBJS += builtin/config.o
BUILTIN_OBJS += builtin/count-objects.o
+BUILTIN_OBJS += builtin/credential.o
BUILTIN_OBJS += builtin/describe.o
BUILTIN_OBJS += builtin/diff-files.o
BUILTIN_OBJS += builtin/diff-index.o
@@ -851,6 +912,8 @@ BUILTIN_OBJS += builtin/write-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
EXTLIBS =
+GIT_USER_AGENT = git/$(GIT_VERSION)
+
#
# Platform specific tweaks
#
@@ -859,6 +922,9 @@ EXTLIBS =
# because maintaining the nesting to match is a pain. If
# we had "elif" things would have been much nicer...
+ifeq ($(uname_M),x86_64)
+ XDL_FAST_HASH = YesPlease
+endif
ifeq ($(uname_S),OSF1)
# Need this for u_short definitions et al
BASIC_CFLAGS += -D_OSF_SOURCE
@@ -934,6 +1000,8 @@ ifeq ($(uname_S),Darwin)
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
HAVE_DEV_TTY = YesPlease
+ COMPAT_OBJS += compat/precompose_utf8.o
+ BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@@ -995,6 +1063,7 @@ ifeq ($(uname_O),Cygwin)
NO_IPV6 = YesPlease
OLD_ICONV = UnfortunatelyYes
endif
+ NO_THREAD_SAFE_PREAD = YesPlease
NEEDS_LIBICONV = YesPlease
NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
@@ -1180,6 +1249,7 @@ ifeq ($(uname_S),Windows)
BLK_SHA1 = YesPlease
NO_POSIX_GOODIES = UnfortunatelyYes
NATIVE_CRLF = YesPlease
+ DEFAULT_HELP_FORMAT = html
CC = compat/vcbuild/scripts/clink.pl
AR = compat/vcbuild/scripts/lib.pl
@@ -1529,6 +1599,7 @@ ifdef GETTEXT_POISON
endif
ifdef NO_GETTEXT
BASIC_CFLAGS += -DNO_GETTEXT
+ USE_GETTEXT_SCHEME ?= fallthrough
endif
ifdef NO_STRCASESTR
COMPAT_CFLAGS += -DNO_STRCASESTR
@@ -1602,6 +1673,10 @@ endif
ifdef NO_PREAD
COMPAT_CFLAGS += -DNO_PREAD
COMPAT_OBJS += compat/pread.o
+ NO_THREAD_SAFE_PREAD = YesPlease
+endif
+ifdef NO_THREAD_SAFE_PREAD
+ BASIC_CFLAGS += -DNO_THREAD_SAFE_PREAD
endif
ifdef NO_FAST_WORKING_DIRECTORY
BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
@@ -1731,6 +1806,10 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS
MSGFMT += --check --statistics
endif
+ifneq (,$(XDL_FAST_HASH))
+ BASIC_CFLAGS += -DXDL_FAST_HASH
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
endif
@@ -1773,8 +1852,8 @@ ifndef V
endif
endif
-ifdef ASCIIDOC7
- export ASCIIDOC7
+ifdef NO_INSTALL_HARDLINKS
+ export NO_INSTALL_HARDLINKS
endif
### profile feedback build
@@ -1843,6 +1922,25 @@ DEFAULT_PAGER_CQ_SQ = $(subst ','\'',$(DEFAULT_PAGER_CQ))
BASIC_CFLAGS += -DDEFAULT_PAGER='$(DEFAULT_PAGER_CQ_SQ)'
endif
+ifdef SHELL_PATH
+SHELL_PATH_CQ = "$(subst ",\",$(subst \,\\,$(SHELL_PATH)))"
+SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHELL_PATH_CQ))
+
+BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)'
+endif
+
+GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT))
+GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))"
+GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ))
+GIT-USER-AGENT: FORCE
+ @if test x'$(GIT_USER_AGENT_SQ)' != x"`cat GIT-USER-AGENT 2>/dev/null`"; then \
+ echo '$(GIT_USER_AGENT_SQ)' >GIT-USER-AGENT; \
+ fi
+
+ifdef DEFAULT_HELP_FORMAT
+BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
+endif
+
ALL_CFLAGS += $(BASIC_CFLAGS)
ALL_LDFLAGS += $(BASIC_LDFLAGS)
@@ -1889,8 +1987,41 @@ shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
strip: $(PROGRAMS) git$X
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
-git.o: common-cmds.h
-git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
+### Target-specific flags and dependencies
+
+# The generic compilation pattern rule and automatically
+# computed header dependencies (falling back to a dependency on
+# LIB_H) are enough to describe how most targets should be built,
+# but some targets are special enough to need something a little
+# different.
+#
+# - When a source file "foo.c" #includes a generated header file,
+# we need to list that dependency for the "foo.o" target.
+#
+# We also list it from other targets that are built from foo.c
+# like "foo.sp" and "foo.s", even though that is easy to forget
+# to do because the generated header is already present around
+# after a regular build attempt.
+#
+# - Some code depends on configuration kept in makefile
+# variables. The target-specific variable EXTRA_CPPFLAGS can
+# be used to convey that information to the C preprocessor
+# using -D options.
+#
+# The "foo.o" target should have a corresponding dependency on
+# a file that changes when the value of the makefile variable
+# changes. For example, targets making use of the
+# $(GIT_VERSION) variable depend on GIT-VERSION-FILE.
+#
+# Technically the ".sp" and ".s" targets do not need this
+# dependency because they are force-built, but they get the
+# same dependency for consistency. This way, you do not have to
+# know how each target is implemented. And it means the
+# dependencies here will not need to change if the force-build
+# details change some day.
+
+git.sp git.s git.o: GIT-PREFIX
+git.sp git.s git.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"'
@@ -1899,14 +2030,19 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
-help.sp help.o: common-cmds.h
+help.sp help.s help.o: common-cmds.h
-builtin/help.sp builtin/help.o: common-cmds.h
+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"'
+version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
+version.sp version.s version.o: EXTRA_CPPFLAGS = \
+ '-DGIT_VERSION="$(GIT_VERSION)"' \
+ '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)'
+
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
ln git$X $@ 2>/dev/null || \
@@ -1918,34 +2054,47 @@ common-cmds.h: ./generate-cmdlist.sh command-list.txt
common-cmds.h: $(wildcard Documentation/git-*.txt)
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
+SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
+ $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
+ $(gitwebdir_SQ):$(PERL_PATH_SQ)
define cmd_munge_script
$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-e 's|@@DIFF@@|$(DIFF_SQ)|' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
+ -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \
-e $(BROKEN_PATH_FIX) \
+ -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
+ -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
$@.sh >$@+
endef
-$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
+GIT-SCRIPT-DEFINES: FORCE
+ @FLAGS='$(SCRIPT_DEFINES)'; \
+ if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+ echo 1>&2 " * new script parameters"; \
+ echo "$$FLAGS" >$@; \
+ fi
+
+
+$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
-$(SCRIPT_LIB) : % : %.sh
+$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
mv $@+ $@
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
-perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
+perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
-$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
+$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
sed -e '1{' \
@@ -1965,14 +2114,8 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
gitweb:
$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
-git-instaweb: git-instaweb.sh gitweb
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
- -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
- -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
- -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
- $@.sh > $@+ && \
+git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES
+ $(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
else # NO_PERL
@@ -1986,7 +2129,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
endif # NO_PERL
ifndef NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX
$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
@@ -2008,32 +2151,36 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
mv $@+ $@
endif # NO_PYTHON
-configure: configure.ac
+configure: configure.ac GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $<+ && \
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
$< > $<+ && \
autoconf -o $@ $<+ && \
$(RM) $<+
-# These can record GIT_VERSION
-git.o git.spec \
- $(patsubst %.sh,%,$(SCRIPT_SH)) \
- $(patsubst %.perl,%,$(SCRIPT_PERL)) \
- : GIT-VERSION-FILE
+XDIFF_OBJS += xdiff/xdiffi.o
+XDIFF_OBJS += xdiff/xprepare.o
+XDIFF_OBJS += xdiff/xutils.o
+XDIFF_OBJS += xdiff/xemit.o
+XDIFF_OBJS += xdiff/xmerge.o
+XDIFF_OBJS += xdiff/xpatience.o
+XDIFF_OBJS += xdiff/xhistogram.o
+
+VCSSVN_OBJS += vcs-svn/line_buffer.o
+VCSSVN_OBJS += vcs-svn/sliding_window.o
+VCSSVN_OBJS += vcs-svn/repo_tree.o
+VCSSVN_OBJS += vcs-svn/fast_export.o
+VCSSVN_OBJS += vcs-svn/svndiff.o
+VCSSVN_OBJS += vcs-svn/svndump.o
TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
-GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
+OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
+ $(XDIFF_OBJS) \
+ $(VCSSVN_OBJS) \
git.o
ifndef NO_CURL
- GIT_OBJS += http.o http-walker.o remote-curl.o
+ OBJECTS += http.o http-walker.o remote-curl.o
endif
-XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
- xdiff/xmerge.o xdiff/xpatience.o xdiff/xhistogram.o
-VCSSVN_OBJS = vcs-svn/string_pool.o vcs-svn/line_buffer.o \
- vcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o
-VCSSVN_TEST_OBJS = test-obj-pool.o test-string-pool.o \
- test-line-buffer.o test-treap.o
-OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
@@ -2132,57 +2279,32 @@ else
# Dependencies on automatically generated headers such as common-cmds.h
# should _not_ be included here, since they are necessary even when
# building an object for the first time.
-#
-# XXX. Please check occasionally that these include all dependencies
-# gcc detects!
-
-$(GIT_OBJS): $(LIB_H)
-builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o transport.o: branch.h
-builtin/bundle.o bundle.o transport.o: bundle.h
-builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
-builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
-builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h
-builtin/send-pack.o transport.o: send-pack.h
-builtin/log.o builtin/shortlog.o: shortlog.h
-builtin/prune.o builtin/reflog.o reachable.o: reachable.h
-builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
-builtin/tar-tree.o archive-tar.o: tar.h
-connect.o transport.o url.o http-backend.o: url.h
-http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
-http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
-
-xdiff-interface.o $(XDIFF_OBJS): \
- xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
- xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
-$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \
- vcs-svn/obj_pool.h vcs-svn/trp.h vcs-svn/string_pool.h \
- vcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \
- vcs-svn/svndump.h
-
-test-svn-fe.o: vcs-svn/svndump.h
+$(OBJECTS): $(LIB_H)
endif
+exec_cmd.sp exec_cmd.s exec_cmd.o: GIT-PREFIX
exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
'-DBINDIR="$(bindir_relative_SQ)"' \
'-DPREFIX="$(prefix_SQ)"'
+builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX
builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
+config.sp config.s config.o: GIT-PREFIX
config.sp config.s config.o: EXTRA_CPPFLAGS = \
-DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
+attr.sp attr.s attr.o: GIT-PREFIX
attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
-DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
+gettext.sp gettext.s gettext.o: GIT-PREFIX
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
-DGIT_LOCALE_PATH='"$(localedir_SQ)"'
-http.sp http.s http.o: EXTRA_CPPFLAGS = \
- -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
-
ifdef NO_EXPAT
http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
endif
@@ -2230,6 +2352,8 @@ $(XDIFF_LIB): $(XDIFF_OBJS)
$(VCSSVN_LIB): $(VCSSVN_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(VCSSVN_OBJS)
+export DEFAULT_EDITOR DEFAULT_PAGER
+
doc:
$(MAKE) -C Documentation all
@@ -2254,7 +2378,7 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
--keyword=_ --keyword=N_ --keyword="Q_:1,2"
XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell
XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
-LOCALIZED_C := $(C_OBJ:o=c)
+LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
LOCALIZED_SH := $(SCRIPT_SH)
LOCALIZED_PERL := $(SCRIPT_PERL)
@@ -2301,14 +2425,22 @@ cscope:
$(FIND_SOURCE_FILES) | xargs cscope -b
### Detect prefix changes
-TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
- $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
- $(localedir_SQ)
+TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
+ $(localedir_SQ)
+
+GIT-PREFIX: FORCE
+ @FLAGS='$(TRACK_PREFIX)'; \
+ if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \
+ echo 1>&2 " * new prefix flags"; \
+ echo "$$FLAGS" >GIT-PREFIX; \
+ fi
+
+TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME)
GIT-CFLAGS: FORCE
@FLAGS='$(TRACK_CFLAGS)'; \
if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
- echo 1>&2 " * new build flags or prefix"; \
+ echo 1>&2 " * new build flags"; \
echo "$$FLAGS" >GIT-CFLAGS; \
fi
@@ -2334,6 +2466,10 @@ GIT-BUILD-OPTIONS: FORCE
@echo USE_LIBPCRE=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE)))'\' >>$@
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
+ @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@
+ifdef GIT_TEST_OPTS
+ @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@
+endif
ifdef GIT_TEST_CMP
@echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@
endif
@@ -2342,7 +2478,18 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
endif
@echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@
@echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@
- @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@
+ifdef GIT_PERF_REPEAT_COUNT
+ @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@
+endif
+ifdef GIT_PERF_REPO
+ @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@
+endif
+ifdef GIT_PERF_LARGE_REPO
+ @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@
+endif
+ifdef GIT_PERF_MAKE_OPTS
+ @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@
+endif
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
@@ -2378,6 +2525,11 @@ export NO_SVN_TESTS
test: all
$(MAKE) -C t/ all
+perf: all
+ $(MAKE) -C t/perf/ all
+
+.PHONY: test perf
+
test-ctype$X: ctype.o
test-date$X: date.o ctype.o
@@ -2388,8 +2540,6 @@ test-line-buffer$X: vcs-svn/lib.a
test-parse-options$X: parse-options.o parse-options-cb.o
-test-string-pool$X: vcs-svn/lib.a
-
test-svn-fe$X: vcs-svn/lib.a
.PRECIOUS: $(TEST_OBJS)
@@ -2482,19 +2632,21 @@ endif
{ test "$$bindir/" = "$$execdir/" || \
for p in git$X $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \
$(RM) "$$execdir/$$p" && \
- test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
+ test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \
cp "$$bindir/$$p" "$$execdir/$$p" || exit; \
done; \
} && \
for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
$(RM) "$$bindir/$$p" && \
+ test -z "$(NO_INSTALL_HARDLINKS)" && \
ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
cp "$$bindir/git$X" "$$bindir/$$p" || exit; \
done && \
for p in $(BUILT_INS); do \
$(RM) "$$execdir/$$p" && \
+ test -z "$(NO_INSTALL_HARDLINKS)" && \
ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
@@ -2502,6 +2654,7 @@ endif
remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
for p in $$remote_curl_aliases; do \
$(RM) "$$execdir/$$p" && \
+ test -z "$(NO_INSTALL_HARDLINKS)" && \
ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \
@@ -2539,7 +2692,7 @@ quick-install-html:
### Maintainer's dist rules
-git.spec: git.spec.in
+git.spec: git.spec.in GIT-VERSION-FILE
sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+
mv $@+ $@
@@ -2589,7 +2742,6 @@ dist-doc:
distclean: clean
$(RM) configure
- $(RM) po/git.pot
profile-clean:
$(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
@@ -2624,6 +2776,7 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui clean
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
+ $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES
.PHONY: all install profile-clean clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --git a/RelNotes b/RelNotes
index 3f4ce9f..19bb2eb 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.9.6.txt \ No newline at end of file
+Documentation/RelNotes/1.7.12.txt \ No newline at end of file
diff --git a/advice.c b/advice.c
index 65a0785..a492eea 100644
--- a/advice.c
+++ b/advice.c
@@ -1,6 +1,9 @@
#include "cache.h"
int advice_push_nonfastforward = 1;
+int advice_push_non_ff_current = 1;
+int advice_push_non_ff_default = 1;
+int advice_push_non_ff_matching = 1;
int advice_status_hints = 1;
int advice_commit_before_merge = 1;
int advice_resolve_conflict = 1;
@@ -12,6 +15,9 @@ static struct {
int *preference;
} advice_config[] = {
{ "pushnonfastforward", &advice_push_nonfastforward },
+ { "pushnonffcurrent", &advice_push_non_ff_current },
+ { "pushnonffdefault", &advice_push_non_ff_default },
+ { "pushnonffmatching", &advice_push_non_ff_matching },
{ "statushints", &advice_status_hints },
{ "commitbeforemerge", &advice_commit_before_merge },
{ "resolveconflict", &advice_resolve_conflict },
@@ -73,3 +79,17 @@ void NORETURN die_resolve_conflict(const char *me)
error_resolve_conflict(me);
die("Exiting because of an unresolved conflict.");
}
+
+void detach_advice(const char *new_name)
+{
+ const char fmt[] =
+ "Note: checking out '%s'.\n\n"
+ "You are in 'detached HEAD' state. You can look around, make experimental\n"
+ "changes and commit them, and you can discard any commits you make in this\n"
+ "state without impacting any branches by performing another checkout.\n\n"
+ "If you want to create a new branch to retain commits you create, you may\n"
+ "do so (now or later) by using -b with the checkout command again. Example:\n\n"
+ " git checkout -b new_branch_name\n\n";
+
+ fprintf(stderr, fmt, new_name);
+}
diff --git a/advice.h b/advice.h
index e5d0af7..f3cdbbf 100644
--- a/advice.h
+++ b/advice.h
@@ -4,6 +4,9 @@
#include "git-compat-util.h"
extern int advice_push_nonfastforward;
+extern int advice_push_non_ff_current;
+extern int advice_push_non_ff_default;
+extern int advice_push_non_ff_matching;
extern int advice_status_hints;
extern int advice_commit_before_merge;
extern int advice_resolve_conflict;
@@ -14,5 +17,6 @@ int git_default_advice_config(const char *var, const char *value);
void advise(const char *advice, ...);
int error_resolve_conflict(const char *me);
extern void NORETURN die_resolve_conflict(const char *me);
+void detach_advice(const char *new_name);
#endif /* ADVICE_H */
diff --git a/archive-tar.c b/archive-tar.c
index 20af005..0ba3f25 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "tar.h"
#include "archive.h"
+#include "streaming.h"
#include "run-command.h"
#define RECORDSIZE (512)
@@ -30,10 +31,9 @@ static void write_if_needed(void)
* queues up writes, so that all our write(2) calls write exactly one
* full block; pads writes to RECORDSIZE
*/
-static void write_blocked(const void *data, unsigned long size)
+static void do_write_blocked(const void *data, unsigned long size)
{
const char *buf = data;
- unsigned long tail;
if (offset) {
unsigned long chunk = BLOCKSIZE - offset;
@@ -54,6 +54,11 @@ static void write_blocked(const void *data, unsigned long size)
memcpy(block + offset, buf, size);
offset += size;
}
+}
+
+static void finish_record(void)
+{
+ unsigned long tail;
tail = offset % RECORDSIZE;
if (tail) {
memset(block + offset, 0, RECORDSIZE - tail);
@@ -62,6 +67,12 @@ static void write_blocked(const void *data, unsigned long size)
write_if_needed();
}
+static void write_blocked(const void *data, unsigned long size)
+{
+ do_write_blocked(data, size);
+ finish_record();
+}
+
/*
* The end of tar archives is marked by 2*512 nul bytes and after that
* follows the rest of the block (if any).
@@ -78,6 +89,33 @@ static void write_trailer(void)
}
/*
+ * queues up writes, so that all our write(2) calls write exactly one
+ * full block; pads writes to RECORDSIZE
+ */
+static int stream_blocked(const unsigned char *sha1)
+{
+ struct git_istream *st;
+ enum object_type type;
+ unsigned long sz;
+ char buf[BLOCKSIZE];
+ ssize_t readlen;
+
+ st = open_istream(sha1, &type, &sz, NULL);
+ if (!st)
+ return error("cannot stream blob %s", sha1_to_hex(sha1));
+ for (;;) {
+ readlen = read_istream(st, buf, sizeof(buf));
+ if (readlen <= 0)
+ break;
+ do_write_blocked(buf, readlen);
+ }
+ close_istream(st);
+ if (!readlen)
+ finish_record();
+ return readlen;
+}
+
+/*
* pax extended header records have the format "%u %s=%s\n". %u contains
* the size of the whole string (including the %u), the first %s is the
* keyword, the second one is the value. This function constructs such a
@@ -101,13 +139,13 @@ static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
static unsigned int ustar_header_chksum(const struct ustar_header *header)
{
- char *p = (char *)header;
+ const unsigned char *p = (const unsigned char *)header;
unsigned int chksum = 0;
- while (p < header->chksum)
+ while (p < (const unsigned char *)header->chksum)
chksum += *p++;
chksum += sizeof(header->chksum) * ' ';
p += sizeof(header->chksum);
- while (p < (char *)header + sizeof(struct ustar_header))
+ while (p < (const unsigned char *)header + sizeof(struct ustar_header))
chksum += *p++;
return chksum;
}
@@ -123,56 +161,101 @@ static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
return i;
}
+static void prepare_header(struct archiver_args *args,
+ struct ustar_header *header,
+ unsigned int mode, unsigned long size)
+{
+ sprintf(header->mode, "%07o", mode & 07777);
+ sprintf(header->size, "%011lo", S_ISREG(mode) ? size : 0);
+ sprintf(header->mtime, "%011lo", (unsigned long) args->time);
+
+ sprintf(header->uid, "%07o", 0);
+ sprintf(header->gid, "%07o", 0);
+ strlcpy(header->uname, "root", sizeof(header->uname));
+ strlcpy(header->gname, "root", sizeof(header->gname));
+ sprintf(header->devmajor, "%07o", 0);
+ sprintf(header->devminor, "%07o", 0);
+
+ memcpy(header->magic, "ustar", 6);
+ memcpy(header->version, "00", 2);
+
+ sprintf(header->chksum, "%07o", ustar_header_chksum(header));
+}
+
+static int write_extended_header(struct archiver_args *args,
+ const unsigned char *sha1,
+ const void *buffer, unsigned long size)
+{
+ struct ustar_header header;
+ unsigned int mode;
+ memset(&header, 0, sizeof(header));
+ *header.typeflag = TYPEFLAG_EXT_HEADER;
+ mode = 0100666;
+ sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
+ prepare_header(args, &header, mode, size);
+ write_blocked(&header, sizeof(header));
+ write_blocked(buffer, size);
+ return 0;
+}
+
static int write_tar_entry(struct archiver_args *args,
- const unsigned char *sha1, const char *path, size_t pathlen,
- unsigned int mode, void *buffer, unsigned long size)
+ const unsigned char *sha1,
+ const char *path, size_t pathlen,
+ unsigned int mode)
{
struct ustar_header header;
struct strbuf ext_header = STRBUF_INIT;
+ unsigned int old_mode = mode;
+ unsigned long size;
+ void *buffer;
int err = 0;
memset(&header, 0, sizeof(header));
- if (!sha1) {
- *header.typeflag = TYPEFLAG_GLOBAL_HEADER;
- mode = 0100666;
- strcpy(header.name, "pax_global_header");
- } else if (!path) {
- *header.typeflag = TYPEFLAG_EXT_HEADER;
- mode = 0100666;
- sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
+ if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
+ *header.typeflag = TYPEFLAG_DIR;
+ mode = (mode | 0777) & ~tar_umask;
+ } else if (S_ISLNK(mode)) {
+ *header.typeflag = TYPEFLAG_LNK;
+ mode |= 0777;
+ } else if (S_ISREG(mode)) {
+ *header.typeflag = TYPEFLAG_REG;
+ mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
} else {
- if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
- *header.typeflag = TYPEFLAG_DIR;
- mode = (mode | 0777) & ~tar_umask;
- } else if (S_ISLNK(mode)) {
- *header.typeflag = TYPEFLAG_LNK;
- mode |= 0777;
- } else if (S_ISREG(mode)) {
- *header.typeflag = TYPEFLAG_REG;
- mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
+ return error("unsupported file mode: 0%o (SHA1: %s)",
+ mode, sha1_to_hex(sha1));
+ }
+ if (pathlen > sizeof(header.name)) {
+ size_t plen = get_path_prefix(path, pathlen,
+ sizeof(header.prefix));
+ size_t rest = pathlen - plen - 1;
+ if (plen > 0 && rest <= sizeof(header.name)) {
+ memcpy(header.prefix, path, plen);
+ memcpy(header.name, path + plen + 1, rest);
} else {
- return error("unsupported file mode: 0%o (SHA1: %s)",
- mode, sha1_to_hex(sha1));
+ sprintf(header.name, "%s.data",
+ sha1_to_hex(sha1));
+ strbuf_append_ext_header(&ext_header, "path",
+ path, pathlen);
}
- if (pathlen > sizeof(header.name)) {
- size_t plen = get_path_prefix(path, pathlen,
- sizeof(header.prefix));
- size_t rest = pathlen - plen - 1;
- if (plen > 0 && rest <= sizeof(header.name)) {
- memcpy(header.prefix, path, plen);
- memcpy(header.name, path + plen + 1, rest);
- } else {
- sprintf(header.name, "%s.data",
- sha1_to_hex(sha1));
- strbuf_append_ext_header(&ext_header, "path",
- path, pathlen);
- }
- } else
- memcpy(header.name, path, pathlen);
+ } else
+ memcpy(header.name, path, pathlen);
+
+ if (S_ISREG(mode) && !args->convert &&
+ sha1_object_info(sha1, &size) == OBJ_BLOB &&
+ size > big_file_threshold)
+ buffer = NULL;
+ else if (S_ISLNK(mode) || S_ISREG(mode)) {
+ enum object_type type;
+ buffer = sha1_file_to_archive(args, path, sha1, old_mode, &type, &size);
+ if (!buffer)
+ return error("cannot read %s", sha1_to_hex(sha1));
+ } else {
+ buffer = NULL;
+ size = 0;
}
- if (S_ISLNK(mode) && buffer) {
+ if (S_ISLNK(mode)) {
if (size > sizeof(header.linkname)) {
sprintf(header.linkname, "see %s.paxheader",
sha1_to_hex(sha1));
@@ -182,32 +265,25 @@ static int write_tar_entry(struct archiver_args *args,
memcpy(header.linkname, buffer, size);
}
- sprintf(header.mode, "%07o", mode & 07777);
- sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
- sprintf(header.mtime, "%011lo", (unsigned long) args->time);
-
- sprintf(header.uid, "%07o", 0);
- sprintf(header.gid, "%07o", 0);
- strlcpy(header.uname, "root", sizeof(header.uname));
- strlcpy(header.gname, "root", sizeof(header.gname));
- sprintf(header.devmajor, "%07o", 0);
- sprintf(header.devminor, "%07o", 0);
-
- memcpy(header.magic, "ustar", 6);
- memcpy(header.version, "00", 2);
-
- sprintf(header.chksum, "%07o", ustar_header_chksum(&header));
+ prepare_header(args, &header, mode, size);
if (ext_header.len > 0) {
- err = write_tar_entry(args, sha1, NULL, 0, 0, ext_header.buf,
- ext_header.len);
- if (err)
+ err = write_extended_header(args, sha1, ext_header.buf,
+ ext_header.len);
+ if (err) {
+ free(buffer);
return err;
+ }
}
strbuf_release(&ext_header);
write_blocked(&header, sizeof(header));
- if (S_ISREG(mode) && buffer && size > 0)
- write_blocked(buffer, size);
+ if (S_ISREG(mode) && size > 0) {
+ if (buffer)
+ write_blocked(buffer, size);
+ else
+ err = stream_blocked(sha1);
+ }
+ free(buffer);
return err;
}
@@ -215,11 +291,18 @@ static int write_global_extended_header(struct archiver_args *args)
{
const unsigned char *sha1 = args->commit_sha1;
struct strbuf ext_header = STRBUF_INIT;
- int err;
+ struct ustar_header header;
+ unsigned int mode;
+ int err = 0;
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
- err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf,
- ext_header.len);
+ memset(&header, 0, sizeof(header));
+ *header.typeflag = TYPEFLAG_GLOBAL_HEADER;
+ mode = 0100666;
+ strcpy(header.name, "pax_global_header");
+ prepare_header(args, &header, mode, ext_header.len);
+ write_blocked(&header, sizeof(header));
+ write_blocked(ext_header.buf, ext_header.len);
strbuf_release(&ext_header);
return err;
}
diff --git a/archive-zip.c b/archive-zip.c
index 02d1f37..f5af81f 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -3,6 +3,7 @@
*/
#include "cache.h"
#include "archive.h"
+#include "streaming.h"
static int zip_date;
static int zip_time;
@@ -15,6 +16,7 @@ static unsigned int zip_dir_offset;
static unsigned int zip_dir_entries;
#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
+#define ZIP_STREAM (8)
struct zip_local_header {
unsigned char magic[4];
@@ -31,6 +33,14 @@ struct zip_local_header {
unsigned char _end[1];
};
+struct zip_data_desc {
+ unsigned char magic[4];
+ unsigned char crc32[4];
+ unsigned char compressed_size[4];
+ unsigned char size[4];
+ unsigned char _end[1];
+};
+
struct zip_dir_header {
unsigned char magic[4];
unsigned char creator_version[2];
@@ -70,6 +80,7 @@ struct zip_dir_trailer {
* we're interested in.
*/
#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end)
+#define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end)
#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end)
@@ -120,20 +131,59 @@ static void *zlib_deflate(void *data, unsigned long size,
return buffer;
}
+static void write_zip_data_desc(unsigned long size,
+ unsigned long compressed_size,
+ unsigned long crc)
+{
+ struct zip_data_desc trailer;
+
+ copy_le32(trailer.magic, 0x08074b50);
+ copy_le32(trailer.crc32, crc);
+ copy_le32(trailer.compressed_size, compressed_size);
+ copy_le32(trailer.size, size);
+ write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE);
+}
+
+static void set_zip_dir_data_desc(struct zip_dir_header *header,
+ unsigned long size,
+ unsigned long compressed_size,
+ unsigned long crc)
+{
+ copy_le32(header->crc32, crc);
+ copy_le32(header->compressed_size, compressed_size);
+ copy_le32(header->size, size);
+}
+
+static void set_zip_header_data_desc(struct zip_local_header *header,
+ unsigned long size,
+ unsigned long compressed_size,
+ unsigned long crc)
+{
+ copy_le32(header->crc32, crc);
+ copy_le32(header->compressed_size, compressed_size);
+ copy_le32(header->size, size);
+}
+
+#define STREAM_BUFFER_SIZE (1024 * 16)
+
static int write_zip_entry(struct archiver_args *args,
- const unsigned char *sha1, const char *path, size_t pathlen,
- unsigned int mode, void *buffer, unsigned long size)
+ const unsigned char *sha1,
+ const char *path, size_t pathlen,
+ unsigned int mode)
{
struct zip_local_header header;
struct zip_dir_header dirent;
unsigned long attr2;
unsigned long compressed_size;
- unsigned long uncompressed_size;
unsigned long crc;
unsigned long direntsize;
int method;
unsigned char *out;
void *deflated = NULL;
+ void *buffer;
+ struct git_istream *stream = NULL;
+ unsigned long flags = 0;
+ unsigned long size;
crc = crc32(0, NULL, 0);
@@ -146,24 +196,43 @@ static int write_zip_entry(struct archiver_args *args,
method = 0;
attr2 = 16;
out = NULL;
- uncompressed_size = 0;
+ size = 0;
compressed_size = 0;
+ buffer = NULL;
+ size = 0;
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
+ enum object_type type = sha1_object_info(sha1, &size);
+
method = 0;
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
(mode & 0111) ? ((mode) << 16) : 0;
- if (S_ISREG(mode) && args->compression_level != 0)
+ if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
method = 8;
- crc = crc32(crc, buffer, size);
- out = buffer;
- uncompressed_size = size;
compressed_size = size;
+
+ if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
+ size > big_file_threshold) {
+ stream = open_istream(sha1, &type, &size, NULL);
+ if (!stream)
+ return error("cannot stream blob %s",
+ sha1_to_hex(sha1));
+ flags |= ZIP_STREAM;
+ out = buffer = NULL;
+ } else {
+ buffer = sha1_file_to_archive(args, path, sha1, mode,
+ &type, &size);
+ if (!buffer)
+ return error("cannot read %s",
+ sha1_to_hex(sha1));
+ crc = crc32(crc, buffer, size);
+ out = buffer;
+ }
} else {
return error("unsupported file mode: 0%o (SHA1: %s)", mode,
sha1_to_hex(sha1));
}
- if (method == 8) {
+ if (buffer && method == 8) {
deflated = zlib_deflate(buffer, size, args->compression_level,
&compressed_size);
if (deflated && compressed_size - 6 < size) {
@@ -188,13 +257,11 @@ static int write_zip_entry(struct archiver_args *args,
copy_le16(dirent.creator_version,
S_ISLNK(mode) || (S_ISREG(mode) && (mode & 0111)) ? 0x0317 : 0);
copy_le16(dirent.version, 10);
- copy_le16(dirent.flags, 0);
+ copy_le16(dirent.flags, flags);
copy_le16(dirent.compression_method, method);
copy_le16(dirent.mtime, zip_time);
copy_le16(dirent.mdate, zip_date);
- copy_le32(dirent.crc32, crc);
- copy_le32(dirent.compressed_size, compressed_size);
- copy_le32(dirent.size, uncompressed_size);
+ set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
copy_le16(dirent.filename_length, pathlen);
copy_le16(dirent.extra_length, 0);
copy_le16(dirent.comment_length, 0);
@@ -202,33 +269,120 @@ static int write_zip_entry(struct archiver_args *args,
copy_le16(dirent.attr1, 0);
copy_le32(dirent.attr2, attr2);
copy_le32(dirent.offset, zip_offset);
- memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
- zip_dir_offset += ZIP_DIR_HEADER_SIZE;
- memcpy(zip_dir + zip_dir_offset, path, pathlen);
- zip_dir_offset += pathlen;
- zip_dir_entries++;
copy_le32(header.magic, 0x04034b50);
copy_le16(header.version, 10);
- copy_le16(header.flags, 0);
+ copy_le16(header.flags, flags);
copy_le16(header.compression_method, method);
copy_le16(header.mtime, zip_time);
copy_le16(header.mdate, zip_date);
- copy_le32(header.crc32, crc);
- copy_le32(header.compressed_size, compressed_size);
- copy_le32(header.size, uncompressed_size);
+ if (flags & ZIP_STREAM)
+ set_zip_header_data_desc(&header, 0, 0, 0);
+ else
+ set_zip_header_data_desc(&header, size, compressed_size, crc);
copy_le16(header.filename_length, pathlen);
copy_le16(header.extra_length, 0);
write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
zip_offset += ZIP_LOCAL_HEADER_SIZE;
write_or_die(1, path, pathlen);
zip_offset += pathlen;
- if (compressed_size > 0) {
+ if (stream && method == 0) {
+ unsigned char buf[STREAM_BUFFER_SIZE];
+ ssize_t readlen;
+
+ for (;;) {
+ readlen = read_istream(stream, buf, sizeof(buf));
+ if (readlen <= 0)
+ break;
+ crc = crc32(crc, buf, readlen);
+ write_or_die(1, buf, readlen);
+ }
+ close_istream(stream);
+ if (readlen)
+ return readlen;
+
+ compressed_size = size;
+ zip_offset += compressed_size;
+
+ write_zip_data_desc(size, compressed_size, crc);
+ zip_offset += ZIP_DATA_DESC_SIZE;
+
+ set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
+ } else if (stream && method == 8) {
+ unsigned char buf[STREAM_BUFFER_SIZE];
+ ssize_t readlen;
+ git_zstream zstream;
+ int result;
+ size_t out_len;
+ unsigned char compressed[STREAM_BUFFER_SIZE * 2];
+
+ memset(&zstream, 0, sizeof(zstream));
+ git_deflate_init(&zstream, args->compression_level);
+
+ compressed_size = 0;
+ zstream.next_out = compressed;
+ zstream.avail_out = sizeof(compressed);
+
+ for (;;) {
+ readlen = read_istream(stream, buf, sizeof(buf));
+ if (readlen <= 0)
+ break;
+ crc = crc32(crc, buf, readlen);
+
+ zstream.next_in = buf;
+ zstream.avail_in = readlen;
+ result = git_deflate(&zstream, 0);
+ if (result != Z_OK)
+ die("deflate error (%d)", result);
+ out = compressed;
+ if (!compressed_size)
+ out += 2;
+ out_len = zstream.next_out - out;
+
+ if (out_len > 0) {
+ write_or_die(1, out, out_len);
+ compressed_size += out_len;
+ zstream.next_out = compressed;
+ zstream.avail_out = sizeof(compressed);
+ }
+
+ }
+ close_istream(stream);
+ if (readlen)
+ return readlen;
+
+ zstream.next_in = buf;
+ zstream.avail_in = 0;
+ result = git_deflate(&zstream, Z_FINISH);
+ if (result != Z_STREAM_END)
+ die("deflate error (%d)", result);
+
+ git_deflate_end(&zstream);
+ out = compressed;
+ if (!compressed_size)
+ out += 2;
+ out_len = zstream.next_out - out - 4;
+ write_or_die(1, out, out_len);
+ compressed_size += out_len;
+ zip_offset += compressed_size;
+
+ write_zip_data_desc(size, compressed_size, crc);
+ zip_offset += ZIP_DATA_DESC_SIZE;
+
+ set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
+ } else if (compressed_size > 0) {
write_or_die(1, out, compressed_size);
zip_offset += compressed_size;
}
free(deflated);
+ free(buffer);
+
+ memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
+ zip_dir_offset += ZIP_DIR_HEADER_SIZE;
+ memcpy(zip_dir + zip_dir_offset, path, pathlen);
+ zip_dir_offset += pathlen;
+ zip_dir_entries++;
return 0;
}
diff --git a/archive.c b/archive.c
index 1ee837d..a484433 100644
--- a/archive.c
+++ b/archive.c
@@ -59,12 +59,15 @@ static void format_subst(const struct commit *commit,
free(to_free);
}
-static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
- unsigned int mode, enum object_type *type,
- unsigned long *sizep, const struct commit *commit)
+void *sha1_file_to_archive(const struct archiver_args *args,
+ const char *path, const unsigned char *sha1,
+ unsigned int mode, enum object_type *type,
+ unsigned long *sizep)
{
void *buffer;
+ const struct commit *commit = args->convert ? args->commit : NULL;
+ path += args->baselen;
buffer = read_sha1_file(sha1, type, sizep);
if (buffer && S_ISREG(mode)) {
struct strbuf buf = STRBUF_INIT;
@@ -109,12 +112,9 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
write_archive_entry_fn_t write_entry = c->write_entry;
struct git_attr_check check[2];
const char *path_without_prefix;
- int convert = 0;
int err;
- enum object_type type;
- unsigned long size;
- void *buffer;
+ args->convert = 0;
strbuf_reset(&path);
strbuf_grow(&path, PATH_MAX);
strbuf_add(&path, args->base, args->baselen);
@@ -126,28 +126,22 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
if (ATTR_TRUE(check[0].value))
return 0;
- convert = ATTR_TRUE(check[1].value);
+ args->convert = ATTR_TRUE(check[1].value);
}
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
strbuf_addch(&path, '/');
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
- err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
+ err = write_entry(args, sha1, path.buf, path.len, mode);
if (err)
return err;
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
}
- buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,
- &type, &size, convert ? args->commit : NULL);
- if (!buffer)
- return error("cannot read %s", sha1_to_hex(sha1));
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
- err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
- free(buffer);
- return err;
+ return write_entry(args, sha1, path.buf, path.len, mode);
}
int write_archive_entries(struct archiver_args *args,
@@ -167,7 +161,7 @@ int write_archive_entries(struct archiver_args *args,
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)len, args->base);
err = write_entry(args, args->tree->object.sha1, args->base,
- len, 040777, NULL, 0);
+ len, 040777);
if (err)
return err;
}
@@ -260,18 +254,11 @@ static void parse_treeish_arg(const char **argv,
/* Remotes are only allowed to fetch actual refs */
if (remote) {
char *ref = NULL;
- const char *refname, *colon = NULL;
-
- colon = strchr(name, ':');
- if (colon)
- refname = xstrndup(name, colon - name);
- else
- refname = name;
-
- if (!dwim_ref(refname, strlen(refname), sha1, &ref))
- die("no such ref: %s", refname);
- if (refname != name)
- free((void *)refname);
+ const char *colon = strchr(name, ':');
+ int refnamelen = colon ? colon - name : strlen(name);
+
+ if (!dwim_ref(name, refnamelen, sha1, &ref))
+ die("no such ref: %.*s", refnamelen, name);
free(ref);
}
diff --git a/archive.h b/archive.h
index 2b0884f..895afcd 100644
--- a/archive.h
+++ b/archive.h
@@ -11,6 +11,7 @@ struct archiver_args {
const char **pathspec;
unsigned int verbose : 1;
unsigned int worktree_attributes : 1;
+ unsigned int convert : 1;
int compression_level;
};
@@ -27,11 +28,18 @@ extern void register_archiver(struct archiver *);
extern void init_tar_archiver(void);
extern void init_zip_archiver(void);
-typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
+typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
+ const unsigned char *sha1,
+ const char *path, size_t pathlen,
+ unsigned int mode);
extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix, const char *name_hint, int remote);
const char *archive_format_from_filename(const char *filename);
+extern void *sha1_file_to_archive(const struct archiver_args *args,
+ const char *path, const unsigned char *sha1,
+ unsigned int mode, enum object_type *type,
+ unsigned long *sizep);
#endif /* ARCHIVE_H */
diff --git a/argv-array.c b/argv-array.c
index a4e0420..0b5f889 100644
--- a/argv-array.c
+++ b/argv-array.c
@@ -2,8 +2,7 @@
#include "argv-array.h"
#include "strbuf.h"
-static const char *empty_argv_storage = NULL;
-const char **empty_argv = &empty_argv_storage;
+const char *empty_argv[] = { NULL };
void argv_array_init(struct argv_array *array)
{
@@ -39,6 +38,17 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)
argv_array_push_nodup(array, strbuf_detach(&v, NULL));
}
+void argv_array_pushl(struct argv_array *array, ...)
+{
+ va_list ap;
+ const char *arg;
+
+ va_start(ap, array);
+ while((arg = va_arg(ap, const char *)))
+ argv_array_push(array, arg);
+ va_end(ap);
+}
+
void argv_array_clear(struct argv_array *array)
{
if (array->argv != empty_argv) {
diff --git a/argv-array.h b/argv-array.h
index 74dd2b1..b93a69c 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -1,7 +1,7 @@
#ifndef ARGV_ARRAY_H
#define ARGV_ARRAY_H
-extern const char **empty_argv;
+extern const char *empty_argv[];
struct argv_array {
const char **argv;
@@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);
void argv_array_push(struct argv_array *, const char *);
__attribute__((format (printf,2,3)))
void argv_array_pushf(struct argv_array *, const char *fmt, ...);
+void argv_array_pushl(struct argv_array *, ...);
void argv_array_clear(struct argv_array *);
#endif /* ARGV_ARRAY_H */
diff --git a/attr.c b/attr.c
index 303751f..aef93d8 100644
--- a/attr.c
+++ b/attr.c
@@ -497,6 +497,7 @@ static int git_attr_system(void)
static void bootstrap_attr_stack(void)
{
struct attr_stack *elem;
+ char *xdg_attributes_file;
if (attr_stack)
return;
@@ -515,13 +516,15 @@ static void bootstrap_attr_stack(void)
}
}
- if (git_attributes_file) {
- elem = read_attr_from_file(git_attributes_file, 1);
- if (elem) {
- elem->origin = NULL;
- elem->prev = attr_stack;
- attr_stack = elem;
- }
+ if (!git_attributes_file) {
+ home_config_paths(NULL, &xdg_attributes_file, "attributes");
+ git_attributes_file = xdg_attributes_file;
+ }
+ elem = read_attr_from_file(git_attributes_file, 1);
+ if (elem) {
+ elem->origin = NULL;
+ elem->prev = attr_stack;
+ attr_stack = elem;
}
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
diff --git a/attr.h b/attr.h
index eb8ca0d..8b08d33 100644
--- a/attr.h
+++ b/attr.h
@@ -40,7 +40,7 @@ int git_check_attr(const char *path, int, struct git_attr_check *);
/*
* Retrieve all attributes that apply to the specified path. *num
- * will be set the the number of attributes on the path; **check will
+ * will be set to the number of attributes on the path; **check will
* be set to point at a newly-allocated array of git_attr_check
* objects describing the attributes and their values. *check must be
* free()ed by the caller.
diff --git a/bisect.c b/bisect.c
index 6e186e2..48acf73 100644
--- a/bisect.c
+++ b/bisect.c
@@ -833,7 +833,7 @@ static int check_ancestors(const char *prefix)
*/
static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
{
- const char *filename = git_path("BISECT_ANCESTORS_OK");
+ char *filename = xstrdup(git_path("BISECT_ANCESTORS_OK"));
struct stat st;
int fd;
@@ -842,11 +842,11 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
/* Check if file BISECT_ANCESTORS_OK exists. */
if (!stat(filename, &st) && S_ISREG(st.st_mode))
- return;
+ goto done;
/* Bisecting with no good rev is ok. */
if (good_revs.nr == 0)
- return;
+ goto done;
/* Check if all good revs are ancestor of the bad rev. */
if (check_ancestors(prefix))
@@ -859,6 +859,8 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
filename, strerror(errno));
else
close(fd);
+ done:
+ free(filename);
}
/*
diff --git a/branch.c b/branch.c
index 9971820..2bef1e7 100644
--- a/branch.c
+++ b/branch.c
@@ -74,25 +74,33 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
strbuf_addf(&key, "branch.%s.rebase", local);
git_config_set(key.buf, "true");
}
+ strbuf_release(&key);
if (flag & BRANCH_CONFIG_VERBOSE) {
- strbuf_reset(&key);
-
- strbuf_addstr(&key, origin ? "remote" : "local");
-
- /* Are we tracking a proper "branch"? */
- if (remote_is_branch) {
- strbuf_addf(&key, " branch %s", shortname);
- if (origin)
- strbuf_addf(&key, " from %s", origin);
- }
+ if (remote_is_branch && origin)
+ printf(rebasing ?
+ "Branch %s set up to track remote branch %s from %s by rebasing.\n" :
+ "Branch %s set up to track remote branch %s from %s.\n",
+ local, shortname, origin);
+ else if (remote_is_branch && !origin)
+ printf(rebasing ?
+ "Branch %s set up to track local branch %s by rebasing.\n" :
+ "Branch %s set up to track local branch %s.\n",
+ local, shortname);
+ else if (!remote_is_branch && origin)
+ printf(rebasing ?
+ "Branch %s set up to track remote ref %s by rebasing.\n" :
+ "Branch %s set up to track remote ref %s.\n",
+ local, remote);
+ else if (!remote_is_branch && !origin)
+ printf(rebasing ?
+ "Branch %s set up to track local ref %s by rebasing.\n" :
+ "Branch %s set up to track local ref %s.\n",
+ local, remote);
else
- strbuf_addf(&key, " ref %s", remote);
- printf("Branch %s set up to track %s%s.\n",
- local, key.buf,
- rebasing ? " by rebasing" : "");
+ die("BUG: impossible combination of %d and %p",
+ remote_is_branch, origin);
}
- strbuf_release(&key);
}
/*
@@ -101,9 +109,10 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
* config.
*/
static int setup_tracking(const char *new_ref, const char *orig_ref,
- enum branch_track track)
+ enum branch_track track, int quiet)
{
struct tracking tracking;
+ int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
if (strlen(new_ref) > 1024 - 7 - 7 - 1)
return error("Tracking not set up: name too long: %s",
@@ -128,7 +137,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
return error("Not tracking: ambiguous information for ref %s",
orig_ref);
- install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
+ install_branch_config(config_flags, new_ref, tracking.remote,
tracking.src ? tracking.src : orig_ref);
free(tracking.src);
@@ -191,7 +200,7 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
void create_branch(const char *head,
const char *name, const char *start_name,
int force, int reflog, int clobber_head,
- enum branch_track track)
+ int quiet, enum branch_track track)
{
struct ref_lock *lock = NULL;
struct commit *commit;
@@ -260,7 +269,7 @@ void create_branch(const char *head,
start_name);
if (real_ref && track)
- setup_tracking(ref.buf+11, real_ref, track);
+ setup_tracking(ref.buf+11, real_ref, track, quiet);
if (!dont_change_ref)
if (write_ref_sha1(lock, sha1, msg) < 0)
diff --git a/branch.h b/branch.h
index b99c5a3..64173ab 100644
--- a/branch.h
+++ b/branch.h
@@ -14,7 +14,7 @@
*/
void create_branch(const char *head, const char *name, const char *start_name,
int force, int reflog,
- int clobber_head, enum branch_track track);
+ int clobber_head, int quiet, enum branch_track track);
/*
* Validates that the requested branch may be created, returning the
diff --git a/builtin.h b/builtin.h
index 857b9c8..ba6626b 100644
--- a/builtin.h
+++ b/builtin.h
@@ -9,7 +9,6 @@
#define DEFAULT_MERGE_LOG_LEN 20
-extern const char git_version_string[];
extern const char git_usage_string[];
extern const char git_more_info_string[];
@@ -41,6 +40,8 @@ int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
extern int check_pager_config(const char *cmd);
+struct diff_options;
+extern void setup_diff_pager(struct diff_options *);
extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
@@ -61,10 +62,12 @@ extern int cmd_cherry(int argc, const char **argv, const char *prefix);
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
extern int cmd_clone(int argc, const char **argv, const char *prefix);
extern int cmd_clean(int argc, const char **argv, const char *prefix);
+extern int cmd_column(int argc, const char **argv, const char *prefix);
extern int cmd_commit(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
extern int cmd_config(int argc, const char **argv, const char *prefix);
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_credential(int argc, const char **argv, const char *prefix);
extern int cmd_describe(int argc, const char **argv, const char *prefix);
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
@@ -82,7 +85,6 @@ extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix
extern int cmd_grep(int argc, const char **argv, const char *prefix);
extern int cmd_hash_object(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix);
-extern int cmd_http_fetch(int argc, const char **argv, const char *prefix);
extern int cmd_index_pack(int argc, const char **argv, const char *prefix);
extern int cmd_init_db(int argc, const char **argv, const char *prefix);
extern int cmd_log(int argc, const char **argv, const char *prefix);
@@ -107,7 +109,6 @@ extern int cmd_notes(int argc, const char **argv, const char *prefix);
extern int cmd_pack_objects(int argc, const char **argv, const char *prefix);
extern int cmd_pack_redundant(int argc, const char **argv, const char *prefix);
extern int cmd_patch_id(int argc, const char **argv, const char *prefix);
-extern int cmd_pickaxe(int argc, const char **argv, const char *prefix);
extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
@@ -140,7 +141,6 @@ extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
extern int cmd_update_server_info(int argc, const char **argv, const char *prefix);
extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
-extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
extern int cmd_var(int argc, const char **argv, const char *prefix);
extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
extern int cmd_version(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index b79336d..89dce56 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -281,7 +281,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
- out = open(file, O_CREAT | O_WRONLY, 0644);
+ out = open(file, O_CREAT | O_WRONLY, 0666);
if (out < 0)
die (_("Could not open '%s' for writing."), file);
rev.diffopt.file = xfdopen(out, "w");
@@ -443,6 +443,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (pathspec) {
int i;
+ struct path_exclude_check check;
+
+ path_exclude_check_init(&check, &dir);
if (!seen)
seen = find_used_pathspec(pathspec);
for (i = 0; pathspec[i]; i++) {
@@ -450,7 +453,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
&& !file_exists(pathspec[i])) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
- if (excluded(&dir, pathspec[i], &dtype))
+ if (path_excluded(&check, pathspec[i], -1, &dtype))
dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
} else
die(_("pathspec '%s' did not match any files"),
@@ -458,6 +461,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
}
free(seen);
+ path_exclude_check_clear(&check);
}
plug_bulk_checkin();
diff --git a/builtin/apply.c b/builtin/apply.c
index 389898f..ace04c4 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -16,6 +16,9 @@
#include "dir.h"
#include "diff.h"
#include "parse-options.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
+#include "rerere.h"
/*
* --check turns on checking that the working tree matches the
@@ -46,11 +49,12 @@ static int apply_with_reject;
static int apply_verbosely;
static int allow_overlap;
static int no_add;
+static int threeway;
static const char *fake_ancestor;
static int line_termination = '\n';
static unsigned int p_context = UINT_MAX;
static const char * const apply_usage[] = {
- "git apply [options] [<patch>...]",
+ N_("git apply [options] [<patch>...]"),
NULL
};
@@ -103,7 +107,7 @@ static void parse_whitespace_option(const char *option)
ws_error_action = correct_ws_error;
return;
}
- die("unrecognized whitespace option '%s'", option);
+ die(_("unrecognized whitespace option '%s'"), option);
}
static void parse_ignorewhitespace_option(const char *option)
@@ -118,7 +122,7 @@ static void parse_ignorewhitespace_option(const char *option)
ws_ignore_action = ignore_ws_change;
return;
}
- die("unrecognized whitespace ignore option '%s'", option);
+ die(_("unrecognized whitespace ignore option '%s'"), option);
}
static void set_default_whitespace_mode(const char *whitespace_option)
@@ -152,9 +156,14 @@ struct fragment {
unsigned long leading, trailing;
unsigned long oldpos, oldlines;
unsigned long newpos, newlines;
+ /*
+ * 'patch' is usually borrowed from buf in apply_patch(),
+ * but some codepaths store an allocated buffer.
+ */
const char *patch;
+ unsigned free_patch:1,
+ rejected:1;
int size;
- int rejected;
int linenr;
struct fragment *next;
};
@@ -188,14 +197,49 @@ struct patch {
unsigned int is_copy:1;
unsigned int is_rename:1;
unsigned int recount:1;
+ unsigned int conflicted_threeway:1;
+ unsigned int direct_to_threeway:1;
struct fragment *fragments;
char *result;
size_t resultsize;
char old_sha1_prefix[41];
char new_sha1_prefix[41];
struct patch *next;
+
+ /* three-way fallback result */
+ unsigned char threeway_stage[3][20];
};
+static void free_fragment_list(struct fragment *list)
+{
+ while (list) {
+ struct fragment *next = list->next;
+ if (list->free_patch)
+ free((char *)list->patch);
+ free(list);
+ list = next;
+ }
+}
+
+static void free_patch(struct patch *patch)
+{
+ free_fragment_list(patch->fragments);
+ free(patch->def_name);
+ free(patch->old_name);
+ free(patch->new_name);
+ free(patch->result);
+ free(patch);
+}
+
+static void free_patch_list(struct patch *list)
+{
+ while (list) {
+ struct patch *next = list->next;
+ free_patch(list);
+ list = next;
+ }
+}
+
/*
* A line in a file, len-bytes long (includes the terminating LF,
* except for an incomplete line at the end if the file ends with
@@ -302,6 +346,11 @@ static void add_line_info(struct image *img, const char *bol, size_t len, unsign
img->nr++;
}
+/*
+ * "buf" has the file contents to be patched (read from various sources).
+ * attach it to "image" and add line-based index to it.
+ * "image" now owns the "buf".
+ */
static void prepare_image(struct image *image, char *buf, size_t len,
int prepare_linetable)
{
@@ -331,29 +380,31 @@ static void prepare_image(struct image *image, char *buf, size_t len,
static void clear_image(struct image *image)
{
free(image->buf);
- image->buf = NULL;
- image->len = 0;
+ free(image->line_allocated);
+ memset(image, 0, sizeof(*image));
}
-static void say_patch_name(FILE *output, const char *pre,
- struct patch *patch, const char *post)
+/* fmt must contain _one_ %s and no other substitution */
+static void say_patch_name(FILE *output, const char *fmt, struct patch *patch)
{
- fputs(pre, output);
+ struct strbuf sb = STRBUF_INIT;
+
if (patch->old_name && patch->new_name &&
strcmp(patch->old_name, patch->new_name)) {
- quote_c_style(patch->old_name, NULL, output, 0);
- fputs(" => ", output);
- quote_c_style(patch->new_name, NULL, output, 0);
+ quote_c_style(patch->old_name, &sb, NULL, 0);
+ strbuf_addstr(&sb, " => ");
+ quote_c_style(patch->new_name, &sb, NULL, 0);
} else {
const char *n = patch->new_name;
if (!n)
n = patch->old_name;
- quote_c_style(n, NULL, output, 0);
+ quote_c_style(n, &sb, NULL, 0);
}
- fputs(post, output);
+ fprintf(output, fmt, sb.buf);
+ fputc('\n', output);
+ strbuf_release(&sb);
}
-#define CHUNKSIZE (8192)
#define SLOP (16)
static void read_patch_file(struct strbuf *sb, int fd)
@@ -416,7 +467,7 @@ static char *squash_slash(char *name)
return name;
}
-static char *find_name_gnu(const char *line, char *def, int p_value)
+static char *find_name_gnu(const char *line, const char *def, int p_value)
{
struct strbuf name = STRBUF_INIT;
char *cp;
@@ -439,11 +490,7 @@ static char *find_name_gnu(const char *line, char *def, int p_value)
cp++;
}
- /* name can later be freed, so we need
- * to memmove, not just return cp
- */
strbuf_remove(&name, 0, cp - name.buf);
- free(def);
if (root)
strbuf_insert(&name, 0, root, root_len);
return squash_slash(strbuf_detach(&name, NULL));
@@ -608,8 +655,13 @@ static size_t diff_timestamp_len(const char *line, size_t len)
return line + len - end;
}
-static char *find_name_common(const char *line, char *def, int p_value,
- const char *end, int terminate)
+static char *null_strdup(const char *s)
+{
+ return s ? xstrdup(s) : NULL;
+}
+
+static char *find_name_common(const char *line, const char *def,
+ int p_value, const char *end, int terminate)
{
int len;
const char *start = NULL;
@@ -630,10 +682,10 @@ static char *find_name_common(const char *line, char *def, int p_value,
start = line;
}
if (!start)
- return squash_slash(def);
+ return squash_slash(null_strdup(def));
len = line - start;
if (!len)
- return squash_slash(def);
+ return squash_slash(null_strdup(def));
/*
* Generally we prefer the shorter name, especially
@@ -644,8 +696,7 @@ static char *find_name_common(const char *line, char *def, int p_value,
if (def) {
int deflen = strlen(def);
if (deflen < len && !strncmp(start, def, deflen))
- return squash_slash(def);
- free(def);
+ return squash_slash(xstrdup(def));
}
if (root) {
@@ -770,7 +821,7 @@ static int has_epoch_timestamp(const char *nameline)
if (!stamp) {
stamp = xmalloc(sizeof(*stamp));
if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
- warning("Cannot prepare timestamp regexp %s",
+ warning(_("Cannot prepare timestamp regexp %s"),
stamp_regexp);
return 0;
}
@@ -779,7 +830,7 @@ static int has_epoch_timestamp(const char *nameline)
status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
if (status) {
if (status != REG_NOMATCH)
- warning("regexec returned %d for input: %s",
+ warning(_("regexec returned %d for input: %s"),
status, timestamp);
return 0;
}
@@ -842,8 +893,10 @@ static void parse_traditional_patch(const char *first, const char *second, struc
name = find_name_traditional(first, NULL, p_value);
patch->old_name = name;
} else {
- name = find_name_traditional(first, NULL, p_value);
- name = find_name_traditional(second, name, p_value);
+ char *first_name;
+ first_name = find_name_traditional(first, NULL, p_value);
+ name = find_name_traditional(second, first_name, p_value);
+ free(first_name);
if (has_epoch_timestamp(first)) {
patch->is_new = 1;
patch->is_delete = 0;
@@ -853,11 +906,12 @@ static void parse_traditional_patch(const char *first, const char *second, struc
patch->is_delete = 1;
patch->old_name = name;
} else {
- patch->old_name = patch->new_name = name;
+ patch->old_name = name;
+ patch->new_name = xstrdup(name);
}
}
if (!name)
- die("unable to find filename in patch at line %d", linenr);
+ die(_("unable to find filename in patch at line %d"), linenr);
}
static int gitdiff_hdrend(const char *line, struct patch *patch)
@@ -874,7 +928,10 @@ static int gitdiff_hdrend(const char *line, struct patch *patch)
* their names against any previous information, just
* to make sure..
*/
-static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, const char *oldnew)
+#define DIFF_OLD_NAME 0
+#define DIFF_NEW_NAME 1
+
+static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, int side)
{
if (!orig_name && !isnull)
return find_name(line, NULL, p_value, TERM_TAB);
@@ -886,30 +943,40 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name,
name = orig_name;
len = strlen(name);
if (isnull)
- die("git apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
+ die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"), name, linenr);
another = find_name(line, NULL, p_value, TERM_TAB);
if (!another || memcmp(another, name, len + 1))
- die("git apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
+ die((side == DIFF_NEW_NAME) ?
+ _("git apply: bad git-diff - inconsistent new filename on line %d") :
+ _("git apply: bad git-diff - inconsistent old filename on line %d"), linenr);
free(another);
return orig_name;
}
else {
/* expect "/dev/null" */
if (memcmp("/dev/null", line, 9) || line[9] != '\n')
- die("git apply: bad git-diff - expected /dev/null on line %d", linenr);
+ die(_("git apply: bad git-diff - expected /dev/null on line %d"), linenr);
return NULL;
}
}
static int gitdiff_oldname(const char *line, struct patch *patch)
{
- patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name, "old");
+ char *orig = patch->old_name;
+ patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name,
+ DIFF_OLD_NAME);
+ if (orig != patch->old_name)
+ free(orig);
return 0;
}
static int gitdiff_newname(const char *line, struct patch *patch)
{
- patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name, "new");
+ char *orig = patch->new_name;
+ patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name,
+ DIFF_NEW_NAME);
+ if (orig != patch->new_name)
+ free(orig);
return 0;
}
@@ -928,20 +995,23 @@ static int gitdiff_newmode(const char *line, struct patch *patch)
static int gitdiff_delete(const char *line, struct patch *patch)
{
patch->is_delete = 1;
- patch->old_name = patch->def_name;
+ free(patch->old_name);
+ patch->old_name = null_strdup(patch->def_name);
return gitdiff_oldmode(line, patch);
}
static int gitdiff_newfile(const char *line, struct patch *patch)
{
patch->is_new = 1;
- patch->new_name = patch->def_name;
+ free(patch->new_name);
+ patch->new_name = null_strdup(patch->def_name);
return gitdiff_newmode(line, patch);
}
static int gitdiff_copysrc(const char *line, struct patch *patch)
{
patch->is_copy = 1;
+ free(patch->old_name);
patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
return 0;
}
@@ -949,6 +1019,7 @@ static int gitdiff_copysrc(const char *line, struct patch *patch)
static int gitdiff_copydst(const char *line, struct patch *patch)
{
patch->is_copy = 1;
+ free(patch->new_name);
patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
return 0;
}
@@ -956,6 +1027,7 @@ static int gitdiff_copydst(const char *line, struct patch *patch)
static int gitdiff_renamesrc(const char *line, struct patch *patch)
{
patch->is_rename = 1;
+ free(patch->old_name);
patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
return 0;
}
@@ -963,6 +1035,7 @@ static int gitdiff_renamesrc(const char *line, struct patch *patch)
static int gitdiff_renamedst(const char *line, struct patch *patch)
{
patch->is_rename = 1;
+ free(patch->new_name);
patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
return 0;
}
@@ -1044,7 +1117,7 @@ static const char *stop_at_slash(const char *line, int llen)
* creation or deletion of an empty file. In any of these cases,
* both sides are the same name under a/ and b/ respectively.
*/
-static char *git_header_name(char *line, int llen)
+static char *git_header_name(const char *line, int llen)
{
const char *name;
const char *second = NULL;
@@ -1171,7 +1244,7 @@ static char *git_header_name(char *line, int llen)
}
/* Verify that we recognize the lines following a git header */
-static int parse_git_header(char *line, int len, unsigned int size, struct patch *patch)
+static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
{
unsigned long offset;
@@ -1287,7 +1360,7 @@ static int parse_range(const char *line, int len, int offset, const char *expect
return offset + ex;
}
-static void recount_diff(char *line, int size, struct fragment *fragment)
+static void recount_diff(const char *line, int size, struct fragment *fragment)
{
int oldlines = 0, newlines = 0, ret = 0;
@@ -1327,7 +1400,7 @@ static void recount_diff(char *line, int size, struct fragment *fragment)
break;
}
if (ret) {
- warning("recount: unexpected line: %.*s",
+ warning(_("recount: unexpected line: %.*s"),
(int)linelen(line, size), line);
return;
}
@@ -1341,7 +1414,7 @@ static void recount_diff(char *line, int size, struct fragment *fragment)
* Parse a unified diff fragment header of the
* form "@@ -a,b +c,d @@"
*/
-static int parse_fragment_header(char *line, int len, struct fragment *fragment)
+static int parse_fragment_header(const char *line, int len, struct fragment *fragment)
{
int offset;
@@ -1355,7 +1428,7 @@ static int parse_fragment_header(char *line, int len, struct fragment *fragment)
return offset;
}
-static int find_header(char *line, unsigned long size, int *hdrsize, struct patch *patch)
+static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
{
unsigned long offset, len;
@@ -1384,7 +1457,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
struct fragment dummy;
if (parse_fragment_header(line, len, &dummy) < 0)
continue;
- die("patch fragment without header at line %d: %.*s",
+ die(_("patch fragment without header at line %d: %.*s"),
linenr, (int)len-1, line);
}
@@ -1401,9 +1474,14 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
continue;
if (!patch->old_name && !patch->new_name) {
if (!patch->def_name)
- die("git diff header lacks filename information when removing "
- "%d leading pathname components (line %d)" , p_value, linenr);
- patch->old_name = patch->new_name = patch->def_name;
+ die(Q_("git diff header lacks filename information when removing "
+ "%d leading pathname component (line %d)",
+ "git diff header lacks filename information when removing "
+ "%d leading pathname components (line %d)",
+ p_value),
+ p_value, linenr);
+ patch->old_name = xstrdup(patch->def_name);
+ patch->new_name = xstrdup(patch->def_name);
}
if (!patch->is_delete && !patch->new_name)
die("git diff header lacks filename information "
@@ -1466,7 +1544,7 @@ static void check_whitespace(const char *line, int len, unsigned ws_rule)
* between a "---" that is part of a patch, and a "---" that starts
* the next patch is to look at the line counts..
*/
-static int parse_fragment(char *line, unsigned long size,
+static int parse_fragment(const char *line, unsigned long size,
struct patch *patch, struct fragment *fragment)
{
int added, deleted;
@@ -1556,13 +1634,21 @@ static int parse_fragment(char *line, unsigned long size,
patch->lines_deleted += deleted;
if (0 < patch->is_new && oldlines)
- return error("new file depends on old contents");
+ return error(_("new file depends on old contents"));
if (0 < patch->is_delete && newlines)
- return error("deleted file still has contents");
+ return error(_("deleted file still has contents"));
return offset;
}
-static int parse_single_patch(char *line, unsigned long size, struct patch *patch)
+/*
+ * We have seen "diff --git a/... b/..." header (or a traditional patch
+ * header). Read hunks that belong to this patch into fragments and hang
+ * them to the given patch structure.
+ *
+ * The (fragment->patch, fragment->size) pair points into the memory given
+ * by the caller, not a copy, when we return.
+ */
+static int parse_single_patch(const char *line, unsigned long size, struct patch *patch)
{
unsigned long offset = 0;
unsigned long oldlines = 0, newlines = 0, context = 0;
@@ -1576,7 +1662,7 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
fragment->linenr = linenr;
len = parse_fragment(line, size, patch, fragment);
if (len <= 0)
- die("corrupt patch at line %d", linenr);
+ die(_("corrupt patch at line %d"), linenr);
fragment->patch = line;
fragment->size = len;
oldlines += fragment->oldlines;
@@ -1612,12 +1698,14 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
patch->is_delete = 0;
if (0 < patch->is_new && oldlines)
- die("new file %s depends on old contents", patch->new_name);
+ die(_("new file %s depends on old contents"), patch->new_name);
if (0 < patch->is_delete && newlines)
- die("deleted file %s still has contents", patch->old_name);
+ die(_("deleted file %s still has contents"), patch->old_name);
if (!patch->is_delete && !newlines && context)
- fprintf(stderr, "** warning: file %s becomes empty but "
- "is not deleted\n", patch->new_name);
+ fprintf_ln(stderr,
+ _("** warning: "
+ "file %s becomes empty but is not deleted"),
+ patch->new_name);
return offset;
}
@@ -1655,6 +1743,11 @@ static char *inflate_it(const void *data, unsigned long size,
return out;
}
+/*
+ * Read a binary hunk and return a new fragment; fragment->patch
+ * points at an allocated memory that the caller must free, so
+ * it is marked as "->free_patch = 1".
+ */
static struct fragment *parse_binary_hunk(char **buf_p,
unsigned long *sz_p,
int *status_p,
@@ -1742,6 +1835,7 @@ static struct fragment *parse_binary_hunk(char **buf_p,
frag = xcalloc(1, sizeof(*frag));
frag->patch = inflate_it(data, hunk_size, origlen);
+ frag->free_patch = 1;
if (!frag->patch)
goto corrupt;
free(data);
@@ -1755,7 +1849,7 @@ static struct fragment *parse_binary_hunk(char **buf_p,
corrupt:
free(data);
*status_p = -1;
- error("corrupt binary patch at line %d: %.*s",
+ error(_("corrupt binary patch at line %d: %.*s"),
linenr-1, llen-1, buffer);
return NULL;
}
@@ -1784,7 +1878,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
forward = parse_binary_hunk(&buffer, &size, &status, &used);
if (!forward && !status)
/* there has to be one hunk (forward hunk) */
- return error("unrecognized binary patch at line %d", linenr-1);
+ return error(_("unrecognized binary patch at line %d"), linenr-1);
if (status)
/* otherwise we already gave an error message */
return status;
@@ -1807,6 +1901,13 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
return used;
}
+/*
+ * Read the patch text in "buffer" taht extends for "size" bytes; stop
+ * reading after seeing a single patch (i.e. changes to a single file).
+ * Create fragments (i.e. patch hunks) and hang them to the given patch.
+ * Return the number of bytes consumed, so that the caller can call us
+ * again for the next patch.
+ */
static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
{
int hdrsize, patchsize;
@@ -1863,7 +1964,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
*/
if ((apply || check) &&
(!patch->is_binary && !metadata_changes(patch)))
- die("patch with only garbage at line %d", linenr);
+ die(_("patch with only garbage at line %d"), linenr);
}
return offset + hdrsize + patchsize;
@@ -1953,11 +2054,11 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
switch (st->st_mode & S_IFMT) {
case S_IFLNK:
if (strbuf_readlink(buf, path, st->st_size) < 0)
- return error("unable to read symlink %s", path);
+ return error(_("unable to read symlink %s"), path);
return 0;
case S_IFREG:
if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
- return error("unable to open or read %s", path);
+ return error(_("unable to open or read %s"), path);
convert_to_git(path, buf->buf, buf->len, buf, 0);
return 0;
default:
@@ -2028,7 +2129,7 @@ static void update_pre_post_images(struct image *preimage,
ctx++;
}
if (preimage->nr <= ctx)
- die("oops");
+ die(_("oops"));
/* and copy it in, while fixing the line length */
len = preimage->line[ctx].len;
@@ -2367,6 +2468,11 @@ static void remove_last_line(struct image *img)
img->len -= img->line[--img->nr].len;
}
+/*
+ * The change from "preimage" and "postimage" has been found to
+ * apply at applied_pos (counts in line numbers) in "img".
+ * Update "img" to remove "preimage" and replace it with "postimage".
+ */
static void update_image(struct image *img,
int applied_pos,
struct image *preimage,
@@ -2438,6 +2544,11 @@ static void update_image(struct image *img,
img->nr = nr;
}
+/*
+ * Use the patch-hunk text in "frag" to prepare two images (preimage and
+ * postimage) for the hunk. Find lines that match "preimage" in "img" and
+ * replace the part of "img" with "postimage" text.
+ */
static int apply_one_fragment(struct image *img, struct fragment *frag,
int inaccurate_eof, unsigned ws_rule,
int nth_fragment)
@@ -2540,7 +2651,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
break;
default:
if (apply_verbosely)
- error("invalid start of line: '%c'", first);
+ error(_("invalid start of line: '%c'"), first);
return -1;
}
if (added_blank_line) {
@@ -2657,9 +2768,11 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
int offset = applied_pos - pos;
if (apply_in_reverse)
offset = 0 - offset;
- fprintf(stderr,
- "Hunk #%d succeeded at %d (offset %d lines).\n",
- nth_fragment, applied_pos + 1, offset);
+ fprintf_ln(stderr,
+ Q_("Hunk #%d succeeded at %d (offset %d line).",
+ "Hunk #%d succeeded at %d (offset %d lines).",
+ offset),
+ nth_fragment, applied_pos + 1, offset);
}
/*
@@ -2668,13 +2781,13 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
*/
if ((leading != frag->leading) ||
(trailing != frag->trailing))
- fprintf(stderr, "Context reduced to (%ld/%ld)"
- " to apply fragment at %d\n",
- leading, trailing, applied_pos+1);
+ fprintf_ln(stderr, _("Context reduced to (%ld/%ld)"
+ " to apply fragment at %d"),
+ leading, trailing, applied_pos+1);
update_image(img, applied_pos, &preimage, &postimage);
} else {
if (apply_verbosely)
- error("while searching for:\n%.*s",
+ error(_("while searching for:\n%.*s"),
(int)(old - oldlines), oldlines);
}
@@ -2693,7 +2806,7 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
void *dst;
if (!fragment)
- return error("missing binary patch data for '%s'",
+ return error(_("missing binary patch data for '%s'"),
patch->new_name ?
patch->new_name :
patch->old_name);
@@ -2728,6 +2841,12 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
return -1;
}
+/*
+ * Replace "img" with the result of applying the binary patch.
+ * The binary patch data itself in patch->fragment is still kept
+ * but the preimage prepared by the caller in "img" is freed here
+ * or in the helper function apply_binary_fragment() this calls.
+ */
static int apply_binary(struct image *img, struct patch *patch)
{
const char *name = patch->old_name ? patch->old_name : patch->new_name;
@@ -2790,13 +2909,13 @@ static int apply_binary(struct image *img, struct patch *patch)
* in the patch->fragments->{patch,size}.
*/
if (apply_binary_fragment(img, patch))
- return error("binary patch does not apply to '%s'",
+ return error(_("binary patch does not apply to '%s'"),
name);
/* verify that the result matches */
hash_sha1_file(img->buf, img->len, blob_type, sha1);
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
- return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
+ return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
name, patch->new_sha1_prefix, sha1_to_hex(sha1));
}
@@ -2817,7 +2936,7 @@ static int apply_fragments(struct image *img, struct patch *patch)
while (frag) {
nth++;
if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
- error("patch failed: %s:%ld", name, frag->oldpos);
+ error(_("patch failed: %s:%ld"), name, frag->oldpos);
if (!apply_with_reject)
return -1;
frag->rejected = 1;
@@ -2827,20 +2946,17 @@ static int apply_fragments(struct image *img, struct patch *patch)
return 0;
}
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
{
- if (!ce)
- return 0;
-
- if (S_ISGITLINK(ce->ce_mode)) {
+ if (S_ISGITLINK(mode)) {
strbuf_grow(buf, 100);
- strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+ strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
} else {
enum object_type type;
unsigned long sz;
char *result;
- result = read_sha1_file(ce->sha1, &type, &sz);
+ result = read_sha1_file(sha1, &type, &sz);
if (!result)
return -1;
/* XXX read_sha1_file NUL-terminates */
@@ -2849,6 +2965,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
return 0;
}
+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+{
+ if (!ce)
+ return 0;
+ return read_blob_object(buf, ce->sha1, ce->ce_mode);
+}
+
static struct patch *in_fn_table(const char *name)
{
struct string_list_item *item;
@@ -2867,9 +2990,15 @@ static struct patch *in_fn_table(const char *name)
* 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.
+ * path that a previously applied patch has already removed, or
+ * PATH_TO_BE_DELETED for a path that a later patch would remove.
+ *
+ * The latter is needed to deal with a case where two paths A and B
+ * are swapped by first renaming A to B and then renaming B to A;
+ * moving A to B should not be prevented due to presense of B as we
+ * will remove it in a later patch.
*/
- #define PATH_TO_BE_DELETED ((struct patch *) -2)
+#define PATH_TO_BE_DELETED ((struct patch *) -2)
#define PATH_WAS_DELETED ((struct patch *) -1)
static int to_be_deleted(struct patch *patch)
@@ -2921,152 +3050,346 @@ static void prepare_fn_table(struct patch *patch)
}
}
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int checkout_target(struct cache_entry *ce, struct stat *st)
+{
+ struct checkout costate;
+
+ memset(&costate, 0, sizeof(costate));
+ costate.base_dir = "";
+ costate.refresh_cache = 1;
+ if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+ return error(_("cannot checkout %s"), ce->name);
+ return 0;
+}
+
+static struct patch *previous_patch(struct patch *patch, int *gone)
+{
+ struct patch *previous;
+
+ *gone = 0;
+ if (patch->is_copy || patch->is_rename)
+ return NULL; /* "git" patches do not depend on the order */
+
+ previous = in_fn_table(patch->old_name);
+ if (!previous)
+ return NULL;
+
+ if (to_be_deleted(previous))
+ return NULL; /* the deletion hasn't happened yet */
+
+ if (was_deleted(previous))
+ *gone = 1;
+
+ return previous;
+}
+
+static int verify_index_match(struct cache_entry *ce, struct stat *st)
+{
+ if (S_ISGITLINK(ce->ce_mode)) {
+ if (!S_ISDIR(st->st_mode))
+ return -1;
+ return 0;
+ }
+ return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+}
+
+#define SUBMODULE_PATCH_WITHOUT_INDEX 1
+
+static int load_patch_target(struct strbuf *buf,
+ struct cache_entry *ce,
+ struct stat *st,
+ const char *name,
+ unsigned expected_mode)
+{
+ if (cached) {
+ if (read_file_or_gitlink(ce, buf))
+ return error(_("read of %s failed"), name);
+ } else if (name) {
+ if (S_ISGITLINK(expected_mode)) {
+ if (ce)
+ return read_file_or_gitlink(ce, buf);
+ else
+ return SUBMODULE_PATCH_WITHOUT_INDEX;
+ } else {
+ if (read_old_data(st, name, buf))
+ return error(_("read of %s failed"), name);
+ }
+ }
+ return 0;
+}
+
+/*
+ * We are about to apply "patch"; populate the "image" with the
+ * current version we have, from the working tree or from the index,
+ * depending on the situation e.g. --cached/--index. If we are
+ * applying a non-git patch that incrementally updates the tree,
+ * we read from the result of a previous diff.
+ */
+static int load_preimage(struct image *image,
+ struct patch *patch, struct stat *st, struct cache_entry *ce)
{
struct strbuf buf = STRBUF_INIT;
- struct image image;
size_t len;
char *img;
- struct patch *tpatch;
+ struct patch *previous;
+ int status;
- if (!(patch->is_copy || patch->is_rename) &&
- (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);
- }
- /* We have a patched copy in memory use that */
- strbuf_add(&buf, tpatch->result, tpatch->resultsize);
- } else if (cached) {
- if (read_file_or_gitlink(ce, &buf))
- return error("read of %s failed", patch->old_name);
- } else if (patch->old_name) {
- if (S_ISGITLINK(patch->old_mode)) {
- if (ce) {
- read_file_or_gitlink(ce, &buf);
- } else {
- /*
- * There is no way to apply subproject
- * patch without looking at the index.
- */
- patch->fragments = NULL;
- }
- } else {
- if (read_old_data(st, patch->old_name, &buf))
- return error("read of %s failed", patch->old_name);
+ previous = previous_patch(patch, &status);
+ if (status)
+ return error(_("path %s has been renamed/deleted"),
+ patch->old_name);
+ if (previous) {
+ /* We have a patched copy in memory; use that. */
+ strbuf_add(&buf, previous->result, previous->resultsize);
+ } else {
+ status = load_patch_target(&buf, ce, st,
+ patch->old_name, patch->old_mode);
+ if (status < 0)
+ return status;
+ else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
+ /*
+ * There is no way to apply subproject
+ * patch without looking at the index.
+ * NEEDSWORK: shouldn't this be flagged
+ * as an error???
+ */
+ free_fragment_list(patch->fragments);
+ patch->fragments = NULL;
+ } else if (status) {
+ return error(_("read of %s failed"), patch->old_name);
}
}
img = strbuf_detach(&buf, &len);
- prepare_image(&image, img, len, !patch->is_binary);
+ prepare_image(image, img, len, !patch->is_binary);
+ return 0;
+}
- if (apply_fragments(&image, patch) < 0)
- return -1; /* note with --reject this succeeds. */
- patch->result = image.buf;
- patch->resultsize = image.len;
- add_to_fn_table(patch);
- free(image.line_allocated);
+static int three_way_merge(struct image *image,
+ char *path,
+ const unsigned char *base,
+ const unsigned char *ours,
+ const unsigned char *theirs)
+{
+ mmfile_t base_file, our_file, their_file;
+ mmbuffer_t result = { NULL };
+ int status;
- if (0 < patch->is_delete && patch->resultsize)
- return error("removal patch leaves file contents");
+ read_mmblob(&base_file, base);
+ read_mmblob(&our_file, ours);
+ read_mmblob(&their_file, theirs);
+ status = ll_merge(&result, path,
+ &base_file, "base",
+ &our_file, "ours",
+ &their_file, "theirs", NULL);
+ free(base_file.ptr);
+ free(our_file.ptr);
+ free(their_file.ptr);
+ if (status < 0 || !result.ptr) {
+ free(result.ptr);
+ return -1;
+ }
+ clear_image(image);
+ image->buf = result.ptr;
+ image->len = result.size;
+
+ return status;
+}
+
+/*
+ * When directly falling back to add/add three-way merge, we read from
+ * the current contents of the new_name. In no cases other than that
+ * this function will be called.
+ */
+static int load_current(struct image *image, struct patch *patch)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int status, pos;
+ size_t len;
+ char *img;
+ struct stat st;
+ struct cache_entry *ce;
+ char *name = patch->new_name;
+ unsigned mode = patch->new_mode;
+
+ if (!patch->is_new)
+ die("BUG: patch to %s is not a creation", patch->old_name);
+
+ pos = cache_name_pos(name, strlen(name));
+ if (pos < 0)
+ return error(_("%s: does not exist in index"), name);
+ ce = active_cache[pos];
+ if (lstat(name, &st)) {
+ if (errno != ENOENT)
+ return error(_("%s: %s"), name, strerror(errno));
+ if (checkout_target(ce, &st))
+ return -1;
+ }
+ if (verify_index_match(ce, &st))
+ return error(_("%s: does not match index"), name);
+ status = load_patch_target(&buf, ce, &st, name, mode);
+ if (status < 0)
+ return status;
+ else if (status)
+ return -1;
+ img = strbuf_detach(&buf, &len);
+ prepare_image(image, img, len, !patch->is_binary);
return 0;
}
-static int check_to_create_blob(const char *new_name, int ok_if_exists)
+static int try_threeway(struct image *image, struct patch *patch,
+ struct stat *st, struct cache_entry *ce)
{
- struct stat nst;
- if (!lstat(new_name, &nst)) {
- if (S_ISDIR(nst.st_mode) || ok_if_exists)
- return 0;
- /*
- * A leading component of new_name might be a symlink
- * that is going to be removed with this patch, but
- * still pointing at somewhere that has the path.
- * In such a case, path "new_name" does not exist as
- * far as git is concerned.
- */
- if (has_symlink_leading_path(new_name, strlen(new_name)))
- return 0;
+ unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
+ struct strbuf buf = STRBUF_INIT;
+ size_t len;
+ int status;
+ char *img;
+ struct image tmp_image;
+
+ /* No point falling back to 3-way merge in these cases */
+ if (patch->is_delete ||
+ S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
+ return -1;
+
+ /* Preimage the patch was prepared for */
+ if (patch->is_new)
+ write_sha1_file("", 0, blob_type, pre_sha1);
+ else if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
+ read_blob_object(&buf, pre_sha1, patch->old_mode))
+ return error("repository lacks the necessary blob to fall back on 3-way merge.");
+
+ fprintf(stderr, "Falling back to three-way merge...\n");
- return error("%s: already exists in working directory", new_name);
+ img = strbuf_detach(&buf, &len);
+ prepare_image(&tmp_image, img, len, 1);
+ /* Apply the patch to get the post image */
+ if (apply_fragments(&tmp_image, patch) < 0) {
+ clear_image(&tmp_image);
+ return -1;
+ }
+ /* post_sha1[] is theirs */
+ write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
+ clear_image(&tmp_image);
+
+ /* our_sha1[] is ours */
+ if (patch->is_new) {
+ if (load_current(&tmp_image, patch))
+ return error("cannot read the current contents of '%s'",
+ patch->new_name);
+ } else {
+ if (load_preimage(&tmp_image, patch, st, ce))
+ return error("cannot read the current contents of '%s'",
+ patch->old_name);
+ }
+ write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
+ clear_image(&tmp_image);
+
+ /* in-core three-way merge between post and our using pre as base */
+ status = three_way_merge(image, patch->new_name,
+ pre_sha1, our_sha1, post_sha1);
+ if (status < 0) {
+ fprintf(stderr, "Failed to fall back on three-way merge...\n");
+ return status;
+ }
+
+ if (status) {
+ patch->conflicted_threeway = 1;
+ if (patch->is_new)
+ hashclr(patch->threeway_stage[0]);
+ else
+ hashcpy(patch->threeway_stage[0], pre_sha1);
+ hashcpy(patch->threeway_stage[1], our_sha1);
+ hashcpy(patch->threeway_stage[2], post_sha1);
+ fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
+ } else {
+ fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
}
- else if ((errno != ENOENT) && (errno != ENOTDIR))
- return error("%s: %s", new_name, strerror(errno));
return 0;
}
-static int verify_index_match(struct cache_entry *ce, struct stat *st)
+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
- if (S_ISGITLINK(ce->ce_mode)) {
- if (!S_ISDIR(st->st_mode))
+ struct image image;
+
+ if (load_preimage(&image, patch, st, ce) < 0)
+ return -1;
+
+ if (patch->direct_to_threeway ||
+ apply_fragments(&image, patch) < 0) {
+ /* Note: with --reject, apply_fragments() returns 0 */
+ if (!threeway || try_threeway(&image, patch, st, ce) < 0)
return -1;
- return 0;
}
- return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+ patch->result = image.buf;
+ patch->resultsize = image.len;
+ add_to_fn_table(patch);
+ free(image.line_allocated);
+
+ if (0 < patch->is_delete && patch->resultsize)
+ return error(_("removal patch leaves file contents"));
+
+ return 0;
}
+/*
+ * If "patch" that we are looking at modifies or deletes what we have,
+ * we would want it not to lose any local modification we have, either
+ * in the working tree or in the index.
+ *
+ * This also decides if a non-git patch is a creation patch or a
+ * modification to an existing empty file. We do not check the state
+ * of the current tree for a creation patch in this function; the caller
+ * check_patch() separately makes sure (and errors out otherwise) that
+ * the path the patch creates does not exist in the current tree.
+ */
static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
{
const char *old_name = patch->old_name;
- struct patch *tpatch = NULL;
- int stat_ret = 0;
+ struct patch *previous = NULL;
+ int stat_ret = 0, status;
unsigned st_mode = 0;
- /*
- * Make sure that we do not have local modifications from the
- * index when we are looking at the index. Also make sure
- * we have the preimage file to be patched in the work tree,
- * unless --cached, which tells git to apply only in the index.
- */
if (!old_name)
return 0;
assert(patch->is_new <= 0);
+ previous = previous_patch(patch, &status);
- if (!(patch->is_copy || patch->is_rename) &&
- (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;
+ if (status)
+ return error(_("path %s has been renamed/deleted"), old_name);
+ if (previous) {
+ st_mode = previous->new_mode;
} else if (!cached) {
stat_ret = lstat(old_name, st);
if (stat_ret && errno != ENOENT)
- return error("%s: %s", old_name, strerror(errno));
+ return error(_("%s: %s"), old_name, strerror(errno));
}
- if (to_be_deleted(tpatch))
- tpatch = NULL;
-
- if (check_index && !tpatch) {
+ if (check_index && !previous) {
int pos = cache_name_pos(old_name, strlen(old_name));
if (pos < 0) {
if (patch->is_new < 0)
goto is_new;
- return error("%s: does not exist in index", old_name);
+ return error(_("%s: does not exist in index"), old_name);
}
*ce = active_cache[pos];
if (stat_ret < 0) {
- struct checkout costate;
- /* checkout */
- memset(&costate, 0, sizeof(costate));
- costate.base_dir = "";
- costate.refresh_cache = 1;
- if (checkout_entry(*ce, &costate, NULL) ||
- lstat(old_name, st))
+ if (checkout_target(*ce, st))
return -1;
}
if (!cached && verify_index_match(*ce, st))
- return error("%s: does not match index", old_name);
+ return error(_("%s: does not match index"), old_name);
if (cached)
st_mode = (*ce)->ce_mode;
} else if (stat_ret < 0) {
if (patch->is_new < 0)
goto is_new;
- return error("%s: %s", old_name, strerror(errno));
+ return error(_("%s: %s"), old_name, strerror(errno));
}
- if (!cached && !tpatch)
+ if (!cached && !previous)
st_mode = ce_mode_from_stat(*ce, st->st_mode);
if (patch->is_new < 0)
@@ -3074,9 +3397,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
if (!patch->old_mode)
patch->old_mode = st_mode;
if ((st_mode ^ patch->old_mode) & S_IFMT)
- return error("%s: wrong type", old_name);
+ return error(_("%s: wrong type"), old_name);
if (st_mode != patch->old_mode)
- warning("%s has type %o, expected %o",
+ warning(_("%s has type %o, expected %o"),
old_name, st_mode, patch->old_mode);
if (!patch->new_mode && !patch->is_delete)
patch->new_mode = st_mode;
@@ -3085,10 +3408,50 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
is_new:
patch->is_new = 1;
patch->is_delete = 0;
+ free(patch->old_name);
patch->old_name = NULL;
return 0;
}
+
+#define EXISTS_IN_INDEX 1
+#define EXISTS_IN_WORKTREE 2
+
+static int check_to_create(const char *new_name, int ok_if_exists)
+{
+ struct stat nst;
+
+ if (check_index &&
+ cache_name_pos(new_name, strlen(new_name)) >= 0 &&
+ !ok_if_exists)
+ return EXISTS_IN_INDEX;
+ if (cached)
+ return 0;
+
+ if (!lstat(new_name, &nst)) {
+ if (S_ISDIR(nst.st_mode) || ok_if_exists)
+ return 0;
+ /*
+ * A leading component of new_name might be a symlink
+ * that is going to be removed with this patch, but
+ * still pointing at somewhere that has the path.
+ * In such a case, path "new_name" does not exist as
+ * far as git is concerned.
+ */
+ if (has_symlink_leading_path(new_name, strlen(new_name)))
+ return 0;
+
+ return EXISTS_IN_WORKTREE;
+ } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
+ return error("%s: %s", new_name, strerror(errno));
+ }
+ return 0;
+}
+
+/*
+ * Check and apply the patch in-core; leave the result in patch->result
+ * for the caller to write it out to the final destination.
+ */
static int check_patch(struct patch *patch)
{
struct stat st;
@@ -3107,31 +3470,45 @@ static int check_patch(struct patch *patch)
return status;
old_name = patch->old_name;
+ /*
+ * A type-change diff is always split into a patch to delete
+ * old, immediately followed by a patch to create new (see
+ * diff.c::run_diff()); in such a case it is Ok that the entry
+ * to be deleted by the previous patch is still in the working
+ * tree and in the index.
+ *
+ * A patch to swap-rename between A and B would first rename A
+ * to B and then rename B to A. While applying the first one,
+ * the presense of B should not stop A from getting renamed to
+ * B; ask to_be_deleted() about the later rename. Removal of
+ * B and rename from A to B is handled the same way by asking
+ * was_deleted().
+ */
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
- * create new (see diff.c::run_diff()); in such a case
- * it is Ok that the entry to be deleted by the
- * previous patch is still in the working tree and in
- * the index.
- */
+ (was_deleted(tpatch) || to_be_deleted(tpatch)))
ok_if_exists = 1;
else
ok_if_exists = 0;
if (new_name &&
((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
- if (check_index &&
- cache_name_pos(new_name, strlen(new_name)) >= 0 &&
- !ok_if_exists)
- return error("%s: already exists in index", new_name);
- if (!cached) {
- int err = check_to_create_blob(new_name, ok_if_exists);
- if (err)
- return err;
+ int err = check_to_create(new_name, ok_if_exists);
+
+ if (err && threeway) {
+ patch->direct_to_threeway = 1;
+ } else switch (err) {
+ case 0:
+ break; /* happy */
+ case EXISTS_IN_INDEX:
+ return error(_("%s: already exists in index"), new_name);
+ break;
+ case EXISTS_IN_WORKTREE:
+ return error(_("%s: already exists in working directory"),
+ new_name);
+ default:
+ return err;
}
+
if (!patch->new_mode) {
if (0 < patch->is_new)
patch->new_mode = S_IFREG | 0644;
@@ -3144,14 +3521,22 @@ static int check_patch(struct patch *patch)
int same = !strcmp(old_name, new_name);
if (!patch->new_mode)
patch->new_mode = patch->old_mode;
- if ((patch->old_mode ^ patch->new_mode) & S_IFMT)
- return error("new mode (%o) of %s does not match old mode (%o)%s%s",
- patch->new_mode, new_name, patch->old_mode,
- same ? "" : " of ", same ? "" : old_name);
+ if ((patch->old_mode ^ patch->new_mode) & S_IFMT) {
+ if (same)
+ return error(_("new mode (%o) of %s does not "
+ "match old mode (%o)"),
+ patch->new_mode, new_name,
+ patch->old_mode);
+ else
+ return error(_("new mode (%o) of %s does not "
+ "match old mode (%o) of %s"),
+ patch->new_mode, new_name,
+ patch->old_mode, old_name);
+ }
}
if (apply_data(patch, &st, ce) < 0)
- return error("%s: patch does not apply", name);
+ return error(_("%s: patch does not apply"), name);
patch->rejected = 0;
return 0;
}
@@ -3164,7 +3549,7 @@ static int check_patch_list(struct patch *patch)
while (patch) {
if (apply_verbosely)
say_patch_name(stderr,
- "Checking patch ", patch, "...\n");
+ _("Checking patch %s..."), patch);
err |= check_patch(patch);
patch = patch->next;
}
@@ -3219,7 +3604,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
if (!ce)
- die("make_cache_entry failed for path '%s'", name);
+ die(_("make_cache_entry failed for path '%s'"), name);
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
die ("Could not add %s to temporary index", name);
}
@@ -3362,7 +3747,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
{
if (update_index) {
if (remove_file_from_cache(patch->old_name) < 0)
- die("unable to remove %s from index", patch->old_name);
+ die(_("unable to remove %s from index"), patch->old_name);
}
if (!cached) {
if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
@@ -3389,19 +3774,19 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
const char *s = buf;
if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
- die("corrupt patch for subproject %s", path);
+ die(_("corrupt patch for subproject %s"), path);
} else {
if (!cached) {
if (lstat(path, &st) < 0)
- die_errno("unable to stat newly created file '%s'",
+ die_errno(_("unable to stat newly created file '%s'"),
path);
fill_stat_cache_info(ce, &st);
}
if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
- die("unable to create backing store for newly created file %s", path);
+ die(_("unable to create backing store for newly created file %s"), path);
}
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
- die("unable to add cache entry for %s", path);
+ die(_("unable to add cache entry for %s"), path);
}
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
@@ -3434,7 +3819,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
strbuf_release(&nbuf);
if (close(fd) < 0)
- die_errno("closing file '%s'", path);
+ die_errno(_("closing file '%s'"), path);
return 0;
}
@@ -3483,7 +3868,33 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
++nr;
}
}
- die_errno("unable to write file '%s' mode %o", path, mode);
+ die_errno(_("unable to write file '%s' mode %o"), path, mode);
+}
+
+static void add_conflicted_stages_file(struct patch *patch)
+{
+ int stage, namelen;
+ unsigned ce_size, mode;
+ struct cache_entry *ce;
+
+ if (!update_index)
+ return;
+ namelen = strlen(patch->new_name);
+ ce_size = cache_entry_size(namelen);
+ mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
+
+ remove_file_from_cache(patch->new_name);
+ for (stage = 1; stage < 4; stage++) {
+ if (is_null_sha1(patch->threeway_stage[stage - 1]))
+ continue;
+ ce = xcalloc(1, ce_size);
+ memcpy(ce->name, patch->new_name, namelen);
+ ce->ce_mode = create_ce_mode(mode);
+ ce->ce_flags = create_ce_flags(namelen, stage);
+ hashcpy(ce->sha1, patch->threeway_stage[stage - 1]);
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
+ die(_("unable to add cache entry for %s"), patch->new_name);
+ }
}
static void create_file(struct patch *patch)
@@ -3496,7 +3907,11 @@ static void create_file(struct patch *patch)
if (!mode)
mode = S_IFREG | 0644;
create_one_file(path, mode, buf, size);
- add_index_file(path, mode, buf, size);
+
+ if (patch->conflicted_threeway)
+ add_conflicted_stages_file(patch);
+ else
+ add_index_file(path, mode, buf, size);
}
/* phase zero is to remove, phase one is to create */
@@ -3528,6 +3943,7 @@ static int write_out_one_reject(struct patch *patch)
char namebuf[PATH_MAX];
struct fragment *frag;
int cnt = 0;
+ struct strbuf sb = STRBUF_INIT;
for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
if (!frag->rejected)
@@ -3538,7 +3954,7 @@ static int write_out_one_reject(struct patch *patch)
if (!cnt) {
if (apply_verbosely)
say_patch_name(stderr,
- "Applied patch ", patch, " cleanly.\n");
+ _("Applied patch %s cleanly."), patch);
return 0;
}
@@ -3546,16 +3962,20 @@ static int write_out_one_reject(struct patch *patch)
* contents are marked "rejected" at the patch level.
*/
if (!patch->new_name)
- die("internal error");
+ die(_("internal error"));
/* Say this even without --verbose */
- say_patch_name(stderr, "Applying patch ", patch, " with");
- fprintf(stderr, " %d rejects...\n", cnt);
+ strbuf_addf(&sb, Q_("Applying patch %%s with %d reject...",
+ "Applying patch %%s with %d rejects...",
+ cnt),
+ cnt);
+ say_patch_name(stderr, sb.buf, patch);
+ strbuf_release(&sb);
cnt = strlen(patch->new_name);
if (ARRAY_SIZE(namebuf) <= cnt + 5) {
cnt = ARRAY_SIZE(namebuf) - 5;
- warning("truncating .rej filename to %.*s.rej",
+ warning(_("truncating .rej filename to %.*s.rej"),
cnt - 1, patch->new_name);
}
memcpy(namebuf, patch->new_name, cnt);
@@ -3563,7 +3983,7 @@ static int write_out_one_reject(struct patch *patch)
rej = fopen(namebuf, "w");
if (!rej)
- return error("cannot open %s: %s", namebuf, strerror(errno));
+ return error(_("cannot open %s: %s"), namebuf, strerror(errno));
/* Normal git tools never deal with .rej, so do not pretend
* this is a git patch by saying --git nor give extended
@@ -3576,10 +3996,10 @@ static int write_out_one_reject(struct patch *patch)
frag;
cnt++, frag = frag->next) {
if (!frag->rejected) {
- fprintf(stderr, "Hunk #%d applied cleanly.\n", cnt);
+ fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt);
continue;
}
- fprintf(stderr, "Rejected hunk #%d.\n", cnt);
+ fprintf_ln(stderr, _("Rejected hunk #%d."), cnt);
fprintf(rej, "%.*s", frag->size, frag->patch);
if (frag->patch[frag->size-1] != '\n')
fputc('\n', rej);
@@ -3593,6 +4013,7 @@ static int write_out_results(struct patch *list)
int phase;
int errs = 0;
struct patch *l;
+ struct string_list cpath = STRING_LIST_INIT_DUP;
for (phase = 0; phase < 2; phase++) {
l = list;
@@ -3601,12 +4022,30 @@ static int write_out_results(struct patch *list)
errs = 1;
else {
write_out_one_result(l, phase);
- if (phase == 1 && write_out_one_reject(l))
- errs = 1;
+ if (phase == 1) {
+ if (write_out_one_reject(l))
+ errs = 1;
+ if (l->conflicted_threeway) {
+ string_list_append(&cpath, l->new_name);
+ errs = 1;
+ }
+ }
}
l = l->next;
}
}
+
+ if (cpath.nr) {
+ struct string_list_item *item;
+
+ sort_string_list(&cpath);
+ for_each_string_list_item(item, &cpath)
+ fprintf(stderr, "U %s\n", item->string);
+ string_list_clear(&cpath, 0);
+
+ rerere(0);
+ }
+
return errs;
}
@@ -3665,15 +4104,8 @@ static void prefix_patches(struct patch *p)
if (!prefix || p->is_toplevel_relative)
return;
for ( ; p; p = p->next) {
- if (p->new_name == p->old_name) {
- char *prefixed = p->new_name;
- prefix_one(&prefixed);
- p->new_name = p->old_name = prefixed;
- }
- else {
- prefix_one(&p->new_name);
- prefix_one(&p->old_name);
- }
+ prefix_one(&p->new_name);
+ prefix_one(&p->old_name);
}
}
@@ -3683,12 +4115,10 @@ static void prefix_patches(struct patch *p)
static int apply_patch(int fd, const char *filename, int options)
{
size_t offset;
- struct strbuf buf = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT; /* owns the patch text */
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
- /* FIXME - memory leak when using multiple patch files as inputs */
- memset(&fn_table, 0, sizeof(struct string_list));
patch_input_file = filename;
read_patch_file(&buf, fd);
offset = 0;
@@ -3712,15 +4142,14 @@ static int apply_patch(int fd, const char *filename, int options)
listp = &patch->next;
}
else {
- /* perhaps free it a bit better? */
- free(patch);
+ free_patch(patch);
skipped_patch++;
}
offset += nr;
}
if (!list && !skipped_patch)
- die("unrecognized input");
+ die(_("unrecognized input"));
if (whitespace_error && (ws_error_action == die_on_ws_error))
apply = 0;
@@ -3731,7 +4160,7 @@ static int apply_patch(int fd, const char *filename, int options)
if (check_index) {
if (read_cache() < 0)
- die("unable to read index file");
+ die(_("unable to read index file"));
}
if ((check || apply) &&
@@ -3739,8 +4168,12 @@ static int apply_patch(int fd, const char *filename, int options)
!apply_with_reject)
exit(1);
- if (apply && write_out_results(list))
- exit(1);
+ if (apply && write_out_results(list)) {
+ if (apply_with_reject)
+ exit(1);
+ /* with --3way, we still need to write the index out */
+ return 1;
+ }
if (fake_ancestor)
build_fake_ancestor(list, fake_ancestor);
@@ -3754,7 +4187,9 @@ static int apply_patch(int fd, const char *filename, int options)
if (summary)
summary_patch_list(list);
+ free_patch_list(list);
strbuf_release(&buf);
+ string_list_clear(&fn_table, 0);
return 0;
}
@@ -3844,66 +4279,68 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
const char *whitespace_option = NULL;
struct option builtin_apply_options[] = {
- { OPTION_CALLBACK, 0, "exclude", NULL, "path",
- "don't apply changes matching the given path",
+ { OPTION_CALLBACK, 0, "exclude", NULL, N_("path"),
+ N_("don't apply changes matching the given path"),
0, option_parse_exclude },
- { OPTION_CALLBACK, 0, "include", NULL, "path",
- "apply changes matching the given path",
+ { OPTION_CALLBACK, 0, "include", NULL, N_("path"),
+ N_("apply changes matching the given path"),
0, option_parse_include },
- { OPTION_CALLBACK, 'p', NULL, NULL, "num",
- "remove <num> leading slashes from traditional diff paths",
+ { OPTION_CALLBACK, 'p', NULL, NULL, N_("num"),
+ N_("remove <num> leading slashes from traditional diff paths"),
0, option_parse_p },
OPT_BOOLEAN(0, "no-add", &no_add,
- "ignore additions made by the patch"),
+ N_("ignore additions made by the patch")),
OPT_BOOLEAN(0, "stat", &diffstat,
- "instead of applying the patch, output diffstat for the input"),
+ N_("instead of applying the patch, output diffstat for the input")),
OPT_NOOP_NOARG(0, "allow-binary-replacement"),
OPT_NOOP_NOARG(0, "binary"),
OPT_BOOLEAN(0, "numstat", &numstat,
- "shows number of added and deleted lines in decimal notation"),
+ N_("shows number of added and deleted lines in decimal notation")),
OPT_BOOLEAN(0, "summary", &summary,
- "instead of applying the patch, output a summary for the input"),
+ N_("instead of applying the patch, output a summary for the input")),
OPT_BOOLEAN(0, "check", &check,
- "instead of applying the patch, see if the patch is applicable"),
+ N_("instead of applying the patch, see if the patch is applicable")),
OPT_BOOLEAN(0, "index", &check_index,
- "make sure the patch is applicable to the current index"),
+ N_("make sure the patch is applicable to the current index")),
OPT_BOOLEAN(0, "cached", &cached,
- "apply a patch without touching the working tree"),
+ N_("apply a patch without touching the working tree")),
OPT_BOOLEAN(0, "apply", &force_apply,
- "also apply the patch (use with --stat/--summary/--check)"),
+ N_("also apply the patch (use with --stat/--summary/--check)")),
+ OPT_BOOL('3', "3way", &threeway,
+ N_( "attempt three-way merge if a patch does not apply")),
OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
- "build a temporary index based on embedded index information"),
+ N_("build a temporary index based on embedded index information")),
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
- "paths are separated with NUL character",
+ N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
OPT_INTEGER('C', NULL, &p_context,
- "ensure at least <n> lines of context match"),
- { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, "action",
- "detect new or modified lines that have whitespace errors",
+ N_("ensure at least <n> lines of context match")),
+ { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"),
+ N_("detect new or modified lines that have whitespace errors"),
0, option_parse_whitespace },
{ OPTION_CALLBACK, 0, "ignore-space-change", NULL, NULL,
- "ignore changes in whitespace when finding context",
+ N_("ignore changes in whitespace when finding context"),
PARSE_OPT_NOARG, option_parse_space_change },
{ OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
- "ignore changes in whitespace when finding context",
+ N_("ignore changes in whitespace when finding context"),
PARSE_OPT_NOARG, option_parse_space_change },
OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
- "apply the patch in reverse"),
+ N_("apply the patch in reverse")),
OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
- "don't expect at least one line of context"),
+ N_("don't expect at least one line of context")),
OPT_BOOLEAN(0, "reject", &apply_with_reject,
- "leave the rejected hunks in corresponding *.rej files"),
+ N_("leave the rejected hunks in corresponding *.rej files")),
OPT_BOOLEAN(0, "allow-overlap", &allow_overlap,
- "allow overlapping hunks"),
- OPT__VERBOSE(&apply_verbosely, "be verbose"),
+ N_("allow overlapping hunks")),
+ OPT__VERBOSE(&apply_verbosely, N_("be verbose")),
OPT_BIT(0, "inaccurate-eof", &options,
- "tolerate incorrectly detected missing new-line at the end of file",
+ N_("tolerate incorrectly detected missing new-line at the end of file"),
INACCURATE_EOF),
OPT_BIT(0, "recount", &options,
- "do not trust the line counts in the hunk headers",
+ N_("do not trust the line counts in the hunk headers"),
RECOUNT),
- { OPTION_CALLBACK, 0, "directory", NULL, "root",
- "prepend <root> to all filenames",
+ { OPTION_CALLBACK, 0, "directory", NULL, N_("root"),
+ N_("prepend <root> to all filenames"),
0, option_parse_directory },
OPT_END()
};
@@ -3919,15 +4356,24 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
argc = parse_options(argc, argv, prefix, builtin_apply_options,
apply_usage, 0);
+ if (apply_with_reject && threeway)
+ die("--reject and --3way cannot be used together.");
+ if (cached && threeway)
+ die("--cached and --3way cannot be used together.");
+ if (threeway) {
+ if (is_not_gitdir)
+ die(_("--3way outside a repository"));
+ check_index = 1;
+ }
if (apply_with_reject)
apply = apply_verbosely = 1;
if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
apply = 0;
if (check_index && is_not_gitdir)
- die("--index outside a repository");
+ die(_("--index outside a repository"));
if (cached) {
if (is_not_gitdir)
- die("--cached outside a repository");
+ die(_("--cached outside a repository"));
check_index = 1;
}
for (i = 0; i < argc; i++) {
@@ -3943,7 +4389,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
fd = open(arg, O_RDONLY);
if (fd < 0)
- die_errno("can't open patch '%s'", arg);
+ die_errno(_("can't open patch '%s'"), arg);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
errs |= apply_patch(fd, arg, options);
@@ -3957,32 +4403,32 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
squelch_whitespace_errors < whitespace_error) {
int squelched =
whitespace_error - squelch_whitespace_errors;
- warning("squelched %d "
- "whitespace error%s",
- squelched,
- squelched == 1 ? "" : "s");
+ warning(Q_("squelched %d whitespace error",
+ "squelched %d whitespace errors",
+ squelched),
+ squelched);
}
if (ws_error_action == die_on_ws_error)
- die("%d line%s add%s whitespace errors.",
- whitespace_error,
- whitespace_error == 1 ? "" : "s",
- whitespace_error == 1 ? "s" : "");
+ die(Q_("%d line adds whitespace errors.",
+ "%d lines add whitespace errors.",
+ whitespace_error),
+ whitespace_error);
if (applied_after_fixing_ws && apply)
warning("%d line%s applied after"
" fixing whitespace errors.",
applied_after_fixing_ws,
applied_after_fixing_ws == 1 ? "" : "s");
else if (whitespace_error)
- warning("%d line%s add%s whitespace errors.",
- whitespace_error,
- whitespace_error == 1 ? "" : "s",
- whitespace_error == 1 ? "s" : "");
+ warning(Q_("%d line adds whitespace errors.",
+ "%d lines add whitespace errors.",
+ whitespace_error),
+ whitespace_error);
}
if (update_index) {
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(&lock_file))
- die("Unable to write new index file");
+ die(_("Unable to write new index file"));
}
return !!errs;
diff --git a/builtin/blame.c b/builtin/blame.c
index 5a67c20..960c58d 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -88,6 +88,20 @@ struct origin {
char path[FLEX_ARRAY];
};
+static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,
+ xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)
+{
+ xpparam_t xpp = {0};
+ xdemitconf_t xecfg = {0};
+ xdemitcb_t ecb = {NULL};
+
+ xpp.flags = xdl_opts;
+ xecfg.ctxlen = ctxlen;
+ xecfg.hunk_func = hunk_func;
+ ecb.priv = cb_data;
+ return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);
+}
+
/*
* Prepare diff_filespec and convert it using diff textconv API
* if the textconv driver exists.
@@ -759,12 +773,14 @@ struct blame_chunk_cb_data {
long tlno;
};
-static void blame_chunk_cb(void *data, long same, long p_next, long t_next)
+static int blame_chunk_cb(long start_a, long count_a,
+ long start_b, long count_b, void *data)
{
struct blame_chunk_cb_data *d = data;
- blame_chunk(d->sb, d->tlno, d->plno, same, d->target, d->parent);
- d->plno = p_next;
- d->tlno = t_next;
+ blame_chunk(d->sb, d->tlno, d->plno, start_b, d->target, d->parent);
+ d->plno = start_a + count_a;
+ d->tlno = start_b + count_b;
+ return 0;
}
/*
@@ -779,8 +795,7 @@ static int pass_blame_to_parent(struct scoreboard *sb,
int last_in_target;
mmfile_t file_p, file_o;
struct blame_chunk_cb_data d;
- xpparam_t xpp;
- xdemitconf_t xecfg;
+
memset(&d, 0, sizeof(d));
d.sb = sb; d.target = target; d.parent = parent;
last_in_target = find_last_in_target(sb, target);
@@ -791,11 +806,7 @@ static int pass_blame_to_parent(struct scoreboard *sb,
fill_origin_blob(&sb->revs->diffopt, target, &file_o);
num_get_patch++;
- memset(&xpp, 0, sizeof(xpp));
- xpp.flags = xdl_opts;
- memset(&xecfg, 0, sizeof(xecfg));
- xecfg.ctxlen = 0;
- xdi_diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, &xpp, &xecfg);
+ diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
/* The rest (i.e. anything after tlno) are the same as the parent */
blame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);
@@ -899,12 +910,15 @@ struct handle_split_cb_data {
long tlno;
};
-static void handle_split_cb(void *data, long same, long p_next, long t_next)
+static int handle_split_cb(long start_a, long count_a,
+ long start_b, long count_b, void *data)
{
struct handle_split_cb_data *d = data;
- handle_split(d->sb, d->ent, d->tlno, d->plno, same, d->parent, d->split);
- d->plno = p_next;
- d->tlno = t_next;
+ handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent,
+ d->split);
+ d->plno = start_a + count_a;
+ d->tlno = start_b + count_b;
+ return 0;
}
/*
@@ -922,8 +936,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
int cnt;
mmfile_t file_o;
struct handle_split_cb_data d;
- xpparam_t xpp;
- xdemitconf_t xecfg;
+
memset(&d, 0, sizeof(d));
d.sb = sb; d.ent = ent; d.parent = parent; d.split = split;
/*
@@ -943,12 +956,8 @@ static void find_copy_in_blob(struct scoreboard *sb,
* file_o is a part of final image we are annotating.
* file_p partially may match that image.
*/
- memset(&xpp, 0, sizeof(xpp));
- xpp.flags = xdl_opts;
- memset(&xecfg, 0, sizeof(xecfg));
- xecfg.ctxlen = 1;
memset(split, 0, sizeof(struct blame_entry [3]));
- xdi_diff_hunks(file_p, &file_o, handle_split_cb, &d, &xpp, &xecfg);
+ diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
/* remainder, if any, all match the preimage */
handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
}
@@ -1828,16 +1837,14 @@ static int read_ancestry(const char *graft_file)
return 0;
}
-/*
- * How many columns do we need to show line numbers in decimal?
- */
-static int lineno_width(int lines)
+static int update_auto_abbrev(int auto_abbrev, struct origin *suspect)
{
- int i, width;
-
- for (width = 1, i = 10; i <= lines; width++)
- i *= 10;
- return width;
+ const char *uniq = find_unique_abbrev(suspect->commit->object.sha1,
+ auto_abbrev);
+ int len = strlen(uniq);
+ if (auto_abbrev < len)
+ return len;
+ return auto_abbrev;
}
/*
@@ -1850,12 +1857,16 @@ static void find_alignment(struct scoreboard *sb, int *option)
int longest_dst_lines = 0;
unsigned largest_score = 0;
struct blame_entry *e;
+ int compute_auto_abbrev = (abbrev < 0);
+ int auto_abbrev = default_abbrev;
for (e = sb->ent; e; e = e->next) {
struct origin *suspect = e->suspect;
struct commit_info ci;
int num;
+ if (compute_auto_abbrev)
+ auto_abbrev = update_auto_abbrev(auto_abbrev, suspect);
if (strcmp(suspect->path, sb->path))
*option |= OUTPUT_SHOW_NAME;
num = strlen(suspect->path);
@@ -1880,9 +1891,13 @@ static void find_alignment(struct scoreboard *sb, int *option)
if (largest_score < ent_score(sb, e))
largest_score = ent_score(sb, e);
}
- max_orig_digits = lineno_width(longest_src_lines);
- max_digits = lineno_width(longest_dst_lines);
- max_score_digits = lineno_width(largest_score);
+ max_orig_digits = decimal_width(longest_src_lines);
+ max_digits = decimal_width(longest_dst_lines);
+ max_score_digits = decimal_width(largest_score);
+
+ if (compute_auto_abbrev)
+ /* one more abbrev length is needed for the boundary commit */
+ abbrev = auto_abbrev + 1;
}
/*
@@ -2050,14 +2065,8 @@ static int git_blame_config(const char *var, const char *value, void *cb)
return 0;
}
- switch (userdiff_config(var, value)) {
- case 0:
- break;
- case -1:
+ if (userdiff_config(var, value) < 0)
return -1;
- default:
- return 0;
- }
return git_default_config(var, value, cb);
}
@@ -2320,6 +2329,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
OPT_BIT('e', "show-email", &output_option, "Show author email instead of name (Default: off)", OUTPUT_SHOW_EMAIL),
OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
+ OPT_BIT(0, "minimal", &xdl_opts, "Spend extra cycles to find better match", XDF_NEED_MINIMAL),
OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
{ OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
@@ -2361,10 +2371,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_done:
argc = parse_options_end(&ctx);
- if (abbrev == -1)
- abbrev = default_abbrev;
- /* one more abbrev length is needed for the boundary commit */
- abbrev++;
+ if (0 < abbrev)
+ /* one more abbrev length is needed for the boundary commit */
+ abbrev++;
if (revs_file && read_ancestry(revs_file))
die_errno("reading graft file '%s' failed", revs_file);
diff --git a/builtin/branch.c b/builtin/branch.c
index d8cccf7..0e060f2 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -15,6 +15,8 @@
#include "branch.h"
#include "diff.h"
#include "revision.h"
+#include "string-list.h"
+#include "column.h"
static const char * const builtin_branch_usage[] = {
"git branch [options] [-r | -a] [--merged | --no-merged]",
@@ -53,6 +55,9 @@ static enum merge_filter {
} merge_filter;
static unsigned char merge_filter_ref[20];
+static struct string_list output = STRING_LIST_INIT_DUP;
+static unsigned int colopts;
+
static int parse_branch_color_slot(const char *var, int ofs)
{
if (!strcasecmp(var+ofs, "plain"))
@@ -70,6 +75,8 @@ static int parse_branch_color_slot(const char *var, int ofs)
static int git_branch_config(const char *var, const char *value, void *cb)
{
+ if (!prefixcmp(var, "column."))
+ return git_column_config(var, value, "branch", &colopts);
if (!strcmp(var, "color.branch")) {
branch_use_color = git_config_colorbool(var, value);
return 0;
@@ -146,26 +153,28 @@ static int branch_merged(int kind, const char *name,
return merged;
}
-static int delete_branches(int argc, const char **argv, int force, int kinds)
+static int delete_branches(int argc, const char **argv, int force, int kinds,
+ int quiet)
{
struct commit *rev, *head_rev = NULL;
unsigned char sha1[20];
char *name = NULL;
- const char *fmt, *remote;
+ const char *fmt;
int i;
int ret = 0;
+ int remote_branch = 0;
struct strbuf bname = STRBUF_INIT;
switch (kinds) {
case REF_REMOTE_BRANCH:
fmt = "refs/remotes/%s";
- /* TRANSLATORS: This is "remote " in "remote branch '%s' not found" */
- remote = _("remote ");
+ /* For subsequent UI messages */
+ remote_branch = 1;
+
force = 1;
break;
case REF_LOCAL_BRANCH:
fmt = "refs/heads/%s";
- remote = "";
break;
default:
die(_("cannot use -a with -d"));
@@ -189,8 +198,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
name = xstrdup(mkpath(fmt, bname.buf));
if (read_ref(name, sha1)) {
- error(_("%sbranch '%s' not found."),
- remote, bname.buf);
+ error(remote_branch
+ ? _("remote branch '%s' not found.")
+ : _("branch '%s' not found."), bname.buf);
ret = 1;
continue;
}
@@ -211,14 +221,19 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
}
if (delete_ref(name, sha1, 0)) {
- error(_("Error deleting %sbranch '%s'"), remote,
+ error(remote_branch
+ ? _("Error deleting remote branch '%s'")
+ : _("Error deleting branch '%s'"),
bname.buf);
ret = 1;
} else {
struct strbuf buf = STRBUF_INIT;
- printf(_("Deleted %sbranch %s (was %s).\n"), remote,
- bname.buf,
- find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ if (!quiet)
+ printf(remote_branch
+ ? _("Deleted remote branch %s (was %s).\n")
+ : _("Deleted branch %s (was %s).\n"),
+ bname.buf,
+ find_unique_abbrev(sha1, DEFAULT_ABBREV));
strbuf_addf(&buf, "branch.%s", bname.buf);
if (git_config_rename_section(buf.buf, NULL) < 0)
warning(_("Update of config-file failed"));
@@ -376,6 +391,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
int show_upstream_ref)
{
int ours, theirs;
+ char *ref = NULL;
struct branch *branch = branch_get(branch_name);
if (!stat_tracking_info(branch, &ours, &theirs)) {
@@ -386,16 +402,29 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
return;
}
- strbuf_addch(stat, '[');
if (show_upstream_ref)
- strbuf_addf(stat, "%s: ",
- shorten_unambiguous_ref(branch->merge[0]->dst, 0));
- if (!ours)
- strbuf_addf(stat, _("behind %d] "), theirs);
- else if (!theirs)
- strbuf_addf(stat, _("ahead %d] "), ours);
- else
- strbuf_addf(stat, _("ahead %d, behind %d] "), ours, theirs);
+ ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
+ if (!ours) {
+ if (ref)
+ strbuf_addf(stat, _("[%s: behind %d]"), ref, theirs);
+ else
+ strbuf_addf(stat, _("[behind %d]"), theirs);
+
+ } else if (!theirs) {
+ if (ref)
+ strbuf_addf(stat, _("[%s: ahead %d]"), ref, ours);
+ else
+ strbuf_addf(stat, _("[ahead %d]"), ours);
+ } else {
+ if (ref)
+ strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
+ ref, ours, theirs);
+ else
+ strbuf_addf(stat, _("[ahead %d, behind %d]"),
+ ours, theirs);
+ }
+ strbuf_addch(stat, ' ');
+ free(ref);
}
static int matches_merge_filter(struct commit *commit)
@@ -474,7 +503,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
else if (verbose)
/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
add_verbose_info(&out, item, verbose, abbrev);
- printf("%s\n", out.buf);
+ if (column_active(colopts)) {
+ assert(!verbose && "--column and --verbose are incompatible");
+ string_list_append(&output, out.buf);
+ } else {
+ printf("%s\n", out.buf);
+ }
strbuf_release(&name);
strbuf_release(&out);
}
@@ -655,7 +689,7 @@ static int edit_branch_description(const char *branch_name)
fp = fopen(git_path(edit_description), "w");
if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) {
strbuf_release(&buf);
- return error(_("could not write branch description template: %s\n"),
+ return error(_("could not write branch description template: %s"),
strerror(errno));
}
strbuf_reset(&buf);
@@ -678,6 +712,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int delete = 0, rename = 0, force_create = 0, list = 0;
int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0, edit_description = 0;
+ int quiet = 0;
enum branch_track track;
int kinds = REF_LOCAL_BRANCH;
struct commit_list *with_commit = NULL;
@@ -686,6 +721,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_GROUP("Generic options"),
OPT__VERBOSE(&verbose,
"show hash and subject, give twice for upstream branch"),
+ OPT__QUIET(&quiet, "suppress informational messages"),
OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))",
BRANCH_TRACK_EXPLICIT),
OPT_SET_INT( 0, "set-upstream", &track, "change upstream info",
@@ -731,6 +767,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
opt_parse_merge_filter, (intptr_t) "HEAD",
},
+ OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
OPT_END(),
};
@@ -753,6 +790,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
}
hashcpy(merge_filter_ref, head_sha1);
+
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
@@ -764,12 +802,22 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (abbrev == -1)
abbrev = DEFAULT_ABBREV;
+ finalize_colopts(&colopts, -1);
+ if (verbose) {
+ if (explicitly_enable_column(colopts))
+ die(_("--column and --verbose are incompatible"));
+ colopts = 0;
+ }
if (delete)
- return delete_branches(argc, argv, delete > 1, kinds);
- else if (list)
- return print_ref_list(kinds, detached, verbose, abbrev,
- with_commit, argv);
+ return delete_branches(argc, argv, delete > 1, kinds, quiet);
+ else if (list) {
+ int ret = print_ref_list(kinds, detached, verbose, abbrev,
+ with_commit, argv);
+ print_columns(&output, colopts, NULL);
+ string_list_clear(&output, 0);
+ return ret;
+ }
else if (edit_description) {
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
@@ -808,7 +856,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
- force_create, reflog, 0, track);
+ force_create, reflog, 0, quiet, track);
} else
usage_with_options(builtin_branch_usage, options);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 07bd984..36a9104 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -11,6 +11,7 @@
#include "parse-options.h"
#include "diff.h"
#include "userdiff.h"
+#include "streaming.h"
#define BATCH 1
#define BATCH_CHECK 2
@@ -127,6 +128,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
return cmd_ls_tree(2, ls_args, NULL);
}
+ if (type == OBJ_BLOB)
+ return stream_blob_to_fd(1, sha1, NULL, 0);
buf = read_sha1_file(sha1, &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -149,6 +152,28 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
break;
case 0:
+ if (type_from_string(exp_type) == OBJ_BLOB) {
+ unsigned char blob_sha1[20];
+ if (sha1_object_info(sha1, NULL) == OBJ_TAG) {
+ enum object_type type;
+ unsigned long size;
+ char *buffer = read_sha1_file(sha1, &type, &size);
+ if (memcmp(buffer, "object ", 7) ||
+ get_sha1_hex(buffer + 7, blob_sha1))
+ die("%s not a valid tag", sha1_to_hex(sha1));
+ free(buffer);
+ } else
+ hashcpy(blob_sha1, sha1);
+
+ if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
+ return stream_blob_to_fd(1, blob_sha1, NULL, 0);
+ /*
+ * we attempted to dereference a tag to a blob
+ * and failed; there may be new dereference
+ * mechanisms this code is not aware of.
+ * fall-back to the usual case.
+ */
+ }
buf = read_object_with_reference(sha1, exp_type, &size, NULL);
break;
@@ -226,14 +251,8 @@ static const char * const cat_file_usage[] = {
static int git_cat_file_config(const char *var, const char *value, void *cb)
{
- switch (userdiff_config(var, value)) {
- case 0:
- break;
- case -1:
+ if (userdiff_config(var, value) < 0)
return -1;
- default:
- return 0;
- }
return git_default_config(var, value, cb);
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a76aa2a..3980d5d 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -343,7 +343,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
opts.reset = 1;
opts.merge = 1;
opts.fn = oneway_merge;
- opts.verbose_update = !o->quiet;
+ opts.verbose_update = !o->quiet && isatty(2);
opts.src_index = &the_index;
opts.dst_index = &the_index;
parse_tree(tree);
@@ -420,7 +420,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.update = 1;
topts.merge = 1;
topts.gently = opts->merge && old->commit;
- topts.verbose_update = !opts->quiet;
+ topts.verbose_update = !opts->quiet && isatty(2);
topts.fn = twoway_merge;
if (opts->overwrite_ignore) {
topts.dir = xcalloc(1, sizeof(*topts.dir));
@@ -514,20 +514,6 @@ static void report_tracking(struct branch_info *new)
strbuf_release(&sb);
}
-static void detach_advice(const char *old_path, const char *new_name)
-{
- const char fmt[] =
- "Note: checking out '%s'.\n\n"
- "You are in 'detached HEAD' state. You can look around, make experimental\n"
- "changes and commit them, and you can discard any commits you make in this\n"
- "state without impacting any branches by performing another checkout.\n\n"
- "If you want to create a new branch to retain commits you create, you may\n"
- "do so (now or later) by using -b with the checkout command again. Example:\n\n"
- " git checkout -b new_branch_name\n\n";
-
- fprintf(stderr, fmt, new_name);
-}
-
static void update_refs_for_switch(struct checkout_opts *opts,
struct branch_info *old,
struct branch_info *new)
@@ -557,6 +543,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
opts->new_branch_force ? 1 : 0,
opts->new_branch_log,
opts->new_branch_force ? 1 : 0,
+ opts->quiet,
opts->track);
new->name = opts->new_branch;
setup_branch_path(new);
@@ -575,7 +562,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
REF_NODEREF, DIE_ON_ERR);
if (!opts->quiet) {
if (old->path && advice_detached_head)
- detach_advice(old->path, new->name);
+ detach_advice(new->name);
describe_detached_head(_("HEAD is now at"), new->commit);
}
} else if (new->path) { /* Switch branches. */
@@ -685,10 +672,10 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
* HEAD. If it is not reachable from any ref, this is the last chance
* for the user to do so without resorting to reflog.
*/
-static void orphaned_commit_warning(struct commit *commit)
+static void orphaned_commit_warning(struct commit *old, struct commit *new)
{
struct rev_info revs;
- struct object *object = &commit->object;
+ struct object *object = &old->object;
struct object_array refs;
init_revisions(&revs, NULL);
@@ -698,16 +685,17 @@ static void orphaned_commit_warning(struct commit *commit)
add_pending_object(&revs, object, sha1_to_hex(object->sha1));
for_each_ref(add_pending_uninteresting_ref, &revs);
+ add_pending_sha1(&revs, "HEAD", new->object.sha1, UNINTERESTING);
refs = revs.pending;
revs.leak_pending = 1;
if (prepare_revision_walk(&revs))
die(_("internal error in revision walk"));
- if (!(commit->object.flags & UNINTERESTING))
- suggest_reattach(commit, &revs);
+ if (!(old->object.flags & UNINTERESTING))
+ suggest_reattach(old, &revs);
else
- describe_detached_head(_("Previous HEAD position was"), commit);
+ describe_detached_head(_("Previous HEAD position was"), old);
clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
free(refs.objects);
@@ -744,7 +732,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
}
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
- orphaned_commit_warning(old.commit);
+ orphaned_commit_warning(old.commit, new->commit);
update_refs_for_switch(opts, &old, new);
@@ -927,6 +915,8 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts)
int status;
struct strbuf branch_ref = STRBUF_INIT;
+ if (!opts->new_branch)
+ die(_("You are on a branch yet to be born"));
strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
status = create_symref("HEAD", branch_ref.buf, "checkout -b");
strbuf_release(&branch_ref);
@@ -1104,7 +1094,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (opts.writeout_stage)
die(_("--ours/--theirs is incompatible with switching branches."));
- if (!new.commit) {
+ if (!new.commit && opts.new_branch) {
unsigned char rev[20];
int flag;
diff --git a/builtin/clone.c b/builtin/clone.c
index 0fb5956..e314b0b 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -37,8 +37,8 @@ static const char * const builtin_clone_usage[] = {
NULL
};
-static int option_no_checkout, option_bare, option_mirror;
-static int option_local, option_no_hardlinks, option_shared, option_recursive;
+static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
+static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
static char *option_template, *option_depth;
static char *option_origin = NULL;
static char *option_branch = NULL;
@@ -70,8 +70,8 @@ static struct option builtin_clone_options[] = {
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_BOOLEAN(0, "mirror", &option_mirror,
"create a mirror repository (implies bare)"),
- OPT_BOOLEAN('l', "local", &option_local,
- "to clone from a local repository"),
+ OPT_BOOL('l', "local", &option_local,
+ "to clone from a local repository"),
OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
"don't use local hardlinks, always copy"),
OPT_BOOLEAN('s', "shared", &option_shared,
@@ -92,6 +92,8 @@ static struct option builtin_clone_options[] = {
"path to git-upload-pack on the remote"),
OPT_STRING(0, "depth", &option_depth, "depth",
"create a shallow clone of that depth"),
+ OPT_BOOL(0, "single-branch", &option_single_branch,
+ "clone only one branch, HEAD or --branch"),
OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
"separate git dir from working tree"),
OPT_STRING_LIST('c', "config", &option_config, "key=value",
@@ -230,9 +232,6 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
{
char *ref_git;
struct strbuf alternate = STRBUF_INIT;
- struct remote *remote;
- struct transport *transport;
- const struct ref *extra;
/* Beware: real_path() and mkpath() return static buffer */
ref_git = xstrdup(real_path(item->string));
@@ -247,14 +246,6 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
strbuf_addf(&alternate, "%s/objects", ref_git);
add_to_alternates_file(alternate.buf);
strbuf_release(&alternate);
-
- remote = remote_get(ref_git);
- transport = transport_get(remote, ref_git);
- for (extra = transport_get_remote_refs(transport); extra;
- extra = extra->next)
- add_extra_ref(extra->name, extra->old_sha1, 0);
-
- transport_disconnect(transport);
free(ref_git);
return 0;
}
@@ -351,7 +342,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;
- if (option_local)
+ if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
}
@@ -361,13 +352,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
closedir(dir);
}
-static const struct ref *clone_local(const char *src_repo,
- const char *dest_repo)
+static void clone_local(const char *src_repo, const char *dest_repo)
{
- const struct ref *ret;
- struct remote *remote;
- struct transport *transport;
-
if (option_shared) {
struct strbuf alt = STRBUF_INIT;
strbuf_addf(&alt, "%s/objects", src_repo);
@@ -383,13 +369,8 @@ static const struct ref *clone_local(const char *src_repo,
strbuf_release(&dest);
}
- remote = remote_get(src_repo);
- transport = transport_get(remote, src_repo);
- ret = transport_get_remote_refs(transport);
- transport_disconnect(transport);
if (0 <= option_verbosity)
printf(_("done.\n"));
- return ret;
}
static const char *junk_work_tree;
@@ -420,6 +401,26 @@ static void remove_junk_on_signal(int signo)
raise(signo);
}
+static struct ref *find_remote_branch(const struct ref *refs, const char *branch)
+{
+ struct ref *ref;
+ struct strbuf head = STRBUF_INIT;
+ strbuf_addstr(&head, "refs/heads/");
+ strbuf_addstr(&head, branch);
+ ref = find_ref_by_name(refs, head.buf);
+ strbuf_release(&head);
+
+ if (ref)
+ return ref;
+
+ strbuf_addstr(&head, "refs/tags/");
+ strbuf_addstr(&head, branch);
+ ref = find_ref_by_name(refs, head.buf);
+ strbuf_release(&head);
+
+ return ref;
+}
+
static struct ref *wanted_peer_refs(const struct ref *refs,
struct refspec *refspec)
{
@@ -427,8 +428,30 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
struct ref *local_refs = head;
struct ref **tail = head ? &head->next : &local_refs;
- get_fetch_map(refs, refspec, &tail, 0);
- if (!option_mirror)
+ if (option_single_branch) {
+ struct ref *remote_head = NULL;
+
+ if (!option_branch)
+ remote_head = guess_remote_head(head, refs, 0);
+ else {
+ local_refs = NULL;
+ tail = &local_refs;
+ remote_head = copy_ref(find_remote_branch(refs, option_branch));
+ }
+
+ if (!remote_head && option_branch)
+ warning(_("Could not find remote branch %s to clone."),
+ option_branch);
+ else {
+ get_fetch_map(remote_head, refspec, &tail, 0);
+
+ /* if --branch=tag, pull the requested tag explicitly */
+ get_fetch_map(remote_head, tag_refspec, &tail, 0);
+ }
+ } else
+ get_fetch_map(refs, refspec, &tail, 0);
+
+ if (!option_mirror && !option_single_branch)
get_fetch_map(refs, tag_refspec, &tail, 0);
return local_refs;
@@ -441,11 +464,134 @@ static void write_remote_refs(const struct ref *local_refs)
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
- add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
+ add_packed_ref(r->peer_ref->name, r->old_sha1);
}
pack_refs(PACK_REFS_ALL);
- clear_extra_refs();
+}
+
+static void write_followtags(const struct ref *refs, const char *msg)
+{
+ const struct ref *ref;
+ for (ref = refs; ref; ref = ref->next) {
+ if (prefixcmp(ref->name, "refs/tags/"))
+ continue;
+ if (!suffixcmp(ref->name, "^{}"))
+ continue;
+ if (!has_sha1_file(ref->old_sha1))
+ continue;
+ update_ref(msg, ref->name, ref->old_sha1,
+ NULL, 0, DIE_ON_ERR);
+ }
+}
+
+static void update_remote_refs(const struct ref *refs,
+ const struct ref *mapped_refs,
+ const struct ref *remote_head_points_at,
+ const char *branch_top,
+ const char *msg)
+{
+ if (refs) {
+ write_remote_refs(mapped_refs);
+ if (option_single_branch)
+ write_followtags(refs, msg);
+ }
+
+ if (remote_head_points_at && !option_bare) {
+ struct strbuf head_ref = STRBUF_INIT;
+ strbuf_addstr(&head_ref, branch_top);
+ strbuf_addstr(&head_ref, "HEAD");
+ create_symref(head_ref.buf,
+ remote_head_points_at->peer_ref->name,
+ msg);
+ }
+}
+
+static void update_head(const struct ref *our, const struct ref *remote,
+ const char *msg)
+{
+ if (our && !prefixcmp(our->name, "refs/heads/")) {
+ /* Local default branch link */
+ create_symref("HEAD", our->name, NULL);
+ if (!option_bare) {
+ const char *head = skip_prefix(our->name, "refs/heads/");
+ update_ref(msg, "HEAD", our->old_sha1, NULL, 0, DIE_ON_ERR);
+ install_branch_config(0, head, option_origin, our->name);
+ }
+ } else if (our) {
+ struct commit *c = lookup_commit_reference(our->old_sha1);
+ /* --branch specifies a non-branch (i.e. tags), detach HEAD */
+ update_ref(msg, "HEAD", c->object.sha1,
+ NULL, REF_NODEREF, DIE_ON_ERR);
+ } else if (remote) {
+ /*
+ * We know remote HEAD points to a non-branch, or
+ * HEAD points to a branch but we don't know which one.
+ * Detach HEAD in all these cases.
+ */
+ update_ref(msg, "HEAD", remote->old_sha1,
+ NULL, REF_NODEREF, DIE_ON_ERR);
+ }
+}
+
+static int checkout(void)
+{
+ unsigned char sha1[20];
+ char *head;
+ struct lock_file *lock_file;
+ struct unpack_trees_options opts;
+ struct tree *tree;
+ struct tree_desc t;
+ int err = 0, fd;
+
+ if (option_no_checkout)
+ return 0;
+
+ head = resolve_refdup("HEAD", sha1, 1, NULL);
+ if (!head) {
+ warning(_("remote HEAD refers to nonexistent ref, "
+ "unable to checkout.\n"));
+ return 0;
+ }
+ if (!strcmp(head, "HEAD")) {
+ if (advice_detached_head)
+ detach_advice(sha1_to_hex(sha1));
+ } else {
+ if (prefixcmp(head, "refs/heads/"))
+ die(_("HEAD not found below refs/heads!"));
+ }
+ free(head);
+
+ /* We need to be in the new work tree for the checkout */
+ setup_work_tree();
+
+ lock_file = xcalloc(1, sizeof(struct lock_file));
+ fd = hold_locked_index(lock_file, 1);
+
+ memset(&opts, 0, sizeof opts);
+ opts.update = 1;
+ opts.merge = 1;
+ opts.fn = oneway_merge;
+ opts.verbose_update = (option_verbosity >= 0);
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
+
+ tree = parse_tree_indirect(sha1);
+ parse_tree(tree);
+ init_tree_desc(&t, tree->buffer, tree->size);
+ unpack_trees(1, &t, &opts);
+
+ if (write_cache(fd, active_cache, active_nr) ||
+ commit_locked_index(lock_file))
+ die(_("unable to write new index file"));
+
+ err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
+ sha1_to_hex(sha1), "1", NULL);
+
+ if (!err && option_recursive)
+ err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
+
+ return err;
}
static int write_one_config(const char *key, const char *value, void *data)
@@ -475,11 +621,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
const struct ref *remote_head_points_at;
const struct ref *our_head_points_at;
struct ref *mapped_refs;
+ const struct ref *ref;
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
- char *src_ref_prefix = "refs/heads/";
- int err = 0;
+ const char *src_ref_prefix = "refs/heads/";
+ struct remote *remote;
+ int err = 0, complete_refs_before_fetch = 1;
struct refspec *refspec;
const char *fetch_pattern;
@@ -498,6 +646,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("You must specify a repository to clone."),
builtin_clone_usage, builtin_clone_options);
+ if (option_single_branch == -1)
+ option_single_branch = option_depth ? 1 : 0;
+
if (option_mirror)
option_bare = 1;
@@ -520,7 +671,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("repository '%s' does not exist"), repo_name);
else
repo = repo_name;
- is_local = path && !is_bundle;
+ is_local = option_local != 0 && path && !is_bundle;
if (is_local && option_depth)
warning(_("--depth is ignored in local clones; use file:// instead."));
@@ -557,7 +708,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (safe_create_leading_directories_const(work_tree) < 0)
die_errno(_("could not create leading directories of '%s'"),
work_tree);
- if (!dest_exists && mkdir(work_tree, 0755))
+ if (!dest_exists && mkdir(work_tree, 0777))
die_errno(_("could not create work tree dir '%s'."),
work_tree);
set_git_work_tree(work_tree);
@@ -630,13 +781,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_reset(&value);
- if (is_local) {
- refs = clone_local(path, git_dir);
- mapped_refs = wanted_peer_refs(refs, refspec);
- } else {
- struct remote *remote = remote_get(option_origin);
- transport = transport_get(remote, remote->url[0]);
+ remote = remote_get(option_origin);
+ transport = transport_get(remote, remote->url[0]);
+ if (!is_local) {
if (!transport->get_refs_list || !transport->fetch)
die(_("Don't know how to clone %s"), transport->url);
@@ -645,49 +793,57 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_depth)
transport_set_option(transport, TRANS_OPT_DEPTH,
option_depth);
+ if (option_single_branch)
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
transport_set_verbosity(transport, option_verbosity, option_progress);
if (option_upload_pack)
transport_set_option(transport, TRANS_OPT_UPLOADPACK,
option_upload_pack);
-
- refs = transport_get_remote_refs(transport);
- if (refs) {
- mapped_refs = wanted_peer_refs(refs, refspec);
- transport_fetch_refs(transport, mapped_refs);
- }
}
+ refs = transport_get_remote_refs(transport);
+
if (refs) {
- clear_extra_refs();
+ mapped_refs = wanted_peer_refs(refs, refspec);
+ /*
+ * transport_get_remote_refs() may return refs with null sha-1
+ * in mapped_refs (see struct transport->get_refs_list
+ * comment). In that case we need fetch it early because
+ * remote_head code below relies on it.
+ *
+ * for normal clones, transport_get_remote_refs() should
+ * return reliable ref set, we can delay cloning until after
+ * remote HEAD check.
+ */
+ for (ref = refs; ref; ref = ref->next)
+ if (is_null_sha1(ref->old_sha1)) {
+ complete_refs_before_fetch = 0;
+ break;
+ }
- write_remote_refs(mapped_refs);
+ if (!is_local && !complete_refs_before_fetch)
+ transport_fetch_refs(transport, mapped_refs);
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
guess_remote_head(remote_head, mapped_refs, 0);
if (option_branch) {
- struct strbuf head = STRBUF_INIT;
- strbuf_addstr(&head, src_ref_prefix);
- strbuf_addstr(&head, option_branch);
our_head_points_at =
- find_ref_by_name(mapped_refs, head.buf);
- strbuf_release(&head);
-
- if (!our_head_points_at) {
- warning(_("Remote branch %s not found in "
- "upstream %s, using HEAD instead"),
- option_branch, option_origin);
- our_head_points_at = remote_head_points_at;
- }
+ find_remote_branch(mapped_refs, option_branch);
+
+ if (!our_head_points_at)
+ die(_("Remote branch %s not found in upstream %s"),
+ option_branch, option_origin);
}
else
our_head_points_at = remote_head_points_at;
}
else {
warning(_("You appear to have cloned an empty repository."));
+ mapped_refs = NULL;
our_head_points_at = NULL;
remote_head_points_at = NULL;
remote_head = NULL;
@@ -697,84 +853,20 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
"refs/heads/master");
}
- if (remote_head_points_at && !option_bare) {
- struct strbuf head_ref = STRBUF_INIT;
- strbuf_addstr(&head_ref, branch_top.buf);
- strbuf_addstr(&head_ref, "HEAD");
- create_symref(head_ref.buf,
- remote_head_points_at->peer_ref->name,
- reflog_msg.buf);
- }
+ if (is_local)
+ clone_local(path, git_dir);
+ else if (refs && complete_refs_before_fetch)
+ transport_fetch_refs(transport, mapped_refs);
- if (our_head_points_at) {
- /* Local default branch link */
- create_symref("HEAD", our_head_points_at->name, NULL);
- if (!option_bare) {
- const char *head = skip_prefix(our_head_points_at->name,
- "refs/heads/");
- update_ref(reflog_msg.buf, "HEAD",
- our_head_points_at->old_sha1,
- NULL, 0, DIE_ON_ERR);
- install_branch_config(0, head, option_origin,
- our_head_points_at->name);
- }
- } else if (remote_head) {
- /* Source had detached HEAD pointing somewhere. */
- if (!option_bare) {
- update_ref(reflog_msg.buf, "HEAD",
- remote_head->old_sha1,
- NULL, REF_NODEREF, DIE_ON_ERR);
- our_head_points_at = remote_head;
- }
- } else {
- /* Nothing to checkout out */
- if (!option_no_checkout)
- warning(_("remote HEAD refers to nonexistent ref, "
- "unable to checkout.\n"));
- option_no_checkout = 1;
- }
+ update_remote_refs(refs, mapped_refs, remote_head_points_at,
+ branch_top.buf, reflog_msg.buf);
- if (transport) {
- transport_unlock_pack(transport);
- transport_disconnect(transport);
- }
+ update_head(our_head_points_at, remote_head, reflog_msg.buf);
- if (!option_no_checkout) {
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
- struct unpack_trees_options opts;
- struct tree *tree;
- struct tree_desc t;
- int fd;
-
- /* We need to be in the new work tree for the checkout */
- setup_work_tree();
-
- fd = hold_locked_index(lock_file, 1);
-
- memset(&opts, 0, sizeof opts);
- opts.update = 1;
- opts.merge = 1;
- opts.fn = oneway_merge;
- opts.verbose_update = (option_verbosity > 0);
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
-
- tree = parse_tree_indirect(our_head_points_at->old_sha1);
- parse_tree(tree);
- init_tree_desc(&t, tree->buffer, tree->size);
- unpack_trees(1, &t, &opts);
-
- if (write_cache(fd, active_cache, active_nr) ||
- commit_locked_index(lock_file))
- die(_("unable to write new index file"));
-
- err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
- sha1_to_hex(our_head_points_at->old_sha1), "1",
- NULL);
-
- if (!err && option_recursive)
- err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
- }
+ transport_unlock_pack(transport);
+ transport_disconnect(transport);
+
+ err = checkout();
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000..5ea798a
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,59 @@
+#include "builtin.h"
+#include "cache.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+ "git column [options]",
+ NULL
+};
+static unsigned int colopts;
+
+static int column_config(const char *var, const char *value, void *cb)
+{
+ return git_column_config(var, value, cb, &colopts);
+}
+
+int cmd_column(int argc, const char **argv, const char *prefix)
+{
+ struct string_list list = STRING_LIST_INIT_DUP;
+ struct strbuf sb = STRBUF_INIT;
+ struct column_options copts;
+ const char *command = NULL, *real_command = NULL;
+ struct option options[] = {
+ OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
+ OPT_COLUMN(0, "mode", &colopts, "layout to use"),
+ OPT_INTEGER(0, "raw-mode", &colopts, "layout to use"),
+ OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
+ OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
+ OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
+ OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+ OPT_END()
+ };
+
+ /* This one is special and must be the first one */
+ if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
+ command = argv[1] + 10;
+ git_config(column_config, (void *)command);
+ } else
+ git_config(column_config, NULL);
+
+ memset(&copts, 0, sizeof(copts));
+ copts.width = term_columns();
+ copts.padding = 1;
+ argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
+ if (argc)
+ usage_with_options(builtin_column_usage, options);
+ if (real_command || command) {
+ if (!real_command || !command || strcmp(real_command, command))
+ die(_("--command must be the first argument"));
+ }
+ finalize_colopts(&colopts, -1);
+ while (!strbuf_getline(&sb, stdin, '\n'))
+ string_list_append(&list, sb.buf);
+
+ print_columns(&list, colopts, &copts);
+ return 0;
+}
diff --git a/builtin/commit.c b/builtin/commit.c
index 4b4e7e7..6515da2 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -27,6 +27,7 @@
#include "quote.h"
#include "submodule.h"
#include "gpg-interface.h"
+#include "column.h"
static const char * const builtin_commit_usage[] = {
"git commit [options] [--] <filepattern>...",
@@ -109,13 +110,11 @@ static int show_ignored_in_status;
static const char *only_include_assumed;
static struct strbuf message = STRBUF_INIT;
-static int null_termination;
static enum {
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
STATUS_FORMAT_PORCELAIN
} status_format = STATUS_FORMAT_LONG;
-static int status_show_branch;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
{
@@ -129,59 +128,6 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
return 0;
}
-static struct option builtin_commit_options[] = {
- OPT__QUIET(&quiet, "suppress summary after successful commit"),
- OPT__VERBOSE(&verbose, "show diff in commit message template"),
-
- OPT_GROUP("Commit message options"),
- OPT_FILENAME('F', "file", &logfile, "read message from file"),
- OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
- OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
- OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
- OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
- OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
- OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
- OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
- OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
- OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
- OPT_FILENAME('t', "template", &template_file, "use specified template file"),
- OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
- OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
- OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
- { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
- "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- /* end commit message options */
-
- OPT_GROUP("Commit contents options"),
- OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
- OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
- OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
- OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
- OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
- OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
- OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
- OPT_SET_INT(0, "short", &status_format, "show status concisely",
- STATUS_FORMAT_SHORT),
- OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"),
- OPT_SET_INT(0, "porcelain", &status_format,
- "machine-readable output", STATUS_FORMAT_PORCELAIN),
- OPT_BOOLEAN('z', "null", &null_termination,
- "terminate entries with NUL"),
- OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
- OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
- { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
- /* end commit contents options */
-
- { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
- "ok to record an empty change",
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
- "ok to record a change with an empty message",
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
-
- OPT_END()
-};
-
static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path("MERGE_HEAD")))
@@ -194,24 +140,6 @@ static void determine_whence(struct wt_status *s)
s->whence = whence;
}
-static const char *whence_s(void)
-{
- const char *s = "";
-
- switch (whence) {
- case FROM_COMMIT:
- break;
- case FROM_MERGE:
- s = _("merge");
- break;
- case FROM_CHERRY_PICK:
- s = _("cherry-pick");
- break;
- }
-
- return s;
-}
-
static void rollback_index_files(void)
{
switch (commit_style) {
@@ -400,7 +328,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
fd = hold_locked_index(&index_lock, 1);
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
refresh_cache_or_die(refresh_flags);
- update_main_cache_tree(1);
+ update_main_cache_tree(WRITE_TREE_SILENT);
if (write_cache(fd, active_cache, active_nr) ||
close_lock_file(&index_lock))
die(_("unable to write new_index file"));
@@ -421,7 +349,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
fd = hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
if (active_cache_changed) {
- update_main_cache_tree(1);
+ update_main_cache_tree(WRITE_TREE_SILENT);
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(&index_lock))
die(_("unable to write new_index file"));
@@ -453,8 +381,12 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
*/
commit_style = COMMIT_PARTIAL;
- if (whence != FROM_COMMIT)
- die(_("cannot do a partial commit during a %s."), whence_s());
+ if (whence != FROM_COMMIT) {
+ if (whence == FROM_MERGE)
+ die(_("cannot do a partial commit during a merge."));
+ else if (whence == FROM_CHERRY_PICK)
+ die(_("cannot do a partial commit during a cherry-pick."));
+ }
memset(&partial, 0, sizeof(partial));
partial.strdup_strings = 1;
@@ -513,10 +445,10 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
switch (status_format) {
case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(s, null_termination, status_show_branch);
+ wt_shortstatus_print(s);
break;
case STATUS_FORMAT_PORCELAIN:
- wt_porcelain_print(s, null_termination);
+ wt_porcelain_print(s);
break;
case STATUS_FORMAT_LONG:
wt_status_print(s);
@@ -533,9 +465,20 @@ static int is_a_merge(const struct commit *current_head)
static const char sign_off_header[] = "Signed-off-by: ";
+static void export_one(const char *var, const char *s, const char *e, int hack)
+{
+ struct strbuf buf = STRBUF_INIT;
+ if (hack)
+ strbuf_addch(&buf, hack);
+ strbuf_addf(&buf, "%.*s", (int)(e - s), s);
+ setenv(var, buf.buf, 1);
+ strbuf_release(&buf);
+}
+
static void determine_author_info(struct strbuf *author_ident)
{
char *name, *email, *date;
+ struct ident_split author;
name = getenv("GIT_AUTHOR_NAME");
email = getenv("GIT_AUTHOR_EMAIL");
@@ -583,8 +526,12 @@ static void determine_author_info(struct strbuf *author_ident)
if (force_date)
date = force_date;
- strbuf_addstr(author_ident, fmt_ident(name, email, date,
- IDENT_ERROR_ON_NO_NAME));
+ strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
+ if (!split_ident_line(&author, author_ident->buf, author_ident->len)) {
+ export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
+ export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
+ export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
+ }
}
static int ends_rfc2822_footer(struct strbuf *sb)
@@ -652,6 +599,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int ident_shown = 0;
int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
+ /* This checks and barfs if author is badly specified */
+ determine_author_info(author_ident);
+
if (!no_verify && run_hook(index_file, "pre-commit", NULL))
return 0;
@@ -771,37 +721,37 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
strbuf_release(&sb);
- /* This checks and barfs if author is badly specified */
- determine_author_info(author_ident);
-
/* This checks if committer ident is explicitly given */
strbuf_addstr(&committer_ident, git_committer_info(0));
if (use_editor && include_status) {
char *ai_tmp, *ci_tmp;
if (whence != FROM_COMMIT)
status_printf_ln(s, GIT_COLOR_NORMAL,
- _("\n"
- "It looks like you may be committing a %s.\n"
- "If this is not correct, please remove the file\n"
- " %s\n"
- "and try again.\n"
- ""),
- whence_s(),
+ whence == FROM_MERGE
+ ? _("\n"
+ "It looks like you may be committing a merge.\n"
+ "If this is not correct, please remove the file\n"
+ " %s\n"
+ "and try again.\n")
+ : _("\n"
+ "It looks like you may be committing a cherry-pick.\n"
+ "If this is not correct, please remove the file\n"
+ " %s\n"
+ "and try again.\n"),
git_path(whence == FROM_MERGE
? "MERGE_HEAD"
: "CHERRY_PICK_HEAD"));
fprintf(s->fp, "\n");
- status_printf(s, GIT_COLOR_NORMAL,
- _("Please enter the commit message for your changes."));
if (cleanup_mode == CLEANUP_ALL)
- status_printf_more(s, GIT_COLOR_NORMAL,
- _(" Lines starting\n"
- "with '#' will be ignored, and an empty"
+ status_printf(s, GIT_COLOR_NORMAL,
+ _("Please enter the commit message for your changes."
+ " Lines starting\nwith '#' will be ignored, and an empty"
" message aborts the commit.\n"));
else /* CLEANUP_SPACE, that is. */
- status_printf_more(s, GIT_COLOR_NORMAL,
- _(" Lines starting\n"
+ status_printf(s, GIT_COLOR_NORMAL,
+ _("Please enter the commit message for your changes."
+ " Lines starting\n"
"with '#' will be kept; you may remove them"
" yourself if you want to.\n"
"An empty message aborts the commit.\n"));
@@ -905,27 +855,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
return 1;
}
-/*
- * Find out if the message in the strbuf contains only whitespace and
- * Signed-off-by lines.
- */
-static int message_is_empty(struct strbuf *sb)
+static int rest_is_empty(struct strbuf *sb, int start)
{
- struct strbuf tmpl = STRBUF_INIT;
+ int i, eol;
const char *nl;
- int eol, i, start = 0;
-
- if (cleanup_mode == CLEANUP_NONE && sb->len)
- return 0;
-
- /* See if the template is just a prefix of the message. */
- if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
- stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
- if (start + tmpl.len <= sb->len &&
- memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
- start += tmpl.len;
- }
- strbuf_release(&tmpl);
/* Check if the rest is just whitespace and Signed-of-by's. */
for (i = start; i < sb->len; i++) {
@@ -948,6 +881,40 @@ static int message_is_empty(struct strbuf *sb)
return 1;
}
+/*
+ * Find out if the message in the strbuf contains only whitespace and
+ * Signed-off-by lines.
+ */
+static int message_is_empty(struct strbuf *sb)
+{
+ if (cleanup_mode == CLEANUP_NONE && sb->len)
+ return 0;
+ return rest_is_empty(sb, 0);
+}
+
+/*
+ * See if the user edited the message in the editor or left what
+ * was in the template intact
+ */
+static int template_untouched(struct strbuf *sb)
+{
+ struct strbuf tmpl = STRBUF_INIT;
+ char *start;
+
+ if (cleanup_mode == CLEANUP_NONE && sb->len)
+ return 0;
+
+ if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
+ return 0;
+
+ stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
+ start = (char *)skip_prefix(sb->buf, tmpl.buf);
+ if (!start)
+ start = sb->buf;
+ strbuf_release(&tmpl);
+ return rest_is_empty(sb, start - sb->buf);
+}
+
static const char *find_author_by_nickname(const char *name)
{
struct rev_info revs;
@@ -1013,6 +980,7 @@ static const char *read_commit_message(const char *name)
}
static int parse_and_validate_options(int argc, const char *argv[],
+ const struct option *options,
const char * const usage[],
const char *prefix,
struct commit *current_head,
@@ -1020,8 +988,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
{
int f = 0;
- argc = parse_options(argc, argv, prefix, builtin_commit_options, usage,
- 0);
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
if (force_author && !strchr(force_author, '>'))
force_author = find_author_by_nickname(force_author);
@@ -1039,8 +1006,12 @@ static int parse_and_validate_options(int argc, const char *argv[],
/* Sanity check options */
if (amend && !current_head)
die(_("You have nothing to amend."));
- if (amend && whence != FROM_COMMIT)
- die(_("You are in the middle of a %s -- cannot amend."), whence_s());
+ if (amend && whence != FROM_COMMIT) {
+ if (whence == FROM_MERGE)
+ die(_("You are in the middle of a merge -- cannot amend."));
+ else if (whence == FROM_CHERRY_PICK)
+ die(_("You are in the middle of a cherry-pick -- cannot amend."));
+ }
if (fixup_message && squash_message)
die(_("Options --squash and --fixup cannot be used together"));
if (use_message)
@@ -1055,6 +1026,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
die(_("Only one of -c/-C/-F/--fixup can be used."));
if (message.len && f > 0)
die((_("Option -m cannot be combined with -c/-C/-F/--fixup.")));
+ if (f || message.len)
+ template_file = NULL;
if (edit_message)
use_message = edit_message;
if (amend && !use_message && !fixup_message)
@@ -1100,7 +1073,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (all && argc > 0)
die(_("Paths with -a does not make sense."));
- if (null_termination && status_format == STATUS_FORMAT_LONG)
+ if (s->null_termination && status_format == STATUS_FORMAT_LONG)
status_format = STATUS_FORMAT_PORCELAIN;
if (status_format != STATUS_FORMAT_LONG)
dry_run = 1;
@@ -1145,6 +1118,8 @@ static int git_status_config(const char *k, const char *v, void *cb)
{
struct wt_status *s = cb;
+ if (!prefixcmp(k, "column."))
+ return git_column_config(k, v, "status", &s->colopts);
if (!strcmp(k, "status.submodulesummary")) {
int is_bool;
s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
@@ -1187,19 +1162,19 @@ static int git_status_config(const char *k, const char *v, void *cb)
int cmd_status(int argc, const char **argv, const char *prefix)
{
- struct wt_status s;
+ static struct wt_status s;
int fd;
unsigned char sha1[20];
static struct option builtin_status_options[] = {
OPT__VERBOSE(&verbose, "be verbose"),
OPT_SET_INT('s', "short", &status_format,
"show status concisely", STATUS_FORMAT_SHORT),
- OPT_BOOLEAN('b', "branch", &status_show_branch,
+ OPT_BOOLEAN('b', "branch", &s.show_branch,
"show branch information"),
OPT_SET_INT(0, "porcelain", &status_format,
"machine-readable output",
STATUS_FORMAT_PORCELAIN),
- OPT_BOOLEAN('z', "null", &null_termination,
+ OPT_BOOLEAN('z', "null", &s.null_termination,
"terminate entries with NUL"),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
"mode",
@@ -1210,6 +1185,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
"ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+ OPT_COLUMN(0, "column", &s.colopts, "list untracked files in columns"),
OPT_END(),
};
@@ -1223,8 +1199,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_status_options,
builtin_status_usage, 0);
+ finalize_colopts(&s.colopts, -1);
- if (null_termination && status_format == STATUS_FORMAT_LONG)
+ if (s.null_termination && status_format == STATUS_FORMAT_LONG)
status_format = STATUS_FORMAT_PORCELAIN;
handle_untracked_files_arg(&s);
@@ -1249,10 +1226,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
switch (status_format) {
case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(&s, null_termination, status_show_branch);
+ wt_shortstatus_print(&s);
break;
case STATUS_FORMAT_PORCELAIN:
- wt_porcelain_print(&s, null_termination);
+ wt_porcelain_print(&s);
break;
case STATUS_FORMAT_LONG:
s.verbose = verbose;
@@ -1387,6 +1364,60 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
int cmd_commit(int argc, const char **argv, const char *prefix)
{
+ static struct wt_status s;
+ static struct option builtin_commit_options[] = {
+ OPT__QUIET(&quiet, "suppress summary after successful commit"),
+ OPT__VERBOSE(&verbose, "show diff in commit message template"),
+
+ OPT_GROUP("Commit message options"),
+ OPT_FILENAME('F', "file", &logfile, "read message from file"),
+ OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
+ OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
+ OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
+ OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
+ OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
+ OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
+ OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
+ OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
+ OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
+ OPT_FILENAME('t', "template", &template_file, "use specified template file"),
+ OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
+ OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
+ OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
+ { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
+ "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+ /* end commit message options */
+
+ OPT_GROUP("Commit contents options"),
+ OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
+ OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
+ OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
+ OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
+ OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
+ OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
+ OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
+ OPT_SET_INT(0, "short", &status_format, "show status concisely",
+ STATUS_FORMAT_SHORT),
+ OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"),
+ OPT_SET_INT(0, "porcelain", &status_format,
+ "machine-readable output", STATUS_FORMAT_PORCELAIN),
+ OPT_BOOLEAN('z', "null", &s.null_termination,
+ "terminate entries with NUL"),
+ OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
+ OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
+ { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+ /* end commit contents options */
+
+ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
+ "ok to record an empty change",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
+ "ok to record a change with an empty message",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+
+ OPT_END()
+ };
+
struct strbuf sb = STRBUF_INIT;
struct strbuf author_ident = STRBUF_INIT;
const char *index_file, *reflog_msg;
@@ -1396,7 +1427,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
int allow_fast_forward = 1;
- struct wt_status s;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
@@ -1406,6 +1436,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
wt_status_prepare(&s);
git_config(git_commit_config, &s);
determine_whence(&s);
+ s.colopts = 0;
if (get_sha1("HEAD", sha1))
current_head = NULL;
@@ -1414,7 +1445,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!current_head || parse_commit(current_head))
die(_("could not parse HEAD commit"));
}
- argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
+ argc = parse_and_validate_options(argc, argv, builtin_commit_options,
+ builtin_commit_usage,
prefix, current_head, &s);
if (dry_run)
return dry_run_commit(argc, argv, prefix, current_head, &s);
@@ -1494,6 +1526,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
+ if (template_untouched(&sb) && !allow_empty_message) {
+ rollback_index_files();
+ fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
+ exit(1);
+ }
if (message_is_empty(&sb) && !allow_empty_message) {
rollback_index_files();
fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
diff --git a/builtin/config.c b/builtin/config.c
index d35c06a..e8e1c0a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -25,6 +25,7 @@ static const char *given_config_file;
static int actions, types;
static const char *get_color_slot, *get_colorbool_slot;
static int end_null;
+static int respect_includes = -1;
#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
@@ -74,6 +75,7 @@ static struct option builtin_config_options[] = {
OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
OPT_GROUP("Other"),
OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
+ OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"),
OPT_END(),
};
@@ -159,17 +161,18 @@ static int show_config(const char *key_, const char *value_, void *cb)
static int get_value(const char *key_, const char *regex_)
{
int ret = -1;
- char *global = NULL, *repo_config = NULL;
+ char *global = NULL, *xdg = NULL, *repo_config = NULL;
const char *system_wide = NULL, *local;
+ struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ config_fn_t fn;
+ void *data;
- local = config_exclusive_filename;
+ local = given_config_file;
if (!local) {
- const char *home = getenv("HOME");
local = repo_config = git_pathdup("config");
- if (home)
- global = xstrdup(mkpath("%s/.gitconfig", home));
if (git_config_system())
system_wide = git_etc_gitconfig();
+ home_config_paths(&global, &xdg, "config");
}
if (use_key_regexp) {
@@ -213,19 +216,32 @@ static int get_value(const char *key_, const char *regex_)
}
}
+ fn = show_config;
+ data = NULL;
+ if (respect_includes) {
+ inc.fn = fn;
+ inc.data = data;
+ fn = git_config_include;
+ data = &inc;
+ }
+
if (do_all && system_wide)
- git_config_from_file(show_config, system_wide, NULL);
+ git_config_from_file(fn, system_wide, data);
+ if (do_all && xdg)
+ git_config_from_file(fn, xdg, data);
if (do_all && global)
- git_config_from_file(show_config, global, NULL);
+ git_config_from_file(fn, global, data);
if (do_all)
- git_config_from_file(show_config, local, NULL);
- git_config_from_parameters(show_config, NULL);
+ git_config_from_file(fn, local, data);
+ git_config_from_parameters(fn, data);
if (!do_all && !seen)
- git_config_from_file(show_config, local, NULL);
+ git_config_from_file(fn, local, data);
if (!do_all && !seen && global)
- git_config_from_file(show_config, global, NULL);
+ git_config_from_file(fn, global, data);
+ if (!do_all && !seen && xdg)
+ git_config_from_file(fn, xdg, data);
if (!do_all && !seen && system_wide)
- git_config_from_file(show_config, system_wide, NULL);
+ git_config_from_file(fn, system_wide, data);
free(key);
if (regexp) {
@@ -241,6 +257,7 @@ static int get_value(const char *key_, const char *regex_)
free_strings:
free(repo_config);
free(global);
+ free(xdg);
return ret;
}
@@ -301,7 +318,8 @@ static void get_color(const char *def_color)
{
get_color_found = 0;
parsed_color[0] = '\0';
- git_config(git_get_color_config, NULL);
+ git_config_with_options(git_get_color_config, NULL,
+ given_config_file, respect_includes);
if (!get_color_found && def_color)
color_parse(def_color, "command line", parsed_color);
@@ -328,7 +346,8 @@ static int get_colorbool(int print)
{
get_colorbool_found = -1;
get_diff_color_found = -1;
- git_config(git_get_colorbool_config, NULL);
+ git_config_with_options(git_get_colorbool_config, NULL,
+ given_config_file, respect_includes);
if (get_colorbool_found < 0) {
if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -351,7 +370,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
int nongit = !startup_info->have_repository;
char *value;
- config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
+ given_config_file = getenv(CONFIG_ENVIRONMENT);
argc = parse_options(argc, argv, prefix, builtin_config_options,
builtin_config_usage,
@@ -363,27 +382,33 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
if (use_global_config) {
- char *home = getenv("HOME");
- if (home) {
- char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
- config_exclusive_filename = user_config;
- } else {
+ char *user_config = NULL;
+ char *xdg_config = NULL;
+
+ home_config_paths(&user_config, &xdg_config, "config");
+
+ if (access(user_config, R_OK) && !access(xdg_config, R_OK))
+ given_config_file = xdg_config;
+ else if (user_config)
+ given_config_file = user_config;
+ else
die("$HOME not set");
- }
}
else if (use_system_config)
- config_exclusive_filename = git_etc_gitconfig();
+ given_config_file = git_etc_gitconfig();
else if (use_local_config)
- config_exclusive_filename = git_pathdup("config");
+ given_config_file = git_pathdup("config");
else if (given_config_file) {
if (!is_absolute_path(given_config_file) && prefix)
- config_exclusive_filename = prefix_filename(prefix,
- strlen(prefix),
- given_config_file);
- else
- config_exclusive_filename = given_config_file;
+ given_config_file =
+ xstrdup(prefix_filename(prefix,
+ strlen(prefix),
+ given_config_file));
}
+ if (respect_includes == -1)
+ respect_includes = !given_config_file;
+
if (end_null) {
term = '\0';
delim = '\n';
@@ -420,28 +445,30 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
- if (git_config(show_all_config, NULL) < 0) {
- if (config_exclusive_filename)
+ if (git_config_with_options(show_all_config, NULL,
+ given_config_file,
+ respect_includes) < 0) {
+ if (given_config_file)
die_errno("unable to read config file '%s'",
- config_exclusive_filename);
+ given_config_file);
else
die("error processing config file(s)");
}
}
else if (actions == ACTION_EDIT) {
check_argc(argc, 0, 0);
- if (!config_exclusive_filename && nongit)
+ if (!given_config_file && nongit)
die("not in a git directory");
git_config(git_default_config, NULL);
- launch_editor(config_exclusive_filename ?
- config_exclusive_filename : git_path("config"),
+ launch_editor(given_config_file ?
+ given_config_file : git_path("config"),
NULL, NULL);
}
else if (actions == ACTION_SET) {
int ret;
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- ret = git_config_set(argv[0], value);
+ ret = git_config_set_in_file(given_config_file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s.", argv[0]);
@@ -450,17 +477,20 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_SET_ALL) {
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- return git_config_set_multivar(argv[0], value, argv[2], 0);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], value, argv[2], 0);
}
else if (actions == ACTION_ADD) {
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- return git_config_set_multivar(argv[0], value, "^$", 0);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], value, "^$", 0);
}
else if (actions == ACTION_REPLACE_ALL) {
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- return git_config_set_multivar(argv[0], value, argv[2], 1);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], value, argv[2], 1);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -481,18 +511,22 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_UNSET) {
check_argc(argc, 1, 2);
if (argc == 2)
- return git_config_set_multivar(argv[0], NULL, argv[1], 0);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], NULL, argv[1], 0);
else
- return git_config_set(argv[0], NULL);
+ return git_config_set_in_file(given_config_file,
+ argv[0], NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_argc(argc, 1, 2);
- return git_config_set_multivar(argv[0], NULL, argv[1], 1);
+ return git_config_set_multivar_in_file(given_config_file,
+ argv[0], NULL, argv[1], 1);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;
check_argc(argc, 2, 2);
- ret = git_config_rename_section(argv[0], argv[1]);
+ ret = git_config_rename_section_in_file(given_config_file,
+ argv[0], argv[1]);
if (ret < 0)
return ret;
if (ret == 0)
@@ -501,7 +535,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_REMOVE_SECTION) {
int ret;
check_argc(argc, 1, 1);
- ret = git_config_rename_section(argv[0], NULL);
+ ret = git_config_rename_section_in_file(given_config_file,
+ argv[0], NULL);
if (ret < 0)
return ret;
if (ret == 0)
diff --git a/builtin/credential.c b/builtin/credential.c
new file mode 100644
index 0000000..0412fa0
--- /dev/null
+++ b/builtin/credential.c
@@ -0,0 +1,31 @@
+#include "git-compat-util.h"
+#include "credential.h"
+#include "builtin.h"
+
+static const char usage_msg[] =
+ "git credential [fill|approve|reject]";
+
+int cmd_credential(int argc, const char **argv, const char *prefix)
+{
+ const char *op;
+ struct credential c = CREDENTIAL_INIT;
+
+ op = argv[1];
+ if (!op)
+ usage(usage_msg);
+
+ if (credential_read(&c, stdin) < 0)
+ die("unable to read credential from stdin");
+
+ if (!strcmp(op, "fill")) {
+ credential_fill(&c);
+ credential_write(&c, stdout);
+ } else if (!strcmp(op, "approve")) {
+ credential_approve(&c);
+ } else if (!strcmp(op, "reject")) {
+ credential_reject(&c);
+ } else {
+ usage(usage_msg);
+ }
+ return 0;
+}
diff --git a/builtin/diff.c b/builtin/diff.c
index 387afa7..da8f6aa 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -285,6 +285,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
/* Otherwise, we are doing the usual "git" diff */
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
+ /* Scale to real terminal size and respect statGraphWidth config */
+ rev.diffopt.stat_width = -1;
+ rev.diffopt.stat_graph_width = -1;
+
/* Default to let external and textconv be used */
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
@@ -300,13 +304,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
- /*
- * If the user asked for our exit code then don't start a
- * pager or we would end up reporting its exit code instead.
- */
- if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) &&
- check_pager_config("diff") != 0)
- setup_pager();
+ setup_diff_pager(&rev.diffopt);
/*
* Do we have --cached and not have a pending object, then
@@ -323,7 +321,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
- tree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN);
+ tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
@@ -417,3 +415,19 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
refresh_index_quietly();
return result;
}
+
+void setup_diff_pager(struct diff_options *opt)
+{
+ /*
+ * If the user asked for our exit code, then either they want --quiet
+ * or --exit-code. We should definitely not bother with a pager in the
+ * former case, as we will generate no output. Since we still properly
+ * report our exit code even when a pager is run, we _could_ run a
+ * pager with --exit-code. But since we have not done so historically,
+ * and because it is easy to find people oneline advising "git diff
+ * --exit-code" in hooks and other scripts, we do not do so.
+ */
+ if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+ check_pager_config("diff") != 0)
+ setup_pager();
+}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 08fed98..9ab6db3 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -185,6 +185,8 @@ static void print_path(const char *path)
int need_quote = quote_c_style(path, NULL, NULL, 0);
if (need_quote)
quote_c_style(path, NULL, stdout, 0);
+ else if (strchr(path, ' '))
+ printf("\"%s\"", path);
else
printf("%s", path);
}
@@ -610,7 +612,7 @@ static void import_marks(char *input_file)
die ("Could not read blob %s", sha1_to_hex(sha1));
if (object->flags & SHOWN)
- error("Object %s already has a mark", sha1);
+ error("Object %s already has a mark", sha1_to_hex(sha1));
mark_object(object, mark);
if (last_idnum < mark)
@@ -647,9 +649,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Output full tree for each commit"),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
"Use the done feature to terminate the stream"),
- { OPTION_NEGBIT, 0, "data", &no_data, NULL,
- "Skip output of blob data",
- PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
+ OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
OPT_END()
};
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index a4d3e90..149db88 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -23,7 +23,9 @@ static struct fetch_pack_args args = {
};
static const char fetch_pack_usage[] =
-"git fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
+"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
+"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
@@ -58,9 +60,9 @@ static void rev_list_push(struct commit *commit, int mark)
}
}
-static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- struct object *o = deref_tag(parse_object(sha1), path, 0);
+ struct object *o = deref_tag(parse_object(sha1), refname, 0);
if (o && o->type == OBJ_COMMIT)
rev_list_push((struct commit *)o, SEEN);
@@ -68,9 +70,9 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int
return 0;
}
-static int clear_marks(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- struct object *o = deref_tag(parse_object(sha1), path, 0);
+ struct object *o = deref_tag(parse_object(sha1), refname, 0);
if (o && o->type == OBJ_COMMIT)
clear_commit_marks((struct commit *)o,
@@ -256,11 +258,6 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused)
rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
}
-static void insert_alternate_refs(void)
-{
- for_each_alternate_ref(insert_one_alternate_ref, NULL);
-}
-
#define INITIAL_FLUSH 16
#define PIPESAFE_FLUSH 32
#define LARGE_FLUSH 1024
@@ -295,7 +292,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
marked = 1;
for_each_ref(rev_list_insert_ref, NULL);
- insert_alternate_refs();
+ for_each_alternate_ref(insert_one_alternate_ref, NULL);
fetching = 0;
for ( ; refs ; refs = refs->next) {
@@ -493,7 +490,7 @@ done:
static struct commit_list *complete;
-static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *o = parse_object(sha1);
@@ -531,6 +528,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
struct ref **newtail = &newlist;
struct ref *ref, *next;
struct ref *fastarray[32];
+ int match_pos;
if (nr_match && !args.fetch_all) {
if (ARRAY_SIZE(fastarray) < nr_match)
@@ -543,6 +541,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
else
return_refs = NULL;
+ match_pos = 0;
for (ref = *refs; ref; ref = next) {
next = ref->next;
if (!memcmp(ref->name, "refs/", 5) &&
@@ -556,15 +555,20 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
continue;
}
else {
- int i;
- for (i = 0; i < nr_match; i++) {
- if (!strcmp(ref->name, match[i])) {
- match[i][0] = '\0';
- return_refs[i] = ref;
+ int cmp = -1;
+ while (match_pos < nr_match) {
+ cmp = strcmp(ref->name, match[match_pos]);
+ if (cmp < 0) /* definitely do not have it */
+ break;
+ else if (cmp == 0) { /* definitely have it */
+ match[match_pos][0] = '\0';
+ return_refs[match_pos] = ref;
break;
}
+ else /* might have it; keep looking */
+ match_pos++;
}
- if (i < nr_match)
+ if (!cmp)
continue; /* we will link it later */
}
free(ref);
@@ -586,6 +590,11 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
*refs = newlist;
}
+static void mark_alternate_complete(const struct ref *ref, void *unused)
+{
+ mark_complete(NULL, ref->old_sha1, 0, NULL);
+}
+
static int everything_local(struct ref **refs, int nr_match, char **match)
{
struct ref *ref;
@@ -614,6 +623,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
if (!args.depth) {
for_each_ref(mark_complete, NULL);
+ for_each_alternate_ref(mark_alternate_complete, NULL);
if (cutoff)
mark_recent_complete_commits(cutoff);
}
@@ -774,6 +784,8 @@ static struct ref *do_fetch_pack(int fd[2],
struct ref *ref = copy_ref_list(orig_ref);
unsigned char sha1[20];
+ sort_ref_list(&ref, ref_compare_name);
+
if (is_repository_shallow() && !server_supports("shallow"))
die("Server does not support shallow clients");
if (server_supports("multi_ack_detailed")) {
@@ -831,21 +843,12 @@ static int remove_duplicates(int nr_heads, char **heads)
{
int src, dst;
- for (src = dst = 0; src < nr_heads; src++) {
- /* If heads[src] is different from any of
- * heads[0..dst], push it in.
- */
- int i;
- for (i = 0; i < dst; i++) {
- if (!strcmp(heads[i], heads[src]))
- break;
- }
- if (i < dst)
- continue;
- if (src != dst)
- heads[dst] = heads[src];
- dst++;
- }
+ if (!nr_heads)
+ return 0;
+
+ for (src = dst = 1; src < nr_heads; src++)
+ if (strcmp(heads[src], heads[dst-1]))
+ heads[dst++] = heads[src];
return dst;
}
@@ -896,9 +899,11 @@ static void fetch_pack_setup(void)
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
- int i, ret, nr_heads;
+ int i, ret;
struct ref *ref = NULL;
- char *dest = NULL, **heads;
+ const char *dest = NULL;
+ int alloc_heads = 0, nr_heads = 0;
+ char **heads = NULL;
int fd[2];
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
@@ -906,78 +911,111 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
packet_trace_identity("fetch-pack");
- nr_heads = 0;
- heads = NULL;
- for (i = 1; i < argc; i++) {
+ for (i = 1; i < argc && *argv[i] == '-'; i++) {
const char *arg = argv[i];
- if (*arg == '-') {
- if (!prefixcmp(arg, "--upload-pack=")) {
- args.uploadpack = arg + 14;
- continue;
- }
- if (!prefixcmp(arg, "--exec=")) {
- args.uploadpack = arg + 7;
- continue;
- }
- if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
- args.quiet = 1;
- continue;
- }
- if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
- args.lock_pack = args.keep_pack;
- args.keep_pack = 1;
- continue;
- }
- if (!strcmp("--thin", arg)) {
- args.use_thin_pack = 1;
- continue;
- }
- if (!strcmp("--include-tag", arg)) {
- args.include_tag = 1;
- continue;
- }
- if (!strcmp("--all", arg)) {
- args.fetch_all = 1;
- continue;
- }
- if (!strcmp("-v", arg)) {
- args.verbose = 1;
- continue;
- }
- if (!prefixcmp(arg, "--depth=")) {
- args.depth = strtol(arg + 8, NULL, 0);
- continue;
- }
- if (!strcmp("--no-progress", arg)) {
- args.no_progress = 1;
- continue;
- }
- if (!strcmp("--stateless-rpc", arg)) {
- args.stateless_rpc = 1;
- continue;
+ if (!prefixcmp(arg, "--upload-pack=")) {
+ args.uploadpack = arg + 14;
+ continue;
+ }
+ if (!prefixcmp(arg, "--exec=")) {
+ args.uploadpack = arg + 7;
+ continue;
+ }
+ if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
+ args.quiet = 1;
+ continue;
+ }
+ if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
+ args.lock_pack = args.keep_pack;
+ args.keep_pack = 1;
+ continue;
+ }
+ if (!strcmp("--thin", arg)) {
+ args.use_thin_pack = 1;
+ continue;
+ }
+ if (!strcmp("--include-tag", arg)) {
+ args.include_tag = 1;
+ continue;
+ }
+ if (!strcmp("--all", arg)) {
+ args.fetch_all = 1;
+ continue;
+ }
+ if (!strcmp("--stdin", arg)) {
+ args.stdin_refs = 1;
+ continue;
+ }
+ if (!strcmp("-v", arg)) {
+ args.verbose = 1;
+ continue;
+ }
+ if (!prefixcmp(arg, "--depth=")) {
+ args.depth = strtol(arg + 8, NULL, 0);
+ continue;
+ }
+ if (!strcmp("--no-progress", arg)) {
+ args.no_progress = 1;
+ continue;
+ }
+ if (!strcmp("--stateless-rpc", arg)) {
+ args.stateless_rpc = 1;
+ continue;
+ }
+ if (!strcmp("--lock-pack", arg)) {
+ args.lock_pack = 1;
+ pack_lockfile_ptr = &pack_lockfile;
+ continue;
+ }
+ usage(fetch_pack_usage);
+ }
+
+ if (i < argc)
+ dest = argv[i++];
+ else
+ usage(fetch_pack_usage);
+
+ /*
+ * Copy refs from cmdline to growable list, then append any
+ * refs from the standard input:
+ */
+ ALLOC_GROW(heads, argc - i, alloc_heads);
+ for (; i < argc; i++)
+ heads[nr_heads++] = xstrdup(argv[i]);
+ if (args.stdin_refs) {
+ if (args.stateless_rpc) {
+ /* in stateless RPC mode we use pkt-line to read
+ * from stdin, until we get a flush packet
+ */
+ static char line[1000];
+ for (;;) {
+ int n = packet_read_line(0, line, sizeof(line));
+ if (!n)
+ break;
+ if (line[n-1] == '\n')
+ n--;
+ ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
+ heads[nr_heads++] = xmemdupz(line, n);
}
- if (!strcmp("--lock-pack", arg)) {
- args.lock_pack = 1;
- pack_lockfile_ptr = &pack_lockfile;
- continue;
+ }
+ else {
+ /* read from stdin one ref per line, until EOF */
+ struct strbuf line = STRBUF_INIT;
+ while (strbuf_getline(&line, stdin, '\n') != EOF) {
+ ALLOC_GROW(heads, nr_heads + 1, alloc_heads);
+ heads[nr_heads++] = strbuf_detach(&line, NULL);
}
- usage(fetch_pack_usage);
+ strbuf_release(&line);
}
- dest = (char *)arg;
- heads = (char **)(argv + i + 1);
- nr_heads = argc - i - 1;
- break;
}
- if (!dest)
- usage(fetch_pack_usage);
if (args.stateless_rpc) {
conn = NULL;
fd[0] = 0;
fd[1] = 1;
} else {
- conn = git_connect(fd, (char *)dest, args.uploadpack,
+ conn = git_connect(fd, dest, args.uploadpack,
args.verbose ? CONNECT_VERBOSE : 0);
}
@@ -1016,6 +1054,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
return ret;
}
+static int compare_heads(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+
struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd[], struct child_process *conn,
const struct ref *ref,
@@ -1035,8 +1078,11 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
st.st_mtime = 0;
}
- if (heads && nr_heads)
+ if (heads && nr_heads) {
+ qsort(heads, nr_heads, sizeof(*heads), compare_heads);
nr_heads = remove_duplicates(nr_heads, heads);
+ }
+
if (!ref) {
packet_flush(fd[1]);
die("no matching remote head");
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8ec4eae..bb9a074 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -240,6 +240,7 @@ static int s_update_ref(const char *action,
static int update_local_ref(struct ref *ref,
const char *remote,
+ const struct ref *remote_ref,
struct strbuf *display)
{
struct commit *current = NULL, *updated;
@@ -293,18 +294,26 @@ static int update_local_ref(struct ref *ref,
const char *msg;
const char *what;
int r;
- if (!strncmp(ref->name, "refs/tags/", 10)) {
+ /*
+ * Nicely describe the new ref we're fetching.
+ * Base this on the remote's ref name, as it's
+ * more likely to follow a standard layout.
+ */
+ const char *name = remote_ref ? remote_ref->name : "";
+ if (!prefixcmp(name, "refs/tags/")) {
msg = "storing tag";
what = _("[new tag]");
- }
- else {
+ } else if (!prefixcmp(name, "refs/heads/")) {
msg = "storing head";
what = _("[new branch]");
- if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
- (recurse_submodules != RECURSE_SUBMODULES_ON))
- check_for_new_submodule_commits(ref->new_sha1);
+ } else {
+ msg = "storing ref";
+ what = _("[new ref]");
}
+ if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
+ (recurse_submodules != RECURSE_SUBMODULES_ON))
+ check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref(msg, ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
r ? '!' : '*',
@@ -466,7 +475,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, what, &note);
+ rc |= update_local_ref(ref, what, rm, &note);
free(ref);
} else
strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
@@ -537,8 +546,8 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
const char *dangling_msg = dry_run
- ? _(" (%s will become dangling)\n")
- : _(" (%s has become dangling)\n");
+ ? _(" (%s will become dangling)")
+ : _(" (%s has become dangling)");
for (ref = stale_refs; ref; ref = ref->next) {
if (!dry_run)
@@ -585,7 +594,7 @@ static void find_non_local_tags(struct transport *transport,
for_each_ref(add_existing, &existing_refs);
for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags"))
+ if (prefixcmp(ref->name, "refs/tags/"))
continue;
/*
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index c81a7fe..2c4d435 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -27,6 +27,8 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
merge_log_config = DEFAULT_MERGE_LOG_LEN;
} else if (!strcmp(key, "merge.branchdesc")) {
use_branch_desc = git_config_bool(key, value);
+ } else {
+ return git_default_config(key, value, cb);
}
return 0;
}
@@ -53,7 +55,48 @@ static void init_src_data(struct src_data *data)
static struct string_list srcs = STRING_LIST_INIT_DUP;
static struct string_list origins = STRING_LIST_INIT_DUP;
-static int handle_line(char *line)
+struct merge_parents {
+ int alloc, nr;
+ struct merge_parent {
+ unsigned char given[20];
+ unsigned char commit[20];
+ unsigned char used;
+ } *item;
+};
+
+/*
+ * I know, I know, this is inefficient, but you won't be pulling and merging
+ * hundreds of heads at a time anyway.
+ */
+static struct merge_parent *find_merge_parent(struct merge_parents *table,
+ unsigned char *given,
+ unsigned char *commit)
+{
+ int i;
+ for (i = 0; i < table->nr; i++) {
+ if (given && hashcmp(table->item[i].given, given))
+ continue;
+ if (commit && hashcmp(table->item[i].commit, commit))
+ continue;
+ return &table->item[i];
+ }
+ return NULL;
+}
+
+static void add_merge_parent(struct merge_parents *table,
+ unsigned char *given,
+ unsigned char *commit)
+{
+ if (table->nr && find_merge_parent(table, given, commit))
+ return;
+ ALLOC_GROW(table->item, table->nr + 1, table->alloc);
+ hashcpy(table->item[table->nr].given, given);
+ hashcpy(table->item[table->nr].commit, commit);
+ table->item[table->nr].used = 0;
+ table->nr++;
+}
+
+static int handle_line(char *line, struct merge_parents *merge_parents)
{
int i, len = strlen(line);
struct origin_data *origin_data;
@@ -61,6 +104,7 @@ static int handle_line(char *line)
struct src_data *src_data;
struct string_list_item *item;
int pulling_head = 0;
+ unsigned char sha1[20];
if (len < 43 || line[40] != '\t')
return 1;
@@ -71,14 +115,15 @@ static int handle_line(char *line)
if (line[41] != '\t')
return 2;
- line[40] = 0;
- origin_data = xcalloc(1, sizeof(struct origin_data));
- i = get_sha1(line, origin_data->sha1);
- line[40] = '\t';
- if (i) {
- free(origin_data);
+ i = get_sha1_hex(line, sha1);
+ if (i)
return 3;
- }
+
+ if (!find_merge_parent(merge_parents, sha1, NULL))
+ return 0; /* subsumed by other parents */
+
+ origin_data = xcalloc(1, sizeof(struct origin_data));
+ hashcpy(origin_data->sha1, sha1);
if (line[len - 1] == '\n')
line[len - 1] = 0;
@@ -180,6 +225,101 @@ static void add_branch_desc(struct strbuf *out, const char *name)
strbuf_release(&desc);
}
+#define util_as_integral(elem) ((intptr_t)((elem)->util))
+
+static void record_person(int which, struct string_list *people,
+ struct commit *commit)
+{
+ char *name_buf, *name, *name_end;
+ struct string_list_item *elem;
+ const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
+
+ name = strstr(commit->buffer, field);
+ if (!name)
+ return;
+ name += strlen(field);
+ name_end = strchrnul(name, '<');
+ if (*name_end)
+ name_end--;
+ while (isspace(*name_end) && name <= name_end)
+ name_end--;
+ if (name_end < name)
+ return;
+ name_buf = xmemdupz(name, name_end - name + 1);
+
+ elem = string_list_lookup(people, name_buf);
+ if (!elem) {
+ elem = string_list_insert(people, name_buf);
+ elem->util = (void *)0;
+ }
+ elem->util = (void*)(util_as_integral(elem) + 1);
+ free(name_buf);
+}
+
+static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
+{
+ const struct string_list_item *a = a_, *b = b_;
+ return util_as_integral(b) - util_as_integral(a);
+}
+
+static void add_people_count(struct strbuf *out, struct string_list *people)
+{
+ if (people->nr == 1)
+ strbuf_addf(out, "%s", people->items[0].string);
+ else if (people->nr == 2)
+ strbuf_addf(out, "%s (%d) and %s (%d)",
+ people->items[0].string,
+ (int)util_as_integral(&people->items[0]),
+ people->items[1].string,
+ (int)util_as_integral(&people->items[1]));
+ else if (people->nr)
+ strbuf_addf(out, "%s (%d) and others",
+ people->items[0].string,
+ (int)util_as_integral(&people->items[0]));
+}
+
+static void credit_people(struct strbuf *out,
+ struct string_list *them,
+ int kind)
+{
+ const char *label;
+ const char *me;
+
+ if (kind == 'a') {
+ label = "\n# By ";
+ me = git_author_info(IDENT_NO_DATE);
+ } else {
+ label = "\n# Via ";
+ me = git_committer_info(IDENT_NO_DATE);
+ }
+
+ if (!them->nr ||
+ (them->nr == 1 &&
+ me &&
+ (me = skip_prefix(me, them->items->string)) != NULL &&
+ skip_prefix(me, " <")))
+ return;
+ strbuf_addstr(out, label);
+ add_people_count(out, them);
+}
+
+static void add_people_info(struct strbuf *out,
+ struct string_list *authors,
+ struct string_list *committers)
+{
+ if (authors->nr)
+ qsort(authors->items,
+ authors->nr, sizeof(authors->items[0]),
+ cmp_string_list_util_as_integral);
+ if (committers->nr)
+ qsort(committers->items,
+ committers->nr, sizeof(committers->items[0]),
+ cmp_string_list_util_as_integral);
+
+ credit_people(out, authors, 'a');
+ credit_people(out, committers, 'c');
+}
+
static void shortlog(const char *name,
struct origin_data *origin_data,
struct commit *head,
@@ -190,6 +330,8 @@ static void shortlog(const char *name,
struct commit *commit;
struct object *branch;
struct string_list subjects = STRING_LIST_INIT_DUP;
+ struct string_list authors = STRING_LIST_INIT_DUP;
+ struct string_list committers = STRING_LIST_INIT_DUP;
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
struct strbuf sb = STRBUF_INIT;
const unsigned char *sha1 = origin_data->sha1;
@@ -199,7 +341,6 @@ static void shortlog(const char *name,
return;
setup_revisions(0, NULL, rev, NULL);
- rev->ignore_merges = 1;
add_pending_object(rev, branch, name);
add_pending_object(rev, &head->object, "^HEAD");
head->object.flags |= UNINTERESTING;
@@ -208,10 +349,15 @@ static void shortlog(const char *name,
while ((commit = get_revision(rev)) != NULL) {
struct pretty_print_context ctx = {0};
- /* ignore merges */
- if (commit->parents && commit->parents->next)
+ if (commit->parents && commit->parents->next) {
+ /* do not list a merge but count committer */
+ record_person('c', &committers, commit);
continue;
-
+ }
+ if (!count)
+ /* the 'tip' committer */
+ record_person('c', &committers, commit);
+ record_person('a', &authors, commit);
count++;
if (subjects.nr > limit)
continue;
@@ -226,6 +372,7 @@ static void shortlog(const char *name,
string_list_append(&subjects, strbuf_detach(&sb, NULL));
}
+ add_people_info(out, &authors, &committers);
if (count > limit)
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
else
@@ -246,6 +393,8 @@ static void shortlog(const char *name,
rev->commits = NULL;
rev->pending.nr = 0;
+ string_list_clear(&authors, 0);
+ string_list_clear(&committers, 0);
string_list_clear(&subjects, 0);
}
@@ -313,7 +462,10 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
strbuf_add(tagbuf, tag_body, buf + len - tag_body);
}
strbuf_complete_line(tagbuf);
- strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
+ if (sig->len) {
+ strbuf_addch(tagbuf, '\n');
+ strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
+ }
}
static void fmt_merge_msg_sigs(struct strbuf *out)
@@ -366,6 +518,67 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_release(&tagbuf);
}
+static void find_merge_parents(struct merge_parents *result,
+ struct strbuf *in, unsigned char *head)
+{
+ struct commit_list *parents, *next;
+ struct commit *head_commit;
+ int pos = 0, i, j;
+
+ parents = NULL;
+ while (pos < in->len) {
+ int len;
+ char *p = in->buf + pos;
+ char *newline = strchr(p, '\n');
+ unsigned char sha1[20];
+ struct commit *parent;
+ struct object *obj;
+
+ len = newline ? newline - p : strlen(p);
+ pos += len + !!newline;
+
+ if (len < 43 ||
+ get_sha1_hex(p, sha1) ||
+ p[40] != '\t' ||
+ p[41] != '\t')
+ continue; /* skip not-for-merge */
+ /*
+ * Do not use get_merge_parent() here; we do not have
+ * "name" here and we do not want to contaminate its
+ * util field yet.
+ */
+ obj = parse_object(sha1);
+ parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
+ if (!parent)
+ continue;
+ commit_list_insert(parent, &parents);
+ add_merge_parent(result, obj->sha1, parent->object.sha1);
+ }
+ head_commit = lookup_commit(head);
+ if (head_commit)
+ commit_list_insert(head_commit, &parents);
+ parents = reduce_heads(parents);
+
+ while (parents) {
+ for (i = 0; i < result->nr; i++)
+ if (!hashcmp(result->item[i].commit,
+ parents->item->object.sha1))
+ result->item[i].used = 1;
+ next = parents->next;
+ free(parents);
+ parents = next;
+ }
+
+ for (i = j = 0; i < result->nr; i++) {
+ if (result->item[i].used) {
+ if (i != j)
+ result->item[j] = result->item[i];
+ j++;
+ }
+ }
+ result->nr = j;
+}
+
int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct fmt_merge_msg_opts *opts)
{
@@ -373,6 +586,9 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
unsigned char head_sha1[20];
const char *current_branch;
void *current_branch_to_free;
+ struct merge_parents merge_parents;
+
+ memset(&merge_parents, 0, sizeof(merge_parents));
/* get current branch */
current_branch = current_branch_to_free =
@@ -382,6 +598,8 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
if (!prefixcmp(current_branch, "refs/heads/"))
current_branch += 11;
+ find_merge_parents(&merge_parents, in, head_sha1);
+
/* get a line */
while (pos < in->len) {
int len;
@@ -392,7 +610,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
pos += len + !!newline;
i++;
p[len] = 0;
- if (handle_line(p))
+ if (handle_line(p, &merge_parents))
die ("Error in line %d: %.*s", i, len, p);
}
@@ -412,8 +630,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
rev.ignore_merges = 1;
rev.limited = 1;
- if (suffixcmp(out->buf, "\n"))
- strbuf_addch(out, '\n');
+ strbuf_complete_line(out);
for (i = 0; i < origins.nr; i++)
shortlog(origins.items[i].string,
@@ -423,6 +640,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
strbuf_complete_line(out);
free(current_branch_to_free);
+ free(merge_parents.item);
return 0;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 8c479a7..a710227 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -12,6 +12,7 @@
#include "parse-options.h"
#include "dir.h"
#include "progress.h"
+#include "streaming.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -29,6 +30,7 @@ static int errors_found;
static int write_lost_and_found;
static int verbose;
static int show_progress = -1;
+static int show_dangling = 1;
#define ERROR_OBJECT 01
#define ERROR_REACHABLE 02
#define ERROR_PACK 04
@@ -221,8 +223,9 @@ static void check_unreachable_object(struct object *obj)
* start looking at, for example.
*/
if (!obj->used) {
- printf("dangling %s %s\n", typename(obj->type),
- sha1_to_hex(obj->sha1));
+ if (show_dangling)
+ printf("dangling %s %s\n", typename(obj->type),
+ sha1_to_hex(obj->sha1));
if (write_lost_and_found) {
char *filename = git_path("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
@@ -236,13 +239,8 @@ static void check_unreachable_object(struct object *obj)
if (!(f = fopen(filename, "w")))
die_errno("Could not open '%s'", filename);
if (obj->type == OBJ_BLOB) {
- enum object_type type;
- unsigned long size;
- char *buf = read_sha1_file(obj->sha1,
- &type, &size);
- if (buf && fwrite(buf, 1, size, f) != size)
+ if (stream_blob_to_fd(fileno(f), obj->sha1, NULL, 1))
die_errno("Could not write '%s'", filename);
- free(buf);
} else
fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
if (fclose(f))
@@ -614,6 +612,7 @@ static char const * const fsck_usage[] = {
static struct option fsck_opts[] = {
OPT__VERBOSE(&verbose, "be verbose"),
OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"),
+ OPT_BOOL(0, "dangling", &show_dangling, "show dangling objects"),
OPT_BOOLEAN(0, "tags", &show_tags, "report tags"),
OPT_BOOLEAN(0, "root", &show_root, "report root nodes"),
OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"),
diff --git a/builtin/gc.c b/builtin/gc.c
index 271376d..9b4232c 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -14,6 +14,7 @@
#include "cache.h"
#include "parse-options.h"
#include "run-command.h"
+#include "argv-array.h"
#define FAILED_RUN "failed to run %s"
@@ -28,12 +29,11 @@ static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50;
static const char *prune_expire = "2.weeks.ago";
-#define MAX_ADD 10
-static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
-static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
-static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
-static const char *argv_prune[] = {"prune", "--expire", NULL, NULL, NULL};
-static const char *argv_rerere[] = {"rerere", "gc", NULL};
+static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
+static struct argv_array reflog = ARGV_ARRAY_INIT;
+static struct argv_array repack = ARGV_ARRAY_INIT;
+static struct argv_array prune = ARGV_ARRAY_INIT;
+static struct argv_array rerere = ARGV_ARRAY_INIT;
static int gc_config(const char *var, const char *value, void *cb)
{
@@ -67,19 +67,6 @@ static int gc_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-static void append_option(const char **cmd, const char *opt, int max_length)
-{
- int i;
-
- for (i = 0; cmd[i]; i++)
- ;
-
- if (i + 2 >= max_length)
- die(_("Too many options specified"));
- cmd[i++] = opt;
- cmd[i] = NULL;
-}
-
static int too_many_loose_objects(void)
{
/*
@@ -144,6 +131,17 @@ static int too_many_packs(void)
return gc_auto_pack_limit <= cnt;
}
+static void add_repack_all_option(void)
+{
+ if (prune_expire && !strcmp(prune_expire, "now"))
+ argv_array_push(&repack, "-a");
+ else {
+ argv_array_push(&repack, "-A");
+ if (prune_expire)
+ argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
+ }
+}
+
static int need_to_gc(void)
{
/*
@@ -160,10 +158,7 @@ static int need_to_gc(void)
* there is no need.
*/
if (too_many_packs())
- append_option(argv_repack,
- prune_expire && !strcmp(prune_expire, "now") ?
- "-a" : "-A",
- MAX_ADD);
+ add_repack_all_option();
else if (!too_many_loose_objects())
return 0;
@@ -177,7 +172,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int aggressive = 0;
int auto_gc = 0;
int quiet = 0;
- char buf[80];
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, "suppress progress reporting"),
@@ -192,6 +186,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_gc_usage, builtin_gc_options);
+ argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
+ argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
+ argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
+ argv_array_pushl(&prune, "prune", "--expire", NULL );
+ argv_array_pushl(&rerere, "rerere", "gc", NULL);
+
git_config(gc_config, NULL);
if (pack_refs < 0)
@@ -203,15 +203,13 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
usage_with_options(builtin_gc_usage, builtin_gc_options);
if (aggressive) {
- append_option(argv_repack, "-f", MAX_ADD);
- append_option(argv_repack, "--depth=250", MAX_ADD);
- if (aggressive_window > 0) {
- sprintf(buf, "--window=%d", aggressive_window);
- append_option(argv_repack, buf, MAX_ADD);
- }
+ argv_array_push(&repack, "-f");
+ argv_array_push(&repack, "--depth=250");
+ if (aggressive_window > 0)
+ argv_array_pushf(&repack, "--window=%d", aggressive_window);
}
if (quiet)
- append_option(argv_repack, "-q", MAX_ADD);
+ argv_array_push(&repack, "-q");
if (auto_gc) {
/*
@@ -227,30 +225,27 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
"run \"git gc\" manually. See "
"\"git help gc\" for more information.\n"));
} else
- append_option(argv_repack,
- prune_expire && !strcmp(prune_expire, "now")
- ? "-a" : "-A",
- MAX_ADD);
+ add_repack_all_option();
- if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_pack_refs[0]);
+ if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, pack_refs_cmd.argv[0]);
- if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_reflog[0]);
+ if (run_command_v_opt(reflog.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, reflog.argv[0]);
- if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_repack[0]);
+ if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, repack.argv[0]);
if (prune_expire) {
- argv_prune[2] = prune_expire;
+ argv_array_push(&prune, prune_expire);
if (quiet)
- argv_prune[3] = "--no-progress";
- if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_prune[0]);
+ argv_array_push(&prune, "--no-progress");
+ if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, prune.argv[0]);
}
- if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
- return error(FAILED_RUN, argv_rerere[0]);
+ if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
+ return error(FAILED_RUN, rerere.argv[0]);
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
diff --git a/builtin/grep.c b/builtin/grep.c
index 9fc3e95..29adb0a 100644
--- a/builtin/grep.c
+++ b/