summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap2
-rw-r--r--.travis.yml2
-rw-r--r--Documentation/RelNotes/2.10.0.txt675
-rw-r--r--Documentation/RelNotes/2.10.1.txt131
-rw-r--r--Documentation/RelNotes/2.11.0.txt372
-rw-r--r--Documentation/RelNotes/2.3.10.txt2
-rw-r--r--Documentation/RelNotes/2.4.10.txt2
-rw-r--r--Documentation/RelNotes/2.5.4.txt2
-rw-r--r--Documentation/RelNotes/2.6.1.txt2
-rw-r--r--Documentation/RelNotes/2.9.4.txt83
-rw-r--r--Documentation/SubmittingPatches10
-rw-r--r--Documentation/config.txt177
-rw-r--r--Documentation/diff-config.txt16
-rw-r--r--Documentation/diff-heuristic-options.txt7
-rw-r--r--Documentation/diff-options.txt27
-rw-r--r--Documentation/git-add.txt7
-rw-r--r--Documentation/git-am.txt3
-rw-r--r--Documentation/git-annotate.txt1
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--Documentation/git-cat-file.txt40
-rw-r--r--Documentation/git-check-ref-format.txt4
-rw-r--r--Documentation/git-checkout.txt12
-rw-r--r--Documentation/git-clone.txt5
-rw-r--r--Documentation/git-config.txt3
-rw-r--r--Documentation/git-cvsimport.txt2
-rw-r--r--Documentation/git-fast-import.txt2
-rw-r--r--Documentation/git-fetch.txt51
-rw-r--r--Documentation/git-format-patch.txt8
-rw-r--r--Documentation/git-fsck.txt9
-rw-r--r--Documentation/git-index-pack.txt2
-rw-r--r--Documentation/git-log.txt4
-rw-r--r--Documentation/git-ls-files.txt3
-rw-r--r--Documentation/git-mailsplit.txt7
-rw-r--r--Documentation/git-pack-objects.txt4
-rw-r--r--Documentation/git-push.txt13
-rw-r--r--Documentation/git-receive-pack.txt3
-rw-r--r--Documentation/git-remote-fd.txt2
-rw-r--r--Documentation/git-repack.txt19
-rw-r--r--Documentation/git-status.txt133
-rw-r--r--Documentation/git-submodule.txt11
-rw-r--r--Documentation/git-svn.txt3
-rw-r--r--Documentation/git-unpack-objects.txt3
-rw-r--r--Documentation/git-upload-pack.txt16
-rw-r--r--Documentation/git-worktree.txt49
-rw-r--r--Documentation/git.txt14
-rw-r--r--Documentation/gitattributes.txt69
-rw-r--r--Documentation/gitcvs-migration.txt6
-rw-r--r--Documentation/githooks.txt18
-rw-r--r--Documentation/gitk.txt2
-rw-r--r--Documentation/gitmodules.txt5
-rw-r--r--Documentation/gitrevisions.txt6
-rw-r--r--Documentation/gitweb.conf.txt21
-rw-r--r--Documentation/pretty-formats.txt12
-rw-r--r--Documentation/rev-list-options.txt53
-rw-r--r--Documentation/revisions.txt138
-rw-r--r--Documentation/technical/api-sha1-array.txt8
-rw-r--r--Documentation/technical/pack-protocol.txt10
-rw-r--r--Documentation/technical/protocol-capabilities.txt9
-rw-r--r--Documentation/technical/protocol-common.txt6
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile94
l---------RelNotes2
-rw-r--r--advice.c23
-rw-r--r--apply.c4986
-rw-r--r--apply.h137
-rw-r--r--archive-tar.c77
-rw-r--r--archive.c12
-rw-r--r--bisect.c65
-rw-r--r--builtin.h2
-rw-r--r--builtin/add.c47
-rw-r--r--builtin/am.c411
-rw-r--r--builtin/apply.c4661
-rw-r--r--builtin/blame.c136
-rw-r--r--builtin/branch.c32
-rw-r--r--builtin/cat-file.c178
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c104
-rw-r--r--builtin/clone.c127
-rw-r--r--builtin/commit-tree.c20
-rw-r--r--builtin/commit.c80
-rw-r--r--builtin/config.c7
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff.c27
-rw-r--r--builtin/fast-export.c12
-rw-r--r--builtin/fetch.c205
-rw-r--r--builtin/fmt-merge-msg.c14
-rw-r--r--builtin/fsck.c84
-rw-r--r--builtin/gc.c2
-rw-r--r--builtin/grep.c3
-rw-r--r--builtin/hash-object.c13
-rw-r--r--builtin/help.c37
-rw-r--r--builtin/index-pack.c26
-rw-r--r--builtin/init-db.c126
-rw-r--r--builtin/interpret-trailers.c2
-rw-r--r--builtin/log.c176
-rw-r--r--builtin/ls-files.c5
-rw-r--r--builtin/mailsplit.c18
-rw-r--r--builtin/merge-index.c2
-rw-r--r--builtin/merge-recursive.c39
-rw-r--r--builtin/merge.c120
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/mv.c13
-rw-r--r--builtin/name-rev.c3
-rw-r--r--builtin/notes.c89
-rw-r--r--builtin/pack-objects.c295
-rw-r--r--builtin/pull.c5
-rw-r--r--builtin/push.c21
-rw-r--r--builtin/read-tree.c2
-rw-r--r--builtin/receive-pack.c269
-rw-r--r--builtin/remote.c32
-rw-r--r--builtin/repack.c12
-rw-r--r--builtin/reset.c58
-rw-r--r--builtin/rev-list.c91
-rw-r--r--builtin/rev-parse.c54
-rw-r--r--builtin/rm.c18
-rw-r--r--builtin/shortlog.c23
-rw-r--r--builtin/show-branch.c36
-rw-r--r--builtin/submodule--helper.c290
-rw-r--r--builtin/symbolic-ref.c2
-rw-r--r--builtin/unpack-objects.c11
-rw-r--r--builtin/update-index.c101
-rw-r--r--builtin/worktree.c87
-rw-r--r--cache-tree.c4
-rw-r--r--cache.h149
-rw-r--r--color.c37
-rw-r--r--color.h15
-rw-r--r--combine-diff.c16
-rw-r--r--commit-slab.h8
-rw-r--r--commit.c38
-rw-r--r--commit.h14
-rw-r--r--common-main.c41
-rw-r--r--compat/mingw.c42
-rw-r--r--compat/mingw.h9
-rw-r--r--compat/nedmalloc/nedmalloc.c16
-rw-r--r--compat/strdup.c11
-rw-r--r--config.c239
-rw-r--r--config.mak.uname3
-rw-r--r--configure.ac21
-rw-r--r--connect.c55
-rw-r--r--connected.c71
-rw-r--r--connected.h37
-rw-r--r--contrib/coccinelle/.gitignore1
-rw-r--r--contrib/coccinelle/README2
-rw-r--r--contrib/coccinelle/array.cocci26
-rw-r--r--contrib/coccinelle/object_id.cocci95
-rw-r--r--contrib/coccinelle/qsort.cocci37
-rw-r--r--contrib/coccinelle/strbuf.cocci40
-rw-r--r--contrib/completion/git-completion.bash150
-rw-r--r--contrib/diff-highlight/Makefile5
-rwxr-xr-xcontrib/diff-highlight/diff-highlight19
-rw-r--r--contrib/diff-highlight/t/.gitignore2
-rw-r--r--contrib/diff-highlight/t/Makefile22
-rwxr-xr-xcontrib/diff-highlight/t/t9400-diff-highlight.sh296
-rwxr-xr-xcontrib/fast-import/import-tars.perl31
-rw-r--r--contrib/git-jump/README6
-rwxr-xr-xcontrib/git-jump/git-jump8
-rw-r--r--contrib/hooks/multimail/CHANGES59
-rw-r--r--contrib/hooks/multimail/CONTRIBUTING.rst9
-rw-r--r--contrib/hooks/multimail/README89
-rw-r--r--contrib/hooks/multimail/README.Git4
-rw-r--r--contrib/hooks/multimail/doc/troubleshooting.rst34
-rwxr-xr-xcontrib/hooks/multimail/git_multimail.py810
-rw-r--r--contrib/mw-to-git/.perlcriticrc2
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl2
-rwxr-xr-xcontrib/subtree/git-subtree.sh677
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh2
-rw-r--r--convert.c127
-rw-r--r--convert.h3
-rw-r--r--credential-cache--daemon.c2
-rw-r--r--credential-cache.c2
-rw-r--r--credential-store.c2
-rw-r--r--daemon.c16
-rw-r--r--date.c8
-rw-r--r--diff-lib.c31
-rw-r--r--diff-no-index.c3
-rw-r--r--diff.c262
-rw-r--r--diff.h14
-rw-r--r--diffcore-break.c4
-rw-r--r--diffcore-delta.c5
-rw-r--r--diffcore-order.c2
-rw-r--r--diffcore-pickaxe.c18
-rw-r--r--diffcore-rename.c20
-rw-r--r--diffcore.h4
-rw-r--r--dir-iterator.c202
-rw-r--r--dir-iterator.h87
-rw-r--r--dir.c11
-rw-r--r--dir.h23
-rw-r--r--entry.c9
-rw-r--r--environment.c13
-rw-r--r--fast-import.c74
-rw-r--r--fetch-pack.c32
-rw-r--r--fsck.c131
-rw-r--r--fsck.h7
-rwxr-xr-xgit-add--interactive.perl5
-rwxr-xr-xgit-bisect.sh8
-rw-r--r--git-compat-util.h66
-rwxr-xr-xgit-difftool--helper.sh7
-rw-r--r--git-gui/lib/commit.tcl3
-rw-r--r--git-gui/lib/index.tcl6
-rw-r--r--git-gui/lib/merge.tcl7
-rw-r--r--git-gui/po/glossary/pt_pt.po293
-rw-r--r--git-gui/po/ja.po2747
-rw-r--r--git-gui/po/pt_pt.po2716
-rwxr-xr-xgit-merge-octopus.sh25
-rwxr-xr-xgit-p4.py4
-rw-r--r--git-rebase--interactive.sh258
-rwxr-xr-xgit-rebase.sh5
-rwxr-xr-xgit-send-email.perl40
-rw-r--r--git-sh-i18n.sh18
-rw-r--r--git-sh-setup.sh71
-rwxr-xr-xgit-stash.sh11
-rwxr-xr-xgit-submodule.sh74
-rwxr-xr-xgit-svn.perl9
-rw-r--r--git.c54
-rwxr-xr-xgitweb/gitweb.perl14
-rw-r--r--gpg-interface.c94
-rw-r--r--graph.c132
-rw-r--r--graph.h22
-rw-r--r--grep.c22
-rw-r--r--help.c15
-rw-r--r--hex.c17
-rw-r--r--http-backend.c225
-rw-r--r--http-fetch.c6
-rw-r--r--http-push.c10
-rw-r--r--http-walker.c55
-rw-r--r--http.c208
-rw-r--r--http.h2
-rw-r--r--ident.c34
-rw-r--r--imap-send.c10
-rw-r--r--iterator.h81
-rw-r--r--line-log.c48
-rw-r--r--list.h166
-rw-r--r--lockfile.h4
-rw-r--r--log-tree.c78
-rw-r--r--mailinfo.c207
-rw-r--r--mailinfo.h1
-rw-r--r--merge-recursive.c789
-rw-r--r--merge-recursive.h8
-rw-r--r--merge.c9
-rw-r--r--mru.c50
-rw-r--r--mru.h45
-rw-r--r--notes-merge.c167
-rw-r--r--notes.c14
-rw-r--r--pack-bitmap-write.c3
-rw-r--r--pack-check.c9
-rw-r--r--pack-objects.h9
-rw-r--r--pack-revindex.c2
-rw-r--r--pack-write.c4
-rw-r--r--pager.c125
-rw-r--r--parse-options-cb.c14
-rw-r--r--parse-options.h1
-rw-r--r--patch-ids.c125
-rw-r--r--patch-ids.h11
-rw-r--r--path.c41
-rw-r--r--pathspec.c8
-rw-r--r--pathspec.h6
-rw-r--r--perl/Git/SVN.pm33
-rw-r--r--pkt-line.c23
-rw-r--r--po/TEAMS5
-rw-r--r--po/ca.po6013
-rw-r--r--po/fr.po4868
-rw-r--r--po/git.pot4325
-rw-r--r--po/is.po46
-rw-r--r--po/ko.po4665
-rw-r--r--po/pt_PT.po4924
-rw-r--r--po/sv.po4834
-rw-r--r--po/vi.po4828
-rw-r--r--po/zh_CN.po4511
-rw-r--r--pretty.c61
-rw-r--r--read-cache.c72
-rw-r--r--ref-filter.c44
-rw-r--r--refs.c413
-rw-r--r--refs.h155
-rw-r--r--refs/files-backend.c2029
-rw-r--r--refs/iterator.c384
-rw-r--r--refs/refs-internal.h501
-rw-r--r--remote-curl.c5
-rw-r--r--remote-testsvn.c3
-rw-r--r--remote.c17
-rw-r--r--remote.h1
-rw-r--r--rerere.c3
-rw-r--r--resolve-undo.c2
-rw-r--r--revision.c58
-rw-r--r--run-command.c157
-rw-r--r--run-command.h31
-rw-r--r--send-pack.c27
-rw-r--r--send-pack.h3
-rw-r--r--sequencer.c215
-rw-r--r--server-info.c2
-rw-r--r--setup.c34
-rw-r--r--sh-i18n--envsubst.c5
-rw-r--r--sha1-array.c10
-rw-r--r--sha1-array.h8
-rw-r--r--sha1_file.c378
-rw-r--r--sha1_name.c219
-rw-r--r--shallow.c2
-rw-r--r--shell.c13
-rw-r--r--shortlog.h1
-rw-r--r--show-index.c4
-rw-r--r--split-index.c6
-rw-r--r--strbuf.c2
-rw-r--r--streaming.c18
-rw-r--r--streaming.h2
-rw-r--r--string-list.c2
-rw-r--r--submodule-config.c22
-rw-r--r--submodule-config.h2
-rw-r--r--submodule.c200
-rw-r--r--submodule.h8
-rw-r--r--t/Makefile11
-rw-r--r--t/README2
-rw-r--r--t/helper/test-chmtime.c2
-rw-r--r--t/helper/test-config.c41
-rw-r--r--t/helper/test-ctype.c2
-rw-r--r--t/helper/test-date.c14
-rw-r--r--t/helper/test-delta.c2
-rw-r--r--t/helper/test-dump-cache-tree.c2
-rw-r--r--t/helper/test-dump-split-index.c4
-rw-r--r--t/helper/test-dump-untracked-cache.c8
-rw-r--r--t/helper/test-fake-ssh.c2
-rw-r--r--t/helper/test-genrandom.c2
-rw-r--r--t/helper/test-hashmap.c2
-rw-r--r--t/helper/test-index-version.c2
-rw-r--r--t/helper/test-line-buffer.c2
-rw-r--r--t/helper/test-match-trees.c2
-rw-r--r--t/helper/test-mergesort.c2
-rw-r--r--t/helper/test-mktemp.c2
-rw-r--r--t/helper/test-parse-options.c4
-rw-r--r--t/helper/test-path-utils.c4
-rw-r--r--t/helper/test-prio-queue.c2
-rw-r--r--t/helper/test-read-cache.c2
-rw-r--r--t/helper/test-regex.c2
-rw-r--r--t/helper/test-revision-walking.c2
-rw-r--r--t/helper/test-run-command.c2
-rw-r--r--t/helper/test-scrap-cache-tree.c2
-rw-r--r--t/helper/test-sha1-array.c5
-rw-r--r--t/helper/test-sha1.c2
-rw-r--r--t/helper/test-sigchain.c2
-rw-r--r--t/helper/test-string-list.c2
-rw-r--r--t/helper/test-submodule-config.c8
-rw-r--r--t/helper/test-subprocess.c2
-rw-r--r--t/helper/test-svn-fe.c4
-rw-r--r--t/helper/test-urlmatch-normalization.c2
-rw-r--r--t/helper/test-wildmatch.c2
-rw-r--r--t/lib-git-svn.sh91
-rw-r--r--t/lib-httpd.sh9
-rw-r--r--t/lib-httpd/apache.conf4
-rw-r--r--t/lib-rebase.sh1
-rw-r--r--t/perf/README12
-rwxr-xr-xt/perf/p0003-delta-base-cache.sh31
-rwxr-xr-xt/perf/p3400-rebase.sh36
-rwxr-xr-xt/perf/p4211-line-log.sh6
-rwxr-xr-xt/perf/p5303-many-packs.sh87
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh14
-rw-r--r--t/perf/perf-lib.sh5
-rwxr-xr-xt/perf/run8
-rwxr-xr-xt/t0001-init.sh26
-rwxr-xr-xt/t0006-date.sh3
-rwxr-xr-xt/t0008-ignores.sh4
-rwxr-xr-xt/t0012-help.sh52
-rwxr-xr-xt/t0025-crlf-auto.sh4
-rwxr-xr-xt/t0027-auto-crlf.sh35
-rwxr-xr-xt/t1006-cat-file.sh2
-rwxr-xr-xt/t1007-hash-object.sh68
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh2
-rwxr-xr-xt/t1300-repo-config.sh8
-rwxr-xr-xt/t1301-shared-repo.sh41
-rwxr-xr-xt/t1302-repo-version.sh32
-rwxr-xr-xt/t1307-config-blob.sh5
-rwxr-xr-xt/t1308-config-set.sh39
-rwxr-xr-xt/t1350-config-hooks-path.sh6
-rwxr-xr-xt/t1400-update-ref.sh43
-rwxr-xr-xt/t1401-symbolic-ref.sh21
-rwxr-xr-xt/t1404-update-ref-df-conflicts.sh107
-rwxr-xr-xt/t1404-update-ref-errors.sh407
-rwxr-xr-xt/t1410-reflog.sh1
-rwxr-xr-xt/t1430-bad-ref-name.sh2
-rwxr-xr-xt/t1450-fsck.sh38
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh2
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh70
-rwxr-xr-xt/t2010-checkout-ambiguous.sh11
-rwxr-xr-xt/t2018-checkout-branch.sh2
-rwxr-xr-xt/t2020-checkout-detach.sh23
-rwxr-xr-xt/t2024-checkout-dwim.sh12
-rwxr-xr-xt/t2025-worktree-add.sh16
-rwxr-xr-xt/t2028-worktree-move.sh62
-rwxr-xr-xt/t2107-update-index-basic.sh13
-rwxr-xr-xt/t3030-merge-recursive.sh18
-rwxr-xr-xt/t3101-ls-tree-dirname.sh2
-rwxr-xr-xt/t3200-branch.sh15
-rwxr-xr-xt/t3201-branch-contains.sh2
-rwxr-xr-xt/t3310-notes-merge-manual-resolve.sh10
-rwxr-xr-xt/t3320-notes-merge-worktrees.sh4
-rwxr-xr-xt/t3400-rebase.sh4
-rwxr-xr-xt/t3404-rebase-interactive.sh32
-rwxr-xr-xt/t3415-rebase-autosquash.sh33
-rwxr-xr-xt/t3420-rebase-autostash.sh4
-rwxr-xr-xt/t3700-add.sh113
-rwxr-xr-xt/t3900-i18n-commit.sh8
-rwxr-xr-xt/t3901-i18n-patch.sh2
-rwxr-xr-xt/t4012-diff-binary.sh4
-rwxr-xr-xt/t4013-diff-various.sh6
-rw-r--r--t/t4013/diff.diff_--line-prefix=abc_master_master^_side29
-rw-r--r--t/t4013/diff.diff_--line-prefix_--cached_--_file015
-rwxr-xr-xt/t4014-format-patch.sh123
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/css-brace-in-col-15
-rw-r--r--t/t4018/css-colon-eol4
-rw-r--r--t/t4018/css-colon-selector5
-rw-r--r--t/t4018/css-common4
-rw-r--r--t/t4018/css-long-selector-list6
-rw-r--r--t/t4018/css-prop-sans-indent5
-rw-r--r--t/t4018/css-short-selector-list4
-rw-r--r--t/t4018/css-trailing-space5
-rwxr-xr-xt/t4021-format-patch-numbered.sh17
-rwxr-xr-xt/t4026-color.sh9
-rwxr-xr-xt/t4034-diff-words.sh1
-rw-r--r--t/t4034/css/expect16
-rw-r--r--t/t4034/css/post10
-rw-r--r--t/t4034/css/pre10
-rwxr-xr-xt/t4051-diff-function-context.sh25
-rwxr-xr-xt/t4053-diff-no-index.sh38
-rwxr-xr-xt/t4059-diff-submodule-not-initialized.sh127
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh749
-rwxr-xr-xt/t4061-diff-indent.sh216
-rwxr-xr-xt/t4062-diff-pickaxe.sh22
-rwxr-xr-xt/t4150-am.sh43
-rwxr-xr-xt/t4153-am-resume-override-opts.sh2
-rwxr-xr-xt/t4201-shortlog.sh6
-rwxr-xr-xt/t4202-log.sh355
-rwxr-xr-xt/t4204-patch-id.sh14
-rwxr-xr-xt/t4207-log-decoration-colors.sh2
-rwxr-xr-xt/t4208-log-magic-pathspec.sh4
-rwxr-xr-xt/t4211-line-log.sh7
-rwxr-xr-xt/t4254-am-corrupt.sh2
-rwxr-xr-xt/t5000-tar-tree.sh74
-rw-r--r--t/t5000/19f9c8273ec45a8938e6999cb59b3ff66739902abin0 -> 2048 bytes
-rw-r--r--t/t5000/huge-and-future.tarbin0 -> 2048 bytes
-rwxr-xr-xt/t5100-mailinfo.sh111
-rw-r--r--t/t5100/0001mboxrd4
-rw-r--r--t/t5100/0002mboxrd5
-rw-r--r--t/t5100/comment.expect5
-rw-r--r--t/t5100/comment.in9
-rw-r--r--t/t5100/info00185
-rw-r--r--t/t5100/info0018--no-inbody-headers5
-rw-r--r--t/t5100/msg00152
-rw-r--r--t/t5100/msg00182
-rw-r--r--t/t5100/msg0018--no-inbody-headers8
-rw-r--r--t/t5100/patch00186
-rw-r--r--t/t5100/patch0018--no-inbody-headers6
-rw-r--r--t/t5100/quoted-string.expect5
-rw-r--r--t/t5100/quoted-string.in9
-rw-r--r--t/t5100/sample.mbox19
-rw-r--r--t/t5100/sample.mboxrd19
-rwxr-xr-xt/t5305-include-tag.sh94
-rwxr-xr-xt/t5310-pack-bitmaps.sh108
-rwxr-xr-xt/t5314-pack-cycle-detection.sh113
-rwxr-xr-xt/t5505-remote.sh2
-rwxr-xr-xt/t5510-fetch.sh32
-rwxr-xr-xt/t5512-ls-remote.sh42
-rwxr-xr-xt/t5520-pull.sh50
-rwxr-xr-xt/t5523-push-upstream.sh12
-rwxr-xr-xt/t5526-fetch-submodules.sh35
-rwxr-xr-xt/t5533-push-cas.sh38
-rwxr-xr-xt/t5536-fetch-conflicts.sh4
-rwxr-xr-xt/t5541-http-push-smart.sh14
-rwxr-xr-xt/t5544-pack-objects-hook.sh62
-rwxr-xr-xt/t5545-push-options.sh103
-rwxr-xr-xt/t5546-receive-limits.sh55
-rwxr-xr-xt/t5550-http-fetch-dumb.sh18
-rwxr-xr-xt/t5551-http-fetch-smart.sh15
-rwxr-xr-xt/t5614-clone-submodules.sh52
-rwxr-xr-xt/t6007-rev-list-cherry-pick-file.sh21
-rwxr-xr-xt/t6018-rev-list-glob.sh2
-rwxr-xr-xt/t6026-merge-attr.sh15
-rwxr-xr-xt/t6030-bisect-porcelain.sh28
-rwxr-xr-xt/t6038-merge-text-auto.sh74
-rwxr-xr-xt/t6101-rev-parse-parents.sh94
-rwxr-xr-xt/t6301-for-each-ref-errors.sh10
-rwxr-xr-xt/t7001-mv.sh8
-rwxr-xr-xt/t7004-tag.sh9
-rwxr-xr-xt/t7006-pager.sh13
-rwxr-xr-xt/t7060-wtstatus.sh21
-rwxr-xr-xt/t7063-status-untracked-cache.sh2
-rwxr-xr-xt/t7064-wtstatus-pv2.sh593
-rwxr-xr-xt/t7102-reset.sh4
-rwxr-xr-xt/t7201-co.sh2
-rwxr-xr-xt/t7400-submodule-basic.sh2
-rwxr-xr-xt/t7403-submodule-sync.sh4
-rwxr-xr-xt/t7406-submodule-update.sh80
-rwxr-xr-xt/t7408-submodule-reference.sh185
-rwxr-xr-xt/t7411-submodule-config.sh2
-rwxr-xr-xt/t7508-status.sh4
-rwxr-xr-xt/t7510-signed-commit.sh7
-rwxr-xr-xt/t7517-per-repo-email.sh47
-rwxr-xr-xt/t7607-merge-overwrite.sh2
-rwxr-xr-xt/t7701-repack-unpack-unreachable.sh28
-rwxr-xr-xt/t7800-difftool.sh6
-rwxr-xr-xt/t7810-grep.sh2
-rwxr-xr-xt/t8002-blame.sh5
-rwxr-xr-xt/t8003-blame-corner-cases.sh4
-rwxr-xr-xt/t8010-cat-file-filters.sh64
-rwxr-xr-xt/t9003-help-autocorrect.sh4
-rwxr-xr-xt/t9100-git-svn-basic.sh23
-rwxr-xr-xt/t9115-git-svn-dcommit-funky-renames.sh7
-rwxr-xr-xt/t9118-git-svn-funky-branch-names.sh2
-rwxr-xr-xt/t9120-git-svn-clone-with-percent-escapes.sh2
-rwxr-xr-xt/t9142-git-svn-shallow-clone.sh2
-rwxr-xr-xt/t9158-git-svn-mergeinfo.sh2
-rwxr-xr-xt/t9160-git-svn-preserve-empty-dirs.sh1
-rwxr-xr-xt/t9300-fast-import.sh25
-rwxr-xr-xt/t9302-fast-import-unpack-limit.sh105
-rwxr-xr-xt/t9401-git-cvsserver-crlf.sh2
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh8
-rwxr-xr-xt/t9801-git-p4-branch.sh4
-rwxr-xr-xt/t9903-bash-prompt.sh2
-rw-r--r--t/test-lib-functions.sh18
-rw-r--r--t/test-lib.sh9
-rw-r--r--tempfile.c7
-rw-r--r--tempfile.h4
-rw-r--r--templates/hooks--pre-receive.sample24
-rw-r--r--trace.c55
-rw-r--r--trailer.c2
-rw-r--r--transport-helper.c10
-rw-r--r--transport.c36
-rw-r--r--transport.h7
-rw-r--r--tree-diff.c4
-rw-r--r--tree-walk.c83
-rw-r--r--tree-walk.h8
-rw-r--r--tree.c5
-rw-r--r--unpack-trees.c23
-rw-r--r--upload-pack.c73
-rw-r--r--url.c21
-rw-r--r--usage.c16
-rw-r--r--userdiff.c12
-rw-r--r--vcs-svn/fast_export.c4
-rw-r--r--walker.c10
-rw-r--r--walker.h3
-rw-r--r--worktree.c95
-rw-r--r--worktree.h21
-rw-r--r--wrapper.c52
-rw-r--r--write_or_die.c12
-rw-r--r--wt-status.c586
-rw-r--r--wt-status.h19
-rw-r--r--xdiff-interface.c21
-rw-r--r--xdiff-interface.h3
-rw-r--r--xdiff/xdiff.h1
-rw-r--r--xdiff/xdiffi.c635
-rw-r--r--xdiff/xemit.c11
548 files changed, 55050 insertions, 27080 deletions
diff --git a/.mailmap b/.mailmap
index a714e69..9cc33e9 100644
--- a/.mailmap
+++ b/.mailmap
@@ -33,6 +33,7 @@ Cheng Renquan <crquan@gmail.com>
Chris Shoemaker <c.shoemaker@cox.net>
Chris Wright <chrisw@sous-sol.org> <chrisw@osdl.org>
Cord Seele <cowose@gmail.com> <cowose@googlemail.com>
+Christian Couder <chriscool@tuxfamily.org> <christian.couder@gmail.com>
Christian Stimming <stimming@tuhh.de> <chs@ckiste.goetheallee>
Csaba Henk <csaba@gluster.com> <csaba@lowlife.hu>
Dan Johnson <computerdruid@gmail.com>
@@ -47,6 +48,7 @@ David Kågedal <davidk@lysator.liu.se>
David Reiss <dreiss@facebook.com> <dreiss@dreiss-vmware.(none)>
David S. Miller <davem@davemloft.net>
David Turner <novalis@novalis.org> <dturner@twopensource.com>
+David Turner <novalis@novalis.org> <dturner@twosigma.com>
Deskin Miller <deskinm@umich.edu>
Dirk Süsserott <newsletter@dirk.my1.cc>
Eric Blake <eblake@redhat.com> <ebb9@byu.net>
diff --git a/.travis.yml b/.travis.yml
index 477c3d2..37a1e1f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -78,7 +78,7 @@ before_install:
FORMULA=$1
SHA=$(brew fetch --force $FORMULA 2>&1 | grep ^SHA256: | cut -d ' ' -f 2)
sed -E -i.bak "s/sha256 \"[0-9a-f]{64}\"/sha256 \"$SHA\"/g" \
- /usr/local/Library/Taps/homebrew/homebrew-binary/$FORMULA.rb
+ "$(brew --repository homebrew/homebrew-binary)/$FORMULA.rb"
}
brew update --quiet
brew tap homebrew/binary --quiet
diff --git a/Documentation/RelNotes/2.10.0.txt b/Documentation/RelNotes/2.10.0.txt
new file mode 100644
index 0000000..f4da28a
--- /dev/null
+++ b/Documentation/RelNotes/2.10.0.txt
@@ -0,0 +1,675 @@
+Git 2.10 Release Notes
+======================
+
+Backward compatibility notes
+----------------------------
+
+Updates since v2.9
+------------------
+
+UI, Workflows & Features
+
+ * "git pull --rebase --verify-signature" learned to warn the user
+ that "--verify-signature" is a no-op when rebasing.
+
+ * An upstream project can make a recommendation to shallowly clone
+ some submodules in the .gitmodules file it ships.
+
+ * "git worktree add" learned that '-' can be used as a short-hand for
+ "@{-1}", the previous branch.
+
+ * Update the funcname definition to support css files.
+
+ * The completion script (in contrib/) learned to complete "git
+ status" options.
+
+ * Messages that are generated by auto gc during "git push" on the
+ receiving end are now passed back to the sending end in such a way
+ that they are shown with "remote: " prefix to avoid confusing the
+ users.
+
+ * "git add -i/-p" learned to honor diff.compactionHeuristic
+ experimental knob, so that the user can work on the same hunk split
+ as "git diff" output.
+
+ * "upload-pack" allows a custom "git pack-objects" replacement when
+ responding to "fetch/clone" via the uploadpack.packObjectsHook.
+ (merge b738396 jk/upload-pack-hook later to maint).
+
+ * Teach format-patch and mailsplit (hence "am") how a line that
+ happens to begin with "From " in the e-mail message is quoted with
+ ">", so that these lines can be restored to their original shape.
+ (merge d9925d1 ew/mboxrd-format-am later to maint).
+
+ * "git repack" learned the "--keep-unreachable" option, which sends
+ loose unreachable objects to a pack instead of leaving them loose.
+ This helps heuristics based on the number of loose objects
+ (e.g. "gc --auto").
+ (merge e26a8c4 jk/repack-keep-unreachable later to maint).
+
+ * "log --graph --format=" learned that "%>|(N)" specifies the width
+ relative to the terminal's left edge, not relative to the area to
+ draw text that is to the right of the ancestry-graph section. It
+ also now accepts negative N that means the column limit is relative
+ to the right border.
+
+ * A careless invocation of "git send-email directory/" after editing
+ 0001-change.patch with an editor often ends up sending both
+ 0001-change.patch and its backup file, 0001-change.patch~, causing
+ embarrassment and a minor confusion. Detect such an input and
+ offer to skip the backup files when sending the patches out.
+ (merge 531220b jc/send-email-skip-backup later to maint).
+
+ * "git submodule update" that drives many "git clone" could
+ eventually hit flaky servers/network conditions on one of the
+ submodules; the command learned to retry the attempt.
+
+ * The output coloring scheme learned two new attributes, italic and
+ strike, in addition to existing bold, reverse, etc.
+
+ * "git log" learns log.showSignature configuration variable, and a
+ command line option "--no-show-signature" to countermand it.
+ (merge fce04c3 mj/log-show-signature-conf later to maint).
+
+ * More markings of messages for i18n, with updates to various tests
+ to pass GETTEXT_POISON tests.
+
+ * "git archive" learned to handle files that are larger than 8GB and
+ commits far in the future than expressible by the traditional US-TAR
+ format.
+ (merge 560b0e8 jk/big-and-future-archive-tar later to maint).
+
+
+ * A new configuration variable core.sshCommand has been added to
+ specify what value for GIT_SSH_COMMAND to use per repository.
+
+ * "git worktree prune" protected worktrees that are marked as
+ "locked" by creating a file in a known location. "git worktree"
+ command learned a dedicated command pair to create and remove such
+ a file, so that the users do not have to do this with editor.
+
+ * A handful of "git svn" updates.
+
+ * "git push" learned to accept and pass extra options to the
+ receiving end so that hooks can read and react to them.
+
+ * "git status" learned to suggest "merge --abort" during a conflicted
+ merge, just like it already suggests "rebase --abort" during a
+ conflicted rebase.
+
+ * "git jump" script (in contrib/) has been updated a bit.
+ (merge a91e692 jk/git-jump later to maint).
+
+ * "git push" and "git clone" learned to give better progress meters
+ to the end user who is waiting on the terminal.
+
+ * An entry "git log --decorate" for the tip of the current branch is
+ shown as "HEAD -> name" (where "name" is the name of the branch);
+ the arrow is now painted in the same color as "HEAD", not in the
+ color for commits.
+
+ * "git format-patch" learned format.from configuration variable to
+ specify the default settings for its "--from" option.
+
+ * "git am -3" calls "git merge-recursive" when it needs to fall back
+ to a three-way merge; this call has been turned into an internal
+ subroutine call instead of spawning a separate subprocess.
+
+ * The command line completion scripts (in contrib/) now knows about
+ "git branch --delete/--move [--remote]".
+ (merge 2703c22 vs/completion-branch-fully-spelled-d-m-r later to maint).
+
+ * "git rev-parse --git-path hooks/<hook>" learned to take
+ core.hooksPath configuration variable (introduced during 2.9 cycle)
+ into account.
+ (merge 9445b49 ab/hooks later to maint).
+
+ * "git log --show-signature" and other commands that display the
+ verification status of PGP signature now shows the longer key-id,
+ as 32-bit key-id is so last century.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git fast-import" learned the same performance trick to avoid
+ creating too small a packfile as "git fetch" and "git push" have,
+ using *.unpackLimit configuration.
+
+ * When "git daemon" is run without --[init-]timeout specified, a
+ connection from a client that silently goes offline can hang around
+ for a long time, wasting resources. The socket-level KEEPALIVE has
+ been enabled to allow the OS to notice such failed connections.
+
+ * "git upload-pack" command has been updated to use the parse-options
+ API.
+
+ * The "git apply" standalone program is being libified; the first
+ step to move many state variables into a structure that can be
+ explicitly (re)initialized to make the machinery callable more
+ than once has been merged.
+
+ * HTTP transport gained an option to produce more detailed debugging
+ trace.
+ (merge 73e57aa ep/http-curl-trace later to maint).
+
+ * Instead of taking advantage of the fact that a struct string_list
+ that is allocated with all NULs happens to be the INIT_NODUP kind,
+ the users of string_list structures are taught to initialize them
+ explicitly as such, to document their behaviour better.
+ (merge 2721ce2 jk/string-list-static-init later to maint).
+
+ * HTTPd tests learned to show the server error log to help diagnosing
+ a failing tests.
+ (merge 44f243d nd/test-lib-httpd-show-error-log-in-verbose later to maint).
+
+ * The ownership rule for the piece of memory that hold references to
+ be fetched in "git fetch" was screwy, which has been cleaned up.
+
+ * "git bisect" makes an internal call to "git diff-tree" when
+ bisection finds the culprit, but this call did not initialize the
+ data structure to pass to the diff-tree API correctly.
+
+ * Further preparatory clean-up for "worktree" feature continues.
+ (merge 0409e0b nd/worktree-cleanup-post-head-protection later to maint).
+
+ * Formats of the various data (and how to validate them) where we use
+ GPG signature have been documented.
+
+ * A new run-command API function pipe_command() is introduced to
+ sanely feed data to the standard input while capturing data from
+ the standard output and the standard error of an external process,
+ which is cumbersome to hand-roll correctly without deadlocking.
+
+ * The codepath to sign data in a prepared buffer with GPG has been
+ updated to use this API to read from the status-fd to check for
+ errors (instead of relying on GPG's exit status).
+ (merge efee955 jk/gpg-interface-cleanup later to maint).
+
+ * Allow t/perf framework to use the features from the most recent
+ version of Git even when testing an older installed version.
+
+ * The commands in the "log/diff" family have had an FILE* pointer in the
+ data structure they pass around for a long time, but some codepaths
+ used to always write to the standard output. As a preparatory step
+ to make "git format-patch" available to the internal callers, these
+ codepaths have been updated to consistently write into that FILE*
+ instead.
+
+ * Conversion from unsigned char sha1[20] to struct object_id
+ continues.
+
+ * Improve the look of the way "git fetch" reports what happened to
+ each ref that was fetched.
+
+ * The .c/.h sources are marked as such in our .gitattributes file so
+ that "git diff -W" and friends would work better.
+
+ * Code clean-up to avoid using a variable string that compilers may
+ feel untrustable as printf-style format given to write_file()
+ helper function.
+
+ * "git p4" used a location outside $GIT_DIR/refs/ to place its
+ temporary branches, which has been moved to refs/git-p4-tmp/.
+
+ * Existing autoconf generated test for the need to link with pthread
+ library did not check all the functions from pthread libraries;
+ recent FreeBSD has some functions in libc but not others, and we
+ mistakenly thought linking with libc is enough when it is not.
+
+ * When "git fsck" reports a broken link (e.g. a tree object contains
+ a blob that does not exist), both containing object and the object
+ that is referred to were reported with their 40-hex object names.
+ The command learned the "--name-objects" option to show the path to
+ the containing object from existing refs (e.g. "HEAD~24^2:file.txt").
+
+ * Allow http daemon tests in Travis CI tests.
+
+ * Makefile assumed that -lrt is always available on platforms that
+ want to use clock_gettime() and CLOCK_MONOTONIC, which is not a
+ case for recent Mac OS X. The necessary symbols are often found in
+ libc on many modern systems and having -lrt on the command line, as
+ long as the library exists, had no effect, but when the platform
+ removes librt.a that is a different matter--having -lrt will break
+ the linkage.
+
+ This change could be seen as a regression for those who do need to
+ specify -lrt, as they now specifically ask for NEEDS_LIBRT when
+ building. Hopefully they are in the minority these days.
+
+ * Further preparatory work on the refs API before the pluggable
+ backend series can land.
+
+ * Error handling in the codepaths that updates refs has been
+ improved.
+
+ * The API to iterate over all the refs (i.e. for_each_ref(), etc.)
+ has been revamped.
+
+ * The handling of the "text=auto" attribute has been corrected.
+ $ echo "* text=auto eol=crlf" >.gitattributes
+ used to have the same effect as
+ $ echo "* text eol=crlf" >.gitattributes
+ i.e. declaring all files are text (ignoring "auto"). The
+ combination has been fixed to be equivalent to doing
+ $ git config core.autocrlf true
+
+ * Documentation has been updated to show better example usage
+ of the updated "text=auto" attribute.
+
+ * A few tests that specifically target "git rebase -i" have been
+ added.
+
+ * Dumb http transport on the client side has been optimized.
+ (merge ecba195 ew/http-walker later to maint).
+
+ * Users of the parse_options_concat() API function need to allocate
+ extra slots in advance and fill them with OPT_END() when they want
+ to decide the set of supported options dynamically, which makes the
+ code error-prone and hard to read. This has been corrected by tweaking
+ the API to allocate and return a new copy of "struct option" array.
+
+ * "git fetch" exchanges batched have/ack messages between the sender
+ and the receiver, initially doubling every time and then falling
+ back to enlarge the window size linearly. The "smart http"
+ transport, being an half-duplex protocol, outgrows the preset limit
+ too quickly and becomes inefficient when interacting with a large
+ repository. The internal mechanism learned to grow the window size
+ more aggressively when working with the "smart http" transport.
+
+ * Tests for "git svn" have been taught to reuse the lib-httpd test
+ infrastructure when testing the subversion integration that
+ interacts with subversion repositories served over the http://
+ protocol.
+ (merge a8a5d25 ew/git-svn-http-tests later to maint).
+
+ * "git pack-objects" has a few options that tell it not to pack
+ objects found in certain packfiles, which require it to scan .idx
+ files of all available packs. The codepaths involved in these
+ operations have been optimized for a common case of not having any
+ non-local pack and/or any .kept pack.
+
+ * The t3700 test about "add --chmod=-x" have been made a bit more
+ robust and generally cleaned up.
+ (merge 766cdc4 ib/t3700-add-chmod-x-updates later to maint).
+
+ * The build procedure learned PAGER_ENV knob that lists what default
+ environment variable settings to export for popular pagers. This
+ mechanism is used to tweak the default settings to MORE on FreeBSD.
+ (merge 995bc22 ew/build-time-pager-tweaks later to maint).
+
+ * The http-backend (the server-side component of smart-http
+ transport) used to trickle the HTTP header one at a time. Now
+ these write(2)s are batched.
+ (merge b36045c ew/http-backend-batch-headers later to maint).
+
+ * When "git rebase" tries to compare set of changes on the updated
+ upstream and our own branch, it computes patch-id for all of these
+ changes and attempts to find matches. This has been optimized by
+ lazily computing the full patch-id (which is expensive) to be
+ compared only for changes that touch the same set of paths.
+ (merge ba67504 kw/patch-ids-optim later to maint).
+
+ * A handful of tests that were broken under gettext-poison build have
+ been fixed.
+
+ * The recent i18n patch we added during this cycle did a bit too much
+ refactoring of the messages to avoid word-legos; the repetition has
+ been reduced to help translators.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.9
+----------------
+
+Unless otherwise noted, all the fixes since v2.8 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * The commands in `git log` family take %C(auto) in a custom format
+ string. This unconditionally turned the color on, ignoring
+ --no-color or with --color=auto when the output is not connected to
+ a tty; this was corrected to make the format truly behave as
+ "auto".
+
+ * "git rev-list --count" whose walk-length is limited with "-n"
+ option did not work well with the counting optimized to look at the
+ bitmap index.
+
+ * "git show -W" (extend hunks to cover the entire function, delimited
+ by lines that match the "funcname" pattern) used to show the entire
+ file when a change added an entire function at the end of the file,
+ which has been fixed.
+
+ * The documentation set has been updated so that literal commands,
+ configuration variables and environment variables are consistently
+ typeset in fixed-width font and bold in manpages.
+
+ * "git svn propset" subcommand that was added in 2.3 days is
+ documented now.
+
+ * The documentation tries to consistently spell "GPG"; when
+ referring to the specific program name, "gpg" is used.
+
+ * "git reflog" stopped upon seeing an entry that denotes a branch
+ creation event (aka "unborn"), which made it appear as if the
+ reflog was truncated.
+
+ * The git-prompt scriptlet (in contrib/) was not friendly with those
+ who uses "set -u", which has been fixed.
+
+ * compat/regex code did not cleanly compile.
+
+ * A codepath that used alloca(3) to place an unbounded amount of data
+ on the stack has been updated to avoid doing so.
+
+ * "git update-index --add --chmod=+x file" may be usable as an escape
+ hatch, but not a friendly thing to force for people who do need to
+ use it regularly. "git add --chmod=+x file" can be used instead.
+
+ * Build improvements for gnome-keyring (in contrib/)
+
+ * "git status" used to say "working directory" when it meant "working
+ tree".
+
+ * Comments about misbehaving FreeBSD shells have been clarified with
+ the version number (9.x and before are broken, newer ones are OK).
+
+ * "git cherry-pick A" worked on an unborn branch, but "git
+ cherry-pick A..B" didn't.
+
+ * Fix an unintended regression in v2.9 that breaks "clone --depth"
+ that recurses down to submodules by forcing the submodules to also
+ be cloned shallowly, which many server instances that host upstream
+ of the submodules are not prepared for.
+
+ * Fix unnecessarily waste in the idiomatic use of ': ${VAR=default}'
+ to set the default value, without enclosing it in double quotes.
+
+ * Some platform-specific code had non-ANSI strict declarations of C
+ functions that do not take any parameters, which has been
+ corrected.
+
+ * The internal code used to show local timezone offset is not
+ prepared to handle timestamps beyond year 2100, and gave a
+ bogus offset value to the caller. Use a more benign looking
+ +0000 instead and let "git log" going in such a case, instead
+ of aborting.
+
+ * One among four invocations of readlink(1) in our test suite has
+ been rewritten so that the test can run on systems without the
+ command (others are in valgrind test framework and t9802).
+
+ * t/perf needs /usr/bin/time with GNU extension; the invocation of it
+ is updated to "gtime" on Darwin.
+
+ * A bug, which caused "git p4" while running under verbose mode to
+ report paths that are omitted due to branch prefix incorrectly, has
+ been fixed; the command said "Ignoring file outside of prefix" for
+ paths that are _inside_.
+
+ * The top level documentation "git help git" still pointed at the
+ documentation set hosted at now-defunct google-code repository.
+ Update it to point to https://git.github.io/htmldocs/git.html
+ instead.
+
+ * A helper function that takes the contents of a commit object and
+ finds its subject line did not ignore leading blank lines, as is
+ commonly done by other codepaths. Make it ignore leading blank
+ lines to match.
+
+ * For a long time, we carried an in-code comment that said our
+ colored output would work only when we use fprintf/fputs on
+ Windows, which no longer is the case for the past few years.
+
+ * "gc.autoPackLimit" when set to 1 should not trigger a repacking
+ when there is only one pack, but the code counted poorly and did
+ so.
+
+ * Add a test to specify the desired behaviour that currently is not
+ available in "git rebase -Xsubtree=...".
+
+ * More mark-up updates to typeset strings that are expected to
+ literally typed by the end user in fixed-width font.
+
+ * "git commit --amend --allow-empty-message -S" for a commit without
+ any message body could have misidentified where the header of the
+ commit object ends.
+
+ * "git rebase -i --autostash" did not restore the auto-stashed change
+ when the operation was aborted.
+
+ * Git does not know what the contents in the index should be for a
+ path added with "git add -N" yet, so "git grep --cached" should not
+ show hits (or show lack of hits, with -L) in such a path, but that
+ logic does not apply to "git grep", i.e. searching in the working
+ tree files. But we did so by mistake, which has been corrected.
+
+ * "git blame -M" missed a single line that was moved within the file.
+
+ * Fix recently introduced codepaths that are involved in parallel
+ submodule operations, which gave up on reading too early, and
+ could have wasted CPU while attempting to write under a corner
+ case condition.
+
+ * "git grep -i" has been taught to fold case in non-ascii locales
+ correctly.
+
+ * A test that unconditionally used "mktemp" learned that the command
+ is not necessarily available everywhere.
+
+ * There are certain house-keeping tasks that need to be performed at
+ the very beginning of any Git program, and programs that are not
+ built-in commands had to do them exactly the same way as "git"
+ potty does. It was easy to make mistakes in one-off standalone
+ programs (like test helpers). A common "main()" function that
+ calls cmd_main() of individual program has been introduced to
+ make it harder to make mistakes.
+ (merge de61ceb jk/common-main later to maint).
+
+ * The test framework learned a new helper test_match_signal to
+ check an exit code from getting killed by an expected signal.
+
+ * General code clean-up around a helper function to write a
+ single-liner to a file.
+ (merge 7eb6e10 jk/write-file later to maint).
+
+ * One part of "git am" had an oddball helper function that called
+ stuff from outside "his" as opposed to calling what we have "ours",
+ which was not gender-neutral and also inconsistent with the rest of
+ the system where outside stuff is usuall called "theirs" in
+ contrast to "ours".
+
+ * "git blame file" allowed the lineage of lines in the uncommitted,
+ unadded contents of "file" to be inspected, but it refused when
+ "file" did not appear in the current commit. When "file" was
+ created by renaming an existing file (but the change has not been
+ committed), this restriction was unnecessarily tight.
+
+ * "git add -N dir/file && git write-tree" produced an incorrect tree
+ when there are other paths in the same directory that sorts after
+ "file".
+
+ * "git fetch http://user:pass@host/repo..." scrubbed the userinfo
+ part, but "git push" didn't.
+
+ * "git merge" with renormalization did not work well with
+ merge-recursive, due to "safer crlf" conversion kicking in when it
+ shouldn't.
+ (merge 1335d76 jc/renormalize-merge-kill-safer-crlf later to maint).
+
+ * The use of strbuf in "git rm" to build filename to remove was a bit
+ suboptimal, which has been fixed.
+
+ * An age old bug that caused "git diff --ignore-space-at-eol"
+ misbehave has been fixed.
+
+ * "git notes merge" had a code to see if a path exists (and fails if
+ it does) and then open the path for writing (when it doesn't).
+ Replace it with open with O_EXCL.
+
+ * "git pack-objects" and "git index-pack" mostly operate with off_t
+ when talking about the offset of objects in a packfile, but there
+ were a handful of places that used "unsigned long" to hold that
+ value, leading to an unintended truncation.
+
+ * Recent update to "git daemon" tries to enable the socket-level
+ KEEPALIVE, but when it is spawned via inetd, the standard input
+ file descriptor may not necessarily be connected to a socket.
+ Suppress an ENOTSOCK error from setsockopt().
+
+ * Recent FreeBSD stopped making perl available at /usr/bin/perl;
+ switch the default the built-in path to /usr/local/bin/perl on not
+ too ancient FreeBSD releases.
+
+ * "git commit --help" said "--no-verify" is only about skipping the
+ pre-commit hook, and failed to say that it also skipped the
+ commit-msg hook.
+
+ * "git merge" in Git v2.9 was taught to forbid merging an unrelated
+ lines of history by default, but that is exactly the kind of thing
+ the "--rejoin" mode of "git subtree" (in contrib/) wants to do.
+ "git subtree" has been taught to use the "--allow-unrelated-histories"
+ option to override the default.
+
+ * The build procedure for "git persistent-https" helper (in contrib/)
+ has been updated so that it can be built with more recent versions
+ of Go.
+
+ * There is an optimization used in "git diff $treeA $treeB" to borrow
+ an already checked-out copy in the working tree when it is known to
+ be the same as the blob being compared, expecting that open/mmap of
+ such a file is faster than reading it from the object store, which
+ involves inflating and applying delta. This however kicked in even
+ when the checked-out copy needs to go through the convert-to-git
+ conversion (including the clean filter), which defeats the whole
+ point of the optimization. The optimization has been disabled when
+ the conversion is necessary.
+
+ * "git -c grep.patternType=extended log --basic-regexp" misbehaved
+ because the internal API to access the grep machinery was not
+ designed well.
+
+ * Windows port was failing some tests in t4130, due to the lack of
+ inum in the returned values by its lstat(2) emulation.
+
+ * The reflog output format is documented better, and a new format
+ --date=unix to report the seconds-since-epoch (without timezone)
+ has been added.
+ (merge 442f6fd jk/reflog-date later to maint).
+
+ * "git difftool <paths>..." started in a subdirectory failed to
+ interpret the paths relative to that directory, which has been
+ fixed.
+
+ * The characters in the label shown for tags/refs for commits in
+ "gitweb" output are now properly escaped for proper HTML output.
+
+ * FreeBSD can lie when asked mtime of a directory, which made the
+ untracked cache code to fall back to a slow-path, which in turn
+ caused tests in t7063 to fail because it wanted to verify the
+ behaviour of the fast-path.
+
+ * Squelch compiler warnings for nedmalloc (in compat/) library.
+
+ * A small memory leak in the command line parsing of "git blame"
+ has been plugged.
+
+ * The API documentation for hashmap was unclear if hashmap_entry
+ can be safely discarded without any other consideration. State
+ that it is safe to do so.
+
+ * Not-so-recent rewrite of "git am" that started making internal
+ calls into the commit machinery had an unintended regression, in
+ that no matter how many seconds it took to apply many patches, the
+ resulting committer timestamp for the resulting commits were all
+ the same.
+
+ * "git push --force-with-lease" already had enough logic to allow
+ ensuring that such a push results in creation of a ref (i.e. the
+ receiving end did not have another push from sideways that would be
+ discarded by our force-pushing), but didn't expose this possibility
+ to the users. It does so now.
+ (merge 9eed4f3 jk/push-force-with-lease-creation later to maint).
+
+ * The mechanism to limit the pack window memory size, when packing is
+ done using multiple threads (which is the default), is per-thread,
+ but this was not documented clearly.
+ (merge 954176c ms/document-pack-window-memory-is-per-thread later to maint).
+
+ * "import-tars" fast-import script (in contrib/) used to ignore a
+ hardlink target and replaced it with an empty file, which has been
+ corrected to record the same blob as the other file the hardlink is
+ shared with.
+ (merge 04e0869 js/import-tars-hardlinks later to maint).
+
+ * "git mv dir non-existing-dir/" did not work in some environments
+ the same way as existing mainstream platforms. The code now moves
+ "dir" to "non-existing-dir", without relying on rename("A", "B/")
+ that strips the trailing slash of '/'.
+ (merge 189d035 js/mv-dir-to-new-directory later to maint).
+
+ * The "t/" hierarchy is prone to get an unusual pathname; "make test"
+ has been taught to make sure they do not contain paths that cannot
+ be checked out on Windows (and the mechanism can be reusable to
+ catch pathnames that are not portable to other platforms as need
+ arises).
+ (merge c2cafd3 js/test-lint-pathname later to maint).
+
+ * When "git merge-recursive" works on history with many criss-cross
+ merges in "verbose" mode, the names the command assigns to the
+ virtual merge bases could have overwritten each other by unintended
+ reuse of the same piece of memory.
+ (merge 5447a76 rs/pull-signed-tag later to maint).
+
+ * "git checkout --detach <branch>" used to give the same advice
+ message as that is issued when "git checkout <tag>" (or anything
+ that is not a branch name) is given, but asking with "--detach" is
+ an explicit enough sign that the user knows what is going on. The
+ advice message has been squelched in this case.
+ (merge 779b88a sb/checkout-explit-detach-no-advice later to maint).
+
+ * "git difftool" by default ignores the error exit from the backend
+ commands it spawns, because often they signal that they found
+ differences by exiting with a non-zero status code just like "diff"
+ does; the exit status codes 126 and above however are special in
+ that they are used to signal that the command is not executable,
+ does not exist, or killed by a signal. "git difftool" has been
+ taught to notice these exit status codes.
+ (merge 45a4f5d jk/difftool-command-not-found later to maint).
+
+ * On Windows, help.browser configuration variable used to be ignored,
+ which has been corrected.
+ (merge 6db5967 js/no-html-bypass-on-windows later to maint).
+
+ * The "git -c var[=val] cmd" facility to append a configuration
+ variable definition at the end of the search order was described in
+ git(1) manual page, but not in git-config(1), which was more likely
+ place for people to look for when they ask "can I make a one-shot
+ override, and if so how?"
+ (merge ae1f709 dg/document-git-c-in-git-config-doc later to maint).
+
+ * The tempfile (hence its user lockfile) API lets the caller to open
+ a file descriptor to a temporary file, write into it and then
+ finalize it by first closing the filehandle and then either
+ removing or renaming the temporary file. When the process spawns a
+ subprocess after obtaining the file descriptor, and if the
+ subprocess has not exited when the attempt to remove or rename is
+ made, the last step fails on Windows, because the subprocess has
+ the file descriptor still open. Open tempfile with O_CLOEXEC flag
+ to avoid this (on Windows, this is mapped to O_NOINHERIT).
+ (merge 05d1ed6 bw/mingw-avoid-inheriting-fd-to-lockfile later to maint).
+
+ * Correct an age-old calco (is that a typo-like word for calc)
+ in the documentation.
+ (merge 7841c48 ls/packet-line-protocol-doc-fix later to maint).
+
+ * Other minor clean-ups and documentation updates
+ (merge 02a8cfa rs/merge-add-strategies-simplification later to maint).
+ (merge af4941d rs/merge-recursive-string-list-init later to maint).
+ (merge 1eb47f1 rs/use-strbuf-add-unique-abbrev later to maint).
+ (merge ddd0bfa jk/tighten-alloc later to maint).
+ (merge ecf30b2 rs/mailinfo-lib later to maint).
+ (merge 0eb75ce sg/reflog-past-root later to maint).
+ (merge 4369523 hv/doc-commit-reference-style later to maint).
diff --git a/Documentation/RelNotes/2.10.1.txt b/Documentation/RelNotes/2.10.1.txt
new file mode 100644
index 0000000..70462f7
--- /dev/null
+++ b/Documentation/RelNotes/2.10.1.txt
@@ -0,0 +1,131 @@
+Git v2.10.1 Release Notes
+=========================
+
+Fixes since v2.10
+-----------------
+
+ * Clarify various ways to specify the "revision ranges" in the
+ documentation.
+
+ * "diff-highlight" script (in contrib/) learned to work better with
+ "git log -p --graph" output.
+
+ * The test framework left the number of tests and success/failure
+ count in the t/test-results directory, keyed by the name of the
+ test script plus the process ID. The latter however turned out not
+ to serve any useful purpose. The process ID part of the filename
+ has been removed.
+
+ * Having a submodule whose ".git" repository is somehow corrupt
+ caused a few commands that recurse into submodules loop forever.
+
+ * "git symbolic-ref -d HEAD" happily removes the symbolic ref, but
+ the resulting repository becomes an invalid one. Teach the command
+ to forbid removal of HEAD.
+
+ * A test spawned a short-lived background process, which sometimes
+ prevented the test directory from getting removed at the end of the
+ script on some platforms.
+
+ * Update a few tests that used to use GIT_CURL_VERBOSE to use the
+ newer GIT_TRACE_CURL.
+
+ * Update Japanese translation for "git-gui".
+
+ * "git fetch http::/site/path" did not die correctly and segfaulted
+ instead.
+
+ * "git commit-tree" stopped reading commit.gpgsign configuration
+ variable that was meant for Porcelain "git commit" in Git 2.9; we
+ forgot to update "git gui" to look at the configuration to match
+ this change.
+
+ * "git log --cherry-pick" used to include merge commits as candidates
+ to be matched up with other commits, resulting a lot of wasted time.
+ The patch-id generation logic has been updated to ignore merges to
+ avoid the wastage.
+
+ * The http transport (with curl-multi option, which is the default
+ these days) failed to remove curl-easy handle from a curlm session,
+ which led to unnecessary API failures.
+
+ * "git diff -W" output needs to extend the context backward to
+ include the header line of the current function and also forward to
+ include the body of the entire current function up to the header
+ line of the next one. This process may have to merge to adjacent
+ hunks, but the code forgot to do so in some cases.
+
+ * Performance tests done via "t/perf" did not use the same set of
+ build configuration if the user relied on autoconf generated
+ configuration.
+
+ * "git format-patch --base=..." feature that was recently added
+ showed the base commit information after "-- " e-mail signature
+ line, which turned out to be inconvenient. The base information
+ has been moved above the signature line.
+
+ * Even when "git pull --rebase=preserve" (and the underlying "git
+ rebase --preserve") can complete without creating any new commit
+ (i.e. fast-forwards), it still insisted on having a usable ident
+ information (read: user.email is set correctly), which was less
+ than nice. As the underlying commands used inside "git rebase"
+ would fail with a more meaningful error message and advice text
+ when the bogus ident matters, this extra check was removed.
+
+ * "git gc --aggressive" used to limit the delta-chain length to 250,
+ which is way too deep for gaining additional space savings and is
+ detrimental for runtime performance. The limit has been reduced to
+ 50.
+
+ * Documentation for individual configuration variables to control use
+ of color (like `color.grep`) said that their default value is
+ 'false', instead of saying their default is taken from `color.ui`.
+ When we updated the default value for color.ui from 'false' to
+ 'auto' quite a while ago, all of them broke. This has been
+ corrected.
+
+ * A shell script example in check-ref-format documentation has been
+ fixed.
+
+ * "git checkout <word>" does not follow the usual disambiguation
+ rules when the <word> can be both a rev and a path, to allow
+ checking out a branch 'foo' in a project that happens to have a
+ file 'foo' in the working tree without having to disambiguate.
+ This was poorly documented and the check was incorrect when the
+ command was run from a subdirectory.
+
+ * Some codepaths in "git diff" used regexec(3) on a buffer that was
+ mmap(2)ed, which may not have a terminating NUL, leading to a read
+ beyond the end of the mapped region. This was fixed by introducing
+ a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND
+ extension.
+
+ * The procedure to build Git on Mac OS X for Travis CI hardcoded the
+ internal directory structure we assumed HomeBrew uses, which was a
+ no-no. The procedure has been updated to ask HomeBrew things we
+ need to know to fix this.
+
+ * When "git rebase -i" is given a broken instruction, it told the
+ user to fix it with "--edit-todo", but didn't say what the step
+ after that was (i.e. "--continue").
+
+ * "git add --chmod=+x" added recently lacked documentation, which has
+ been corrected.
+
+ * "git add --chmod=+x <pathspec>" added recently only toggled the
+ executable bit for paths that are either new or modified. This has
+ been corrected to flip the executable bit for all paths that match
+ the given pathspec.
+
+ * "git pack-objects --include-tag" was taught that when we know that
+ we are sending an object C, we want a tag B that directly points at
+ C but also a tag A that points at the tag B. We used to miss the
+ intermediate tag B in some cases.
+
+ * Documentation around tools to import from CVS was fairly outdated.
+
+ * In the codepath that comes up with the hostname to be used in an
+ e-mail when the user didn't tell us, we looked at ai_canonname
+ field in struct addrinfo without making sure it is not NULL first.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.11.0.txt b/Documentation/RelNotes/2.11.0.txt
new file mode 100644
index 0000000..4499268
--- /dev/null
+++ b/Documentation/RelNotes/2.11.0.txt
@@ -0,0 +1,372 @@
+Git 2.11 Release Notes
+======================
+
+Updates since v2.10
+-------------------
+
+UI, Workflows & Features
+
+ * "git format-patch --cover-letter HEAD^" to format a single patch
+ with a separate cover letter now numbers the output as [PATCH 0/1]
+ and [PATCH 1/1] by default.
+
+ * An incoming "git push" that attempts to push too many bytes can now
+ be rejected by setting a new configuration variable at the receiving
+ end.
+
+ * "git nosuchcommand --help" said "No manual entry for gitnosuchcommand",
+ which was not intuitive, given that "git nosuchcommand" said "git:
+ 'nosuchcommand' is not a git command".
+
+ * "git clone --resurse-submodules --reference $path $URL" is a way to
+ reduce network transfer cost by borrowing objects in an existing
+ $path repository when cloning the superproject from $URL; it
+ learned to also peek into $path for presense of corresponding
+ repositories of submodules and borrow objects from there when able.
+
+ * The "git diff --submodule={short,log}" mechanism has been enhanced
+ to allow "--submodule=diff" to show the patch between the submodule
+ commits bound to the superproject.
+
+ * Even though "git hash-objects", which is a tool to take an
+ on-filesystem data stream and put it into the Git object store,
+ allowed to perform the "outside-world-to-Git" conversions (e.g.
+ end-of-line conversions and application of the clean-filter), and
+ it had the feature on by default from very early days, its reverse
+ operation "git cat-file", which takes an object from the Git object
+ store and externalize for the consumption by the outside world,
+ lacked an equivalent mechanism to run the "Git-to-outside-world"
+ conversion. The command learned the "--filters" option to do so.
+
+ * Output from "git diff" can be made easier to read by selecting
+ which lines are common and which lines are added/deleted
+ intelligently when the lines before and after the changed section
+ are the same. A command line option is added to help with the
+ experiment to find a good heuristics.
+
+ * In some projects, it is common to use "[RFC PATCH]" as the subject
+ prefix for a patch meant for discussion rather than application. A
+ new option "--rfc" was a short-hand for "--subject-prefix=RFC PATCH"
+ to help the participants of such projects.
+
+ * "git add --chmod=+x <pathspec>" added recently only toggled the
+ executable bit for paths that are either new or modified. This has
+ been corrected to flip the executable bit for all paths that match
+ the given pathspec.
+
+ * When "git format-patch --stdout" output is placed as an in-body
+ header and it uses the RFC2822 header folding, "git am" failed to
+ put the header line back into a single logical line. The
+ underlying "git mailinfo" was taught to handle this properly.
+
+ * "gitweb" can spawn "highlight" to show blob contents with
+ (programming) language-specific syntax highlighting, but only
+ when the language is known. "highlight" can however be told
+ to make the guess itself by giving it "--force" option, which
+ has been enabled.
+
+ * "git gui" l10n to Portuguese.
+
+ * When given an abbreviated object name that is not (or more
+ realistically, "no longer") unique, we gave a fatal error
+ "ambiguous argument". This error is now accompanied by hints that
+ lists the objects that begins with the given prefix. During the
+ course of development of this new feature, numerous minor bugs were
+ uncovered and corrected, the most notable one of which is that we
+ gave "short SHA1 xxxx is ambiguous." twice without good reason.
+
+ * "git log rev^..rev" is an often-used revision range specification
+ to show what was done on a side branch merged at rev. This has
+ gained a short-hand "rev^-1". In general "rev^-$n" is the same as
+ "^rev^$n rev", i.e. what has happened on other branches while the
+ history leading to nth parent was looking the other way.
+
+ * In recent versions of cURL, GSSAPI credential delegation is
+ disabled by default due to CVE-2011-2192; introduce a configuration
+ to selectively allow enabling this.
+ (merge 26a7b23429 ps/http-gssapi-cred-delegation later to maint).
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The delta-base-cache mechanism has been a key to the performance in
+ a repository with a tightly packed packfile, but it did not scale
+ well even with a larger value of core.deltaBaseCacheLimit.
+
+ * Enhance "git status --porcelain" output by collecting more data on
+ the state of the index and the working tree files, which may
+ further be used to teach git-prompt (in contrib/) to make fewer
+ calls to git.
+
+ * Extract a small helper out of the function that reads the authors
+ script file "git am" internally uses.
+ (merge a77598e jc/am-read-author-file later to maint).
+
+ * Lifts calls to exit(2) and die() higher in the callchain in
+ sequencer.c files so that more helper functions in it can be used
+ by callers that want to handle error conditions themselves.
+
+ * "git am" has been taught to make an internal call to "git apply"'s
+ innards without spawning the latter as a separate process.
+
+ * The ref-store abstraction was introduced to the refs API so that we
+ can plug in different backends to store references.
+
+ * The "unsigned char sha1[20]" to "struct object_id" conversion
+ continues. Notable changes in this round includes that ce->sha1,
+ i.e. the object name recorded in the cache_entry, turns into an
+ object_id.
+
+ * JGit can show a fake ref "capabilities^{}" to "git fetch" when it
+ does not advertise any refs, but "git fetch" was not prepared to
+ see such an advertisement. When the other side disconnects without
+ giving any ref advertisement, we used to say "there may not be a
+ repository at that URL", but we may have seen other advertisement
+ like "shallow" and ".have" in which case we definitely know that a
+ repository is there. The code to detect this case has also been
+ updated.
+
+ * Some codepaths in "git pack-objects" were not ready to use an
+ existing pack bitmap; now they are and as the result they have
+ become faster.
+
+ * The codepath in "git fsck" to detect malformed tree objects has
+ been updated not to die but keep going after detecting them.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.10
+-----------------
+
+Unless otherwise noted, all the fixes since v2.9 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * Clarify various ways to specify the "revision ranges" in the
+ documentation.
+
+ * "diff-highlight" script (in contrib/) learned to work better with
+ "git log -p --graph" output.
+
+ * The test framework left the number of tests and success/failure
+ count in the t/test-results directory, keyed by the name of the
+ test script plus the process ID. The latter however turned out not
+ to serve any useful purpose. The process ID part of the filename
+ has been removed.
+
+ * Having a submodule whose ".git" repository is somehow corrupt
+ caused a few commands that recurse into submodules loop forever.
+
+ * "git symbolic-ref -d HEAD" happily removes the symbolic ref, but
+ the resulting repository becomes an invalid one. Teach the command
+ to forbid removal of HEAD.
+
+ * A test spawned a short-lived background process, which sometimes
+ prevented the test directory from getting removed at the end of the
+ script on some platforms.
+
+ * Update a few tests that used to use GIT_CURL_VERBOSE to use the
+ newer GIT_TRACE_CURL.
+
+ * "git pack-objects --include-tag" was taught that when we know that
+ we are sending an object C, we want a tag B that directly points at
+ C but also a tag A that points at the tag B. We used to miss the
+ intermediate tag B in some cases.
+ (merge b773dde jk/pack-tag-of-tag later to maint).
+
+ * Update Japanese translation for "git-gui".
+ (merge 02748bc sy/git-gui-i18n-ja later to maint).
+
+ * "git fetch http::/site/path" did not die correctly and segfaulted
+ instead.
+ (merge d63ed6e jk/fix-remote-curl-url-wo-proto later to maint).
+
+ * "git commit-tree" stopped reading commit.gpgsign configuration
+ variable that was meant for Porcelain "git commit" in Git 2.9; we
+ forgot to update "git gui" to look at the configuration to match
+ this change.
+ (merge f14a310 js/git-gui-commit-gpgsign later to maint).
+
+ * "git add --chmod=+x" added recently lacked documentation, which has
+ been corrected.
+ (merge 7ef7903 et/add-chmod-x later to maint).
+
+ * "git log --cherry-pick" used to include merge commits as candidates
+ to be matched up with other commits, resulting a lot of wasted time.
+ The patch-id generation logic has been updated to ignore merges to
+ avoid the wastage.
+ (merge 7c81040 jk/patch-ids-no-merges later to maint).
+
+ * The http transport (with curl-multi option, which is the default
+ these days) failed to remove curl-easy handle from a curlm session,
+ which led to unnecessary API failures.
+ (merge 2abc848 ew/http-do-not-forget-to-call-curl-multi-remove-handle later to maint).
+
+ * There were numerous corner cases in which the configuration files
+ are read and used or not read at all depending on the directory a
+ Git command was run, leading to inconsistent behaviour. The code
+ to set-up repository access at the beginning of a Git process has
+ been updated to fix them.
+ (merge 4d0efa1 jk/setup-sequence-update later to maint).
+
+ * "git diff -W" output needs to extend the context backward to
+ include the header line of the current function and also forward to
+ include the body of the entire current function up to the header
+ line of the next one. This process may have to merge to adjacent
+ hunks, but the code forgot to do so in some cases.
+ (merge 45d2f75 rs/xdiff-merge-overlapping-hunks-for-W-context later to maint).
+
+ * Performance tests done via "t/perf" did not use the same set of
+ build configuration if the user relied on autoconf generated
+ configuration.
+ (merge cd5c281 ks/perf-build-with-autoconf later to maint).
+
+ * "git format-patch --base=..." feature that was recently added
+ showed the base commit information after "-- " e-mail signature
+ line, which turned out to be inconvenient. The base information
+ has been moved above the signature line.
+ (merge 480871e jt/format-patch-base-info-above-sig later to maint).
+
+ * More i18n.
+ (merge 43073f8 va/i18n later to maint).
+
+ * Even when "git pull --rebase=preserve" (and the underlying "git
+ rebase --preserve") can complete without creating any new commit
+ (i.e. fast-forwards), it still insisted on having a usable ident
+ information (read: user.email is set correctly), which was less
+ than nice. As the underlying commands used inside "git rebase"
+ would fail with a more meaningful error message and advice text
+ when the bogus ident matters, this extra check was removed.
+ (merge 1e461c4 jk/rebase-i-drop-ident-check later to maint).
+
+ * "git gc --aggressive" used to limit the delta-chain length to 250,
+ which is way too deep for gaining additional space savings and is
+ detrimental for runtime performance. The limit has been reduced to
+ 50.
+ (merge 07e7dbf jk/reduce-gc-aggressive-depth later to maint).
+
+ * Documentation for individual configuration variables to control use
+ of color (like `color.grep`) said that their default value is
+ 'false', instead of saying their default is taken from `color.ui`.
+ When we updated the default value for color.ui from 'false' to
+ 'auto' quite a while ago, all of them broke. This has been
+ corrected.
+ (merge 14d16e2 mm/config-color-ui-default-to-auto later to maint).
+
+ * The pretty-format specifier "%C(auto)" used by the "log" family of
+ commands to enable coloring of the output is taught to also issue a
+ color-reset sequence to the output.
+ (merge c99ad27 rs/c-auto-resets-attributes later to maint).
+
+ * A shell script example in check-ref-format documentation has been
+ fixed.
+ (merge 92dece7 ep/doc-check-ref-format-example later to maint).
+
+ * "git checkout <word>" does not follow the usual disambiguation
+ rules when the <word> can be both a rev and a path, to allow
+ checking out a branch 'foo' in a project that happens to have a
+ file 'foo' in the working tree without having to disambiguate.
+ This was poorly documented and the check was incorrect when the
+ command was run from a subdirectory.
+ (merge b829b94 nd/checkout-disambiguation later to maint).
+
+ * Some codepaths in "git diff" used regexec(3) on a buffer that was
+ mmap(2)ed, which may not have a terminating NUL, leading to a read
+ beyond the end of the mapped region. This was fixed by introducing
+ a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND
+ extension.
+ (merge b7d36ff js/regexec-buf later to maint).
+
+ * The procedure to build Git on Mac OS X for Travis CI hardcoded the
+ internal directory structure we assumed HomeBrew uses, which was a
+ no-no. The procedure has been updated to ask HomeBrew things we
+ need to know to fix this.
+ (merge f86f49b ls/travis-homebrew-path-fix later to maint).
+
+ * When "git rebase -i" is given a broken instruction, it told the
+ user to fix it with "--edit-todo", but didn't say what the step
+ after that was (i.e. "--continue").
+ (merge 37875b4 rt/rebase-i-broken-insn-advise later to maint).
+
+ * Documentation around tools to import from CVS was fairly outdated.
+ (merge 106b672 jk/doc-cvs-update later to maint).
+
+ * "git clone --recurse-submodules" lost the progress eye-candy in
+ recent update, which has been corrected.
+
+ * A low-level function verify_packfile() was meant to show errors
+ that were detected without dying itself, but under some conditions
+ it didn't and died instead, which has been fixed.
+ (merge a9445d859e jk/verify-packfile-gently later to maint).
+
+ * When "git fetch" tries to find where the history of the repository
+ it runs in has diverged from what the other side has, it has a
+ mechanism to avoid digging too deep into irrelevant side branches.
+ This however did not work well over the "smart-http" transport due
+ to a design bug, which has been fixed.
+ (merge 06b3d386e0 jt/fetch-pack-in-vain-count-with-stateless later to maint).
+
+ * In the codepath that comes up with the hostname to be used in an
+ e-mail when the user didn't tell us, we looked at ai_canonname
+ field in struct addrinfo without making sure it is not NULL first.
+ (merge c375a7efa3 jk/ident-ai-canonname-could-be-null later to maint).
+
+ * "git worktree", even though it used the default_abbrev setting that
+ ought to be affected by core.abbrev configuration variable, ignored
+ the variable setting. The command has been taught to read the
+ default set of configuration variables to correct this.
+ (merge d49028e6e7 jc/worktree-config later to maint).
+
+ * "git init" tried to record core.worktree in the repository's
+ 'config' file when GIT_WORK_TREE environment variable was set and
+ it was different from where GIT_DIR appears as ".git" at its top,
+ but the logic was faulty when .git is a "gitdir:" file that points
+ at the real place, causing trouble in working trees that are
+ managed by "git worktree". This has been corrected.
+
+ * Codepaths that read from an on-disk loose object were too loose in
+ validating what they are reading is a proper object file and
+ sometimes read past the data they read from the disk, which has
+ been corrected. H/t to Gustavo Grieco for reporting.
+ (merge d21f842690 jc/verify-loose-object-header later to maint).
+
+ * The original command line syntax for "git merge", which was "git
+ merge <msg> HEAD <parent>...", has been deprecated for quite some
+ time, and "git gui" was the last in-tree user of the syntax. This
+ is finally fixed, so that we can move forward with the deprecation.
+ (merge ff65e796f0 rs/git-gui-use-modern-git-merge-syntax later to maint).
+
+ * An author name, that spelled a backslash-quoted double quote in the
+ human readable part "My \"double quoted\" name", was not unquoted
+ correctly while applying a patch from a piece of e-mail.
+ (merge f357e5de31 kd/mailinfo-quoted-string later to maint).
+
+ * Doc update to clarify what "log -3 --reverse" does.
+ (merge 04be69478f pb/rev-list-reverse-with-count later to maint).
+
+ * Almost everybody uses DEFAULT_ABBREV to refer to the default
+ setting for the abbreviation, but "git blame" peeked into
+ underlying variable bypassing the macro for no good reason.
+ (merge 5293284b4d jc/blame-abbrev later to maint).
+
+ * The "graph" API used in "git log --graph" miscounted the number of
+ output columns consumed so far when drawing a padding line, which
+ has been fixed; this did not affect any existing code as nobody
+ tried to write anything after the padding on such a line, though.
+ (merge 1647793524 jk/graph-padding-fix later to maint).
+
+ * The code that parses the format parameter of for-each-ref command
+ has seen a micro-optimization.
+ (merge e94ce1394e sg/ref-filter-parse-optim later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+ (merge e78d57e bw/pathspec-remove-unused-extern-decl later to maint).
+ (merge ce25e4c rs/checkout-some-states-are-const later to maint).
+ (merge a8342a4 rs/strbuf-remove-fix later to maint).
+ (merge b56aa5b rs/unpack-trees-reduce-file-scope-global later to maint).
+ (merge 5efc60c mr/vcs-svn-printf-ulong later to maint).
+ (merge a22ae75 rs/cocci later to maint).
+ (merge 45ccef87b3 rs/copy-array later to maint).
+ (merge 8201688ecd dt/mailinfo later to maint).
diff --git a/Documentation/RelNotes/2.3.10.txt b/Documentation/RelNotes/2.3.10.txt
index 9d425d8..20c2d2c 100644
--- a/Documentation/RelNotes/2.3.10.txt
+++ b/Documentation/RelNotes/2.3.10.txt
@@ -7,7 +7,7 @@ Fixes since v2.3.9
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
- our input files, for example. Cap the input size to soemwhere
+ our input files, for example. Cap the input size to somewhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
diff --git a/Documentation/RelNotes/2.4.10.txt b/Documentation/RelNotes/2.4.10.txt
index 8621199..702d8d4 100644
--- a/Documentation/RelNotes/2.4.10.txt
+++ b/Documentation/RelNotes/2.4.10.txt
@@ -7,7 +7,7 @@ Fixes since v2.4.9
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
- our input files, for example. Cap the input size to soemwhere
+ our input files, for example. Cap the input size to somewhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
diff --git a/Documentation/RelNotes/2.5.4.txt b/Documentation/RelNotes/2.5.4.txt
index a5e8477..b8a2f93 100644
--- a/Documentation/RelNotes/2.5.4.txt
+++ b/Documentation/RelNotes/2.5.4.txt
@@ -7,7 +7,7 @@ Fixes since v2.5.4
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
- our input files, for example. Cap the input size to soemwhere
+ our input files, for example. Cap the input size to somewhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
diff --git a/Documentation/RelNotes/2.6.1.txt b/Documentation/RelNotes/2.6.1.txt
index 1e51363..f37ea89 100644
--- a/Documentation/RelNotes/2.6.1.txt
+++ b/Documentation/RelNotes/2.6.1.txt
@@ -7,7 +7,7 @@ Fixes since v2.6
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
- our input files, for example. Cap the input size to soemwhere
+ our input files, for example. Cap the input size to somewhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
diff --git a/Documentation/RelNotes/2.9.4.txt b/Documentation/RelNotes/2.9.4.txt
new file mode 100644
index 0000000..01e8642
--- /dev/null
+++ b/Documentation/RelNotes/2.9.4.txt
@@ -0,0 +1,83 @@
+Git v2.9.4 Release Notes
+========================
+
+Fixes since v2.9.3
+------------------
+
+ * There are certain house-keeping tasks that need to be performed at
+ the very beginning of any Git program, and programs that are not
+ built-in commands had to do them exactly the same way as "git"
+ potty does. It was easy to make mistakes in one-off standalone
+ programs (like test helpers). A common "main()" function that
+ calls cmd_main() of individual program has been introduced to
+ make it harder to make mistakes.
+
+ * "git merge" with renormalization did not work well with
+ merge-recursive, due to "safer crlf" conversion kicking in when it
+ shouldn't.
+
+ * The reflog output format is documented better, and a new format
+ --date=unix to report the seconds-since-epoch (without timezone)
+ has been added.
+
+ * "git push --force-with-lease" already had enough logic to allow
+ ensuring that such a push results in creation of a ref (i.e. the
+ receiving end did not have another push from sideways that would be
+ discarded by our force-pushing), but didn't expose this possibility
+ to the users. It does so now.
+
+ * "import-tars" fast-import script (in contrib/) used to ignore a
+ hardlink target and replaced it with an empty file, which has been
+ corrected to record the same blob as the other file the hardlink is
+ shared with.
+
+ * "git mv dir non-existing-dir/" did not work in some environments
+ the same way as existing mainstream platforms. The code now moves
+ "dir" to "non-existing-dir", without relying on rename("A", "B/")
+ that strips the trailing slash of '/'.
+
+ * The "t/" hierarchy is prone to get an unusual pathname; "make test"
+ has been taught to make sure they do not contain paths that cannot
+ be checked out on Windows (and the mechanism can be reusable to
+ catch pathnames that are not portable to other platforms as need
+ arises).
+
+ * When "git merge-recursive" works on history with many criss-cross
+ merges in "verbose" mode, the names the command assigns to the
+ virtual merge bases could have overwritten each other by unintended
+ reuse of the same piece of memory.
+
+ * "git checkout --detach <branch>" used to give the same advice
+ message as that is issued when "git checkout <tag>" (or anything
+ that is not a branch name) is given, but asking with "--detach" is
+ an explicit enough sign that the user knows what is going on. The
+ advice message has been squelched in this case.
+
+ * "git difftool" by default ignores the error exit from the backend
+ commands it spawns, because often they signal that they found
+ differences by exiting with a non-zero status code just like "diff"
+ does; the exit status codes 126 and above however are special in
+ that they are used to signal that the command is not executable,
+ does not exist, or killed by a signal. "git difftool" has been
+ taught to notice these exit status codes.
+
+ * On Windows, help.browser configuration variable used to be ignored,
+ which has been corrected.
+
+ * The "git -c var[=val] cmd" facility to append a configuration
+ variable definition at the end of the search order was described in
+ git(1) manual page, but not in git-config(1), which was more likely
+ place for people to look for when they ask "can I make a one-shot
+ override, and if so how?"
+
+ * The tempfile (hence its user lockfile) API lets the caller to open
+ a file descriptor to a temporary file, write into it and then
+ finalize it by first closing the filehandle and then either
+ removing or renaming the temporary file. When the process spawns a
+ subprocess after obtaining the file descriptor, and if the
+ subprocess has not exited when the attempt to remove or rename is
+ made, the last step fails on Windows, because the subprocess has
+ the file descriptor still open. Open tempfile with O_CLOEXEC flag
+ to avoid this (on Windows, this is mapped to O_NOINHERIT).
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index e8ad978..08352de 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -121,6 +121,16 @@ its behaviour. Try to make sure your explanation can be understood
without external resources. Instead of giving a URL to a mailing list
archive, summarize the relevant points of the discussion.
+If you want to reference a previous commit in the history of a stable
+branch, use the format "abbreviated sha1 (subject, date)",
+with the subject enclosed in a pair of double-quotes, like this:
+
+ Commit f86a374 ("pack-bitmap.c: fix a memleak", 2015-03-30)
+ noticed that ...
+
+The "Copy commit summary" command of gitk can be used to obtain this
+format.
+
(3) Generate your patch using Git tools out of your commits.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6ad3eb6..a179474 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -150,27 +150,34 @@ integer::
1024", "by 1024x1024", etc.
color::
- The value for a variables that takes a color is a list of
- colors (at most two) and attributes (at most one), separated
- by spaces. The colors accepted are `normal`, `black`,
- `red`, `green`, `yellow`, `blue`, `magenta`, `cyan` and
- `white`; the attributes are `bold`, `dim`, `ul`, `blink` and
- `reverse`. The first color given is the foreground; the
- second is the background. The position of the attribute, if
- any, doesn't matter. Attributes may be turned off specifically
- by prefixing them with `no` (e.g., `noreverse`, `noul`, etc).
-+
-Colors (foreground and background) may also be given as numbers between
-0 and 255; these use ANSI 256-color mode (but note that not all
-terminals may support this). If your terminal supports it, you may also
-specify 24-bit RGB values as hex, like `#ff0ab3`.
-+
-The attributes are meant to be reset at the beginning of each item
-in the colored output, so setting color.decorate.branch to `black`
-will paint that branch name in a plain `black`, even if the previous
-thing on the same output line (e.g. opening parenthesis before the
-list of branch names in `log --decorate` output) is set to be
-painted with `bold` or some other attribute.
+ The value for a variable that takes a color is a list of
+ colors (at most two, one for foreground and one for background)
+ and attributes (as many as you want), separated by spaces.
++
+The basic colors accepted are `normal`, `black`, `red`, `green`, `yellow`,
+`blue`, `magenta`, `cyan` and `white`. The first color given is the
+foreground; the second is the background.
++
+Colors may also be given as numbers between 0 and 255; these use ANSI
+256-color mode (but note that not all terminals may support this). If
+your terminal supports it, you may also specify 24-bit RGB values as
+hex, like `#ff0ab3`.
++
+The accepted attributes are `bold`, `dim`, `ul`, `blink`, `reverse`,
+`italic`, and `strike` (for crossed-out or "strikethrough" letters).
+The position of any attributes with respect to the colors
+(before, after, or in between), doesn't matter. Specific attributes may
+be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`,
+`no-ul`, etc).
++
+For git's pre-defined color slots, the attributes are meant to be reset
+at the beginning of each item in the colored output. So setting
+`color.decorate.branch` to `black` will paint that branch name in a
+plain `black`, even if the previous thing on the same output line (e.g.
+opening parenthesis before the list of branch names in `log --decorate`
+output) is set to be painted with `bold` or some other attribute.
+However, custom log formats may do more complicated and layered
+coloring, and the negated forms may be useful there.
pathname::
A variable that takes a pathname value can be given a
@@ -405,13 +412,11 @@ file with mixed line endings would be reported by the `core.safecrlf`
mechanism.
core.autocrlf::
- Setting this variable to "true" is almost the same as setting
- the `text` attribute to "auto" on all files except that text
- files are not guaranteed to be normalized: files that contain
- `CRLF` in the repository will not be touched. Use this
- setting if you want to have `CRLF` line endings in your
- working directory even though the repository does not have
- normalized line endings. This variable can be set to 'input',
+ Setting this variable to "true" is the same as setting
+ the `text` attribute to "auto" on all files and core.eol to "crlf".
+ Set to true if you want to have `CRLF` line endings in your
+ working directory and the repository has LF line endings.
+ This variable can be set to 'input',
in which case no output conversion is performed.
core.symlinks::
@@ -443,6 +448,13 @@ specify that no proxy be used for a given domain pattern.
This is useful for excluding servers inside a firewall from
proxy use, while defaulting to a common proxy for external domains.
+core.sshCommand::
+ If this variable is set, `git fetch` and `git push` will
+ use the specified command instead of `ssh` when they need to
+ connect to a remote system. The command is in the same form as
+ the `GIT_SSH_COMMAND` environment variable and is overridden
+ when the environment variable is set.
+
core.ignoreStat::
If true, Git will avoid using lstat() calls to detect if files have
changed by setting the "assume-unchanged" bit for those tracked files
@@ -941,7 +953,8 @@ color.branch::
A boolean to enable/disable color in the output of
linkgit:git-branch[1]. May be set to `always`,
`false` (or `never`) or `auto` (or `true`), in which case colors are used
- only when the output is to a terminal. Defaults to false.
+ only when the output is to a terminal. If unset, then the
+ value of `color.ui` is used (`auto` by default).
color.branch.<slot>::
Use customized color for branch coloration. `<slot>` is one of
@@ -956,7 +969,8 @@ color.diff::
linkgit:git-log[1], and linkgit:git-show[1] will use color
for all patches. If it is set to `true` or `auto`, those
commands will only use color when output is to the terminal.
- Defaults to false.
+ If unset, then the value of `color.ui` is used (`auto` by
+ default).
+
This does not affect linkgit:git-format-patch[1] or the
'git-diff-{asterisk}' plumbing commands. Can be overridden on the
@@ -979,7 +993,8 @@ color.decorate.<slot>::
color.grep::
When set to `always`, always highlight matches. When `false` (or
`never`), never. When set to `true` or `auto`, use color only
- when the output is written to the terminal. Defaults to `false`.
+ when the output is written to the terminal. If unset, then the
+ value of `color.ui` is used (`auto` by default).
color.grep.<slot>::
Use customized color for grep colorization. `<slot>` specifies which
@@ -1012,7 +1027,8 @@ color.interactive::
and displays (such as those used by "git-add --interactive" and
"git-clean --interactive"). When false (or `never`), never.
When set to `true` or `auto`, use colors only when the output is
- to the terminal. Defaults to false.
+ to the terminal. If unset, then the value of `color.ui` is
+ used (`auto` by default).
color.interactive.<slot>::
Use customized color for 'git add --interactive' and 'git clean
@@ -1028,13 +1044,15 @@ color.showBranch::
A boolean to enable/disable color in the output of
linkgit:git-show-branch[1]. May be set to `always`,
`false` (or `never`) or `auto` (or `true`), in which case colors are used
- only when the output is to a terminal. Defaults to false.
+ only when the output is to a terminal. If unset, then the
+ value of `color.ui` is used (`auto` by default).
color.status::
A boolean to enable/disable color in the output of
linkgit:git-status[1]. May be set to `always`,
`false` (or `never`) or `auto` (or `true`), in which case colors are used
- only when the output is to a terminal. Defaults to false.
+ only when the output is to a terminal. If unset, then the
+ value of `color.ui` is used (`auto` by default).
color.status.<slot>::
Use customized color for status colorization. `<slot>` is
@@ -1189,6 +1207,15 @@ difftool.<tool>.cmd::
difftool.prompt::
Prompt before each invocation of the diff tool.
+fastimport.unpackLimit::
+ If the number of objects imported by linkgit:git-fast-import[1]
+ is below this limit, then the objects will be unpacked into
+ loose object files. However if the number of imported objects
+ equals or exceeds this limit then the pack will be stored as a
+ pack. Storing the pack from a fast-import can make the import
+ operation complete faster, especially on slow filesystems. If
+ not set, the value of `transfer.unpackLimit` is used instead.
+
fetch.recurseSubmodules::
This option can be either set to a boolean value or to 'on-demand'.
Setting it to a boolean changes the behavior of fetch and pull to
@@ -1220,6 +1247,11 @@ fetch.prune::
If true, fetch will automatically behave as if the `--prune`
option was given on the command line. See also `remote.<name>.prune`.
+fetch.output::
+ Control how ref update status is printed. Valid values are
+ `full` and `compact`. Default value is `full`. See section
+ OUTPUT in linkgit:git-fetch[1] for detail.
+
format.attach::
Enable multipart/mixed attachments as the default for
'format-patch'. The value can also be a double quoted string
@@ -1227,6 +1259,16 @@ format.attach::
value as the boundary. See the --attach option in
linkgit:git-format-patch[1].
+format.from::
+ Provides the default value for the `--from` option to format-patch.
+ Accepts a boolean value, or a name and email address. If false,
+ format-patch defaults to `--no-from`, using commit authors directly in
+ the "From:" field of patch mails. If true, format-patch defaults to
+ `--from`, using your committer identity in the "From:" field of patch
+ mails and including a "From:" field in the body of the patch mail if
+ different. If set to a non-boolean value, format-patch uses that
+ value instead of your committer identity. Defaults to false.
+
format.numbered::
A boolean which can enable or disable sequence numbers in patch
subjects. It defaults to "auto" which enables it only if there
@@ -1330,7 +1372,7 @@ fsck.skipList::
gc.aggressiveDepth::
The depth parameter used in the delta compression
algorithm used by 'git gc --aggressive'. This defaults
- to 250.
+ to 50.
gc.aggressiveWindow::
The window size parameter used in the delta compression
@@ -1694,6 +1736,20 @@ http.emptyAuth::
a username in the URL, as libcurl normally requires a username for
authentication.
+http.delegation::
+ Control GSSAPI credential delegation. The delegation is disabled
+ by default in libcurl since version 7.21.7. Set parameter to tell
+ the server what it is allowed to delegate when it comes to user
+ credentials. Used with GSS/kerberos. Possible values are:
++
+--
+* `none` - Don't allow any delegation.
+* `policy` - Delegates if and only if the OK-AS-DELEGATE flag is set in the
+ Kerberos service ticket, which is a matter of realm policy.
+* `always` - Unconditionally allow the server to delegate.
+--
+
+
http.extraHeader::
Pass an additional HTTP header when communicating with a server. If
more than one such entry exists, all of them are added as extra
@@ -2401,8 +2457,13 @@ rebase.instructionFormat
receive.advertiseAtomic::
By default, git-receive-pack will advertise the atomic push
- capability to its clients. If you don't want to this capability
- to be advertised, set this variable to false.
+ capability to its clients. If you don't want to advertise this
+ capability, set this variable to false.
+
+receive.advertisePushOptions::
+ By default, git-receive-pack will advertise the push options
+ capability to its clients. If you don't want to advertise this
+ capability, set this variable to false.
receive.autogc::
By default, git-receive-pack will run "git-gc --auto" after
@@ -2457,6 +2518,15 @@ receive.fsck.skipList::
can be safely ignored such as invalid committer email addresses.
Note: corrupt objects cannot be skipped with this setting.
+receive.keepAlive::
+ After receiving the pack from the client, `receive-pack` may
+ produce no output (if `--quiet` was specified) while processing
+ the pack, causing some networks to drop the TCP connection.
+ With this option set, if `receive-pack` does not transmit
+ any data in this phase for `receive.keepAlive` seconds, it will
+ send a short keepalive packet. The default is 5 seconds; set
+ to 0 to disable keepalives entirely.
+
receive.unpackLimit::
If the number of objects received in a push is below this
limit then the objects will be unpacked into loose object
@@ -2467,6 +2537,12 @@ receive.unpackLimit::
especially on slow filesystems. If not set, the value of
`transfer.unpackLimit` is used instead.
+receive.maxInputSize::
+ If the size of the incoming pack stream is larger than this
+ limit, then git-receive-pack will error out, instead of
+ accepting the pack file. If not set or set to 0, then the size
+ is unlimited.
+
receive.denyDeletes::
If set to true, git-receive-pack will deny a ref update that deletes
the ref. Use this to prevent such a ref deletion via a push.
@@ -2797,6 +2873,18 @@ submodule.fetchJobs::
in parallel. A value of 0 will give some reasonable default.
If unset, it defaults to 1.
+submodule.alternateLocation::
+ Specifies how the submodules obtain alternates when submodules are
+ cloned. Possible values are `no`, `superproject`.
+ By default `no` is assumed, which doesn't add references. When the
+ value is set to `superproject` the submodule to be cloned computes
+ its alternates location relative to the superprojects alternate.
+
+submodule.alternateErrorStrategy
+ Specifies how to treat errors with the alternates for a submodule
+ as computed via `submodule.alternateLocation`. Possible values are
+ `ignore`, `info`, `die`. Default is `die`.
+
tag.forceSignAnnotated::
A boolean to specify whether annotated tags created should be GPG signed.
If `--annotate` is specified on the command line, it takes
@@ -2883,6 +2971,21 @@ uploadpack.keepAlive::
`uploadpack.keepAlive` seconds. Setting this option to 0
disables keepalive packets entirely. The default is 5 seconds.
+uploadpack.packObjectsHook::
+ If this option is set, when `upload-pack` would run
+ `git pack-objects` to create a packfile for a client, it will
+ run this shell command instead. The `pack-objects` command and
+ arguments it _would_ have run (including the `git pack-objects`
+ at the beginning) are appended to the shell command. The stdin
+ and stdout of the hook are treated as if `pack-objects` itself
+ was run. I.e., `upload-pack` will feed input intended for
+ `pack-objects` to the hook, and expects a completed packfile on
+ stdout.
++
+Note that this configuration variable is ignored if it is seen in the
+repository-level config (this is a safety measure against fetching from
+untrusted repositories).
+
url.<base>.insteadOf::
Any URL that starts with this value will be rewritten to
start, instead, with <base>. In cases where some site serves a
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
index d5a5b17..b27a38f 100644
--- a/Documentation/diff-config.txt
+++ b/Documentation/diff-config.txt
@@ -122,10 +122,11 @@ diff.suppressBlankEmpty::
diff.submodule::
Specify the format in which differences in submodules are
- shown. The "log" format lists the commits in the range like
- linkgit:git-submodule[1] `summary` does. The "short" format
- format just shows the names of the commits at the beginning
- and end of the range. Defaults to short.
+ shown. The "short" format just shows the names of the commits
+ at the beginning and end of the range. The "log" format lists
+ the commits in the range like linkgit:git-submodule[1] `summary`
+ does. The "diff" format shows an inline diff of the changed
+ contents of the submodule. Defaults to "short".
diff.wordRegex::
A POSIX Extended Regular Expression used to determine what is a "word"
@@ -170,10 +171,11 @@ diff.tool::
include::mergetools-diff.txt[]
+diff.indentHeuristic::
diff.compactionHeuristic::
- Set this option to `true` to enable an experimental heuristic that
- shifts the hunk boundary in an attempt to make the resulting
- patch easier to read.
+ Set one of these options to `true` to enable one of two
+ experimental heuristics that shift diff hunk boundaries to
+ make patches easier to read.
diff.algorithm::
Choose a diff algorithm. The variants are as follows:
diff --git a/Documentation/diff-heuristic-options.txt b/Documentation/diff-heuristic-options.txt
new file mode 100644
index 0000000..36cb549
--- /dev/null
+++ b/Documentation/diff-heuristic-options.txt
@@ -0,0 +1,7 @@
+--indent-heuristic::
+--no-indent-heuristic::
+--compaction-heuristic::
+--no-compaction-heuristic::
+ These are to help debugging and tuning experimental heuristics
+ (which are off by default) that shift diff hunk boundaries to
+ make patches easier to read.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 705a873..2d77a19 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -63,12 +63,7 @@ ifndef::git-format-patch[]
Synonym for `-p --raw`.
endif::git-format-patch[]
---compaction-heuristic::
---no-compaction-heuristic::
- These are to help debugging and tuning an experimental
- heuristic (which is off by default) that shifts the hunk
- boundary in an attempt to make the resulting patch easier
- to read.
+include::diff-heuristic-options.txt[]
--minimal::
Spend extra time to make sure the smallest possible
@@ -210,13 +205,16 @@ any of those replacements occurred.
of the `--diff-filter` option on what the status letters mean.
--submodule[=<format>]::
- 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. Can be tweaked via the
- `diff.submodule` configuration variable.
+ Specify how differences in submodules are shown. When specifying
+ `--submodule=short` the 'short' format is used. This format just
+ shows the names of the commits at the beginning and end of the range.
+ When `--submodule` or `--submodule=log` is specified, the 'log'
+ format is used. This format lists the commits in the range like
+ linkgit:git-submodule[1] `summary` does. When `--submodule=diff`
+ is specified, the 'diff' format is used. This format shows an
+ inline diff of the changes in the submodule contents between the
+ commit range. Defaults to `diff.submodule` or the 'short' format
+ if the config option is unset.
--color[=<when>]::
Show colored diff.
@@ -569,5 +567,8 @@ endif::git-format-patch[]
--no-prefix::
Do not show any source or destination prefix.
+--line-prefix=<prefix>::
+ Prepend an additional prefix to every line of output.
+
For more detailed explanation on these common options, see also
linkgit:gitdiffcore[7].
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 6a96a66..7ed63dc 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -11,7 +11,7 @@ SYNOPSIS
'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing]
- [--] [<pathspec>...]
+ [--chmod=(+|-)x] [--] [<pathspec>...]
DESCRIPTION
-----------
@@ -165,6 +165,11 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
be ignored, no matter if they are already present in the work
tree or not.
+--chmod=(+|-)x::
+ Override the executable bit of the added files. The executable
+ bit is only changed in the index, the files on disk are left
+ unchanged.
+
\--::
This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 8dd9e4f..12879e4 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -116,7 +116,8 @@ default. You can use `--no-utf8` to override this.
By default the command will try to detect the patch format
automatically. This option allows the user to bypass the automatic
detection and specify the patch format that the patch(es) should be
- interpreted as. Valid formats are mbox, stgit, stgit-series and hg.
+ interpreted as. Valid formats are mbox, mboxrd,
+ stgit, stgit-series and hg.
-i::
--interactive::
diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt
index 05fd482..94be4b8 100644
--- a/Documentation/git-annotate.txt
+++ b/Documentation/git-annotate.txt
@@ -23,6 +23,7 @@ familiar command name for people coming from other SCM systems.
OPTIONS
-------
include::blame-options.txt[]
+include::diff-heuristic-options.txt[]
SEE ALSO
--------
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index ba54175..9dccb33 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -89,6 +89,8 @@ include::blame-options.txt[]
abbreviated object name, use <n>+1 digits. Note that 1 column
is used for a caret to mark the boundary commit.
+include::diff-heuristic-options.txt[]
+
THE PORCELAIN FORMAT
--------------------
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 18d03d8..204541c 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -9,18 +9,22 @@ git-cat-file - Provide content or type and size information for repository objec
SYNOPSIS
--------
[verse]
-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv ) <object>
-'git cat-file' (--batch | --batch-check) [--follow-symlinks]
+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>
+'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]
DESCRIPTION
-----------
In its first form, the command provides the content or the type of an object in
the repository. The type is required unless `-t` or `-p` is used to find the
-object type, or `-s` is used to find the object size, or `--textconv` is used
-(which implies type "blob").
+object type, or `-s` is used to find the object size, or `--textconv` or
+`--filters` is used (which imply type "blob").
In the second form, a list of objects (separated by linefeeds) is provided on
-stdin, and the SHA-1, type, and size of each object is printed on stdout.
+stdin, and the SHA-1, type, and size of each object is printed on stdout. The
+output format can be overridden using the optional `<format>` argument. If
+either `--textconv` or `--filters` was specified, the input is expected to
+list the object names followed by the path name, separated by a single white
+space, so that the appropriate drivers can be determined.
OPTIONS
-------
@@ -54,19 +58,35 @@ OPTIONS
--textconv::
Show the content as transformed by a textconv filter. In this case,
- <object> has be of the form <tree-ish>:<path>, or :<path> in order
- to apply the filter to the content recorded in the index at <path>.
+ <object> has to be of the form <tree-ish>:<path>, or :<path> in
+ order to apply the filter to the content recorded in the index at
+ <path>.
+
+--filters::
+ Show the content as converted by the filters configured in
+ the current working tree for the given <path> (i.e. smudge filters,
+ end-of-line conversion, etc). In this case, <object> has to be of
+ the form <tree-ish>:<path>, or :<path>.
+
+--path=<path>::
+ For use with --textconv or --filters, to allow specifying an object
+ name and a path separately, e.g. when it is difficult to figure out
+ the revision from which the blob came.
--batch::
--batch=<format>::
Print object information and contents for each object provided
- on stdin. May not be combined with any other options or arguments.
- See the section `BATCH OUTPUT` below for details.
+ on stdin. May not be combined with any other options or arguments
+ except `--textconv` or `--filters`, in which case the input lines
+ also need to specify the path, separated by white space. See the
+ section `BATCH OUTPUT` below for details.
--batch-check::
--batch-check=<format>::
Print object information for each object provided on stdin. May
- not be combined with any other options or arguments. See the
+ not be combined with any other options or arguments except
+ `--textconv` or `--filters`, in which case the input lines also
+ need to specify the path, separated by white space. See the
section `BATCH OUTPUT` below for details.
--batch-all-objects::
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 91a3622..8611a99 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -118,8 +118,8 @@ $ git check-ref-format --branch @{-1}
* Determine the reference name to use for a new branch:
+
------------
-$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch") ||
-die "we do not like '$newbranch' as a branch name."
+$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch")||
+{ echo "we do not like '$newbranch' as a branch name." >&2 ; exit 1 ; }
------------
GIT
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 7a2201b..8e2c066 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -419,6 +419,18 @@ $ git reflog -2 HEAD # or
$ git log -g -2 HEAD
------------
+ARGUMENT DISAMBIGUATION
+-----------------------
+
+When there is only one argument given and it is not `--` (e.g. "git
+checkout abc"), and when the argument is both a valid `<tree-ish>`
+(e.g. a branch "abc" exists) and a valid `<pathspec>` (e.g. a file
+or a directory whose name is "abc" exists), Git would usually ask
+you to disambiguate. Because checking out a branch is so common an
+operation, however, "git checkout abc" takes "abc" as a `<tree-ish>`
+in such a situation. Use `git checkout -- <pathspec>` if you want
+to checkout these paths out of the index.
+
EXAMPLES
--------
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index ec41d3d..e316c4b 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -90,13 +90,16 @@ If you want to break the dependency of a repository cloned with `-s` on
its source repository, you can simply run `git repack -a` to copy all
objects from the source repository into a pack in the cloned repository.
---reference <repository>::
+--reference[-if-able] <repository>::
If the reference repository is on the local machine,
automatically setup `.git/objects/info/alternates` to
obtain objects from the reference repository. Using
an already existing repository as an alternate will
require fewer objects to be copied from the repository
being cloned, reducing network and local storage costs.
+ When using the `--reference-if-able`, a non existing
+ directory is skipped with a warning instead of aborting
+ the clone.
+
*NOTE*: see the NOTE for the `--shared` option, and also the
`--dissociate` option.
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index f163113..83f86b9 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -263,6 +263,9 @@ The files are read in the order given above, with last value found taking
precedence over values read earlier. When multiple values are taken then all
values of a key from all files will be used.
+You may override individual configuration parameters when running any git
+command by using the `-c` option. See linkgit:git[1] for details.
+
All writing options will per default write to the repository specific
configuration file. Note that this also affects options like `--replace-all`
and `--unset`. *'git config' will only ever change one file at a time*.
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index 41207a2..de1ebed 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -22,7 +22,7 @@ DESCRIPTION
deprecated; it does not work with cvsps version 3 and later. If you are
performing a one-shot import of a CVS repository consider using
http://cvs2svn.tigris.org/cvs2git.html[cvs2git] or
-https://github.com/BartMassey/parsecvs[parsecvs].
+http://www.catb.org/esr/cvs-fast-export/[cvs-fast-export].
Imports a CVS repository into Git. It will either create a new
repository, or incrementally import into an existing one.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index c105f21..2b76265 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -136,6 +136,8 @@ Performance and Compression Tuning
Maximum size of each output packfile.
The default is unlimited.
+fastimport.unpackLimit::
+ See linkgit:git-config[1]
Performance
-----------
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index efe56e0..9e42169 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -99,6 +99,57 @@ The latter use of the `remote.<repository>.fetch` values can be
overridden by giving the `--refmap=<refspec>` parameter(s) on the
command line.
+OUTPUT
+------
+
+The output of "git fetch" depends on the transport method used; this
+section describes the output when fetching over the Git protocol
+(either locally or via ssh) and Smart HTTP protocol.
+
+The status of the fetch is output in tabular form, with each line
+representing the status of a single ref. Each line is of the form:
+
+-------------------------------
+ <flag> <summary> <from> -> <to> [<reason>]
+-------------------------------
+
+The status of up-to-date refs is shown only if the --verbose option is
+used.
+
+In compact output mode, specified with configuration variable
+fetch.output, if either entire `<from>` or `<to>` is found in the
+other string, it will be substituted with `*` in the other string. For
+example, `master -> origin/master` becomes `master -> origin/*`.
+
+flag::
+ A single character indicating the status of the ref:
+(space);; for a successfully fetched fast-forward;
+`+`;; for a successful forced update;
+`-`;; for a successfully pruned ref;
+`t`;; for a successful tag update;
+`*`;; for a successfully fetched new ref;
+`!`;; for a ref that was rejected or failed to update; and
+`=`;; for a ref that was up to date and did not need fetching.
+
+summary::
+ For a successfully fetched 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).
+
+from::
+ The name of the remote ref being fetched from, minus its
+ `refs/<type>/` prefix. In the case of deletion, the name of
+ the remote ref is "(none)".
+
+to::
+ The name of the local ref being updated, minus its
+ `refs/<type>/` prefix.
+
+reason::
+ A human-readable explanation. In the case of successfully fetched
+ refs, no explanation is needed. For a failed ref, the reason for
+ failure is described.
EXAMPLES
--------
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 9624c84..9b200b3 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -19,7 +19,8 @@ SYNOPSIS
[--start-number <n>] [--numbered-files]
[--in-reply-to=Message-Id] [--suffix=.<sfx>]
[--ignore-if-in-upstream]
- [--subject-prefix=Subject-Prefix] [(--reroll-count|-v) <n>]
+ [--rfc] [--subject-prefix=Subject-Prefix]
+ [(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
[--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
[<common diff options>]
@@ -172,6 +173,11 @@ will want to ensure that threading is disabled for `git send-email`.
allows for useful naming of a patch series, and can be
combined with the `--numbered` option.
+--rfc::
+ Alias for `--subject-prefix="RFC PATCH"`. RFC means "Request For
+ Comments"; use this when sending an experimental patch for
+ discussion rather than application.
+
-v <n>::
--reroll-count=<n>::
Mark the series as the <n>-th iteration of the topic. The
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index 7fc68eb..b9f060e 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -11,7 +11,8 @@ SYNOPSIS
[verse]
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
[--[no-]full] [--strict] [--verbose] [--lost-found]
- [--[no-]dangling] [--[no-]progress] [--connectivity-only] [<object>*]
+ [--[no-]dangling] [--[no-]progress] [--connectivity-only]
+ [--[no-]name-objects] [<object>*]
DESCRIPTION
-----------
@@ -82,6 +83,12 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
a blob, the contents are written into the file, rather than
its object name.
+--name-objects::
+ When displaying names of reachable objects, in addition to the
+ SHA-1 also display a name that describes *how* they are reachable,
+ compatible with linkgit:git-rev-parse[1], e.g.
+ `HEAD@{1234567890}~25^2:src/`.
+
--[no-]progress::
Progress status is reported on the standard error stream by
default when it is attached to a terminal, unless
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 7a4e055..1b4b65d 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -87,6 +87,8 @@ OPTIONS
Specifying 0 will cause Git to auto-detect the number of CPU's
and use maximum 3 threads.
+--max-input-size=<size>::
+ Die, if the pack is larger than <size>.
Note
----
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 4a6c47f..32246fd 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -198,6 +198,10 @@ log.showRoot::
`git log -p` output would be shown without a diff attached.
The default is `true`.
+log.showSignature::
+ If `true`, `git log` and related commands will act as if the
+ `--show-signature` option was passed to them.
+
mailmap.*::
See linkgit:git-shortlog[1].
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 078b556..0d933ac 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -159,8 +159,7 @@ not accessible in the working tree.
+
<eolattr> is the attribute that is used when checking out or committing,
it is either "", "-text", "text", "text=auto", "text eol=lf", "text eol=crlf".
-Note: Currently Git does not support "text=auto eol=lf" or "text=auto eol=crlf",
-that may change in the future.
+Since Git 2.10 "text=auto eol=lf" and "text=auto eol=crlf" are supported.
+
Both the <eolinfo> in the index ("i/<eolinfo>")
and in the working tree ("w/<eolinfo>") are shown for regular files,
diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index 4d1b871..e3b2a88 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program
SYNOPSIS
--------
[verse]
-'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] -o<directory> [--] [(<mbox>|<Maildir>)...]
+'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] [--mboxrd]
+ -o<directory> [--] [(<mbox>|<Maildir>)...]
DESCRIPTION
-----------
@@ -47,6 +48,10 @@ OPTIONS
--keep-cr::
Do not remove `\r` from lines ending with `\r\n`.
+--mboxrd::
+ Input is of the "mboxrd" format and "^>+From " line escaping is
+ reversed.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index 19cdcd0..8973510 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -104,8 +104,8 @@ base-name::
out of memory with a large window, but still be able to take
advantage of the large window for the smaller objects. The
size can be suffixed with "k", "m", or "g".
- `--window-memory=0` makes memory usage unlimited, which is the
- default.
+ `--window-memory=0` makes memory usage unlimited. The default
+ is taken from the `pack.windowMemory` configuration variable.
--max-pack-size=<n>::
Maximum size of each output pack file. The size can be suffixed with
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 93c3527..47b77e6 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
- [-u | --set-upstream]
+ [-u | --set-upstream] [--push-option=<string>]
[--[no-]signed|--sign=(true|false|if-asked)]
[--force-with-lease[=<refname>[:<expect>]]]
[--no-verify] [<repository> [<refspec>...]]
@@ -156,6 +156,12 @@ already exists on the remote side.
Either all refs are updated, or on error, no refs are updated.
If the server does not support atomic pushes the push will fail.
+-o::
+--push-option::
+ Transmit the given string to the server, which passes them to
+ the pre-receive as well as the post-receive hook. The given string
+ must not contain a NUL or LF character.
+
--receive-pack=<git-receive-pack>::
--exec=<git-receive-pack>::
Path to the 'git-receive-pack' program on the remote
@@ -198,10 +204,11 @@ branch we have for it.
+
`--force-with-lease=<refname>:<expect>` will protect the named ref (alone),
if it is going to be updated, by requiring its current value to be
-the same as the specified value <expect> (which is allowed to be
+the same as the specified value `<expect>` (which is allowed to be
different from the remote-tracking branch we have for the refname,
or we do not even have to have such a remote-tracking branch when
-this form is used).
+this form is used). If `<expect>` is the empty string, then the named ref
+must not already exist.
+
Note that all forms other than `--force-with-lease=<refname>:<expect>`
that specifies the expected current value of the ref explicitly are
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 000ee8d..0ccd5fb 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -33,6 +33,9 @@ post-update hooks found in the Documentation/howto directory.
option, which tells it if updates to a ref should be denied if they
are not fast-forwards.
+A number of other receive.* config options are available to tweak
+its behavior, see linkgit:git-config[1].
+
OPTIONS
-------
<directory>::
diff --git a/Documentation/git-remote-fd.txt b/Documentation/git-remote-fd.txt
index e700baf..80afca8 100644
--- a/Documentation/git-remote-fd.txt
+++ b/Documentation/git-remote-fd.txt
@@ -17,7 +17,7 @@ fetch, push or archive.
If only <infd> is given, it is assumed to be a bidirectional socket connected
to remote Git server (git-upload-pack, git-receive-pack or
-git-upload-achive). If both <infd> and <outfd> are given, they are assumed
+git-upload-archive). If both <infd> and <outfd> are given, they are assumed
to be pipes connected to a remote Git server (<infd> being the inbound pipe
and <outfd> being the outbound pipe.
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 0c03eec..26afe6e 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -100,8 +100,10 @@ other objects in that pack they already have locally.
out of memory with a large window, but still be able to take
advantage of the large window for the smaller objects. The
size can be suffixed with "k", "m", or "g".
- `--window-memory=0` makes memory usage unlimited, which is the
- default.
+ `--window-memory=0` makes memory usage unlimited. The default
+ is taken from the `pack.windowMemory` configuration variable.
+ Note that the actual memory usage will be the limit multiplied
+ by the number of threads used by linkgit:git-pack-objects[1].
--max-pack-size=<n>::
Maximum size of each output pack file. The size can be suffixed with
@@ -128,6 +130,19 @@ other objects in that pack they already have locally.
with `-b` or `repack.writeBitmaps`, as it ensures that the
bitmapped packfile has the necessary objects.
+--unpack-unreachable=<when>::
+ When loosening unreachable objects, do not bother loosening any
+ objects older than `<when>`. This can be used to optimize out
+ the write of any objects that would be immediately pruned by
+ a follow-up `git prune`.
+
+-k::
+--keep-unreachable::
+ When used with `-ad`, any unreachable objects from existing
+ packs will be appended to the end of the packfile instead of
+ being removed. In addition, any unreachable loose objects will
+ be packed (and their loose counterparts removed).
+
Configuration
-------------
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index e1e8f57..725065e 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -32,11 +32,14 @@ OPTIONS
--branch::
Show the branch and tracking info even in short-format.
---porcelain::
+--porcelain[=<version>]::
Give the output in an easy-to-parse format for scripts.
This is similar to the short output, but will remain stable
across Git versions and regardless of user configuration. See
below for details.
++
+The version parameter is used to specify the format version.
+This is optional and defaults to the original version 'v1' format.
--long::
Give the output in the long-format. This is the default.
@@ -96,7 +99,7 @@ configuration variable documented in linkgit:git-config[1].
-z::
Terminate entries with NUL, instead of LF. This implies
- the `--porcelain` output format if no other format is given.
+ the `--porcelain=v1` output format if no other format is given.
--column[=<options>]::
--no-column::
@@ -180,12 +183,12 @@ in which case `XY` are `!!`.
If -b is used the short-format status is preceded by a line
-## branchname tracking info
+ ## branchname tracking info
-Porcelain Format
-~~~~~~~~~~~~~~~~
+Porcelain Format Version 1
+~~~~~~~~~~~~~~~~~~~~~~~~~~
-The porcelain format is similar to the short format, but is guaranteed
+Version 1 porcelain format is similar to the short format, but is guaranteed
not to change in a backwards-incompatible way between Git versions or
based on user configuration. This makes it ideal for parsing by scripts.
The description of the short format above also describes the porcelain
@@ -207,6 +210,124 @@ field from the first filename). Third, filenames containing special
characters are not specially formatted; no quoting or
backslash-escaping is performed.
+Porcelain Format Version 2
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Version 2 format adds more detailed information about the state of
+the worktree and changed items. Version 2 also defines an extensible
+set of easy to parse optional headers.
+
+Header lines start with "#" and are added in response to specific
+command line arguments. Parsers should ignore headers they
+don't recognize.
+
+### Branch Headers
+
+If `--branch` is given, a series of header lines are printed with
+information about the current branch.
+
+ Line Notes
+ ------------------------------------------------------------
+ # branch.oid <commit> | (initial) Current commit.
+ # branch.head <branch> | (detached) Current branch.
+ # branch.upstream <upstream_branch> If upstream is set.
+ # branch.ab +<ahead> -<behind> If upstream is set and
+ the commit is present.
+ ------------------------------------------------------------
+
+### Changed Tracked Entries
+
+Following the headers, a series of lines are printed for tracked
+entries. One of three different line formats may be used to describe
+an entry depending on the type of change. Tracked entries are printed
+in an undefined order; parsers should allow for a mixture of the 3
+line types in any order.
+
+Ordinary changed entries have the following format:
+
+ 1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
+
+Renamed or copied entries have the following format:
+
+ 2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><sep><origPath>
+
+ Field Meaning
+ --------------------------------------------------------
+ <XY> A 2 character field containing the staged and
+ unstaged XY values described in the short format,
+ with unchanged indicated by a "." rather than
+ a space.
+ <sub> A 4 character field describing the submodule state.
+ "N..." when the entry is not a submodule.
+ "S<c><m><u>" when the entry is a submodule.
+ <c> is "C" if the commit changed; otherwise ".".
+ <m> is "M" if it has tracked changes; otherwise ".".
+ <u> is "U" if there are untracked changes; otherwise ".".
+ <mH> The octal file mode in HEAD.
+ <mI> The octal file mode in the index.
+ <mW> The octal file mode in the worktree.
+ <hH> The object name in HEAD.
+ <hI> The object name in the index.
+ <X><score> The rename or copy score (denoting the percentage
+ of similarity between the source and target of the
+ move or copy). For example "R100" or "C75".
+ <path> The pathname. In a renamed/copied entry, this
+ is the path in the index and in the working tree.
+ <sep> When the `-z` option is used, the 2 pathnames are separated
+ with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
+ byte separates them.
+ <origPath> The pathname in the commit at HEAD. This is only
+ present in a renamed/copied entry, and tells
+ where the renamed/copied contents came from.
+ --------------------------------------------------------
+
+Unmerged entries have the following format; the first character is
+a "u" to distinguish from ordinary changed entries.
+
+ u <xy> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>
+
+ Field Meaning
+ --------------------------------------------------------
+ <XY> A 2 character field describing the conflict type
+ as described in the short format.
+ <sub> A 4 character field describing the submodule state
+ as described above.
+ <m1> The octal file mode in stage 1.
+ <m2> The octal file mode in stage 2.
+ <m3> The octal file mode in stage 3.
+ <mW> The octal file mode in the worktree.
+ <h1> The object name in stage 1.
+ <h2> The object name in stage 2.
+ <h3> The object name in stage 3.
+ <path> The pathname.
+ --------------------------------------------------------
+
+### Other Items
+
+Following the tracked entries (and if requested), a series of
+lines will be printed for untracked and then ignored items
+found in the worktree.
+
+Untracked items have the following format:
+
+ ? <path>
+
+Ignored items have the following format:
+
+ ! <path>
+
+### Pathname Format Notes and -z
+
+When the `-z` option is given, pathnames are printed as is and
+without any quoting and lines are terminated with a NUL (ASCII 0x00)
+byte.
+
+Otherwise, all pathnames will be "C-quoted" if they contain any tab,
+linefeed, double quote, or backslash characters. In C-quoting, these
+characters will be replaced with the corresponding C-style escape
+sequences and the resulting pathname will be double quoted.
+
+
CONFIGURATION
-------------
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 9226c43..bf3bb37 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -15,8 +15,9 @@ SYNOPSIS
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)
'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch]
- [-f|--force] [--rebase|--merge] [--reference <repository>]
- [--depth <depth>] [--recursive] [--jobs <n>] [--] [<path>...]
+ [--[no-]recommend-shallow] [-f|--force] [--rebase|--merge]
+ [--reference <repository>] [--depth <depth>] [--recursive]
+ [--jobs <n>] [--] [<path>...]
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
[commit] [--] [<path>...]
'git submodule' [--quiet] foreach [--recursive] <command>
@@ -384,6 +385,12 @@ for linkgit:git-clone[1]'s `--reference` and `--shared` options carefully.
clone with a history truncated to the specified number of revisions.
See linkgit:git-clone[1]
+--[no-]recommend-shallow::
+ This option is only valid for the update command.
+ The initial clone of a submodule will use the recommended
+ `submodule.<name>.shallow` as provided by the .gitmodules file
+ by default. To ignore the suggestions use `--no-recommend-shallow`.
+
-j <n>::
--jobs <n>::
This option is only valid for the update command.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 7e17cad..5f9e65b 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -625,6 +625,9 @@ config key: svn.authorsfile
with the committer name as the first argument. The program is
expected to return a single line of the form "Name <email>",
which will be treated as if included in the authors file.
++
+[verse]
+config key: svn.authorsProg
-q::
--quiet::
diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt
index 3e887d1..b3de50d 100644
--- a/Documentation/git-unpack-objects.txt
+++ b/Documentation/git-unpack-objects.txt
@@ -44,6 +44,9 @@ OPTIONS
--strict::
Don't write objects with broken content or links.
+--max-input-size=<size>::
+ Die, if the pack is larger than <size>.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index 0abc806..822ad59 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -9,8 +9,8 @@ git-upload-pack - Send objects packed back to git-fetch-pack
SYNOPSIS
--------
[verse]
-'git-upload-pack' [--strict] [--timeout=<n>] <directory>
-
+'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]
+ [--advertise-refs] <directory>
DESCRIPTION
-----------
Invoked by 'git fetch-pack', learns what
@@ -25,12 +25,22 @@ repository. For push operations, see 'git send-pack'.
OPTIONS
-------
---strict::
+--[no-]strict::
Do not try <directory>/.git/ if <directory> is no Git directory.
--timeout=<n>::
Interrupt transfer after <n> seconds of inactivity.
+--stateless-rpc::
+ Perform only a single read-write cycle with stdin and stdout.
+ This fits with the HTTP POST request processing model where
+ a program may read the request, write a response, and must exit.
+
+--advertise-refs::
+ Only the initial ref advertisement is output, and the program exits
+ immediately. This fits with the HTTP GET request model, where
+ no request content is received but a response must be produced.
+
<directory>::
The repository to sync from.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index c622345..0aeb020 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -10,8 +10,10 @@ SYNOPSIS
--------
[verse]
'git worktree add' [-f] [--detach] [--checkout] [-b <new-branch>] <path> [<branch>]
-'git worktree prune' [-n] [-v] [--expire <expire>]
'git worktree list' [--porcelain]
+'git worktree lock' [--reason <string>] <worktree>
+'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree unlock' <worktree>
DESCRIPTION
-----------
@@ -38,9 +40,8 @@ section "DETAILS" for more information.
If a linked working tree is stored on a portable device or network share
which is not always mounted, you can prevent its administrative files from
-being pruned by creating a file named 'locked' alongside the other
-administrative files, optionally containing a plain text reason that
-pruning should be suppressed. See section "DETAILS" for more information.
+being pruned by issuing the `git worktree lock` command, optionally
+specifying `--reason` to explain why the working tree is locked.
COMMANDS
--------
@@ -48,16 +49,13 @@ add <path> [<branch>]::
Create `<path>` and checkout `<branch>` into it. The new working directory
is linked to the current repository, sharing everything except working
-directory specific files such as HEAD, index, etc.
+directory specific files such as HEAD, index, etc. `-` may also be
+specified as `<branch>`; it is synonymous with `@{-1}`.
+
If `<branch>` is omitted and neither `-b` nor `-B` nor `--detached` used,
then, as a convenience, a new branch based at HEAD is created automatically,
as if `-b $(basename <path>)` was specified.
-prune::
-
-Prune working tree information in $GIT_DIR/worktrees.
-
list::
List details of each worktree. The main worktree is listed first, followed by
@@ -65,6 +63,22 @@ each of the linked worktrees. The output details include if the worktree is
bare, the revision currently checked out, and the branch currently checked out
(or 'detached HEAD' if none).
+lock::
+
+If a working tree is on a portable device or network share which
+is not always mounted, lock it to prevent its administrative
+files from being pruned automatically. This also prevents it from
+being moved or deleted. Optionally, specify a reason for the lock
+with `--reason`.
+
+prune::
+
+Prune working tree information in $GIT_DIR/worktrees.
+
+unlock::
+
+Unlock a working tree, allowing it to be pruned, moved or deleted.
+
OPTIONS
-------
@@ -110,6 +124,18 @@ OPTIONS
--expire <time>::
With `prune`, only expire unused working trees older than <time>.
+--reason <string>::
+ With `lock`, an explanation why the working tree is locked.
+
+<worktree>::
+ Working trees can be identified by path, either relative or
+ absolute.
++
+If the last path components in the working tree's path is unique among
+working trees, it can be used to identify worktrees. For example if
+you only have to working trees at "/abc/def/ghi" and "/abc/def/ggg",
+then "ghi" or "def/ghi" is enough to point to the former working tree.
+
DETAILS
-------
Each linked working tree has a private sub-directory in the repository's
@@ -150,7 +176,8 @@ instead.
To prevent a $GIT_DIR/worktrees entry from being pruned (which
can be useful in some situations, such as when the
-entry's working tree is stored on a portable device), add a file named
+entry's working tree is stored on a portable device), use the
+`git worktree lock` command, which adds a file named
'locked' to the entry's directory. The file contains the reason in
plain text. For example, if a linked working tree's `.git` file points
to `/path/main/.git/worktrees/test-next` then a file named
@@ -226,8 +253,6 @@ performed manually, such as:
- `remove` to remove a linked working tree and its administrative files (and
warn if the working tree is dirty)
- `mv` to move or rename a working tree and update its administrative files
-- `lock` to prevent automatic pruning of administrative files (for instance,
- for a working tree on a portable device)
GIT
---
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 923aa49..b8bec71 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,6 +43,12 @@ unreleased) version of Git, that is available from the 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
+* link:v2.10.1/git.html[documentation for release 2.10.1]
+
+* release notes for
+ link:RelNotes/2.10.1.txt[2.10.1],
+ link:RelNotes/2.10.0.txt[2.10].
+
* link:v2.9.3/git.html[documentation for release 2.9.3]
* release notes for
@@ -1086,6 +1092,14 @@ of clones and fetches.
cloning of shallow repositories.
See `GIT_TRACE` for available trace output options.
+`GIT_TRACE_CURL`::
+ Enables a curl full trace dump of all incoming and outgoing data,
+ including descriptive information, of the git transport protocol.
+ This is similar to doing curl `--trace-ascii` on the command line.
+ This option overrides setting the `GIT_CURL_VERBOSE` environment
+ variable.
+ See `GIT_TRACE` for available trace output options.
+
`GIT_LITERAL_PATHSPECS`::
Setting this variable to `1` will cause Git to treat all
pathspecs literally, rather than as glob patterns. For example,
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 145dd10..7aff940 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the
repository. To control what line ending style is used in the working
directory, use the `eol` attribute for a single file and the
`core.eol` configuration variable for all text files.
+Note that `core.autocrlf` overrides `core.eol`
Set::
@@ -130,8 +131,9 @@ Unset::
Set to string value "auto"::
When `text` is set to "auto", the path is marked for automatic
- end-of-line normalization. If Git decides that the content is
- text, its line endings are normalized to LF on checkin.
+ end-of-line conversion. If Git decides that the content is
+ text, its line endings are converted to LF on checkin.
+ When the file has been committed with CRLF, no conversion is done.
Unspecified::
@@ -146,7 +148,7 @@ unspecified.
^^^^^
This attribute sets a specific line-ending style to be used in the
-working directory. It enables end-of-line normalization without any
+working directory. It enables end-of-line conversion without any
content checks, effectively setting the `text` attribute.
Set to string value "crlf"::
@@ -180,60 +182,51 @@ While Git normally leaves file contents alone, it can be configured to
normalize line endings to LF in the repository and, optionally, to
convert them to CRLF when files are checked out.
-Here is an example that will make Git normalize .txt, .vcproj and .sh
-files, ensure that .vcproj files have CRLF and .sh files have LF in
-the working directory, and prevent .jpg files from being normalized
-regardless of their content.
-
-------------------------
-*.txt text
-*.vcproj eol=crlf
-*.sh eol=lf
-*.jpg -text
-------------------------
-
-Other source code management systems normalize all text files in their
-repositories, and there are two ways to enable similar automatic
-normalization in Git.
-
If you simply want to have CRLF line endings in your working directory
regardless of the repository you are working with, you can set the
-config variable "core.autocrlf" without changing any attributes.
+config variable "core.autocrlf" without using any attributes.
------------------------
[core]
autocrlf = true
------------------------
-This does not force normalization of all text files, but does ensure
+This does not force normalization of text files, but does ensure
that text files that you introduce to the repository have their line
endings normalized to LF when they are added, and that files that are
already normalized in the repository stay normalized.
-If you want to interoperate with a source code management system that
-enforces end-of-line normalization, or you simply want all text files
-in your repository to be normalized, you should instead set the `text`
-attribute to "auto" for _all_ files.
+If you want to ensure that text files that any contributor introduces to
+the repository have their line endings normalized, you can set the
+`text` attribute to "auto" for _all_ files.
------------------------
* text=auto
------------------------
-This ensures that all files that Git considers to be text will have
-normalized (LF) line endings in the repository. The `core.eol`
-configuration variable controls which line endings Git will use for
-normalized files in your working directory; the default is to use the
-native line ending for your platform, or CRLF if `core.autocrlf` is
-set.
+The attributes allow a fine-grained control, how the line endings
+are converted.
+Here is an example that will make Git normalize .txt, .vcproj and .sh
+files, ensure that .vcproj files have CRLF and .sh files have LF in
+the working directory, and prevent .jpg files from being normalized
+regardless of their content.
-NOTE: When `text=auto` normalization is enabled in an existing
-repository, any text files containing CRLFs should be normalized. If
-they are not they will be normalized the next time someone tries to
-change them, causing unfortunate misattribution. From a clean working
-directory:
+------------------------
+* text=auto
+*.txt text
+*.vcproj text eol=crlf
+*.sh text eol=lf
+*.jpg -text
+------------------------
+
+NOTE: When `text=auto` conversion is enabled in a cross-platform
+project using push and pull to a central repository the text files
+containing CRLFs should be normalized.
+
+From a clean working directory:
-------------------------------------------------
-$ echo "* text=auto" >>.gitattributes
+$ echo "* text=auto" >.gitattributes
$ rm .git/index # Remove the index to force Git to
$ git reset # re-scan the working directory
$ git status # Show files that will be normalized
@@ -530,6 +523,8 @@ patterns are available:
- `csharp` suitable for source code in the C# language.
+- `css` suitable for cascading style sheets.
+
- `fortran` suitable for source code in the Fortran language.
- `fountain` suitable for Fountain documents.
diff --git a/Documentation/gitcvs-migration.txt b/Documentation/gitcvs-migration.txt
index b06e852..4c6143c 100644
--- a/Documentation/gitcvs-migration.txt
+++ b/Documentation/gitcvs-migration.txt
@@ -116,8 +116,12 @@ they create are writable and searchable by other group members.
Importing a CVS archive
-----------------------
+NOTE: These instructions use the `git-cvsimport` script which ships with
+git, but other importers may provide better results. See the note in
+linkgit:git-cvsimport[1] for other options.
+
First, install version 2.1 or higher of cvsps from
-http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
+https://github.com/andreyvit/cvsps[https://github.com/andreyvit/cvsps] and make
sure it is in your path. Then cd to a checked out CVS working directory
of the project you are interested in and run linkgit:git-cvsimport[1]:
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index d82e912..9565dc3 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -247,6 +247,15 @@ Both standard output and standard error output are forwarded to
'git send-pack' on the other end, so you can simply `echo` messages
for the user.
+The number of push options given on the command line of
+`git push --push-option=...` can be read from the environment
+variable `GIT_PUSH_OPTION_COUNT`, and the options themselves are
+found in `GIT_PUSH_OPTION_0`, `GIT_PUSH_OPTION_1`,...
+If it is negotiated to not use the push options phase, the
+environment variables will not be set. If the client selects
+to use push options, but doesn't transmit any, the count variable
+will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
+
[[update]]
update
~~~~~~
@@ -322,6 +331,15 @@ a sample script `post-receive-email` provided in the `contrib/hooks`
directory in Git distribution, which implements sending commit
emails.
+The number of push options given on the command line of
+`git push --push-option=...` can be read from the environment
+variable `GIT_PUSH_OPTION_COUNT`, and the options themselves are
+found in `GIT_PUSH_OPTION_0`, `GIT_PUSH_OPTION_1`,...
+If it is negotiated to not use the push options phase, the
+environment variables will not be set. If the client selects
+to use push options, but doesn't transmit any, the count variable
+will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
+
[[post-update]]
post-update
~~~~~~~~~~~
diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt
index a68d860..e382dd9 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.txt
@@ -70,7 +70,7 @@ linkgit:git-rev-list[1] for a complete list.
--left-right::
- Mark which side of a symmetric diff a commit is reachable
+ Mark which side of a symmetric difference a commit is reachable
from. Commits from the left side are prefixed with a `<`
symbol and those from the right with a `>` symbol.
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 07cdd73..10dcc08 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -79,6 +79,11 @@ submodule.<name>.ignore::
"--ignore-submodule" option. The 'git submodule' commands are not
affected by this setting.
+submodule.<name>.shallow::
+ When set to true, a clone of this submodule will be performed as a
+ shallow clone unless the user explicitly asks for a non-shallow
+ clone.
+
EXAMPLES
--------
diff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt
index e903eb7..27dec5b 100644
--- a/Documentation/gitrevisions.txt
+++ b/Documentation/gitrevisions.txt
@@ -15,9 +15,9 @@ DESCRIPTION
Many Git commands take revision parameters as arguments. Depending on
the command, they denote a specific commit or, for commands which
-walk the revision graph (such as linkgit:git-log[1]), all commits which can
-be reached from that commit. In the latter case one can also specify a
-range of revisions explicitly.
+walk the revision graph (such as linkgit:git-log[1]), all commits which are
+reachable from that commit. For commands that walk the revision graph one can
+also specify a range of revisions explicitly.
In addition, some Git commands (such as linkgit:git-show[1]) also take
revision parameters which denote other objects than commits, e.g. blobs
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index a79e350..e632089 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -246,13 +246,20 @@ $highlight_bin::
Note that 'highlight' feature must be set for gitweb to actually
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`
-or `%highlight_basename`, depending on whether you detect type of file
-based on extension (for example "sh") or on its basename (for example
-"Makefile"). The keys of these hashes are extension and basename,
-respectively, and value for given key is name of syntax to be passed via
-`--syntax <syntax>` to highlighter.
+*NOTE*: for a file to be highlighted, its syntax type must be detected
+and that syntax must be supported by "highlight". The default syntax
+detection is minimal, and there are many supported syntax types with no
+detection by default. There are three options for adding syntax
+detection. The first and second priority are `%highlight_basename` and
+`%highlight_ext`, which detect based on basename (the full filename, for
+example "Makefile") and extension (for example "sh"). The keys of these
+hashes are the basename and extension, respectively, and the value for a
+given key is the name of the syntax to be passed via `--syntax <syntax>`
+to "highlight". The last priority is the "highlight" configuration of
+`Shebang` regular expressions to detect the language based on the first
+line in the file, (for example, matching the line "#!/bin/bash"). See
+the highlight documentation and the default config at
+/etc/highlight/filetypes.conf for more details.
+
For example if repositories you are hosting use "phtml" extension for
PHP files, and you want to have correct syntax-highlighting for those
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 29b19b9..a942d57 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -147,8 +147,14 @@ endif::git-rev-list[]
"U" for a good signature with unknown validity and "N" for no signature
- '%GS': show the name of the signer for a signed commit
- '%GK': show the key used to sign a signed commit
-- '%gD': reflog selector, e.g., `refs/stash@{1}`
-- '%gd': shortened reflog selector, e.g., `stash@{1}`
+- '%gD': reflog selector, e.g., `refs/stash@{1}` or
+ `refs/stash@{2 minutes ago`}; the format follows the rules described
+ for the `-g` option. The portion before the `@` is the refname as
+ given on the command line (so `git log -g refs/heads/master` would
+ yield `refs/heads/master@{0}`).
+- '%gd': shortened reflog selector; same as `%gD`, but the refname
+ portion is shortened for human readability (so `refs/heads/master`
+ becomes just `master`).
- '%gn': reflog identity name
- '%gN': reflog identity name (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1])
@@ -166,7 +172,7 @@ endif::git-rev-list[]
respecting the `auto` settings of the former if we are going to a
terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
on the next placeholders until the color is switched again.
-- '%m': left, right or boundary mark
+- '%m': left (`<`), right (`>`) or boundary (`-`) mark
- '%n': newline
- '%%': a raw '%'
- '%x00': print a byte from a hex code
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index c5bd218..5da7cf5 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -225,7 +225,7 @@ excluded from the output.
--left-only::
--right-only::
- List only commits on the respective side of a symmetric range,
+ List only commits on the respective side of a symmetric difference,
i.e. only those which would be marked `<` resp. `>` by
`--left-right`.
+
@@ -252,10 +252,25 @@ list.
+
With `--pretty` format other than `oneline` (for obvious reasons),
this causes the output to have two extra lines of information
-taken from the reflog. By default, 'commit@\{Nth}' notation is
-used in the output. When the starting commit is specified as
-'commit@\{now}', output also uses 'commit@\{timestamp}' notation
-instead. Under `--pretty=oneline`, the commit message is
+taken from the reflog. The reflog designator in the output may be shown
+as `ref@{Nth}` (where `Nth` is the reverse-chronological index in the
+reflog) or as `ref@{timestamp}` (with the timestamp for that entry),
+depending on a few rules:
++
+--
+1. If the starting point is specified as `ref@{Nth}`, show the index
+format.
++
+2. If the starting point was specified as `ref@{now}`, show the
+timestamp format.
++
+3. If neither was used, but `--date` was given on the command line, show
+the timestamp in the format requested by `--date`.
++
+4. Otherwise, show the index format.
+--
++
+Under `--pretty=oneline`, the commit message is
prefixed with this information on the same line.
This option cannot be combined with `--reverse`.
See also linkgit:git-reflog[1].
@@ -274,6 +289,10 @@ ifdef::git-rev-list[]
Try to speed up the traversal using the pack bitmap index (if
one is available). Note that when traversing with `--objects`,
trees and blobs will not have their associated path printed.
+
+--progress=<header>::
+ Show progress reports on stderr as objects are considered. The
+ `<header>` text will be printed with each progress update.
endif::git-rev-list[]
--
@@ -638,8 +657,9 @@ avoid showing the commits from two parallel development track mixed
together.
--reverse::
- Output the commits in reverse order.
- Cannot be combined with `--walk-reflogs`.
+ Output the commits chosen to be shown (see Commit Limiting
+ section above) in reverse order. Cannot be combined with
+ `--walk-reflogs`.
Object Traversal
~~~~~~~~~~~~~~~~
@@ -710,8 +730,8 @@ include::pretty-options.txt[]
`iso-local`), the user's local time zone is used instead.
+
`--date=relative` shows dates relative to the current time,
-e.g. ``2 hours ago''. The `-local` option cannot be used with
-`--raw` or `--relative`.
+e.g. ``2 hours ago''. The `-local` option has no effect for
+`--date=relative`.
+
`--date=local` is an alias for `--date=default-local`.
+
@@ -731,7 +751,18 @@ format, often found in email messages.
+
`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format.
+
-`--date=raw` shows the date in the internal raw Git format `%s %z` format.
+`--date=raw` shows the date as seconds since the epoch (1970-01-01
+00:00:00 UTC), followed by a space, and then the timezone as an offset
+from UTC (a `+` or `-` with four digits; the first two are hours, and
+the second two are minutes). I.e., as if the timestamp were formatted
+with `strftime("%s %z")`).
+Note that the `-local` option does not affect the seconds-since-epoch
+value (which is always measured in UTC), but does switch the accompanying
+timezone value.
++
+`--date=unix` shows the date as a Unix epoch timestamp (seconds since
+1970). As with `--raw`, this is always in UTC and therefore `-local`
+has no effect.
+
`--date=format:...` feeds the format `...` to your system `strftime`.
Use `--date=format:%c` to show the date in your system locale's
@@ -766,7 +797,7 @@ ifdef::git-rev-list[]
endif::git-rev-list[]
--left-right::
- Mark which side of a symmetric diff a commit is reachable from.
+ Mark which side of a symmetric difference a commit is reachable from.
Commits from the left side are prefixed with `<` and those from
the right with `>`. If combined with `--boundary`, those
commits are prefixed with `-`.
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index abae363..ba11b9c 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -237,48 +237,81 @@ SPECIFYING RANGES
-----------------
History traversing commands such as `git log` operate on a set
-of commits, not just a single commit. To these commands,
-specifying a single revision with the notation described in the
-previous section means the set of commits reachable from that
-commit, following the commit ancestry chain.
-
-To exclude commits reachable from a commit, a prefix '{caret}'
-notation is used. E.g. '{caret}r1 r2' means commits reachable
-from 'r2' but exclude the ones reachable from 'r1'.
-
-This set operation appears so often that there is a shorthand
-for it. When you have two commits 'r1' and 'r2' (named according
-to the syntax explained in SPECIFYING REVISIONS above), you can ask
-for commits that are reachable from r2 excluding those that are reachable
-from r1 by '{caret}r1 r2' and it can be written as 'r1..r2'.
-
-A similar notation 'r1\...r2' is called symmetric difference
-of 'r1' and 'r2' and is defined as
-'r1 r2 --not $(git merge-base --all r1 r2)'.
-It is the set of commits that are reachable from either one of
-'r1' or 'r2' but not from both.
-
-In these two shorthands, you can omit one end and let it default to HEAD.
+of commits, not just a single commit.
+
+For these commands,
+specifying a single revision, using the notation described in the
+previous section, means the set of commits `reachable` from the given
+commit.
+
+A commit's reachable set is the commit itself and the commits in
+its ancestry chain.
+
+
+Commit Exclusions
+~~~~~~~~~~~~~~~~~
+
+'{caret}<rev>' (caret) Notation::
+ To exclude commits reachable from a commit, a prefix '{caret}'
+ notation is used. E.g. '{caret}r1 r2' means commits reachable
+ from 'r2' but exclude the ones reachable from 'r1' (i.e. 'r1' and
+ its ancestors).
+
+Dotted Range Notations
+~~~~~~~~~~~~~~~~~~~~~~
+
+The '..' (two-dot) Range Notation::
+ The '{caret}r1 r2' set operation appears so often that there is a shorthand
+ for it. When you have two commits 'r1' and 'r2' (named according
+ to the syntax explained in SPECIFYING REVISIONS above), you can ask
+ for commits that are reachable from r2 excluding those that are reachable
+ from r1 by '{caret}r1 r2' and it can be written as 'r1..r2'.
+
+The '...' (three dot) Symmetric Difference Notation::
+ A similar notation 'r1\...r2' is called symmetric difference
+ of 'r1' and 'r2' and is defined as
+ 'r1 r2 --not $(git merge-base --all r1 r2)'.
+ It is the set of commits that are reachable from either one of
+ 'r1' (left side) or 'r2' (right side) but not from both.
+
+In these two shorthand notations, you can omit one end and let it default to HEAD.
For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What
did I do since I forked from the origin branch?" Similarly, '..origin'
is a shorthand for 'HEAD..origin' and asks "What did the origin do since
I forked from them?" Note that '..' would mean 'HEAD..HEAD' which is an
empty range that is both reachable and unreachable from HEAD.
-Two other shorthands for naming a set that is formed by a commit
-and its parent commits exist. The 'r1{caret}@' notation means all
-parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
-all of its parents.
+Other <rev>{caret} Parent Shorthand Notations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Three other shorthands exist, particularly useful for merge commits,
+for naming a set that is formed by a commit and its parent commits.
+
+The 'r1{caret}@' notation means all parents of 'r1'.
+
+The 'r1{caret}!' notation includes commit 'r1' but excludes all of its parents.
+By itself, this notation denotes the single commit 'r1'.
+
+The '<rev>{caret}-{<n>}' notation includes '<rev>' but excludes the <n>th
+parent (i.e. a shorthand for '<rev>{caret}<n>..<rev>'), with '<n>' = 1 if
+not given. This is typically useful for merge commits where you
+can just pass '<commit>{caret}-' to get all the commits in the branch
+that was merged in merge commit '<commit>' (including '<commit>'
+itself).
+
+While '<rev>{caret}<n>' was about specifying a single commit parent, these
+three notations also consider its parents. For example you can say
+'HEAD{caret}2{caret}@', however you cannot say 'HEAD{caret}@{caret}2'.
-To summarize:
+Revision Range Summary
+----------------------
'<rev>'::
- Include commits that are reachable from (i.e. ancestors of)
- <rev>.
+ Include commits that are reachable from <rev> (i.e. <rev> and its
+ ancestors).
'{caret}<rev>'::
- Exclude commits that are reachable from (i.e. ancestors of)
- <rev>.
+ Exclude commits that are reachable from <rev> (i.e. <rev> and its
+ ancestors).
'<rev1>..<rev2>'::
Include commits that are reachable from <rev2> but exclude
@@ -300,16 +333,33 @@ To summarize:
as giving commit '<rev>' and then all its parents prefixed with
'{caret}' to exclude them (and their ancestors).
-Here are a handful of examples:
-
- D G H D
- D F G H I J D F
- ^G D H D
- ^D B E I J F B
- B..C C
- B...C G H D E B C
- ^D B C E I J F B C
- C I J F C
- C^@ I J F
- C^! C
- F^! D G H D F
+'<rev>{caret}-{<n>}', e.g. 'HEAD{caret}-, HEAD{caret}-2'::
+ Equivalent to '<rev>{caret}<n>..<rev>', with '<n>' = 1 if not
+ given.
+
+Here are a handful of examples using the Loeliger illustration above,
+with each step in the notation's expansion and selection carefully
+spelt out:
+
+ Args Expanded arguments Selected commits
+ D G H D
+ D F G H I J D F
+ ^G D H D
+ ^D B E I J F B
+ ^D B C E I J F B C
+ C I J F C
+ B..C = ^B C C
+ B...C = B ^F C G H D E B C
+ B^- = B^..B
+ = ^B^1 B E I J F B
+ C^@ = C^1
+ = F I J F
+ B^@ = B^1 B^2 B^3
+ = D E F D G H E F I J
+ C^! = C ^C^@
+ = C ^C^1
+ = C ^F C
+ B^! = B ^B^@
+ = B ^B^1 ^B^2 ^B^3
+ = B ^D ^E ^F B
+ F^! D = F ^I ^J D G H D F
diff --git a/Documentation/technical/api-sha1-array.txt b/Documentation/technical/api-sha1-array.txt
index 3e75497..dcc5294 100644
--- a/Documentation/technical/api-sha1-array.txt
+++ b/Documentation/technical/api-sha1-array.txt
@@ -38,16 +38,20 @@ Functions
`sha1_array_for_each_unique`::
Efficiently iterate over each unique element of the list,
executing the callback function for each one. If the array is
- not sorted, this function has the side effect of sorting it.
+ not sorted, this function has the side effect of sorting it. If
+ the callback returns a non-zero value, the iteration ends
+ immediately and the callback's return is propagated; otherwise,
+ 0 is returned.
Examples
--------
-----------------------------------------
-void print_callback(const unsigned char sha1[20],
+int print_callback(const unsigned char sha1[20],
void *data)
{
printf("%s\n", sha1_to_hex(sha1));
+ return 0; /* always continue */
}
void some_func(void)
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index d40ab65..736f389 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -454,7 +454,8 @@ The reference discovery phase is done nearly the same way as it is in the
fetching protocol. Each reference obj-id and name on the server is sent
in packet-line format to the client, followed by a flush-pkt. The only
real difference is that the capability listing is different - the only
-possible values are 'report-status', 'delete-refs' and 'ofs-delta'.
+possible values are 'report-status', 'delete-refs', 'ofs-delta' and
+'push-options'.
Reference Update Request and Packfile Transfer
----------------------------------------------
@@ -465,9 +466,10 @@ that it wants to update, it sends a line listing the obj-id currently on
the server, the obj-id the client would like to update it to and the name
of the reference.
-This list is followed by a flush-pkt and then the packfile that should
-contain all the objects that the server will need to complete the new
-references.
+This list is followed by a flush-pkt. Then the push options are transmitted
+one per packet followed by another flush-pkt. After that the packfile that
+should contain all the objects that the server will need to complete the new
+references will be sent.
----
update-request = *shallow ( command-list | push-cert ) [packfile]
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index eaab6b4..4c28d3a 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -253,6 +253,15 @@ atomic pushes. If the pushing client requests this capability, the server
will update the refs in one atomic transaction. Either all refs are
updated or none.
+push-options
+------------
+
+If the server sends the 'push-options' capability it is able to accept
+push options after the update commands have been sent, but before the
+packfile is streamed. If the pushing client requests this capability,
+the server will pass the options to the pre- and post- receive hooks
+that process this push request.
+
allow-tip-sha1-in-want
----------------------
diff --git a/Documentation/technical/protocol-common.txt b/Documentation/technical/protocol-common.txt
index bf30167..ecedb34 100644
--- a/Documentation/technical/protocol-common.txt
+++ b/Documentation/technical/protocol-common.txt
@@ -67,9 +67,9 @@ with non-binary data the same whether or not they contain the trailing
LF (stripping the LF if present, and not complaining when it is
missing).
-The maximum length of a pkt-line's data component is 65520 bytes.
-Implementations MUST NOT send pkt-line whose length exceeds 65524
-(65520 bytes of payload + 4 bytes of length data).
+The maximum length of a pkt-line's data component is 65516 bytes.
+Implementations MUST NOT send pkt-line whose length exceeds 65520
+(65516 bytes of payload + 4 bytes of length data).
Implementations SHOULD NOT send an empty pkt-line ("0004").
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 0011c3f..55e88b0 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.9.3
+DEF_VER=v2.10.0.GIT
LF='
'
diff --git a/Makefile b/Makefile
index 4579eab..d15bf8d 100644
--- a/Makefile
+++ b/Makefile
@@ -296,7 +296,13 @@ all::
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
#
-# Define NO_REGEX if you have no or inferior regex support in your C library.
+# Define OVERRIDE_STRDUP to override the libc version of strdup(3).
+# This is necessary when using a custom allocator in order to avoid
+# crashes due to allocation and free working on different 'heaps'.
+# It's defined automatically if USE_NED_ALLOCATOR is set.
+#
+# Define NO_REGEX if your C library lacks regex support with REG_STARTEND
+# feature.
#
# Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
# user.
@@ -351,9 +357,12 @@ all::
# Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not
# return NULL when it receives a bogus time_t.
#
-# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
+# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime.
+#
+# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC.
#
-# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC in librt.
+# Define NEEDS_LIBRT if your platform requires linking with librt (glibc version
+# before 2.17) for clock_gettime and CLOCK_MONOTONIC.
#
# Define USE_PARENS_AROUND_GETTEXT_N to "yes" if your compiler happily
# compiles the following initialization:
@@ -367,6 +376,14 @@ all::
# Define HAVE_BSD_SYSCTL if your platform has a BSD-compatible sysctl function.
#
# Define HAVE_GETDELIM if your system has the getdelim() function.
+#
+# Define PAGER_ENV to a SP separated VAR=VAL pairs to define
+# default environment variables to be passed when a pager is spawned, e.g.
+#
+# PAGER_ENV = LESS=FRX LV=-c
+#
+# to say "export LESS=FRX (and LV=-c) if the environment variable
+# LESS (and LV) is not set, respectively".
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -445,10 +462,12 @@ CURL_CONFIG = curl-config
PTHREAD_LIBS = -lpthread
PTHREAD_CFLAGS =
GCOV = gcov
+SPATCH = spatch
export TCL_PATH TCLTK_PATH
SPARSE_FLAGS =
+SPATCH_FLAGS = --all-includes
@@ -680,6 +699,7 @@ LIB_OBJS += abspath.o
LIB_OBJS += advice.o
LIB_OBJS += alias.o
LIB_OBJS += alloc.o
+LIB_OBJS += apply.o
LIB_OBJS += archive.o
LIB_OBJS += archive-tar.o
LIB_OBJS += archive-zip.o
@@ -718,6 +738,7 @@ LIB_OBJS += diff-lib.o
LIB_OBJS += diff-no-index.o
LIB_OBJS += diff.o
LIB_OBJS += dir.o
+LIB_OBJS += dir-iterator.o
LIB_OBJS += editor.o
LIB_OBJS += entry.o
LIB_OBJS += environment.o
@@ -751,6 +772,7 @@ LIB_OBJS += merge.o
LIB_OBJS += merge-blobs.o
LIB_OBJS += merge-recursive.o
LIB_OBJS += mergesort.o
+LIB_OBJS += mru.o
LIB_OBJS += name-hash.o
LIB_OBJS += notes.o
LIB_OBJS += notes-cache.o
@@ -782,6 +804,7 @@ LIB_OBJS += read-cache.o
LIB_OBJS += reflog-walk.o
LIB_OBJS += refs.o
LIB_OBJS += refs/files-backend.o
+LIB_OBJS += refs/iterator.o
LIB_OBJS += ref-filter.o
LIB_OBJS += remote.o
LIB_OBJS += replace_object.o
@@ -939,7 +962,7 @@ BUILTIN_OBJS += builtin/verify-tag.o
BUILTIN_OBJS += builtin/worktree.o
BUILTIN_OBJS += builtin/write-tree.o
-GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
+GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB)
EXTLIBS =
GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -1442,8 +1465,14 @@ ifdef NATIVE_CRLF
endif
ifdef USE_NED_ALLOCATOR
- COMPAT_CFLAGS += -Icompat/nedmalloc
- COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
+ COMPAT_CFLAGS += -Icompat/nedmalloc
+ COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
+ OVERRIDE_STRDUP = YesPlease
+endif
+
+ifdef OVERRIDE_STRDUP
+ COMPAT_CFLAGS += -DOVERRIDE_STRDUP
+ COMPAT_OBJS += compat/strdup.o
endif
ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
@@ -1465,13 +1494,16 @@ endif
ifdef HAVE_CLOCK_GETTIME
BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
- EXTLIBS += -lrt
endif
ifdef HAVE_CLOCK_MONOTONIC
BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
endif
+ifdef NEEDS_LIBRT
+ EXTLIBS += -lrt
+endif
+
ifdef HAVE_BSD_SYSCTL
BASIC_CFLAGS += -DHAVE_BSD_SYSCTL
endif
@@ -1492,6 +1524,10 @@ ifeq ($(PYTHON_PATH),)
NO_PYTHON = NoThanks
endif
+ifndef PAGER_ENV
+PAGER_ENV = LESS=FRX LV=-c
+endif
+
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
@@ -1572,7 +1608,15 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
DIFF_SQ = $(subst ','\'',$(DIFF))
PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
-LIBS = $(GITLIBS) $(EXTLIBS)
+# We must filter out any object files from $(GITLIBS),
+# as it is typically used like:
+#
+# foo: foo.o $(GITLIBS)
+# $(CC) $(filter %.o,$^) $(LIBS)
+#
+# where we use it as a dependency. Since we also pull object files
+# from the dependency list, that would make each entry appear twice.
+LIBS = $(filter-out %.o, $(GITLIBS)) $(EXTLIBS)
BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
$(COMPAT_CFLAGS)
@@ -1613,6 +1657,11 @@ ifdef DEFAULT_HELP_FORMAT
BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
endif
+PAGER_ENV_SQ = $(subst ','\'',$(PAGER_ENV))
+PAGER_ENV_CQ = "$(subst ",\",$(subst \,\\,$(PAGER_ENV)))"
+PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ))
+BASIC_CFLAGS += -DPAGER_ENV='$(PAGER_ENV_CQ_SQ)'
+
ALL_CFLAGS += $(BASIC_CFLAGS)
ALL_LDFLAGS += $(BASIC_LDFLAGS)
@@ -1708,8 +1757,8 @@ git.sp git.s git.o: EXTRA_CPPFLAGS = \
'-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
- $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) git.o \
- $(BUILTIN_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
+ $(filter %.o,$^) $(LIBS)
help.sp help.s help.o: common-cmds.h
@@ -1737,7 +1786,7 @@ common-cmds.h: $(wildcard Documentation/git-*.txt)
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):$(SANE_TEXT_GREP)
+ $(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV)
define cmd_munge_script
$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
@@ -1750,6 +1799,7 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-e 's|@@SANE_TEXT_GREP@@|$(SANE_TEXT_GREP)|g' \
+ -e 's|@@PAGER_ENV@@|$(PAGER_ENV_SQ)|g' \
$@.sh >$@+
endef
@@ -1902,6 +1952,7 @@ TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
$(XDIFF_OBJS) \
$(VCSSVN_OBJS) \
+ common-main.o \
git.o
ifndef NO_CURL
OBJECTS += http.o http-walker.o remote-curl.o
@@ -1993,7 +2044,7 @@ endif
ifdef USE_NED_ALLOCATOR
compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
- -DNDEBUG -DOVERRIDE_STRDUP -DREPLACE_SYSTEM_ALLOCATOR
+ -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR
compat/nedmalloc/nedmalloc.sp: SPARSE_FLAGS += -Wno-non-pointer-null
endif
@@ -2063,7 +2114,10 @@ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
--keyword=gettextln --keyword=eval_gettextln
XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
-LOCALIZED_SH = $(SCRIPT_SH) git-parse-remote.sh
+LOCALIZED_SH = $(SCRIPT_SH)
+LOCALIZED_SH += git-parse-remote.sh
+LOCALIZED_SH += git-rebase--interactive.sh
+LOCALIZED_SH += git-sh-setup.sh
LOCALIZED_PERL = $(SCRIPT_PERL)
ifdef XGETTEXT_INCLUDE_TESTS
@@ -2153,6 +2207,7 @@ GIT-BUILD-OPTIONS: FORCE
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+
@echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
+ @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
ifdef TEST_OUTPUT_DIRECTORY
@echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
endif
@@ -2256,6 +2311,18 @@ check: common-cmds.h
exit 1; \
fi
+C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ))
+%.cocci.patch: %.cocci $(C_SOURCES)
+ @echo ' ' SPATCH $<; \
+ for f in $(C_SOURCES); do \
+ $(SPATCH) --sp-file $< $$f $(SPATCH_FLAGS); \
+ done >$@ 2>$@.log; \
+ if test -s $@; \
+ then \
+ echo ' ' SPATCH result: $@; \
+ fi
+coccicheck: $(patsubst %.cocci,%.cocci.patch,$(wildcard contrib/coccinelle/*.cocci))
+
### Installation rules
ifneq ($(filter /%,$(firstword $(template_dir))),)
@@ -2447,6 +2514,7 @@ clean: profile-clean coverage-clean
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
+ $(RM) contrib/coccinelle/*.cocci.patch*
$(MAKE) -C Documentation/ clean
ifndef NO_PERL
$(MAKE) -C gitweb clean
diff --git a/RelNotes b/RelNotes
index 779efe8..b54330f 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.9.3.txt \ No newline at end of file
+Documentation/RelNotes/2.11.0.txt \ No newline at end of file
diff --git a/advice.c b/advice.c
index 4dc5cf1..b84ae49 100644
--- a/advice.c
+++ b/advice.c
@@ -79,7 +79,20 @@ int git_default_advice_config(const char *var, const char *value)
int error_resolve_conflict(const char *me)
{
- error("%s is not possible because you have unmerged files.", me);
+ if (!strcmp(me, "cherry-pick"))
+ error(_("Cherry-picking is not possible because you have unmerged files."));
+ else if (!strcmp(me, "commit"))
+ error(_("Committing is not possible because you have unmerged files."));
+ else if (!strcmp(me, "merge"))
+ error(_("Merging is not possible because you have unmerged files."));
+ else if (!strcmp(me, "pull"))
+ error(_("Pulling is not possible because you have unmerged files."));
+ else if (!strcmp(me, "revert"))
+ error(_("Reverting is not possible because you have unmerged files."));
+ else
+ error(_("It is not possible to %s because you have unmerged files."),
+ me);
+
if (advice_resolve_conflict)
/*
* Message used both when 'git commit' fails and when
@@ -93,7 +106,7 @@ int error_resolve_conflict(const char *me)
void NORETURN die_resolve_conflict(const char *me)
{
error_resolve_conflict(me);
- die("Exiting because of an unresolved conflict.");
+ die(_("Exiting because of an unresolved conflict."));
}
void NORETURN die_conclude_merge(void)
@@ -106,14 +119,14 @@ void NORETURN die_conclude_merge(void)
void detach_advice(const char *new_name)
{
- const char fmt[] =
- "Note: checking out '%s'.\n\n"
+ 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";
+ " git checkout -b <new-branch-name>\n\n");
fprintf(stderr, fmt, new_name);
}
diff --git a/apply.c b/apply.c
new file mode 100644
index 0000000..b03d274
--- /dev/null
+++ b/apply.c
@@ -0,0 +1,4986 @@
+/*
+ * apply.c
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ *
+ * This applies patches on top of some (arbitrary) version of the SCM.
+ *
+ */
+
+#include "cache.h"
+#include "blob.h"
+#include "delta.h"
+#include "diff.h"
+#include "dir.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
+#include "lockfile.h"
+#include "parse-options.h"
+#include "quote.h"
+#include "rerere.h"
+#include "apply.h"
+
+static void git_apply_config(void)
+{
+ git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
+ git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+ git_config(git_default_config, NULL);
+}
+
+static int parse_whitespace_option(struct apply_state *state, const char *option)
+{
+ if (!option) {
+ state->ws_error_action = warn_on_ws_error;
+ return 0;
+ }
+ if (!strcmp(option, "warn")) {
+ state->ws_error_action = warn_on_ws_error;
+ return 0;
+ }
+ if (!strcmp(option, "nowarn")) {
+ state->ws_error_action = nowarn_ws_error;
+ return 0;
+ }
+ if (!strcmp(option, "error")) {
+ state->ws_error_action = die_on_ws_error;
+ return 0;
+ }
+ if (!strcmp(option, "error-all")) {
+ state->ws_error_action = die_on_ws_error;
+ state->squelch_whitespace_errors = 0;
+ return 0;
+ }
+ if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
+ state->ws_error_action = correct_ws_error;
+ return 0;
+ }
+ return error(_("unrecognized whitespace option '%s'"), option);
+}
+
+static int parse_ignorewhitespace_option(struct apply_state *state,
+ const char *option)
+{
+ if (!option || !strcmp(option, "no") ||
+ !strcmp(option, "false") || !strcmp(option, "never") ||
+ !strcmp(option, "none")) {
+ state->ws_ignore_action = ignore_ws_none;
+ return 0;
+ }
+ if (!strcmp(option, "change")) {
+ state->ws_ignore_action = ignore_ws_change;
+ return 0;
+ }
+ return error(_("unrecognized whitespace ignore option '%s'"), option);
+}
+
+int init_apply_state(struct apply_state *state,
+ const char *prefix,
+ struct lock_file *lock_file)
+{
+ memset(state, 0, sizeof(*state));
+ state->prefix = prefix;
+ state->prefix_length = state->prefix ? strlen(state->prefix) : 0;
+ state->lock_file = lock_file;
+ state->newfd = -1;
+ state->apply = 1;
+ state->line_termination = '\n';
+ state->p_value = 1;
+ state->p_context = UINT_MAX;
+ state->squelch_whitespace_errors = 5;
+ state->ws_error_action = warn_on_ws_error;
+ state->ws_ignore_action = ignore_ws_none;
+ state->linenr = 1;
+ string_list_init(&state->fn_table, 0);
+ string_list_init(&state->limit_by_name, 0);
+ string_list_init(&state->symlink_changes, 0);
+ strbuf_init(&state->root, 0);
+
+ git_apply_config();
+ if (apply_default_whitespace && parse_whitespace_option(state, apply_default_whitespace))
+ return -1;
+ if (apply_default_ignorewhitespace && parse_ignorewhitespace_option(state, apply_default_ignorewhitespace))
+ return -1;
+ return 0;
+}
+
+void clear_apply_state(struct apply_state *state)
+{
+ string_list_clear(&state->limit_by_name, 0);
+ string_list_clear(&state->symlink_changes, 0);
+ strbuf_release(&state->root);
+
+ /* &state->fn_table is cleared at the end of apply_patch() */
+}
+
+static void mute_routine(const char *msg, va_list params)
+{
+ /* do nothing */
+}
+
+int check_apply_state(struct apply_state *state, int force_apply)
+{
+ int is_not_gitdir = !startup_info->have_repository;
+
+ if (state->apply_with_reject && state->threeway)
+ return error("--reject and --3way cannot be used together.");
+ if (state->cached && state->threeway)
+ return error("--cached and --3way cannot be used together.");
+ if (state->threeway) {
+ if (is_not_gitdir)
+ return error(_("--3way outside a repository"));
+ state->check_index = 1;
+ }
+ if (state->apply_with_reject) {
+ state->apply = 1;
+ if (state->apply_verbosity == verbosity_normal)
+ state->apply_verbosity = verbosity_verbose;
+ }
+ if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor))
+ state->apply = 0;
+ if (state->check_index && is_not_gitdir)
+ return error(_("--index outside a repository"));
+ if (state->cached) {
+ if (is_not_gitdir)
+ return error(_("--cached outside a repository"));
+ state->check_index = 1;
+ }
+ if (state->check_index)
+ state->unsafe_paths = 0;
+ if (!state->lock_file)
+ return error("BUG: state->lock_file should not be NULL");
+
+ if (state->apply_verbosity <= verbosity_silent) {
+ state->saved_error_routine = get_error_routine();
+ state->saved_warn_routine = get_warn_routine();
+ set_error_routine(mute_routine);
+ set_warn_routine(mute_routine);
+ }
+
+ return 0;
+}
+
+static void set_default_whitespace_mode(struct apply_state *state)
+{
+ if (!state->whitespace_option && !apply_default_whitespace)
+ state->ws_error_action = (state->apply ? warn_on_ws_error : nowarn_ws_error);
+}
+
+/*
+ * This represents one "hunk" from a patch, starting with
+ * "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
+ * patch text is pointed at by patch, and its byte length
+ * is stored in size. leading and trailing are the number
+ * of context lines.
+ */
+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 linenr;
+ struct fragment *next;
+};
+
+/*
+ * When dealing with a binary patch, we reuse "leading" field
+ * to store the type of the binary hunk, either deflated "delta"
+ * or deflated "literal".
+ */
+#define binary_patch_method leading
+#define BINARY_DELTA_DEFLATED 1
+#define BINARY_LITERAL_DEFLATED 2
+
+/*
+ * This represents a "patch" to a file, both metainfo changes
+ * such as creation/deletion, filemode and content changes represented
+ * as a series of fragments.
+ */
+struct patch {
+ char *new_name, *old_name, *def_name;
+ unsigned int old_mode, new_mode;
+ int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */
+ int rejected;
+ unsigned ws_rule;
+ int lines_added, lines_deleted;
+ int score;
+ unsigned int is_toplevel_relative:1;
+ unsigned int inaccurate_eof:1;
+ unsigned int is_binary:1;
+ 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 */
+ struct object_id threeway_stage[3];
+};
+
+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
+ * one), and its contents hashes to 'hash'.
+ */
+struct line {
+ size_t len;
+ unsigned hash : 24;
+ unsigned flag : 8;
+#define LINE_COMMON 1
+#define LINE_PATCHED 2
+};
+
+/*
+ * This represents a "file", which is an array of "lines".
+ */
+struct image {
+ char *buf;
+ size_t len;
+ size_t nr;
+ size_t alloc;
+ struct line *line_allocated;
+ struct line *line;
+};
+
+static uint32_t hash_line(const char *cp, size_t len)
+{
+ size_t i;
+ uint32_t h;
+ for (i = 0, h = 0; i < len; i++) {
+ if (!isspace(cp[i])) {
+ h = h * 3 + (cp[i] & 0xff);
+ }
+ }
+ return h;
+}
+
+/*
+ * Compare lines s1 of length n1 and s2 of length n2, ignoring
+ * whitespace difference. Returns 1 if they match, 0 otherwise
+ */
+static int fuzzy_matchlines(const char *s1, size_t n1,
+ const char *s2, size_t n2)
+{
+ const char *last1 = s1 + n1 - 1;
+ const char *last2 = s2 + n2 - 1;
+ int result = 0;
+
+ /* ignore line endings */
+ while ((*last1 == '\r') || (*last1 == '\n'))
+ last1--;
+ while ((*last2 == '\r') || (*last2 == '\n'))
+ last2--;
+
+ /* skip leading whitespaces, if both begin with whitespace */
+ if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) {
+ while (isspace(*s1) && (s1 <= last1))
+ s1++;
+ while (isspace(*s2) && (s2 <= last2))
+ s2++;
+ }
+ /* early return if both lines are empty */
+ if ((s1 > last1) && (s2 > last2))
+ return 1;
+ while (!result) {
+ result = *s1++ - *s2++;
+ /*
+ * Skip whitespace inside. We check for whitespace on
+ * both buffers because we don't want "a b" to match
+ * "ab"
+ */
+ if (isspace(*s1) && isspace(*s2)) {
+ while (isspace(*s1) && s1 <= last1)
+ s1++;
+ while (isspace(*s2) && s2 <= last2)
+ s2++;
+ }
+ /*
+ * If we reached the end on one side only,
+ * lines don't match
+ */
+ if (
+ ((s2 > last2) && (s1 <= last1)) ||
+ ((s1 > last1) && (s2 <= last2)))
+ return 0;
+ if ((s1 > last1) && (s2 > last2))
+ break;
+ }
+
+ return !result;
+}
+
+static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)
+{
+ ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);
+ img->line_allocated[img->nr].len = len;
+ img->line_allocated[img->nr].hash = hash_line(bol, len);
+ img->line_allocated[img->nr].flag = flag;
+ 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)
+{
+ const char *cp, *ep;
+
+ memset(image, 0, sizeof(*image));
+ image->buf = buf;
+ image->len = len;
+
+ if (!prepare_linetable)
+ return;
+
+ ep = image->buf + image->len;
+ cp = image->buf;
+ while (cp < ep) {
+ const char *next;
+ for (next = cp; next < ep && *next != '\n'; next++)
+ ;
+ if (next < ep)
+ next++;
+ add_line_info(image, cp, next - cp, 0);
+ cp = next;
+ }
+ image->line = image->line_allocated;
+}
+
+static void clear_image(struct image *image)
+{
+ free(image->buf);
+ free(image->line_allocated);
+ memset(image, 0, sizeof(*image));
+}
+
+/* fmt must contain _one_ %s and no other substitution */
+static void say_patch_name(FILE *output, const char *fmt, struct patch *patch)
+{
+ 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, &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, &sb, NULL, 0);
+ }
+ fprintf(output, fmt, sb.buf);
+ fputc('\n', output);
+ strbuf_release(&sb);
+}
+
+#define SLOP (16)
+
+static int read_patch_file(struct strbuf *sb, int fd)
+{
+ if (strbuf_read(sb, fd, 0) < 0)
+ return error_errno("git apply: failed to read");
+
+ /*
+ * Make sure that we have some slop in the buffer
+ * so that we can do speculative "memcmp" etc, and
+ * see to it that it is NUL-filled.
+ */
+ strbuf_grow(sb, SLOP);
+ memset(sb->buf + sb->len, 0, SLOP);
+ return 0;
+}
+
+static unsigned long linelen(const char *buffer, unsigned long size)
+{
+ unsigned long len = 0;
+ while (size--) {
+ len++;
+ if (*buffer++ == '\n')
+ break;
+ }
+ return len;
+}
+
+static int is_dev_null(const char *str)
+{
+ return skip_prefix(str, "/dev/null", &str) && isspace(*str);
+}
+
+#define TERM_SPACE 1
+#define TERM_TAB 2
+
+static int name_terminate(int c, int terminate)
+{
+ if (c == ' ' && !(terminate & TERM_SPACE))
+ return 0;
+ if (c == '\t' && !(terminate & TERM_TAB))
+ return 0;
+
+ return 1;
+}
+
+/* remove double slashes to make --index work with such filenames */
+static char *squash_slash(char *name)
+{
+ int i = 0, j = 0;
+
+ if (!name)
+ return NULL;
+
+ while (name[i]) {
+ if ((name[j++] = name[i++]) == '/')
+ while (name[i] == '/')
+ i++;
+ }
+ name[j] = '\0';
+ return name;
+}
+
+static char *find_name_gnu(struct apply_state *state,
+ const char *line,
+ const char *def,
+ int p_value)
+{
+ struct strbuf name = STRBUF_INIT;
+ char *cp;
+
+ /*
+ * Proposed "new-style" GNU patch/diff format; see
+ * http://marc.info/?l=git&m=112927316408690&w=2
+ */
+ if (unquote_c_style(&name, line, NULL)) {
+ strbuf_release(&name);
+ return NULL;
+ }
+
+ for (cp = name.buf; p_value; p_value--) {
+ cp = strchr(cp, '/');
+ if (!cp) {
+ strbuf_release(&name);
+ return NULL;
+ }
+ cp++;
+ }
+
+ strbuf_remove(&name, 0, cp - name.buf);
+ if (state->root.len)
+ strbuf_insert(&name, 0, state->root.buf, state->root.len);
+ return squash_slash(strbuf_detach(&name, NULL));
+}
+
+static size_t sane_tz_len(const char *line, size_t len)
+{
+ const char *tz, *p;
+
+ if (len < strlen(" +0500") || line[len-strlen(" +0500")] != ' ')
+ return 0;
+ tz = line + len - strlen(" +0500");
+
+ if (tz[1] != '+' && tz[1] != '-')
+ return 0;
+
+ for (p = tz + 2; p != line + len; p++)
+ if (!isdigit(*p))
+ return 0;
+
+ return line + len - tz;
+}
+
+static size_t tz_with_colon_len(const char *line, size_t len)
+{
+ const char *tz, *p;
+
+ if (len < strlen(" +08:00") || line[len - strlen(":00")] != ':')
+ return 0;
+ tz = line + len - strlen(" +08:00");
+
+ if (tz[0] != ' ' || (tz[1] != '+' && tz[1] != '-'))
+ return 0;
+ p = tz + 2;
+ if (!isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+ !isdigit(*p++) || !isdigit(*p++))
+ return 0;
+
+ return line + len - tz;
+}
+
+static size_t date_len(const char *line, size_t len)
+{
+ const char *date, *p;
+
+ if (len < strlen("72-02-05") || line[len-strlen("-05")] != '-')
+ return 0;
+ p = date = line + len - strlen("72-02-05");
+
+ if (!isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+ !isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+ !isdigit(*p++) || !isdigit(*p++)) /* Not a date. */
+ return 0;
+
+ if (date - line >= strlen("19") &&
+ isdigit(date[-1]) && isdigit(date[-2])) /* 4-digit year */
+ date -= strlen("19");
+
+ return line + len - date;
+}
+
+static size_t short_time_len(const char *line, size_t len)
+{
+ const char *time, *p;
+
+ if (len < strlen(" 07:01:32") || line[len-strlen(":32")] != ':')
+ return 0;
+ p = time = line + len - strlen(" 07:01:32");
+
+ /* Permit 1-digit hours? */
+ if (*p++ != ' ' ||
+ !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+ !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+ !isdigit(*p++) || !isdigit(*p++)) /* Not a time. */
+ return 0;
+
+ return line + len - time;
+}
+
+static size_t fractional_time_len(const char *line, size_t len)
+{
+ const char *p;
+ size_t n;
+
+ /* Expected format: 19:41:17.620000023 */
+ if (!len || !isdigit(line[len - 1]))
+ return 0;
+ p = line + len - 1;
+
+ /* Fractional seconds. */
+ while (p > line && isdigit(*p))
+ p--;
+ if (*p != '.')
+ return 0;
+
+ /* Hours, minutes, and whole seconds. */
+ n = short_time_len(line, p - line);
+ if (!n)
+ return 0;
+
+ return line + len - p + n;
+}
+
+static size_t trailing_spaces_len(const char *line, size_t len)
+{
+ const char *p;
+
+ /* Expected format: ' ' x (1 or more) */
+ if (!len || line[len - 1] != ' ')
+ return 0;
+
+ p = line + len;
+ while (p != line) {
+ p--;
+ if (*p != ' ')
+ return line + len - (p + 1);
+ }
+
+ /* All spaces! */
+ return len;
+}
+
+static size_t diff_timestamp_len(const char *line, size_t len)
+{
+ const char *end = line + len;
+ size_t n;
+
+ /*
+ * Posix: 2010-07-05 19:41:17
+ * GNU: 2010-07-05 19:41:17.620000023 -0500
+ */
+
+ if (!isdigit(end[-1]))
+ return 0;
+
+ n = sane_tz_len(line, end - line);
+ if (!n)
+ n = tz_with_colon_len(line, end - line);
+ end -= n;
+
+ n = short_time_len(line, end - line);
+ if (!n)
+ n = fractional_time_len(line, end - line);
+ end -= n;
+
+ n = date_len(line, end - line);
+ if (!n) /* No date. Too bad. */
+ return 0;
+ end -= n;
+
+ if (end == line) /* No space before date. */
+ return 0;
+ if (end[-1] == '\t') { /* Success! */
+ end--;
+ return line + len - end;
+ }
+ if (end[-1] != ' ') /* No space before date. */
+ return 0;
+
+ /* Whitespace damage. */
+ end -= trailing_spaces_len(line, end - line);
+ return line + len - end;
+}
+
+static char *find_name_common(struct apply_state *state,
+ const char *line,
+ const char *def,
+ int p_value,
+ const char *end,
+ int terminate)
+{
+ int len;
+ const char *start = NULL;
+
+ if (p_value == 0)
+ start = line;
+ while (line != end) {
+ char c = *line;
+
+ if (!end && isspace(c)) {
+ if (c == '\n')
+ break;
+ if (name_terminate(c, terminate))
+ break;
+ }
+ line++;
+ if (c == '/' && !--p_value)
+ start = line;
+ }
+ if (!start)
+ return squash_slash(xstrdup_or_null(def));
+ len = line - start;
+ if (!len)
+ return squash_slash(xstrdup_or_null(def));
+
+ /*
+ * Generally we prefer the shorter name, especially
+ * if the other one is just a variation of that with
+ * something else tacked on to the end (ie "file.orig"
+ * or "file~").
+ */
+ if (def) {
+ int deflen = strlen(def);
+ if (deflen < len && !strncmp(start, def, deflen))
+ return squash_slash(xstrdup(def));
+ }
+
+ if (state->root.len) {
+ char *ret = xstrfmt("%s%.*s", state->root.buf, len, start);
+ return squash_slash(ret);
+ }
+
+ return squash_slash(xmemdupz(start, len));
+}
+
+static char *find_name(struct apply_state *state,
+ const char *line,
+ char *def,
+ int p_value,
+ int terminate)
+{
+ if (*line == '"') {
+ char *name = find_name_gnu(state, line, def, p_value);
+ if (name)
+ return name;
+ }
+
+ return find_name_common(state, line, def, p_value, NULL, terminate);
+}
+
+static char *find_name_traditional(struct apply_state *state,
+ const char *line,
+ char *def,
+ int p_value)
+{
+ size_t len;
+ size_t date_len;
+
+ if (*line == '"') {
+ char *name = find_name_gnu(state, line, def, p_value);
+ if (name)
+ return name;
+ }
+
+ len = strchrnul(line, '\n') - line;
+ date_len = diff_timestamp_len(line, len);
+ if (!date_len)
+ return find_name_common(state, line, def, p_value, NULL, TERM_TAB);
+ len -= date_len;
+
+ return find_name_common(state, line, def, p_value, line + len, 0);
+}
+
+static int count_slashes(const char *cp)
+{
+ int cnt = 0;
+ char ch;
+
+ while ((ch = *cp++))
+ if (ch == '/')
+ cnt++;
+ return cnt;
+}
+
+/*
+ * Given the string after "--- " or "+++ ", guess the appropriate
+ * p_value for the given patch.
+ */
+static int guess_p_value(struct apply_state *state, const char *nameline)
+{
+ char *name, *cp;
+ int val = -1;
+
+ if (is_dev_null(nameline))
+ return -1;
+ name = find_name_traditional(state, nameline, NULL, 0);
+ if (!name)
+ return -1;
+ cp = strchr(name, '/');
+ if (!cp)
+ val = 0;
+ else if (state->prefix) {
+ /*
+ * Does it begin with "a/$our-prefix" and such? Then this is
+ * very likely to apply to our directory.
+ */
+ if (!strncmp(name, state->prefix, state->prefix_length))
+ val = count_slashes(state->prefix);
+ else {
+ cp++;
+ if (!strncmp(cp, state->prefix, state->prefix_length))
+ val = count_slashes(state->prefix) + 1;
+ }
+ }
+ free(name);
+ return val;
+}
+
+/*
+ * Does the ---/+++ line have the POSIX timestamp after the last HT?
+ * GNU diff puts epoch there to signal a creation/deletion event. Is
+ * this such a timestamp?
+ */
+static int has_epoch_timestamp(const char *nameline)
+{
+ /*
+ * We are only interested in epoch timestamp; any non-zero
+ * fraction cannot be one, hence "(\.0+)?" in the regexp below.
+ * For the same reason, the date must be either 1969-12-31 or
+ * 1970-01-01, and the seconds part must be "00".
+ */
+ const char stamp_regexp[] =
+ "^(1969-12-31|1970-01-01)"
+ " "
+ "[0-2][0-9]:[0-5][0-9]:00(\\.0+)?"
+ " "
+ "([-+][0-2][0-9]:?[0-5][0-9])\n";
+ const char *timestamp = NULL, *cp, *colon;
+ static regex_t *stamp;
+ regmatch_t m[10];
+ int zoneoffset;
+ int hourminute;
+ int status;
+
+ for (cp = nameline; *cp != '\n'; cp++) {
+ if (*cp == '\t')
+ timestamp = cp + 1;
+ }
+ if (!timestamp)
+ return 0;
+ if (!stamp) {
+ stamp = xmalloc(sizeof(*stamp));
+ if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
+ warning(_("Cannot prepare timestamp regexp %s"),
+ stamp_regexp);
+ return 0;
+ }
+ }
+
+ status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
+ if (status) {
+ if (status != REG_NOMATCH)
+ warning(_("regexec returned %d for input: %s"),
+ status, timestamp);
+ return 0;
+ }
+
+ zoneoffset = strtol(timestamp + m[3].rm_so + 1, (char **) &colon, 10);
+ if (*colon == ':')
+ zoneoffset = zoneoffset * 60 + strtol(colon + 1, NULL, 10);
+ else
+ zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
+ if (timestamp[m[3].rm_so] == '-')
+ zoneoffset = -zoneoffset;
+
+ /*
+ * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
+ * (west of GMT) or 1970-01-01 (east of GMT)
+ */
+ if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) ||
+ (0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10)))
+ return 0;
+
+ hourminute = (strtol(timestamp + 11, NULL, 10) * 60 +
+ strtol(timestamp + 14, NULL, 10) -
+ zoneoffset);
+
+ return ((zoneoffset < 0 && hourminute == 1440) ||
+ (0 <= zoneoffset && !hourminute));
+}
+
+/*
+ * Get the name etc info from the ---/+++ lines of a traditional patch header
+ *
+ * FIXME! The end-of-filename heuristics are kind of screwy. For existing
+ * files, we can happily check the index for a match, but for creating a
+ * new file we should try to match whatever "patch" does. I have no idea.
+ */
+static int parse_traditional_patch(struct apply_state *state,
+ const char *first,
+ const char *second,
+ struct patch *patch)
+{
+ char *name;
+
+ first += 4; /* skip "--- " */
+ second += 4; /* skip "+++ " */
+ if (!state->p_value_known) {
+ int p, q;
+ p = guess_p_value(state, first);
+ q = guess_p_value(state, second);
+ if (p < 0) p = q;
+ if (0 <= p && p == q) {
+ state->p_value = p;
+ state->p_value_known = 1;
+ }
+ }
+ if (is_dev_null(first)) {
+ patch->is_new = 1;
+ patch->is_delete = 0;
+ name = find_name_traditional(state, second, NULL, state->p_value);
+ patch->new_name = name;
+ } else if (is_dev_null(second)) {
+ patch->is_new = 0;
+ patch->is_delete = 1;
+ name = find_name_traditional(state, first, NULL, state->p_value);
+ patch->old_name = name;
+ } else {
+ char *first_name;
+ first_name = find_name_traditional(state, first, NULL, state->p_value);
+ name = find_name_traditional(state, second, first_name, state->p_value);
+ free(first_name);
+ if (has_epoch_timestamp(first)) {
+ patch->is_new = 1;
+ patch->is_delete = 0;
+ patch->new_name = name;
+ } else if (has_epoch_timestamp(second)) {
+ patch->is_new = 0;
+ patch->is_delete = 1;
+ patch->old_name = name;
+ } else {
+ patch->old_name = name;
+ patch->new_name = xstrdup_or_null(name);
+ }
+ }
+ if (!name)
+ return error(_("unable to find filename in patch at line %d"), state->linenr);
+
+ return 0;
+}
+
+static int gitdiff_hdrend(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ return 1;
+}
+
+/*
+ * We're anal about diff header consistency, to make
+ * sure that we don't end up having strange ambiguous
+ * patches floating around.
+ *
+ * As a result, gitdiff_{old|new}name() will check
+ * their names against any previous information, just
+ * to make sure..
+ */
+#define DIFF_OLD_NAME 0
+#define DIFF_NEW_NAME 1
+
+static int gitdiff_verify_name(struct apply_state *state,
+ const char *line,
+ int isnull,
+ char **name,
+ int side)
+{
+ if (!*name && !isnull) {
+ *name = find_name(state, line, NULL, state->p_value, TERM_TAB);
+ return 0;
+ }
+
+ if (*name) {
+ int len = strlen(*name);
+ char *another;
+ if (isnull)
+ return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
+ *name, state->linenr);
+ another = find_name(state, line, NULL, state->p_value, TERM_TAB);
+ if (!another || memcmp(another, *name, len + 1)) {
+ free(another);
+ return error((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"), state->linenr);
+ }
+ free(another);
+ } else {
+ /* expect "/dev/null" */
+ if (memcmp("/dev/null", line, 9) || line[9] != '\n')
+ return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
+ }
+
+ return 0;
+}
+
+static int gitdiff_oldname(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ return gitdiff_verify_name(state, line,
+ patch->is_new, &patch->old_name,
+ DIFF_OLD_NAME);
+}
+
+static int gitdiff_newname(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ return gitdiff_verify_name(state, line,
+ patch->is_delete, &patch->new_name,
+ DIFF_NEW_NAME);
+}
+
+static int gitdiff_oldmode(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->old_mode = strtoul(line, NULL, 8);
+ return 0;
+}
+
+static int gitdiff_newmode(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->new_mode = strtoul(line, NULL, 8);
+ return 0;
+}
+
+static int gitdiff_delete(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->is_delete = 1;
+ free(patch->old_name);
+ patch->old_name = xstrdup_or_null(patch->def_name);
+ return gitdiff_oldmode(state, line, patch);
+}
+
+static int gitdiff_newfile(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->is_new = 1;
+ free(patch->new_name);
+ patch->new_name = xstrdup_or_null(patch->def_name);
+ return gitdiff_newmode(state, line, patch);
+}
+
+static int gitdiff_copysrc(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->is_copy = 1;
+ free(patch->old_name);
+ patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+ return 0;
+}
+
+static int gitdiff_copydst(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->is_copy = 1;
+ free(patch->new_name);
+ patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+ return 0;
+}
+
+static int gitdiff_renamesrc(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->is_rename = 1;
+ free(patch->old_name);
+ patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+ return 0;
+}
+
+static int gitdiff_renamedst(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ patch->is_rename = 1;
+ free(patch->new_name);
+ patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+ return 0;
+}
+
+static int gitdiff_similarity(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ unsigned long val = strtoul(line, NULL, 10);
+ if (val <= 100)
+ patch->score = val;
+ return 0;
+}
+
+static int gitdiff_dissimilarity(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ unsigned long val = strtoul(line, NULL, 10);
+ if (val <= 100)
+ patch->score = val;
+ return 0;
+}
+
+static int gitdiff_index(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ /*
+ * index line is N hexadecimal, "..", N hexadecimal,
+ * and optional space with octal mode.
+ */
+ const char *ptr, *eol;
+ int len;
+
+ ptr = strchr(line, '.');
+ if (!ptr || ptr[1] != '.' || 40 < ptr - line)
+ return 0;
+ len = ptr - line;
+ memcpy(patch->old_sha1_prefix, line, len);
+ patch->old_sha1_prefix[len] = 0;
+
+ line = ptr + 2;
+ ptr = strchr(line, ' ');
+ eol = strchrnul(line, '\n');
+
+ if (!ptr || eol < ptr)
+ ptr = eol;
+ len = ptr - line;
+
+ if (40 < len)
+ return 0;
+ memcpy(patch->new_sha1_prefix, line, len);
+ patch->new_sha1_prefix[len] = 0;
+ if (*ptr == ' ')
+ patch->old_mode = strtoul(ptr+1, NULL, 8);
+ return 0;
+}
+
+/*
+ * This is normal for a diff that doesn't change anything: we'll fall through
+ * into the next diff. Tell the parser to break out.
+ */
+static int gitdiff_unrecognized(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
+{
+ return 1;
+}
+
+/*
+ * Skip p_value leading components from "line"; as we do not accept
+ * absolute paths, return NULL in that case.
+ */
+static const char *skip_tree_prefix(struct apply_state *state,
+ const char *line,
+ int llen)
+{
+ int nslash;
+ int i;
+
+ if (!state->p_value)
+ return (llen && line[0] == '/') ? NULL : line;
+
+ nslash = state->p_value;
+ for (i = 0; i < llen; i++) {
+ int ch = line[i];
+ if (ch == '/' && --nslash <= 0)
+ return (i == 0) ? NULL : &line[i + 1];
+ }
+ return NULL;
+}
+
+/*
+ * This is to extract the same name that appears on "diff --git"
+ * line. We do not find and return anything if it is a rename
+ * patch, and it is OK because we will find the name elsewhere.
+ * We need to reliably find name only when it is mode-change only,
+ * 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(struct apply_state *state,
+ const char *line,
+ int llen)
+{
+ const char *name;
+ const char *second = NULL;
+ size_t len, line_len;
+
+ line += strlen("diff --git ");
+ llen -= strlen("diff --git ");
+
+ if (*line == '"') {
+ const char *cp;
+ struct strbuf first = STRBUF_INIT;
+ struct strbuf sp = STRBUF_INIT;
+
+ if (unquote_c_style(&first, line, &second))
+ goto free_and_fail1;
+
+ /* strip the a/b prefix including trailing slash */
+ cp = skip_tree_prefix(state, first.buf, first.len);
+ if (!cp)
+ goto free_and_fail1;
+ strbuf_remove(&first, 0, cp - first.buf);
+
+ /*
+ * second points at one past closing dq of name.
+ * find the second name.
+ */
+ while ((second < line + llen) && isspace(*second))
+ second++;
+
+ if (line + llen <= second)
+ goto free_and_fail1;
+ if (*second == '"') {
+ if (unquote_c_style(&sp, second, NULL))
+ goto free_and_fail1;
+ cp = skip_tree_prefix(state, sp.buf, sp.len);
+ if (!cp)
+ goto free_and_fail1;
+ /* They must match, otherwise ignore */
+ if (strcmp(cp, first.buf))
+ goto free_and_fail1;
+ strbuf_release(&sp);
+ return strbuf_detach(&first, NULL);
+ }
+
+ /* unquoted second */
+ cp = skip_tree_prefix(state, second, line + llen - second);
+ if (!cp)
+ goto free_and_fail1;
+ if (line + llen - cp != first.len ||
+ memcmp(first.buf, cp, first.len))
+ goto free_and_fail1;
+ return strbuf_detach(&first, NULL);
+
+ free_and_fail1:
+ strbuf_release(&first);
+ strbuf_release(&sp);
+ return NULL;
+ }
+
+ /* unquoted first name */
+ name = skip_tree_prefix(state, line, llen);
+ if (!name)
+ return NULL;
+
+ /*
+ * since the first name is unquoted, a dq if exists must be
+ * the beginning of the second name.
+ */
+ for (second = name; second < line + llen; second++) {
+ if (*second == '"') {
+ struct strbuf sp = STRBUF_INIT;
+ const char *np;
+
+ if (unquote_c_style(&sp, second, NULL))
+ goto free_and_fail2;
+
+ np = skip_tree_prefix(state, sp.buf, sp.len);
+ if (!np)
+ goto free_and_fail2;
+
+ len = sp.buf + sp.len - np;
+ if (len < second - name &&
+ !strncmp(np, name, len) &&
+ isspace(name[len])) {
+ /* Good */
+ strbuf_remove(&sp, 0, np - sp.buf);
+ return strbuf_detach(&sp, NULL);
+ }
+
+ free_and_fail2:
+ strbuf_release(&sp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Accept a name only if it shows up twice, exactly the same
+ * form.
+ */
+ second = strchr(name, '\n');
+ if (!second)
+ return NULL;
+ line_len = second - name;
+ for (len = 0 ; ; len++) {
+ switch (name[len]) {
+ default:
+ continue;
+ case '\n':
+ return NULL;
+ case '\t': case ' ':
+ /*
+ * Is this the separator between the preimage
+ * and the postimage pathname? Again, we are
+ * only interested in the case where there is
+ * no rename, as this is only to set def_name
+ * and a rename patch has the names elsewhere
+ * in an unambiguous form.
+ */
+ if (!name[len + 1])
+ return NULL; /* no postimage name */
+ second = skip_tree_prefix(state, name + len + 1,
+ line_len - (len + 1));
+ if (!second)
+ return NULL;
+ /*
+ * Does len bytes starting at "name" and "second"
+ * (that are separated by one HT or SP we just
+ * found) exactly match?
+ */
+ if (second[len] == '\n' && !strncmp(name, second, len))
+ return xmemdupz(name, len);
+ }
+ }
+}
+
+/* Verify that we recognize the lines following a git header */
+static int parse_git_header(struct apply_state *state,
+ const char *line,
+ int len,
+ unsigned int size,
+ struct patch *patch)
+{
+ unsigned long offset;
+
+ /* A git diff has explicit new/delete information, so we don't guess */
+ patch->is_new = 0;
+ patch->is_delete = 0;
+
+ /*
+ * Some things may not have the old name in the
+ * rest of the headers anywhere (pure mode changes,
+ * or removing or adding empty files), so we get
+ * the default name from the header.
+ */
+ patch->def_name = git_header_name(state, line, len);
+ if (patch->def_name && state->root.len) {
+ char *s = xstrfmt("%s%s", state->root.buf, patch->def_name);
+ free(patch->def_name);
+ patch->def_name = s;
+ }
+
+ line += len;
+ size -= len;
+ state->linenr++;
+ for (offset = len ; size > 0 ; offset += len, size -= len, line += len, state->linenr++) {
+ static const struct opentry {
+ const char *str;
+ int (*fn)(struct apply_state *, const char *, struct patch *);
+ } optable[] = {
+ { "@@ -", gitdiff_hdrend },
+ { "--- ", gitdiff_oldname },
+ { "+++ ", gitdiff_newname },
+ { "old mode ", gitdiff_oldmode },
+ { "new mode ", gitdiff_newmode },
+ { "deleted file mode ", gitdiff_delete },
+ { "new file mode ", gitdiff_newfile },
+ { "copy from ", gitdiff_copysrc },
+ { "copy to ", gitdiff_copydst },
+ { "rename old ", gitdiff_renamesrc },
+ { "rename new ", gitdiff_renamedst },
+ { "rename from ", gitdiff_renamesrc },
+ { "rename to ", gitdiff_renamedst },
+ { "similarity index ", gitdiff_similarity },
+ { "dissimilarity index ", gitdiff_dissimilarity },
+ { "index ", gitdiff_index },
+ { "", gitdiff_unrecognized },
+ };
+ int i;
+
+ len = linelen(line, size);
+ if (!len || line[len-1] != '\n')
+ break;
+ for (i = 0; i < ARRAY_SIZE(optable); i++) {
+ const struct opentry *p = optable + i;
+ int oplen = strlen(p->str);
+ int res;
+ if (len < oplen || memcmp(p->str, line, oplen))
+ continue;
+ res = p->fn(state, line + oplen, patch);
+ if (res < 0)
+ return -1;
+ if (res > 0)
+ return offset;
+ break;
+ }
+ }
+
+ return offset;
+}
+
+static int parse_num(const char *line, unsigned long *p)
+{
+ char *ptr;
+
+ if (!isdigit(*line))
+ return 0;
+ *p = strtoul(line, &ptr, 10);
+ return ptr - line;
+}
+
+static int parse_range(const char *line, int len, int offset, const char *expect,
+ unsigned long *p1, unsigned long *p2)
+{
+ int digits, ex;
+
+ if (offset < 0 || offset >= len)
+ return -1;
+ line += offset;
+ len -= offset;
+
+ digits = parse_num(line, p1);
+ if (!digits)
+ return -1;
+
+ offset += digits;
+ line += digits;
+ len -= digits;
+
+ *p2 = 1;
+ if (*line == ',') {
+ digits = parse_num(line+1, p2);
+ if (!digits)
+ return -1;
+
+ offset += digits+1;
+ line += digits+1;
+ len -= digits+1;
+ }
+
+ ex = strlen(expect);
+ if (ex > len)
+ return -1;
+ if (memcmp(line, expect, ex))
+ return -1;
+
+ return offset + ex;
+}
+
+static void recount_diff(const char *line, int size, struct fragment *fragment)
+{
+ int oldlines = 0, newlines = 0, ret = 0;
+
+ if (size < 1) {
+ warning("recount: ignore empty hunk");
+ return;
+ }
+
+ for (;;) {
+ int len = linelen(line, size);
+ size -= len;
+ line += len;
+
+ if (size < 1)
+ break;
+
+ switch (*line) {
+ case ' ': case '\n':
+ newlines++;
+ /* fall through */
+ case '-':
+ oldlines++;
+ continue;
+ case '+':
+ newlines++;
+ continue;
+ case '\\':
+ continue;
+ case '@':
+ ret = size < 3 || !starts_with(line, "@@ ");
+ break;
+ case 'd':
+ ret = size < 5 || !starts_with(line, "diff ");
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ if (ret) {
+ warning(_("recount: unexpected line: %.*s"),
+ (int)linelen(line, size), line);
+ return;
+ }
+ break;
+ }
+ fragment->oldlines = oldlines;
+ fragment->newlines = newlines;
+}
+
+/*
+ * Parse a unified diff fragment header of the
+ * form "@@ -a,b +c,d @@"
+ */
+static int parse_fragment_header(const char *line, int len, struct fragment *fragment)
+{
+ int offset;
+
+ if (!len || line[len-1] != '\n')
+ return -1;
+
+ /* Figure out the number of lines in a fragment */
+ offset = parse_range(line, len, 4, " +", &fragment->oldpos, &fragment->oldlines);
+ offset = parse_range(line, len, offset, " @@", &fragment->newpos, &fragment->newlines);
+
+ return offset;
+}
+
+/*
+ * Find file diff header
+ *
+ * Returns:
+ * -1 if no header was found
+ * -128 in case of error
+ * the size of the header in bytes (called "offset") otherwise
+ */
+static int find_header(struct apply_state *state,
+ const char *line,
+ unsigned long size,
+ int *hdrsize,
+ struct patch *patch)
+{
+ unsigned long offset, len;
+
+ patch->is_toplevel_relative = 0;
+ patch->is_rename = patch->is_copy = 0;
+ patch->is_new = patch->is_delete = -1;
+ patch->old_mode = patch->new_mode = 0;
+ patch->old_name = patch->new_name = NULL;
+ for (offset = 0; size > 0; offset += len, size -= len, line += len, state->linenr++) {
+ unsigned long nextlen;
+
+ len = linelen(line, size);
+ if (!len)
+ break;
+
+ /* Testing this early allows us to take a few shortcuts.. */
+ if (len < 6)
+ continue;
+
+ /*
+ * Make sure we don't find any unconnected patch fragments.
+ * That's a sign that we didn't find a header, and that a
+ * patch has become corrupted/broken up.
+ */
+ if (!memcmp("@@ -", line, 4)) {
+ struct fragment dummy;
+ if (parse_fragment_header(line, len, &dummy) < 0)
+ continue;
+ error(_("patch fragment without header at line %d: %.*s"),
+ state->linenr, (int)len-1, line);
+ return -128;
+ }
+
+ if (size < len + 6)
+ break;
+
+ /*
+ * Git patch? It might not have a real patch, just a rename
+ * or mode change, so we handle that specially
+ */
+ if (!memcmp("diff --git ", line, 11)) {
+ int git_hdr_len = parse_git_header(state, line, len, size, patch);
+ if (git_hdr_len < 0)
+ return -128;
+ if (git_hdr_len <= len)
+ continue;
+ if (!patch->old_name && !patch->new_name) {
+ if (!patch->def_name) {
+ error(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)",
+ state->p_value),
+ state->p_value, state->linenr);
+ return -128;
+ }
+ patch->old_name = xstrdup(patch->def_name);
+ patch->new_name = xstrdup(patch->def_name);
+ }
+ if (!patch->is_delete && !patch->new_name) {
+ error("git diff header lacks filename information "
+ "(line %d)", state->linenr);
+ return -128;
+ }
+ patch->is_toplevel_relative = 1;
+ *hdrsize = git_hdr_len;
+ return offset;
+ }
+
+ /* --- followed by +++ ? */
+ if (memcmp("--- ", line, 4) || memcmp("+++ ", line + len, 4))
+ continue;
+
+ /*
+ * We only accept unified patches, so we want it to
+ * at least have "@@ -a,b +c,d @@\n", which is 14 chars
+ * minimum ("@@ -0,0 +1 @@\n" is the shortest).
+ */
+ nextlen = linelen(line + len, size - len);
+ if (size < nextlen + 14 || memcmp("@@ -", line + len + nextlen, 4))
+ continue;
+
+ /* Ok, we'll consider it a patch */
+ if (parse_traditional_patch(state, line, line+len, patch))
+ return -128;
+ *hdrsize = len + nextlen;
+ state->linenr += 2;
+ return offset;
+ }
+ return -1;
+}
+
+static void record_ws_error(struct apply_state *state,
+ unsigned result,
+ const char *line,
+ int len,
+ int linenr)
+{
+ char *err;
+
+ if (!result)
+ return;
+
+ state->whitespace_error++;
+ if (state->squelch_whitespace_errors &&
+ state->squelch_whitespace_errors < state->whitespace_error)
+ return;
+
+ err = whitespace_error_string(result);
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf(stderr, "%s:%d: %s.\n%.*s\n",
+ state->patch_input_file, linenr, err, len, line);
+ free(err);
+}
+
+static void check_whitespace(struct apply_state *state,
+ const char *line,
+ int len,
+ unsigned ws_rule)
+{
+ unsigned result = ws_check(line + 1, len - 1, ws_rule);
+
+ record_ws_error(state, result, line + 1, len - 2, state->linenr);
+}
+
+/*
+ * Parse a unified diff. Note that this really needs to parse each
+ * fragment separately, since the only way to know the difference
+ * 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(struct apply_state *state,
+ const char *line,
+ unsigned long size,
+ struct patch *patch,
+ struct fragment *fragment)
+{
+ int added, deleted;
+ int len = linelen(line, size), offset;
+ unsigned long oldlines, newlines;
+ unsigned long leading, trailing;
+
+ offset = parse_fragment_header(line, len, fragment);
+ if (offset < 0)
+ return -1;
+ if (offset > 0 && patch->recount)
+ recount_diff(line + offset, size - offset, fragment);
+ oldlines = fragment->oldlines;
+ newlines = fragment->newlines;
+ leading = 0;
+ trailing = 0;
+
+ /* Parse the thing.. */
+ line += len;
+ size -= len;
+ state->linenr++;
+ added = deleted = 0;
+ for (offset = len;
+ 0 < size;
+ offset += len, size -= len, line += len, state->linenr++) {
+ if (!oldlines && !newlines)
+ break;
+ len = linelen(line, size);
+ if (!len || line[len-1] != '\n')
+ return -1;
+ switch (*line) {
+ default:
+ return -1;
+ case '\n': /* newer GNU diff, an empty context line */
+ case ' ':
+ oldlines--;
+ newlines--;
+ if (!deleted && !added)
+ leading++;
+ trailing++;
+ if (!state->apply_in_reverse &&
+ state->ws_error_action == correct_ws_error)
+ check_whitespace(state, line, len, patch->ws_rule);
+ break;
+ case '-':
+ if (state->apply_in_reverse &&
+ state->ws_error_action != nowarn_ws_error)
+ check_whitespace(state, line, len, patch->ws_rule);
+ deleted++;
+ oldlines--;
+ trailing = 0;
+ break;
+ case '+':
+ if (!state->apply_in_reverse &&
+ state->ws_error_action != nowarn_ws_error)
+ check_whitespace(state, line, len, patch->ws_rule);
+ added++;
+ newlines--;
+ trailing = 0;
+ break;
+
+ /*
+ * We allow "\ No newline at end of file". Depending
+ * on locale settings when the patch was produced we
+ * don't know what this line looks like. The only
+ * thing we do know is that it begins with "\ ".
+ * Checking for 12 is just for sanity check -- any
+ * l10n of "\ No newline..." is at least that long.
+ */
+ case '\\':
+ if (len < 12 || memcmp(line, "\\ ", 2))
+ return -1;
+ break;
+ }
+ }
+ if (oldlines || newlines)
+ return -1;
+ if (!deleted && !added)
+ return -1;
+
+ fragment->leading = leading;
+ fragment->trailing = trailing;
+
+ /*
+ * If a fragment ends with an incomplete line, we failed to include
+ * it in the above loop because we hit oldlines == newlines == 0
+ * before seeing it.
+ */
+ if (12 < size && !memcmp(line, "\\ ", 2))
+ offset += linelen(line, size);
+
+ patch->lines_added += added;
+ patch->lines_deleted += deleted;
+
+ if (0 < patch->is_new && oldlines)
+ return error(_("new file depends on old contents"));
+ if (0 < patch->is_delete && newlines)
+ return error(_("deleted file still has contents"));
+ return offset;
+}
+
+/*
+ * 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.
+ *
+ * Returns:
+ * -1 in case of error,
+ * the number of bytes in the patch otherwise.
+ */
+static int parse_single_patch(struct apply_state *state,
+ const char *line,
+ unsigned long size,
+ struct patch *patch)
+{
+ unsigned long offset = 0;
+ unsigned long oldlines = 0, newlines = 0, context = 0;
+ struct fragment **fragp = &patch->fragments;
+
+ while (size > 4 && !memcmp(line, "@@ -", 4)) {
+ struct fragment *fragment;
+ int len;
+
+ fragment = xcalloc(1, sizeof(*fragment));
+ fragment->linenr = state->linenr;
+ len = parse_fragment(state, line, size, patch, fragment);
+ if (len <= 0) {
+ free(fragment);
+ return error(_("corrupt patch at line %d"), state->linenr);
+ }
+ fragment->patch = line;
+ fragment->size = len;
+ oldlines += fragment->oldlines;
+ newlines += fragment->newlines;
+ context += fragment->leading + fragment->trailing;
+
+ *fragp = fragment;
+ fragp = &fragment->next;
+
+ offset += len;
+ line += len;
+ size -= len;
+ }
+
+ /*
+ * If something was removed (i.e. we have old-lines) it cannot
+ * be creation, and if something was added it cannot be
+ * deletion. However, the reverse is not true; --unified=0
+ * patches that only add are not necessarily creation even
+ * though they do not have any old lines, and ones that only
+ * delete are not necessarily deletion.
+ *
+ * Unfortunately, a real creation/deletion patch do _not_ have
+ * any context line by definition, so we cannot safely tell it
+ * apart with --unified=0 insanity. At least if the patch has
+ * more than one hunk it is not creation or deletion.
+ */
+ if (patch->is_new < 0 &&
+ (oldlines || (patch->fragments && patch->fragments->next)))
+ patch->is_new = 0;
+ if (patch->is_delete < 0 &&
+ (newlines || (patch->fragments && patch->fragments->next)))
+ patch->is_delete = 0;
+
+ if (0 < patch->is_new && oldlines)
+ return error(_("new file %s depends on old contents"), patch->new_name);
+ if (0 < patch->is_delete && newlines)
+ return error(_("deleted file %s still has contents"), patch->old_name);
+ if (!patch->is_delete && !newlines && context && state->apply_verbosity > verbosity_silent)
+ fprintf_ln(stderr,
+ _("** warning: "
+ "file %s becomes empty but is not deleted"),
+ patch->new_name);
+
+ return offset;
+}
+
+static inline int metadata_changes(struct patch *patch)
+{
+ return patch->is_rename > 0 ||
+ patch->is_copy > 0 ||
+ patch->is_new > 0 ||
+ patch->is_delete ||
+ (patch->old_mode && patch->new_mode &&
+ patch->old_mode != patch->new_mode);
+}
+
+static char *inflate_it(const void *data, unsigned long size,
+ unsigned long inflated_size)
+{
+ git_zstream stream;
+ void *out;
+ int st;
+
+ memset(&stream, 0, sizeof(stream));
+
+ stream.next_in = (unsigned char *)data;
+ stream.avail_in = size;
+ stream.next_out = out = xmalloc(inflated_size);
+ stream.avail_out = inflated_size;
+ git_inflate_init(&stream);
+ st = git_inflate(&stream, Z_FINISH);
+ git_inflate_end(&stream);
+ if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
+ free(out);
+ return NULL;
+ }
+ 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(struct apply_state *state,
+ char **buf_p,
+ unsigned long *sz_p,
+ int *status_p,
+ int *used_p)
+{
+ /*
+ * Expect a line that begins with binary patch method ("literal"
+ * or "delta"), followed by the length of data before deflating.
+ * a sequence of 'length-byte' followed by base-85 encoded data
+ * should follow, terminated by a newline.
+ *
+ * Each 5-byte sequence of base-85 encodes up to 4 bytes,
+ * and we would limit the patch line to 66 characters,
+ * so one line can fit up to 13 groups that would decode
+ * to 52 bytes max. The length byte 'A'-'Z' corresponds
+ * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
+ */
+ int llen, used;
+ unsigned long size = *sz_p;
+ char *buffer = *buf_p;
+ int patch_method;
+ unsigned long origlen;
+ char *data = NULL;
+ int hunk_size = 0;
+ struct fragment *frag;
+
+ llen = linelen(buffer, size);
+ used = llen;
+
+ *status_p = 0;
+
+ if (starts_with(buffer, "delta ")) {
+ patch_method = BINARY_DELTA_DEFLATED;
+ origlen = strtoul(buffer + 6, NULL, 10);
+ }
+ else if (starts_with(buffer, "literal ")) {
+ patch_method = BINARY_LITERAL_DEFLATED;
+ origlen = strtoul(buffer + 8, NULL, 10);
+ }
+ else
+ return NULL;
+
+ state->linenr++;
+ buffer += llen;
+ while (1) {
+ int byte_length, max_byte_length, newsize;
+ llen = linelen(buffer, size);
+ used += llen;
+ state->linenr++;
+ if (llen == 1) {
+ /* consume the blank line */
+ buffer++;
+ size--;
+ break;
+ }
+ /*
+ * Minimum line is "A00000\n" which is 7-byte long,
+ * and the line length must be multiple of 5 plus 2.
+ */
+ if ((llen < 7) || (llen-2) % 5)
+ goto corrupt;
+ max_byte_length = (llen - 2) / 5 * 4;
+ byte_length = *buffer;
+ if ('A' <= byte_length && byte_length <= 'Z')
+ byte_length = byte_length - 'A' + 1;
+ else if ('a' <= byte_length && byte_length <= 'z')
+ byte_length = byte_length - 'a' + 27;
+ else
+ goto corrupt;
+ /* if the input length was not multiple of 4, we would
+ * have filler at the end but the filler should never
+ * exceed 3 bytes
+ */
+ if (max_byte_length < byte_length ||
+ byte_length <= max_byte_length - 4)
+ goto corrupt;
+ newsize = hunk_size + byte_length;
+ data = xrealloc(data, newsize);
+ if (decode_85(data + hunk_size, buffer + 1, byte_length))
+ goto corrupt;
+ hunk_size = newsize;
+ buffer += llen;
+ size -= llen;
+ }
+
+ frag = xcalloc(1, sizeof(*frag));
+ frag->patch = inflate_it(data, hunk_size, origlen);
+ frag->free_patch = 1;
+ if (!frag->patch)
+ goto corrupt;
+ free(data);
+ frag->size = origlen;
+ *buf_p = buffer;
+ *sz_p = size;
+ *used_p = used;
+ frag->binary_patch_method = patch_method;
+ return frag;
+
+ corrupt:
+ free(data);
+ *status_p = -1;
+ error(_("corrupt binary patch at line %d: %.*s"),
+ state->linenr-1, llen-1, buffer);
+ return NULL;
+}
+
+/*
+ * Returns:
+ * -1 in case of error,
+ * the length of the parsed binary patch otherwise
+ */
+static int parse_binary(struct apply_state *state,
+ char *buffer,
+ unsigned long size,
+ struct patch *patch)
+{
+ /*
+ * We have read "GIT binary patch\n"; what follows is a line
+ * that says the patch method (currently, either "literal" or
+ * "delta") and the length of data before deflating; a
+ * sequence of 'length-byte' followed by base-85 encoded data
+ * follows.
+ *
+ * When a binary patch is reversible, there is another binary
+ * hunk in the same format, starting with patch method (either
+ * "literal" or "delta") with the length of data, and a sequence
+ * of length-byte + base-85 encoded data, terminated with another
+ * empty line. This data, when applied to the postimage, produces
+ * the preimage.
+ */
+ struct fragment *forward;
+ struct fragment *reverse;
+ int status;
+ int used, used_1;
+
+ forward = parse_binary_hunk(state, &buffer, &size, &status, &used);
+ if (!forward && !status)
+ /* there has to be one hunk (forward hunk) */
+ return error(_("unrecognized binary patch at line %d"), state->linenr-1);
+ if (status)
+ /* otherwise we already gave an error message */
+ return status;
+
+ reverse = parse_binary_hunk(state, &buffer, &size, &status, &used_1);
+ if (reverse)
+ used += used_1;
+ else if (status) {
+ /*
+ * Not having reverse hunk is not an error, but having
+ * a corrupt reverse hunk is.
+ */
+ free((void*) forward->patch);
+ free(forward);
+ return status;
+ }
+ forward->next = reverse;
+ patch->fragments = forward;
+ patch->is_binary = 1;
+ return used;
+}
+
+static void prefix_one(struct apply_state *state, char **name)
+{
+ char *old_name = *name;
+ if (!old_name)
+ return;
+ *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
+ free(old_name);
+}
+
+static void prefix_patch(struct apply_state *state, struct patch *p)
+{
+ if (!state->prefix || p->is_toplevel_relative)
+ return;
+ prefix_one(state, &p->new_name);
+ prefix_one(state, &p->old_name);
+}
+
+/*
+ * include/exclude
+ */
+
+static void add_name_limit(struct apply_state *state,
+ const char *name,
+ int exclude)
+{
+ struct string_list_item *it;
+
+ it = string_list_append(&state->limit_by_name, name);
+ it->util = exclude ? NULL : (void *) 1;
+}
+
+static int use_patch(struct apply_state *state, struct patch *p)
+{
+ const char *pathname = p->new_name ? p->new_name : p->old_name;
+ int i;
+
+ /* Paths outside are not touched regardless of "--include" */
+ if (0 < state->prefix_length) {
+ int pathlen = strlen(pathname);
+ if (pathlen <= state->prefix_length ||
+ memcmp(state->prefix, pathname, state->prefix_length))
+ return 0;
+ }
+
+ /* See if it matches any of exclude/include rule */
+ for (i = 0; i < state->limit_by_name.nr; i++) {
+ struct string_list_item *it = &state->limit_by_name.items[i];
+ if (!wildmatch(it->string, pathname, 0, NULL))
+ return (it->util != NULL);
+ }
+
+ /*
+ * If we had any include, a path that does not match any rule is
+ * not used. Otherwise, we saw bunch of exclude rules (or none)
+ * and such a path is used.
+ */
+ return !state->has_include;
+}
+
+/*
+ * Read the patch text in "buffer" that 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.
+ *
+ * Returns:
+ * -1 if no header was found or parse_binary() failed,
+ * -128 on another error,
+ * the number of bytes consumed otherwise,
+ * so that the caller can call us again for the next patch.
+ */
+static int parse_chunk(struct apply_state *state, char *buffer, unsigned long size, struct patch *patch)
+{
+ int hdrsize, patchsize;
+ int offset = find_header(state, buffer, size, &hdrsize, patch);
+
+ if (offset < 0)
+ return offset;
+
+ prefix_patch(state, patch);
+
+ if (!use_patch(state, patch))
+ patch->ws_rule = 0;
+ else
+ patch->ws_rule = whitespace_rule(patch->new_name
+ ? patch->new_name
+ : patch->old_name);
+
+ patchsize = parse_single_patch(state,
+ buffer + offset + hdrsize,
+ size - offset - hdrsize,
+ patch);
+
+ if (patchsize < 0)
+ return -128;
+
+ if (!patchsize) {
+ static const char git_binary[] = "GIT binary patch\n";
+ int hd = hdrsize + offset;
+ unsigned long llen = linelen(buffer + hd, size - hd);
+
+ if (llen == sizeof(git_binary) - 1 &&
+ !memcmp(git_binary, buffer + hd, llen)) {
+ int used;
+ state->linenr++;
+ used = parse_binary(state, buffer + hd + llen,
+ size - hd - llen, patch);
+ if (used < 0)
+ return -1;
+ if (used)
+ patchsize = used + llen;
+ else
+ patchsize = 0;
+ }
+ else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
+ static const char *binhdr[] = {
+ "Binary files ",
+ "Files ",
+ NULL,
+ };
+ int i;
+ for (i = 0; binhdr[i]; i++) {
+ int len = strlen(binhdr[i]);
+ if (len < size - hd &&
+ !memcmp(binhdr[i], buffer + hd, len)) {
+ state->linenr++;
+ patch->is_binary = 1;
+ patchsize = llen;
+ break;
+ }
+ }
+ }
+
+ /* Empty patch cannot be applied if it is a text patch
+ * without metadata change. A binary patch appears
+ * empty to us here.
+ */
+ if ((state->apply || state->check) &&
+ (!patch->is_binary && !metadata_changes(patch))) {
+ error(_("patch with only garbage at line %d"), state->linenr);
+ return -128;
+ }
+ }
+
+ return offset + hdrsize + patchsize;
+}
+
+#define swap(a,b) myswap((a),(b),sizeof(a))
+
+#define myswap(a, b, size) do { \
+ unsigned char mytmp[size]; \
+ memcpy(mytmp, &a, size); \
+ memcpy(&a, &b, size); \
+ memcpy(&b, mytmp, size); \
+} while (0)
+
+static void reverse_patches(struct patch *p)
+{
+ for (; p; p = p->next) {
+ struct fragment *frag = p->fragments;
+
+ swap(p->new_name, p->old_name);
+ swap(p->new_mode, p->old_mode);
+ swap(p->is_new, p->is_delete);
+ swap(p->lines_added, p->lines_deleted);
+ swap(p->old_sha1_prefix, p->new_sha1_prefix);
+
+ for (; frag; frag = frag->next) {
+ swap(frag->newpos, frag->oldpos);
+ swap(frag->newlines, frag->oldlines);
+ }
+ }
+}
+
+static const char pluses[] =
+"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
+static const char minuses[]=
+"----------------------------------------------------------------------";
+
+static void show_stats(struct apply_state *state, struct patch *patch)
+{
+ struct strbuf qname = STRBUF_INIT;
+ char *cp = patch->new_name ? patch->new_name : patch->old_name;
+ int max, add, del;
+
+ quote_c_style(cp, &qname, NULL, 0);
+
+ /*
+ * "scale" the filename
+ */
+ max = state->max_len;
+ if (max > 50)
+ max = 50;
+
+ if (qname.len > max) {
+ cp = strchr(qname.buf + qname.len + 3 - max, '/');
+ if (!cp)
+ cp = qname.buf + qname.len + 3 - max;
+ strbuf_splice(&qname, 0, cp - qname.buf, "...", 3);
+ }
+
+ if (patch->is_binary) {
+ printf(" %-*s | Bin\n", max, qname.buf);
+ strbuf_release(&qname);
+ return;
+ }
+
+ printf(" %-*s |", max, qname.buf);
+ strbuf_release(&qname);
+
+ /*
+ * scale the add/delete
+ */
+ max = max + state->max_change > 70 ? 70 - max : state->max_change;
+ add = patch->lines_added;
+ del = patch->lines_deleted;
+
+ if (state->max_change > 0) {
+ int total = ((add + del) * max + state->max_change / 2) / state->max_change;
+ add = (add * max + state->max_change / 2) / state->max_change;
+ del = total - add;
+ }
+ printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
+ add, pluses, del, minuses);
+}
+
+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 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);
+ convert_to_git(path, buf->buf, buf->len, buf, 0);
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Update the preimage, and the common lines in postimage,
+ * from buffer buf of length len. If postlen is 0 the postimage
+ * is updated in place, otherwise it's updated on a new buffer
+ * of length postlen
+ */
+
+static void update_pre_post_images(struct image *preimage,
+ struct image *postimage,
+ char *buf,
+ size_t len, size_t postlen)
+{
+ int i, ctx, reduced;
+ char *new, *old, *fixed;
+ struct image fixed_preimage;
+
+ /*
+ * Update the preimage with whitespace fixes. Note that we
+ * are not losing preimage->buf -- apply_one_fragment() will
+ * free "oldlines".
+ */
+ prepare_image(&fixed_preimage, buf, len, 1);
+ assert(postlen
+ ? fixed_preimage.nr == preimage->nr
+ : fixed_preimage.nr <= preimage->nr);
+ for (i = 0; i < fixed_preimage.nr; i++)
+ fixed_preimage.line[i].flag = preimage->line[i].flag;
+ free(preimage->line_allocated);
+ *preimage = fixed_preimage;
+
+ /*
+ * Adjust the common context lines in postimage. This can be
+ * done in-place when we are shrinking it with whitespace
+ * fixing, but needs a new buffer when ignoring whitespace or
+ * expanding leading tabs to spaces.
+ *
+ * We trust the caller to tell us if the update can be done
+ * in place (postlen==0) or not.
+ */
+ old = postimage->buf;
+ if (postlen)
+ new = postimage->buf = xmalloc(postlen);
+ else
+ new = old;
+ fixed = preimage->buf;
+
+ for (i = reduced = ctx = 0; i < postimage->nr; i++) {
+ size_t l_len = postimage->line[i].len;
+ if (!(postimage->line[i].flag & LINE_COMMON)) {
+ /* an added line -- no counterparts in preimage */
+ memmove(new, old, l_len);
+ old += l_len;
+ new += l_len;
+ continue;
+ }
+
+ /* a common context -- skip it in the original postimage */
+ old += l_len;
+
+ /* and find the corresponding one in the fixed preimage */
+ while (ctx < preimage->nr &&
+ !(preimage->line[ctx].flag & LINE_COMMON)) {
+ fixed += preimage->line[ctx].len;
+ ctx++;
+ }
+
+ /*
+ * preimage is expected to run out, if the caller
+ * fixed addition of trailing blank lines.
+ */
+ if (preimage->nr <= ctx) {
+ reduced++;
+ continue;
+ }
+
+ /* and copy it in, while fixing the line length */
+ l_len = preimage->line[ctx].len;
+ memcpy(new, fixed, l_len);
+ new += l_len;
+ fixed += l_len;
+ postimage->line[i].len = l_len;
+ ctx++;
+ }
+
+ if (postlen
+ ? postlen < new - postimage->buf
+ : postimage->len < new - postimage->buf)
+ die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
+ (int)postlen, (int) postimage->len, (int)(new - postimage->buf));
+
+ /* Fix the length of the whole thing */
+ postimage->len = new - postimage->buf;
+ postimage->nr -= reduced;
+}
+
+static int line_by_line_fuzzy_match(struct image *img,
+ struct image *preimage,
+ struct image *postimage,
+ unsigned long try,
+ int try_lno,
+ int preimage_limit)
+{
+ int i;
+ size_t imgoff = 0;
+ size_t preoff = 0;
+ size_t postlen = postimage->len;
+ size_t extra_chars;
+ char *buf;
+ char *preimage_eof;
+ char *preimage_end;
+ struct strbuf fixed;
+ char *fixed_buf;
+ size_t fixed_len;
+
+ for (i = 0; i < preimage_limit; i++) {
+ size_t prelen = preimage->line[i].len;
+ size_t imglen = img->line[try_lno+i].len;
+
+ if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
+ preimage->buf + preoff, prelen))
+ return 0;
+ if (preimage->line[i].flag & LINE_COMMON)
+ postlen += imglen - prelen;
+ imgoff += imglen;
+ preoff += prelen;
+ }
+
+ /*
+ * Ok, the preimage matches with whitespace fuzz.
+ *
+ * imgoff now holds the true length of the target that
+ * matches the preimage before the end of the file.
+ *
+ * Count the number of characters in the preimage that fall
+ * beyond the end of the file and make sure that all of them
+ * are whitespace characters. (This can only happen if
+ * we are removing blank lines at the end of the file.)
+ */
+ buf = preimage_eof = preimage->buf + preoff;
+ for ( ; i < preimage->nr; i++)
+ preoff += preimage->line[i].len;
+ preimage_end = preimage->buf + preoff;
+ for ( ; buf < preimage_end; buf++)
+ if (!isspace(*buf))
+ return 0;
+
+ /*
+ * Update the preimage and the common postimage context
+ * lines to use the same whitespace as the target.
+ * If whitespace is missing in the target (i.e.
+ * if the preimage extends beyond the end of the file),
+ * use the whitespace from the preimage.
+ */
+ extra_chars = preimage_end - preimage_eof;
+ strbuf_init(&fixed, imgoff + extra_chars);
+ strbuf_add(&fixed, img->buf + try, imgoff);
+ strbuf_add(&fixed, preimage_eof, extra_chars);
+ fixed_buf = strbuf_detach(&fixed, &fixed_len);
+ update_pre_post_images(preimage, postimage,
+ fixed_buf, fixed_len, postlen);
+ return 1;
+}
+
+static int match_fragment(struct apply_state *state,
+ struct image *img,
+ struct image *preimage,
+ struct image *postimage,
+ unsigned long try,
+ int try_lno,
+ unsigned ws_rule,
+ int match_beginning, int match_end)
+{
+ int i;
+ char *fixed_buf, *buf, *orig, *target;
+ struct strbuf fixed;
+ size_t fixed_len, postlen;
+ int preimage_limit;
+
+ if (preimage->nr + try_lno <= img->nr) {
+ /*
+ * The hunk falls within the boundaries of img.
+ */
+ preimage_limit = preimage->nr;
+ if (match_end && (preimage->nr + try_lno != img->nr))
+ return 0;
+ } else if (state->ws_error_action == correct_ws_error &&
+ (ws_rule & WS_BLANK_AT_EOF)) {
+ /*
+ * This hunk extends beyond the end of img, and we are
+ * removing blank lines at the end of the file. This
+ * many lines from the beginning of the preimage must
+ * match with img, and the remainder of the preimage
+ * must be blank.
+ */
+ preimage_limit = img->nr - try_lno;
+ } else {
+ /*
+ * The hunk extends beyond the end of the img and
+ * we are not removing blanks at the end, so we
+ * should reject the hunk at this position.
+ */
+ return 0;
+ }
+
+ if (match_beginning && try_lno)
+ return 0;
+
+ /* Quick hash check */
+ for (i = 0; i < preimage_limit; i++)
+ if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
+ (preimage->line[i].hash != img->line[try_lno + i].hash))
+ return 0;
+
+ if (preimage_limit == preimage->nr) {
+ /*
+ * Do we have an exact match? If we were told to match
+ * at the end, size must be exactly at try+fragsize,
+ * otherwise try+fragsize must be still within the preimage,
+ * and either case, the old piece should match the preimage
+ * exactly.
+ */
+ if ((match_end
+ ? (try + preimage->len == img->len)
+ : (try + preimage->len <= img->len)) &&
+ !memcmp(img->buf + try, preimage->buf, preimage->len))
+ return 1;
+ } else {
+ /*
+ * The preimage extends beyond the end of img, so
+ * there cannot be an exact match.
+ *
+ * There must be one non-blank context line that match
+ * a line before the end of img.
+ */
+ char *buf_end;
+
+ buf = preimage->buf;
+ buf_end = buf;
+ for (i = 0; i < preimage_limit; i++)
+ buf_end += preimage->line[i].len;
+
+ for ( ; buf < buf_end; buf++)
+ if (!isspace(*buf))
+ break;
+ if (buf == buf_end)
+ return 0;
+ }
+
+ /*
+ * No exact match. If we are ignoring whitespace, run a line-by-line
+ * fuzzy matching. We collect all the line length information because
+ * we need it to adjust whitespace if we match.
+ */
+ if (state->ws_ignore_action == ignore_ws_change)
+ return line_by_line_fuzzy_match(img, preimage, postimage,
+ try, try_lno, preimage_limit);
+
+ if (state->ws_error_action != correct_ws_error)
+ return 0;
+
+ /*
+ * The hunk does not apply byte-by-byte, but the hash says
+ * it might with whitespace fuzz. We weren't asked to
+ * ignore whitespace, we were asked to correct whitespace
+ * errors, so let's try matching after whitespace correction.
+ *
+ * While checking the preimage against the target, whitespace
+ * errors in both fixed, we count how large the corresponding
+ * postimage needs to be. The postimage prepared by
+ * apply_one_fragment() has whitespace errors fixed on added
+ * lines already, but the common lines were propagated as-is,
+ * which may become longer when their whitespace errors are
+ * fixed.
+ */
+
+ /* First count added lines in postimage */
+ postlen = 0;
+ for (i = 0; i < postimage->nr; i++) {
+ if (!(postimage->line[i].flag & LINE_COMMON))
+ postlen += postimage->line[i].len;
+ }
+
+ /*
+ * The preimage may extend beyond the end of the file,
+ * but in this loop we will only handle the part of the
+ * preimage that falls within the file.
+ */
+ strbuf_init(&fixed, preimage->len + 1);
+ orig = preimage->buf;
+ target = img->buf + try;
+ for (i = 0; i < preimage_limit; i++) {
+ size_t oldlen = preimage->line[i].len;
+ size_t tgtlen = img->line[try_lno + i].len;
+ size_t fixstart = fixed.len;
+ struct strbuf tgtfix;
+ int match;
+
+ /* Try fixing the line in the preimage */
+ ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
+
+ /* Try fixing the line in the target */
+ strbuf_init(&tgtfix, tgtlen);
+ ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
+
+ /*
+ * If they match, either the preimage was based on
+ * a version before our tree fixed whitespace breakage,
+ * or we are lacking a whitespace-fix patch the tree
+ * the preimage was based on already had (i.e. target
+ * has whitespace breakage, the preimage doesn't).
+ * In either case, we are fixing the whitespace breakages
+ * so we might as well take the fix together with their
+ * real change.
+ */
+ match = (tgtfix.len == fixed.len - fixstart &&
+ !memcmp(tgtfix.buf, fixed.buf + fixstart,
+ fixed.len - fixstart));
+
+ /* Add the length if this is common with the postimage */
+ if (preimage->line[i].flag & LINE_COMMON)
+ postlen += tgtfix.len;
+
+ strbuf_release(&tgtfix);
+ if (!match)
+ goto unmatch_exit;
+
+ orig += oldlen;
+ target += tgtlen;
+ }
+
+
+ /*
+ * Now handle the lines in the preimage that falls beyond the
+ * end of the file (if any). They will only match if they are
+ * empty or only contain whitespace (if WS_BLANK_AT_EOL is
+ * false).
+ */
+ for ( ; i < preimage->nr; i++) {
+ size_t fixstart = fixed.len; /* start of the fixed preimage */
+ size_t oldlen = preimage->line[i].len;
+ int j;
+
+ /* Try fixing the line in the preimage */
+ ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
+
+ for (j = fixstart; j < fixed.len; j++)
+ if (!isspace(fixed.buf[j]))
+ goto unmatch_exit;
+
+ orig += oldlen;
+ }
+
+ /*
+ * Yes, the preimage is based on an older version that still
+ * has whitespace breakages unfixed, and fixing them makes the
+ * hunk match. Update the context lines in the postimage.
+ */
+ fixed_buf = strbuf_detach(&fixed, &fixed_len);
+ if (postlen < postimage->len)
+ postlen = 0;
+ update_pre_post_images(preimage, postimage,
+ fixed_buf, fixed_len, postlen);
+ return 1;
+
+ unmatch_exit:
+ strbuf_release(&fixed);
+ return 0;
+}
+
+static int find_pos(struct apply_state *state,
+ struct image *img,
+ struct image *preimage,
+ struct image *postimage,
+ int line,
+ unsigned ws_rule,
+ int match_beginning, int match_end)
+{
+ int i;
+ unsigned long backwards, forwards, try;
+ int backwards_lno, forwards_lno, try_lno;
+
+ /*
+ * If match_beginning or match_end is specified, there is no
+ * point starting from a wrong line that will never match and
+ * wander around and wait for a match at the specified end.
+ */
+ if (match_beginning)
+ line = 0;
+ else if (match_end)
+ line = img->nr - preimage->nr;
+
+ /*
+ * Because the comparison is unsigned, the following test
+ * will also take care of a negative line number that can
+ * result when match_end and preimage is larger than the target.
+ */
+ if ((size_t) line > img->nr)
+ line = img->nr;
+
+ try = 0;
+ for (i = 0; i < line; i++)
+ try += img->line[i].len;
+
+ /*
+ * There's probably some smart way to do this, but I'll leave
+ * that to the smart and beautiful people. I'm simple and stupid.
+ */
+ backwards = try;
+ backwards_lno = line;
+ forwards = try;
+ forwards_lno = line;
+ try_lno = line;
+
+ for (i = 0; ; i++) {
+ if (match_fragment(state, img, preimage, postimage,
+ try, try_lno, ws_rule,
+ match_beginning, match_end))
+ return try_lno;
+
+ again:
+ if (backwards_lno == 0 && forwards_lno == img->nr)
+ break;
+
+ if (i & 1) {
+ if (backwards_lno == 0) {
+ i++;
+ goto again;
+ }
+ backwards_lno--;
+ backwards -= img->line[backwards_lno].len;
+ try = backwards;
+ try_lno = backwards_lno;
+ } else {
+ if (forwards_lno == img->nr) {
+ i++;
+ goto again;
+ }
+ forwards += img->line[forwards_lno].len;
+ forwards_lno++;
+ try = forwards;
+ try_lno = forwards_lno;
+ }
+
+ }
+ return -1;
+}
+
+static void remove_first_line(struct image *img)
+{
+ img->buf += img->line[0].len;
+ img->len -= img->line[0].len;
+ img->line++;
+ img->nr--;
+}
+
+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 apply_state *state,
+ struct image *img,
+ int applied_pos,
+ struct image *preimage,
+ struct image *postimage)
+{
+ /*
+ * remove the copy of preimage at offset in img
+ * and replace it with postimage
+ */
+ int i, nr;
+ size_t remove_count, insert_count, applied_at = 0;
+ char *result;
+ int preimage_limit;
+
+ /*
+ * If we are removing blank lines at the end of img,
+ * the preimage may extend beyond the end.
+ * If that is the case, we must be careful only to
+ * remove the part of the preimage that falls within
+ * the boundaries of img. Initialize preimage_limit
+ * to the number of lines in the preimage that falls
+ * within the boundaries.
+ */
+ preimage_limit = preimage->nr;
+ if (preimage_limit > img->nr - applied_pos)
+ preimage_limit = img->nr - applied_pos;
+
+ for (i = 0; i < applied_pos; i++)
+ applied_at += img->line[i].len;
+
+ remove_count = 0;
+ for (i = 0; i < preimage_limit; i++)
+ remove_count += img->line[applied_pos + i].len;
+ insert_count = postimage->len;
+
+ /* Adjust the contents */
+ result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));
+ memcpy(result, img->buf, applied_at);
+ memcpy(result + applied_at, postimage->buf, postimage->len);
+ memcpy(result + applied_at + postimage->len,
+ img->buf + (applied_at + remove_count),
+ img->len - (applied_at + remove_count));
+ free(img->buf);
+ img->buf = result;
+ img->len += insert_count - remove_count;
+ result[img->len] = '\0';
+
+ /* Adjust the line table */
+ nr = img->nr + postimage->nr - preimage_limit;
+ if (preimage_limit < postimage->nr) {
+ /*
+ * NOTE: this knows that we never call remove_first_line()
+ * on anything other than pre/post image.
+ */
+ REALLOC_ARRAY(img->line, nr);
+ img->line_allocated = img->line;
+ }
+ if (preimage_limit != postimage->nr)
+ memmove(img->line + applied_pos + postimage->nr,
+ img->line + applied_pos + preimage_limit,
+ (img->nr - (applied_pos + preimage_limit)) *
+ sizeof(*img->line));
+ memcpy(img->line + applied_pos,
+ postimage->line,
+ postimage->nr * sizeof(*img->line));
+ if (!state->allow_overlap)
+ for (i = 0; i < postimage->nr; i++)
+ img->line[applied_pos + i].flag |= LINE_PATCHED;
+ 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 apply_state *state,
+ struct image *img, struct fragment *frag,
+ int inaccurate_eof, unsigned ws_rule,
+ int nth_fragment)
+{
+ int match_beginning, match_end;
+ const char *patch = frag->patch;
+ int size = frag->size;
+ char *old, *oldlines;
+ struct strbuf newlines;
+ int new_blank_lines_at_end = 0;
+ int found_new_blank_lines_at_end = 0;
+ int hunk_linenr = frag->linenr;
+ unsigned long leading, trailing;
+ int pos, applied_pos;
+ struct image preimage;
+ struct image postimage;
+
+ memset(&preimage, 0, sizeof(preimage));
+ memset(&postimage, 0, sizeof(postimage));
+ oldlines = xmalloc(size);
+ strbuf_init(&newlines, size);
+
+ old = oldlines;
+ while (size > 0) {
+ char first;
+ int len = linelen(patch, size);
+ int plen;
+ int added_blank_line = 0;
+ int is_blank_context = 0;
+ size_t start;
+
+ if (!len)
+ break;
+
+ /*
+ * "plen" is how much of the line we should use for
+ * the actual patch data. Normally we just remove the
+ * first character on the line, but if the line is
+ * followed by "\ No newline", then we also remove the
+ * last one (which is the newline, of course).
+ */
+ plen = len - 1;
+ if (len < size && patch[len] == '\\')
+ plen--;
+ first = *patch;
+ if (state->apply_in_reverse) {
+ if (first == '-')
+ first = '+';
+ else if (first == '+')
+ first = '-';
+ }
+
+ switch (first) {
+ case '\n':
+ /* Newer GNU diff, empty context line */
+ if (plen < 0)
+ /* ... followed by '\No newline'; nothing */
+ break;
+ *old++ = '\n';
+ strbuf_addch(&newlines, '\n');
+ add_line_info(&preimage, "\n", 1, LINE_COMMON);
+ add_line_info(&postimage, "\n", 1, LINE_COMMON);
+ is_blank_context = 1;
+ break;
+ case ' ':
+ if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
+ ws_blank_line(patch + 1, plen, ws_rule))
+ is_blank_context = 1;
+ case '-':
+ memcpy(old, patch + 1, plen);
+ add_line_info(&preimage, old, plen,
+ (first == ' ' ? LINE_COMMON : 0));
+ old += plen;
+ if (first == '-')
+ break;
+ /* Fall-through for ' ' */
+ case '+':
+ /* --no-add does not add new lines */
+ if (first == '+' && state->no_add)
+ break;
+
+ start = newlines.len;
+ if (first != '+' ||
+ !state->whitespace_error ||
+ state->ws_error_action != correct_ws_error) {
+ strbuf_add(&newlines, patch + 1, plen);
+ }
+ else {
+ ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &state->applied_after_fixing_ws);
+ }
+ add_line_info(&postimage, newlines.buf + start, newlines.len - start,
+ (first == '+' ? 0 : LINE_COMMON));
+ if (first == '+' &&
+ (ws_rule & WS_BLANK_AT_EOF) &&
+ ws_blank_line(patch + 1, plen, ws_rule))
+ added_blank_line = 1;
+ break;
+ case '@': case '\\':
+ /* Ignore it, we already handled it */
+ break;
+ default:
+ if (state->apply_verbosity > verbosity_normal)
+ error(_("invalid start of line: '%c'"), first);
+ applied_pos = -1;
+ goto out;
+ }
+ if (added_blank_line) {
+ if (!new_blank_lines_at_end)
+ found_new_blank_lines_at_end = hunk_linenr;
+ new_blank_lines_at_end++;
+ }
+ else if (is_blank_context)
+ ;
+ else
+ new_blank_lines_at_end = 0;
+ patch += len;
+ size -= len;
+ hunk_linenr++;
+ }
+ if (inaccurate_eof &&
+ old > oldlines && old[-1] == '\n' &&
+ newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
+ old--;
+ strbuf_setlen(&newlines, newlines.len - 1);
+ }
+
+ leading = frag->leading;
+ trailing = frag->trailing;
+
+ /*
+ * A hunk to change lines at the beginning would begin with
+ * @@ -1,L +N,M @@
+ * but we need to be careful. -U0 that inserts before the second
+ * line also has this pattern.
+ *
+ * And a hunk to add to an empty file would begin with
+ * @@ -0,0 +N,M @@
+ *
+ * In other words, a hunk that is (frag->oldpos <= 1) with or
+ * without leading context must match at the beginning.
+ */
+ match_beginning = (!frag->oldpos ||
+ (frag->oldpos == 1 && !state->unidiff_zero));
+
+ /*
+ * A hunk without trailing lines must match at the end.
+ * However, we simply cannot tell if a hunk must match end
+ * from the lack of trailing lines if the patch was generated
+ * with unidiff without any context.
+ */
+ match_end = !state->unidiff_zero && !trailing;
+
+ pos = frag->newpos ? (frag->newpos - 1) : 0;
+ preimage.buf = oldlines;
+ preimage.len = old - oldlines;
+ postimage.buf = newlines.buf;
+ postimage.len = newlines.len;
+ preimage.line = preimage.line_allocated;
+ postimage.line = postimage.line_allocated;
+
+ for (;;) {
+
+ applied_pos = find_pos(state, img, &preimage, &postimage, pos,
+ ws_rule, match_beginning, match_end);
+
+ if (applied_pos >= 0)
+ break;
+
+ /* Am I at my context limits? */
+ if ((leading <= state->p_context) && (trailing <= state->p_context))
+ break;
+ if (match_beginning || match_end) {
+ match_beginning = match_end = 0;
+ continue;
+ }
+
+ /*
+ * Reduce the number of context lines; reduce both
+ * leading and trailing if they are equal otherwise
+ * just reduce the larger context.
+ */
+ if (leading >= trailing) {
+ remove_first_line(&preimage);
+ remove_first_line(&postimage);
+ pos--;
+ leading--;
+ }
+ if (trailing > leading) {
+ remove_last_line(&preimage);
+ remove_last_line(&postimage);
+ trailing--;
+ }
+ }
+
+ if (applied_pos >= 0) {
+ if (new_blank_lines_at_end &&
+ preimage.nr + applied_pos >= img->nr &&
+ (ws_rule & WS_BLANK_AT_EOF) &&
+ state->ws_error_action != nowarn_ws_error) {
+ record_ws_error(state, WS_BLANK_AT_EOF, "+", 1,
+ found_new_blank_lines_at_end);
+ if (state->ws_error_action == correct_ws_error) {
+ while (new_blank_lines_at_end--)
+ remove_last_line(&postimage);
+ }
+ /*
+ * We would want to prevent write_out_results()
+ * from taking place in apply_patch() that follows
+ * the callchain led us here, which is:
+ * apply_patch->check_patch_list->check_patch->
+ * apply_data->apply_fragments->apply_one_fragment
+ */
+ if (state->ws_error_action == die_on_ws_error)
+ state->apply = 0;
+ }
+
+ if (state->apply_verbosity > verbosity_normal && applied_pos != pos) {
+ int offset = applied_pos - pos;
+ if (state->apply_in_reverse)
+ offset = 0 - 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);
+ }
+
+ /*
+ * Warn if it was necessary to reduce the number
+ * of context lines.
+ */
+ if ((leading != frag->leading ||
+ trailing != frag->trailing) && state->apply_verbosity > verbosity_silent)
+ fprintf_ln(stderr, _("Context reduced to (%ld/%ld)"
+ " to apply fragment at %d"),
+ leading, trailing, applied_pos+1);
+ update_image(state, img, applied_pos, &preimage, &postimage);
+ } else {
+ if (state->apply_verbosity > verbosity_normal)
+ error(_("while searching for:\n%.*s"),
+ (int)(old - oldlines), oldlines);
+ }
+
+out:
+ free(oldlines);
+ strbuf_release(&newlines);
+ free(preimage.line_allocated);
+ free(postimage.line_allocated);
+
+ return (applied_pos < 0);
+}
+
+static int apply_binary_fragment(struct apply_state *state,
+ struct image *img,
+ struct patch *patch)
+{
+ struct fragment *fragment = patch->fragments;
+ unsigned long len;
+ void *dst;
+
+ if (!fragment)
+ return error(_("missing binary patch data for '%s'"),
+ patch->new_name ?
+ patch->new_name :
+ patch->old_name);
+
+ /* Binary patch is irreversible without the optional second hunk */
+ if (state->apply_in_reverse) {
+ if (!fragment->next)
+ return error("cannot reverse-apply a binary patch "
+ "without the reverse hunk to '%s'",
+ patch->new_name
+ ? patch->new_name : patch->old_name);
+ fragment = fragment->next;
+ }
+ switch (fragment->binary_patch_method) {
+ case BINARY_DELTA_DEFLATED:
+ dst = patch_delta(img->buf, img->len, fragment->patch,
+ fragment->size, &len);
+ if (!dst)
+ return -1;
+ clear_image(img);
+ img->buf = dst;
+ img->len = len;
+ return 0;
+ case BINARY_LITERAL_DEFLATED:
+ clear_image(img);
+ img->len = fragment->size;
+ img->buf = xmemdupz(fragment->patch, img->len);
+ return 0;
+ }
+ 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 apply_state *state,
+ struct image *img,
+ struct patch *patch)
+{
+ const char *name = patch->old_name ? patch->old_name : patch->new_name;
+ struct object_id oid;
+
+ /*
+ * For safety, we require patch index line to contain
+ * full 40-byte textual SHA1 for old and new, at least for now.
+ */
+ if (strlen(patch->old_sha1_prefix) != 40 ||
+ strlen(patch->new_sha1_prefix) != 40 ||
+ get_oid_hex(patch->old_sha1_prefix, &oid) ||
+ get_oid_hex(patch->new_sha1_prefix, &oid))
+ return error("cannot apply binary patch to '%s' "
+ "without full index line", name);
+
+ if (patch->old_name) {
+ /*
+ * See if the old one matches what the patch
+ * applies to.
+ */
+ hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+ if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
+ return error("the patch applies to '%s' (%s), "
+ "which does not match the "
+ "current contents.",
+ name, oid_to_hex(&oid));
+ }
+ else {
+ /* Otherwise, the old one must be empty. */
+ if (img->len)
+ return error("the patch applies to an empty "
+ "'%s' but it is not empty", name);
+ }
+
+ get_oid_hex(patch->new_sha1_prefix, &oid);
+ if (is_null_oid(&oid)) {
+ clear_image(img);
+ return 0; /* deletion patch */
+ }
+
+ if (has_sha1_file(oid.hash)) {
+ /* We already have the postimage */
+ enum object_type type;
+ unsigned long size;
+ char *result;
+
+ result = read_sha1_file(oid.hash, &type, &size);
+ if (!result)
+ return error("the necessary postimage %s for "
+ "'%s' cannot be read",
+ patch->new_sha1_prefix, name);
+ clear_image(img);
+ img->buf = result;
+ img->len = size;
+ } else {
+ /*
+ * We have verified buf matches the preimage;
+ * apply the patch data to it, which is stored
+ * in the patch->fragments->{patch,size}.
+ */
+ if (apply_binary_fragment(state, img, patch))
+ return error(_("binary patch does not apply to '%s'"),
+ name);
+
+ /* verify that the result matches */
+ hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+ if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
+ return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
+ name, patch->new_sha1_prefix, oid_to_hex(&oid));
+ }
+
+ return 0;
+}
+
+static int apply_fragments(struct apply_state *state, struct image *img, struct patch *patch)
+{
+ struct fragment *frag = patch->fragments;
+ const char *name = patch->old_name ? patch->old_name : patch->new_name;
+ unsigned ws_rule = patch->ws_rule;
+ unsigned inaccurate_eof = patch->inaccurate_eof;
+ int nth = 0;
+
+ if (patch->is_binary)
+ return apply_binary(state, img, patch);
+
+ while (frag) {
+ nth++;
+ if (apply_one_fragment(state, img, frag, inaccurate_eof, ws_rule, nth)) {
+ error(_("patch failed: %s:%ld"), name, frag->oldpos);
+ if (!state->apply_with_reject)
+ return -1;
+ frag->rejected = 1;
+ }
+ frag = frag->next;
+ }
+ return 0;
+}
+
+static int read_blob_object(struct strbuf *buf, const struct object_id *oid, unsigned mode)
+{
+ if (S_ISGITLINK(mode)) {
+ strbuf_grow(buf, 100);
+ strbuf_addf(buf, "Subproject commit %s\n", oid_to_hex(oid));
+ } else {
+ enum object_type type;
+ unsigned long sz;
+ char *result;
+
+ result = read_sha1_file(oid->hash, &type, &sz);
+ if (!result)
+ return -1;
+ /* XXX read_sha1_file NUL-terminates */
+ strbuf_attach(buf, result, sz, sz + 1);
+ }
+ return 0;
+}
+
+static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf)
+{
+ if (!ce)
+ return 0;
+ return read_blob_object(buf, &ce->oid, ce->ce_mode);
+}
+
+static struct patch *in_fn_table(struct apply_state *state, const char *name)
+{
+ struct string_list_item *item;
+
+ if (name == NULL)
+ return NULL;
+
+ item = string_list_lookup(&state->fn_table, name);
+ if (item != NULL)
+ return (struct patch *)item->util;
+
+ return NULL;
+}
+
+/*
+ * item->util in the filename table records the status of the path.
+ * Usually it points at a patch (whose result records the contents
+ * of it after applying it), but it could be PATH_WAS_DELETED for a
+ * path that a previously applied patch has already removed, 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 presence of B as we
+ * will remove it in a later patch.
+ */
+#define PATH_TO_BE_DELETED ((struct patch *) -2)
+#define PATH_WAS_DELETED ((struct patch *) -1)
+
+static int to_be_deleted(struct patch *patch)
+{
+ return patch == PATH_TO_BE_DELETED;
+}
+
+static int was_deleted(struct patch *patch)
+{
+ return patch == PATH_WAS_DELETED;
+}
+
+static void add_to_fn_table(struct apply_state *state, struct patch *patch)
+{
+ struct string_list_item *item;
+
+ /*
+ * Always add new_name unless patch is a deletion
+ * This should cover the cases for normal diffs,
+ * file creations and copies
+ */
+ if (patch->new_name != NULL) {
+ item = string_list_insert(&state->fn_table, patch->new_name);
+ item->util = patch;
+ }
+
+ /*
+ * store a failure on rename/deletion cases because
+ * later chunks shouldn't patch old names
+ */
+ if ((patch->new_name == NULL) || (patch->is_rename)) {
+ item = string_list_insert(&state->fn_table, patch->old_name);
+ item->util = PATH_WAS_DELETED;
+ }
+}
+
+static void prepare_fn_table(struct apply_state *state, struct patch *patch)
+{
+ /*
+ * store information about incoming file deletion
+ */
+ while (patch) {
+ if ((patch->new_name == NULL) || (patch->is_rename)) {
+ struct string_list_item *item;
+ item = string_list_insert(&state->fn_table, patch->old_name);
+ item->util = PATH_TO_BE_DELETED;
+ }
+ patch = patch->next;
+ }
+}
+
+static int checkout_target(struct index_state *istate,
+ struct cache_entry *ce, struct stat *st)
+{
+ struct checkout costate = CHECKOUT_INIT;
+
+ costate.refresh_cache = 1;
+ costate.istate = istate;
+ 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 apply_state *state,
+ 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(state, 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(const 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 apply_state *state,
+ struct strbuf *buf,
+ const struct cache_entry *ce,
+ struct stat *st,
+ const char *name,
+ unsigned expected_mode)
+{
+ if (state->cached || state->check_index) {
+ if (read_file_or_gitlink(ce, buf))
+ return error(_("failed to read %s"), 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 (has_symlink_leading_path(name, strlen(name))) {
+ return error(_("reading from '%s' beyond a symbolic link"), name);
+ } else {
+ if (read_old_data(st, name, buf))
+ return error(_("failed to read %s"), 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 apply_state *state,
+ struct image *image,
+ struct patch *patch, struct stat *st,
+ const struct cache_entry *ce)
+{
+ struct strbuf buf = STRBUF_INIT;
+ size_t len;
+ char *img;
+ struct patch *previous;
+ int status;
+
+ previous = previous_patch(state, 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(state, &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(_("failed to read %s"), patch->old_name);
+ }
+ }
+
+ img = strbuf_detach(&buf, &len);
+ prepare_image(image, img, len, !patch->is_binary);
+ return 0;
+}
+
+static int three_way_merge(struct image *image,
+ char *path,
+ const struct object_id *base,
+ const struct object_id *ours,
+ const struct object_id *theirs)
+{
+ mmfile_t base_file, our_file, their_file;
+ mmbuffer_t result = { NULL };
+ int status;
+
+ 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 apply_state *state,
+ 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_errno("%s", name);
+ if (checkout_target(&the_index, ce, &st))
+ return -1;
+ }
+ if (verify_index_match(ce, &st))
+ return error(_("%s: does not match index"), name);
+
+ status = load_patch_target(state, &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 try_threeway(struct apply_state *state,
+ struct image *image,
+ struct patch *patch,
+ struct stat *st,
+ const struct cache_entry *ce)
+{
+ struct object_id pre_oid, post_oid, our_oid;
+ 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_oid.hash);
+ else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) ||
+ read_blob_object(&buf, &pre_oid, patch->old_mode))
+ return error("repository lacks the necessary blob to fall back on 3-way merge.");
+
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf(stderr, "Falling back to three-way merge...\n");
+
+ img = strbuf_detach(&buf, &len);
+ prepare_image(&tmp_image, img, len, 1);
+ /* Apply the patch to get the post image */
+ if (apply_fragments(state, &tmp_image, patch) < 0) {
+ clear_image(&tmp_image);
+ return -1;
+ }
+ /* post_oid is theirs */
+ write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
+ clear_image(&tmp_image);
+
+ /* our_oid is ours */
+ if (patch->is_new) {
+ if (load_current(state, &tmp_image, patch))
+ return error("cannot read the current contents of '%s'",
+ patch->new_name);
+ } else {
+ if (load_preimage(state, &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_oid.hash);
+ 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_oid, &our_oid, &post_oid);
+ if (status < 0) {
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf(stderr,
+ "Failed to fall back on three-way merge...\n");
+ return status;
+ }
+
+ if (status) {
+ patch->conflicted_threeway = 1;
+ if (patch->is_new)
+ oidclr(&patch->threeway_stage[0]);
+ else
+ oidcpy(&patch->threeway_stage[0], &pre_oid);
+ oidcpy(&patch->threeway_stage[1], &our_oid);
+ oidcpy(&patch->threeway_stage[2], &post_oid);
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf(stderr,
+ "Applied patch to '%s' with conflicts.\n",
+ patch->new_name);
+ } else {
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf(stderr,
+ "Applied patch to '%s' cleanly.\n",
+ patch->new_name);
+ }
+ return 0;
+}
+
+static int apply_data(struct apply_state *state, struct patch *patch,
+ struct stat *st, const struct cache_entry *ce)
+{
+ struct image image;
+
+ if (load_preimage(state, &image, patch, st, ce) < 0)
+ return -1;
+
+ if (patch->direct_to_threeway ||
+ apply_fragments(state, &image, patch) < 0) {
+ /* Note: with --reject, apply_fragments() returns 0 */
+ if (!state->threeway || try_threeway(state, &image, patch, st, ce) < 0)
+ return -1;
+ }
+ patch->result = image.buf;
+ patch->resultsize = image.len;
+ add_to_fn_table(state, 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 apply_state *state,
+ struct patch *patch,
+ struct cache_entry **ce,
+ struct stat *st)
+{
+ const char *old_name = patch->old_name;
+ struct patch *previous = NULL;
+ int stat_ret = 0, status;
+ unsigned st_mode = 0;
+
+ if (!old_name)
+ return 0;
+
+ assert(patch->is_new <= 0);
+ previous = previous_patch(state, patch, &status);
+
+ if (status)
+ return error(_("path %s has been renamed/deleted"), old_name);
+ if (previous) {
+ st_mode = previous->new_mode;
+ } else if (!state->cached) {
+ stat_ret = lstat(old_name, st);
+ if (stat_ret && errno != ENOENT)
+ return error_errno("%s", old_name);
+ }
+
+ if (state->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);
+ }
+ *ce = active_cache[pos];
+ if (stat_ret < 0) {
+ if (checkout_target(&the_index, *ce, st))
+ return -1;
+ }
+ if (!state->cached && verify_index_match(*ce, st))
+ return error(_("%s: does not match index"), old_name);
+ if (state->cached)
+ st_mode = (*ce)->ce_mode;
+ } else if (stat_ret < 0) {
+ if (patch->is_new < 0)
+ goto is_new;
+ return error_errno("%s", old_name);
+ }
+
+ if (!state->cached && !previous)
+ st_mode = ce_mode_from_stat(*ce, st->st_mode);
+
+ if (patch->is_new < 0)
+ patch->is_new = 0;
+ if (!patch->old_mode)
+ patch->old_mode = st_mode;
+ if ((st_mode ^ patch->old_mode) & S_IFMT)
+ return error(_("%s: wrong type"), old_name);
+ if (st_mode != patch->old_mode)
+ 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;
+ return 0;
+
+ 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(struct apply_state *state,
+ const char *new_name,
+ int ok_if_exists)
+{
+ struct stat nst;
+
+ if (state->check_index &&
+ cache_name_pos(new_name, strlen(new_name)) >= 0 &&
+ !ok_if_exists)
+ return EXISTS_IN_INDEX;
+ if (state->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_errno("%s", new_name);
+ }
+ return 0;
+}
+
+static uintptr_t register_symlink_changes(struct apply_state *state,
+ const char *path,
+ uintptr_t what)
+{
+ struct string_list_item *ent;
+
+ ent = string_list_lookup(&state->symlink_changes, path);
+ if (!ent) {
+ ent = string_list_insert(&state->symlink_changes, path);
+ ent->util = (void *)0;
+ }
+ ent->util = (void *)(what | ((uintptr_t)ent->util));
+ return (uintptr_t)ent->util;
+}
+
+static uintptr_t check_symlink_changes(struct apply_state *state, const char *path)
+{
+ struct string_list_item *ent;
+
+ ent = string_list_lookup(&state->symlink_changes, path);
+ if (!ent)
+ return 0;
+ return (uintptr_t)ent->util;
+}
+
+static void prepare_symlink_changes(struct apply_state *state, struct patch *patch)
+{
+ for ( ; patch; patch = patch->next) {
+ if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
+ (patch->is_rename || patch->is_delete))
+ /* the symlink at patch->old_name is removed */
+ register_symlink_changes(state, patch->old_name, APPLY_SYMLINK_GOES_AWAY);
+
+ if (patch->new_name && S_ISLNK(patch->new_mode))
+ /* the symlink at patch->new_name is created or remains */
+ register_symlink_changes(state, patch->new_name, APPLY_SYMLINK_IN_RESULT);
+ }
+}
+
+static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *name)
+{
+ do {
+ unsigned int change;
+
+ while (--name->len && name->buf[name->len] != '/')
+ ; /* scan backwards */
+ if (!name->len)
+ break;
+ name->buf[name->len] = '\0';
+ change = check_symlink_changes(state, name->buf);
+ if (change & APPLY_SYMLINK_IN_RESULT)
+ return 1;
+ if (change & APPLY_SYMLINK_GOES_AWAY)
+ /*
+ * This cannot be "return 0", because we may
+ * see a new one created at a higher level.
+ */
+ continue;
+
+ /* otherwise, check the preimage */
+ if (state->check_index) {
+ struct cache_entry *ce;
+
+ ce = cache_file_exists(name->buf, name->len, ignore_case);
+ if (ce && S_ISLNK(ce->ce_mode))
+ return 1;
+ } else {
+ struct stat st;
+ if (!lstat(name->buf, &st) && S_ISLNK(st.st_mode))
+ return 1;
+ }
+ } while (1);
+ return 0;
+}
+
+static int path_is_beyond_symlink(struct apply_state *state, const char *name_)
+{
+ int ret;
+ struct strbuf name = STRBUF_INIT;
+
+ assert(*name_ != '\0');
+ strbuf_addstr(&name, name_);
+ ret = path_is_beyond_symlink_1(state, &name);
+ strbuf_release(&name);
+
+ return ret;
+}
+
+static int check_unsafe_path(struct patch *patch)
+{
+ const char *old_name = NULL;
+ const char *new_name = NULL;
+ if (patch->is_delete)
+ old_name = patch->old_name;
+ else if (!patch->is_new && !patch->is_copy)
+ old_name = patch->old_name;
+ if (!patch->is_delete)
+ new_name = patch->new_name;
+
+ if (old_name && !verify_path(old_name))
+ return error(_("invalid path '%s'"), old_name);
+ if (new_name && !verify_path(new_name))
+ return error(_("invalid path '%s'"), new_name);
+ 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 apply_state *state, struct patch *patch)
+{
+ struct stat st;
+ const char *old_name = patch->old_name;
+ const char *new_name = patch->new_name;
+ const char *name = old_name ? old_name : new_name;
+ struct cache_entry *ce = NULL;
+ struct patch *tpatch;
+ int ok_if_exists;
+ int status;
+
+ patch->rejected = 1; /* we will drop this after we succeed */
+
+ status = check_preimage(state, patch, &ce, &st);
+ if (status)
+ 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 presence 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(state, new_name)) &&
+ (was_deleted(tpatch) || to_be_deleted(tpatch)))
+ ok_if_exists = 1;
+ else
+ ok_if_exists = 0;
+
+ if (new_name &&
+ ((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
+ int err = check_to_create(state, new_name, ok_if_exists);
+
+ if (err && state->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;
+ else
+ patch->new_mode = patch->old_mode;
+ }
+ }
+
+ if (new_name && old_name) {
+ 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) {
+ 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 (!state->unsafe_paths && check_unsafe_path(patch))
+ return -128;
+
+ /*
+ * An attempt to read from or delete a path that is beyond a
+ * symbolic link will be prevented by load_patch_target() that
+ * is called at the beginning of apply_data() so we do not
+ * have to worry about a patch marked with "is_delete" bit
+ * here. We however need to make sure that the patch result
+ * is not deposited to a path that is beyond a symbolic link
+ * here.
+ */
+ if (!patch->is_delete && path_is_beyond_symlink(state, patch->new_name))
+ return error(_("affected file '%s' is beyond a symbolic link"),
+ patch->new_name);
+
+ if (apply_data(state, patch, &st, ce) < 0)
+ return error(_("%s: patch does not apply"), name);
+ patch->rejected = 0;
+ return 0;
+}
+
+static int check_patch_list(struct apply_state *state, struct patch *patch)
+{
+ int err = 0;
+
+ prepare_symlink_changes(state, patch);
+ prepare_fn_table(state, patch);
+ while (patch) {
+ int res;
+ if (state->apply_verbosity > verbosity_normal)
+ say_patch_name(stderr,
+ _("Checking patch %s..."), patch);
+ res = check_patch(state, patch);
+ if (res == -128)
+ return -128;
+ err |= res;
+ patch = patch->next;
+ }
+ return err;
+}
+
+static int read_apply_cache(struct apply_state *state)
+{
+ if (state->index_file)
+ return read_cache_from(state->index_file);
+ else
+ return read_cache();
+}
+
+/* This function tries to read the object name from the current index */
+static int get_current_oid(struct apply_state *state, const char *path,
+ struct object_id *oid)
+{
+ int pos;
+
+ if (read_apply_cache(state) < 0)
+ return -1;
+ pos = cache_name_pos(path, strlen(path));
+ if (pos < 0)
+ return -1;
+ oidcpy(oid, &active_cache[pos]->oid);
+ return 0;
+}
+
+static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
+{
+ /*
+ * A usable gitlink patch has only one fragment (hunk) that looks like:
+ * @@ -1 +1 @@
+ * -Subproject commit <old sha1>
+ * +Subproject commit <new sha1>
+ * or
+ * @@ -1 +0,0 @@
+ * -Subproject commit <old sha1>
+ * for a removal patch.
+ */
+ struct fragment *hunk = p->fragments;
+ static const char heading[] = "-Subproject commit ";
+ char *preimage;
+
+ if (/* does the patch have only one hunk? */
+ hunk && !hunk->next &&
+ /* is its preimage one line? */
+ hunk->oldpos == 1 && hunk->oldlines == 1 &&
+ /* does preimage begin with the heading? */
+ (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
+ starts_with(++preimage, heading) &&
+ /* does it record full SHA-1? */
+ !get_oid_hex(preimage + sizeof(heading) - 1, oid) &&
+ preimage[sizeof(heading) + GIT_SHA1_HEXSZ - 1] == '\n' &&
+ /* does the abbreviated name on the index line agree with it? */
+ starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
+ return 0; /* it all looks fine */
+
+ /* we may have full object name on the index line */
+ return get_oid_hex(p->old_sha1_prefix, oid);
+}
+
+/* Build an index that contains the just the files needed for a 3way merge */
+static int build_fake_ancestor(struct apply_state *state, struct patch *list)
+{
+ struct patch *patch;
+ struct index_state result = { NULL };
+ static struct lock_file lock;
+ int res;
+
+ /* Once we start supporting the reverse patch, it may be
+ * worth showing the new sha1 prefix, but until then...
+ */
+ for (patch = list; patch; patch = patch->next) {
+ struct object_id oid;
+ struct cache_entry *ce;
+ const char *name;
+
+ name = patch->old_name ? patch->old_name : patch->new_name;
+ if (0 < patch->is_new)
+ continue;
+
+ if (S_ISGITLINK(patch->old_mode)) {
+ if (!preimage_oid_in_gitlink_patch(patch, &oid))
+ ; /* ok, the textual part looks sane */
+ else
+ return error("sha1 information is lacking or "
+ "useless for submodule %s", name);
+ } else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) {
+ ; /* ok */
+ } else if (!patch->lines_added && !patch->lines_deleted) {
+ /* mode-only change: update the current */
+ if (get_current_oid(state, patch->old_name, &oid))
+ return error("mode change for %s, which is not "
+ "in current HEAD", name);
+ } else
+ return error("sha1 information is lacking or useless "
+ "(%s).", name);
+
+ ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);
+ if (!ce)
+ return error(_("make_cache_entry failed for path '%s'"),
+ name);
+ if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
+ free(ce);
+ return error("Could not add %s to temporary index",
+ name);
+ }
+ }
+
+ hold_lock_file_for_update(&lock, state->fake_ancestor, LOCK_DIE_ON_ERROR);
+ res = write_locked_index(&result, &lock, COMMIT_LOCK);
+ discard_index(&result);
+
+ if (res)
+ return error("Could not write temporary index to %s",
+ state->fake_ancestor);
+
+ return 0;
+ }
+
+ static void stat_patch_list(struct apply_state *state, struct patch *patch)
+ {
+ int files, adds, dels;
+
+ for (files = adds = dels = 0 ; patch ; patch = patch->next) {
+ files++;
+ adds += patch->lines_added;
+ dels += patch->lines_deleted;
+ show_stats(state, patch);
+ }
+
+ print_stat_summary(stdout, files, adds, dels);
+ }
+
+ static void numstat_patch_list(struct apply_state *state,
+ struct patch *patch)
+ {
+ for ( ; patch; patch = patch->next) {
+ const char *name;
+ name = patch->new_name ? patch->new_name : patch->old_name;
+ if (patch->is_binary)
+ printf("-\t-\t");
+ else
+ printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+ write_name_quoted(name, stdout, state->line_termination);
+ }
+ }
+
+ static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
+ {
+ if (mode)
+ printf(" %s mode %06o %s\n", newdelete, mode, name);
+ else
+ printf(" %s %s\n", newdelete, name);
+ }
+
+ static void show_mode_change(struct patch *p, int show_name)
+ {
+ if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
+ if (show_name)
+ printf(" mode change %06o => %06o %s\n",
+ p->old_mode, p->new_mode, p->new_name);
+ else
+ printf(" mode change %06o => %06o\n",
+ p->old_mode, p->new_mode);
+ }
+ }
+
+ static void show_rename_copy(struct patch *p)
+ {
+ const char *renamecopy = p->is_rename ? "rename" : "copy";
+ const char *old, *new;
+
+ /* Find common prefix */
+ old = p->old_name;
+ new = p->new_name;
+ while (1) {
+ const char *slash_old, *slash_new;
+ slash_old = strchr(old, '/');
+ slash_new = strchr(new, '/');
+ if (!slash_old ||
+ !slash_new ||
+ slash_old - old != slash_new - new ||
+ memcmp(old, new, slash_new - new))
+ break;
+ old = slash_old + 1;
+ new = slash_new + 1;
+ }
+ /* p->old_name thru old is the common prefix, and old and new
+ * through the end of names are renames
+ */
+ if (old != p->old_name)
+ printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
+ (int)(old - p->old_name), p->old_name,
+ old, new, p->score);
+ else
+ printf(" %s %s => %s (%d%%)\n", renamecopy,
+ p->old_name, p->new_name, p->score);
+ show_mode_change(p, 0);
+ }
+
+ static void summary_patch_list(struct patch *patch)
+ {
+ struct patch *p;
+
+ for (p = patch; p; p = p->next) {
+ if (p->is_new)
+ show_file_mode_name("create", p->new_mode, p->new_name);
+ else if (p->is_delete)
+ show_file_mode_name("delete", p->old_mode, p->old_name);
+ else {
+ if (p->is_rename || p->is_copy)
+ show_rename_copy(p);
+ else {
+ if (p->score) {
+ printf(" rewrite %s (%d%%)\n",
+ p->new_name, p->score);
+ show_mode_change(p, 0);
+ }
+ else
+ show_mode_change(p, 1);
+ }
+ }
+ }
+ }
+
+ static void patch_stats(struct apply_state *state, struct patch *patch)
+ {
+ int lines = patch->lines_added + patch->lines_deleted;
+
+ if (lines > state->max_change)
+ state->max_change = lines;
+ if (patch->old_name) {
+ int len = quote_c_style(patch->old_name, NULL, NULL, 0);
+ if (!len)
+ len = strlen(patch->old_name);
+ if (len > state->max_len)
+ state->max_len = len;
+ }
+ if (patch->new_name) {
+ int len = quote_c_style(patch->new_name, NULL, NULL, 0);
+ if (!len)
+ len = strlen(patch->new_name);
+ if (len > state->max_len)
+ state->max_len = len;
+ }
+ }
+
+ static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
+ {
+ if (state->update_index) {
+ if (remove_file_from_cache(patch->old_name) < 0)
+ return error(_("unable to remove %s from index"), patch->old_name);
+ }
+ if (!state->cached) {
+ if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
+ remove_path(patch->old_name);
+ }
+ }
+ return 0;
+ }
+
+ static int add_index_file(struct apply_state *state,
+ const char *path,
+ unsigned mode,
+ void *buf,
+ unsigned long size)
+ {
+ struct stat st;
+ struct cache_entry *ce;
+ int namelen = strlen(path);
+ unsigned ce_size = cache_entry_size(namelen);
+
+ if (!state->update_index)
+ return 0;
+
+ ce = xcalloc(1, ce_size);
+ memcpy(ce->name, path, namelen);
+ ce->ce_mode = create_ce_mode(mode);
+ ce->ce_flags = create_ce_flags(0);
+ ce->ce_namelen = namelen;
+ if (S_ISGITLINK(mode)) {
+ const char *s;
+
+ if (!skip_prefix(buf, "Subproject commit ", &s) ||
+ get_oid_hex(s, &ce->oid)) {
+ free(ce);
+ return error(_("corrupt patch for submodule %s"), path);
+ }
+ } else {
+ if (!state->cached) {
+ if (lstat(path, &st) < 0) {
+ free(ce);
+ return error_errno(_("unable to stat newly "
+ "created file '%s'"),
+ path);
+ }
+ fill_stat_cache_info(ce, &st);
+ }
+ if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
+ free(ce);
+ return error(_("unable to create backing store "
+ "for newly created file %s"), path);
+ }
+ }
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
+ free(ce);
+ return error(_("unable to add cache entry for %s"), path);
+ }
+
+ return 0;
+}
+
+/*
+ * Returns:
+ * -1 if an unrecoverable error happened
+ * 0 if everything went well
+ * 1 if a recoverable error happened
+ */
+static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
+{
+ int fd, res;
+ struct strbuf nbuf = STRBUF_INIT;
+
+ if (S_ISGITLINK(mode)) {
+ struct stat st;
+ if (!lstat(path, &st) && S_ISDIR(st.st_mode))
+ return 0;
+ return !!mkdir(path, 0777);
+ }
+
+ if (has_symlinks && S_ISLNK(mode))
+ /* Although buf:size is counted string, it also is NUL
+ * terminated.
+ */
+ return !!symlink(buf, path);
+
+ fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
+ if (fd < 0)
+ return 1;
+
+ if (convert_to_working_tree(path, buf, size, &nbuf)) {
+ size = nbuf.len;
+ buf = nbuf.buf;
+ }
+
+ res = write_in_full(fd, buf, size) < 0;
+ if (res)
+ error_errno(_("failed to write to '%s'"), path);
+ strbuf_release(&nbuf);
+
+ if (close(fd) < 0 && !res)
+ return error_errno(_("closing file '%s'"), path);
+
+ return res ? -1 : 0;
+}
+
+/*
+ * We optimistically assume that the directories exist,
+ * which is true 99% of the time anyway. If they don't,
+ * we create them and try again.
+ *
+ * Returns:
+ * -1 on error
+ * 0 otherwise
+ */
+static int create_one_file(struct apply_state *state,
+ char *path,
+ unsigned mode,
+ const char *buf,
+ unsigned long size)
+{
+ int res;
+
+ if (state->cached)
+ return 0;
+
+ res = try_create_file(path, mode, buf, size);
+ if (res < 0)
+ return -1;
+ if (!res)
+ return 0;
+
+ if (errno == ENOENT) {
+ if (safe_create_leading_directories(path))
+ return 0;
+ res = try_create_file(path, mode, buf, size);
+ if (res < 0)
+ return -1;
+ if (!res)
+ return 0;
+ }
+
+ if (errno == EEXIST || errno == EACCES) {
+ /* We may be trying to create a file where a directory
+ * used to be.
+ */
+ struct stat st;
+ if (!lstat(path, &st) && (!S_ISDIR(st.st_mode) || !rmdir(path)))
+ errno = EEXIST;
+ }
+
+ if (errno == EEXIST) {
+ unsigned int nr = getpid();
+
+ for (;;) {
+ char newpath[PATH_MAX];
+ mksnpath(newpath, sizeof(newpath), "%s~%u", path, nr);
+ res = try_create_file(newpath, mode, buf, size);
+ if (res < 0)
+ return -1;
+ if (!res) {
+ if (!rename(newpath, path))
+ return 0;
+ unlink_or_warn(newpath);
+ break;
+ }
+ if (errno != EEXIST)
+ break;
+ ++nr;
+ }
+ }
+ return error_errno(_("unable to write file '%s' mode %o"),
+ path, mode);
+}
+
+static int add_conflicted_stages_file(struct apply_state *state,
+ struct patch *patch)
+{
+ int stage, namelen;
+ unsigned ce_size, mode;
+ struct cache_entry *ce;
+
+ if (!state->update_index)
+ return 0;
+ 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_oid(&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(stage);
+ ce->ce_namelen = namelen;
+ oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
+ free(ce);
+ return error(_("unable to add cache entry for %s"),
+ patch->new_name);
+ }
+ }
+
+ return 0;
+}
+
+static int create_file(struct apply_state *state, struct patch *patch)
+{
+ char *path = patch->new_name;
+ unsigned mode = patch->new_mode;
+ unsigned long size = patch->resultsize;
+ char *buf = patch->result;
+
+ if (!mode)
+ mode = S_IFREG | 0644;
+ if (create_one_file(state, path, mode, buf, size))
+ return -1;
+
+ if (patch->conflicted_threeway)
+ return add_conflicted_stages_file(state, patch);
+ else
+ return add_index_file(state, path, mode, buf, size);
+}
+
+/* phase zero is to remove, phase one is to create */
+static int write_out_one_result(struct apply_state *state,
+ struct patch *patch,
+ int phase)
+{
+ if (patch->is_delete > 0) {
+ if (phase == 0)
+ return remove_file(state, patch, 1);
+ return 0;
+ }
+ if (patch->is_new > 0 || patch->is_copy) {
+ if (phase == 1)
+ return create_file(state, patch);
+ return 0;
+ }
+ /*
+ * Rename or modification boils down to the same
+ * thing: remove the old, write the new
+ */
+ if (phase == 0)
+ return remove_file(state, patch, patch->is_rename);
+ if (phase == 1)
+ return create_file(state, patch);
+ return 0;
+}
+
+static int write_out_one_reject(struct apply_state *state, struct patch *patch)
+{
+ FILE *rej;
+ 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)
+ continue;
+ cnt++;
+ }
+
+ if (!cnt) {
+ if (state->apply_verbosity > verbosity_normal)
+ say_patch_name(stderr,
+ _("Applied patch %s cleanly."), patch);
+ return 0;
+ }
+
+ /* This should not happen, because a removal patch that leaves
+ * contents are marked "rejected" at the patch level.
+ */
+ if (!patch->new_name)
+ die(_("internal error"));
+
+ /* Say this even without --verbose */
+ strbuf_addf(&sb, Q_("Applying patch %%s with %d reject...",
+ "Applying patch %%s with %d rejects...",
+ cnt),
+ cnt);
+ if (state->apply_verbosity > verbosity_silent)
+ 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"),
+ cnt - 1, patch->new_name);
+ }
+ memcpy(namebuf, patch->new_name, cnt);
+ memcpy(namebuf + cnt, ".rej", 5);
+
+ rej = fopen(namebuf, "w");
+ if (!rej)
+ return error_errno(_("cannot open %s"), namebuf);
+
+ /* Normal git tools never deal with .rej, so do not pretend
+ * this is a git patch by saying --git or giving extended
+ * headers. While at it, maybe please "kompare" that wants
+ * the trailing TAB and some garbage at the end of line ;-).
+ */
+ fprintf(rej, "diff a/%s b/%s\t(rejected hunks)\n",
+ patch->new_name, patch->new_name);
+ for (cnt = 1, frag = patch->fragments;
+ frag;
+ cnt++, frag = frag->next) {
+ if (!frag->rejected) {
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt);
+ continue;
+ }
+ if (state->apply_verbosity > verbosity_silent)
+ fprintf_ln(stderr, _("Rejected hunk #%d."), cnt);
+ fprintf(rej, "%.*s", frag->size, frag->patch);
+ if (frag->patch[frag->size-1] != '\n')
+ fputc('\n', rej);
+ }
+ fclose(rej);
+ return -1;
+}
+
+/*
+ * Returns:
+ * -1 if an error happened
+ * 0 if the patch applied cleanly
+ * 1 if the patch did not apply cleanly
+ */
+static int write_out_results(struct apply_state *state, 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;
+ while (l) {
+ if (l->rejected)
+ errs = 1;
+ else {
+ if (write_out_one_result(state, l, phase)) {
+ string_list_clear(&cpath, 0);
+ return -1;
+ }
+ if (phase == 1) {
+ if (write_out_one_reject(state, 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;
+
+ string_list_sort(&cpath);
+ if (state->apply_verbosity > verbosity_silent) {
+ for_each_string_list_item(item, &cpath)
+ fprintf(stderr, "U %s\n", item->string);
+ }
+ string_list_clear(&cpath, 0);
+
+ rerere(0);
+ }
+
+ return errs;
+}
+
+/*
+ * Try to apply a patch.
+ *
+ * Returns:
+ * -128 if a bad error happened (like patch unreadable)
+ * -1 if patch did not apply and user cannot deal with it
+ * 0 if the patch applied
+ * 1 if the patch did not apply but user might fix it
+ */
+static int apply_patch(struct apply_state *state,
+ int fd,
+ const char *filename,
+ int options)
+{
+ size_t offset;
+ struct strbuf buf = STRBUF_INIT; /* owns the patch text */
+ struct patch *list = NULL, **listp = &list;
+ int skipped_patch = 0;
+ int res = 0;
+
+ state->patch_input_file = filename;
+ if (read_patch_file(&buf, fd) < 0)
+ return -128;
+ offset = 0;
+ while (offset < buf.len) {
+ struct patch *patch;
+ int nr;
+
+ patch = xcalloc(1, sizeof(*patch));
+ patch->inaccurate_eof = !!(options & APPLY_OPT_INACCURATE_EOF);
+ patch->recount = !!(options & APPLY_OPT_RECOUNT);
+ nr = parse_chunk(state, buf.buf + offset, buf.len - offset, patch);
+ if (nr < 0) {
+ free_patch(patch);
+ if (nr == -128) {
+ res = -128;
+ goto end;
+ }
+ break;
+ }
+ if (state->apply_in_reverse)
+ reverse_patches(patch);
+ if (use_patch(state, patch)) {
+ patch_stats(state, patch);
+ *listp = patch;
+ listp = &patch->next;
+ }
+ else {
+ if (state->apply_verbosity > verbosity_normal)
+ say_patch_name(stderr, _("Skipped patch '%s'."), patch);
+ free_patch(patch);
+ skipped_patch++;
+ }
+ offset += nr;
+ }
+
+ if (!list && !skipped_patch) {
+ error(_("unrecognized input"));
+ res = -128;
+ goto end;
+ }
+
+ if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
+ state->apply = 0;
+
+ state->update_index = state->check_index && state->apply;
+ if (state->update_index && state->newfd < 0) {
+ if (state->index_file)
+ state->newfd = hold_lock_file_for_update(state->lock_file,
+ state->index_file,
+ LOCK_DIE_ON_ERROR);
+ else
+ state->newfd = hold_locked_index(state->lock_file, 1);
+ }
+
+ if (state->check_index && read_apply_cache(state) < 0) {
+ error(_("unable to read index file"));
+ res = -128;
+ goto end;
+ }
+
+ if (state->check || state->apply) {
+ int r = check_patch_list(state, list);
+ if (r == -128) {
+ res = -128;
+ goto end;
+ }
+ if (r < 0 && !state->apply_with_reject) {
+ res = -1;
+ goto end;
+ }
+ }
+
+ if (state->apply) {
+ int write_res = write_out_results(state, list);
+ if (write_res < 0) {
+ res = -128;
+ goto end;
+ }
+ if (write_res > 0) {
+ /* with --3way, we still need to write the index out */
+ res = state->apply_with_reject ? -1 : 1;
+ goto end;
+ }
+ }
+
+ if (state->fake_ancestor &&
+ build_fake_ancestor(state, list)) {
+ res = -128;
+ goto end;
+ }
+
+ if (state->diffstat && state->apply_verbosity > verbosity_silent)
+ stat_patch_list(state, list);
+
+ if (state->numstat && state->apply_verbosity > verbosity_silent)
+ numstat_patch_list(state, list);
+
+ if (state->summary && state->apply_verbosity > verbosity_silent)
+ summary_patch_list(list);
+
+end:
+ free_patch_list(list);
+ strbuf_release(&buf);
+ string_list_clear(&state->fn_table, 0);
+ return res;
+}
+
+static int apply_option_parse_exclude(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct apply_state *state = opt->value;
+ add_name_limit(state, arg, 1);
+ return 0;
+}
+
+static int apply_option_parse_include(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct apply_state *state = opt->value;
+ add_name_limit(state, arg, 0);
+ state->has_include = 1;
+ return 0;
+}
+
+static int apply_option_parse_p(const struct option *opt,
+ const char *arg,
+ int unset)
+{
+ struct apply_state *state = opt->value;
+ state->p_value = atoi(arg);
+ state->p_value_known = 1;
+ return 0;
+}
+
+static int apply_option_parse_space_change(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct apply_state *state = opt->value;
+ if (unset)
+ state->ws_ignore_action = ignore_ws_none;
+ else
+ state->ws_ignore_action = ignore_ws_change;
+ return 0;
+}
+
+static int apply_option_parse_whitespace(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct apply_state *state = opt->value;
+ state->whitespace_option = arg;
+ if (parse_whitespace_option(state, arg))
+ exit(1);
+ return 0;
+}
+
+static int apply_option_parse_directory(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct apply_state *state = opt->value;
+ strbuf_reset(&state->root);
+ strbuf_addstr(&state->root, arg);
+ strbuf_complete(&state->root, '/');
+ return 0;
+}
+
+int apply_all_patches(struct apply_state *state,
+ int argc,
+ const char **argv,
+ int options)
+{
+ int i;
+ int res;
+ int errs = 0;
+ int read_stdin = 1;
+
+ for (i = 0; i < argc; i++) {
+ const char *arg = argv[i];
+ int fd;
+
+ if (!strcmp(arg, "-")) {
+ res = apply_patch(state, 0, "<stdin>", options);
+ if (res < 0)
+ goto end;
+ errs |= res;
+ read_stdin = 0;
+ continue;
+ } else if (0 < state->prefix_length)
+ arg = prefix_filename(state->prefix,
+ state->prefix_length,
+ arg);
+
+ fd = open(arg, O_RDONLY);
+ if (fd < 0) {
+ error(_("can't open patch '%s': %s"), arg, strerror(errno));
+ res = -128;
+ goto end;
+ }
+ read_stdin = 0;
+ set_default_whitespace_mode(state);
+ res = apply_patch(state, fd, arg, options);
+ close(fd);
+ if (res < 0)
+ goto end;
+ errs |= res;
+ }
+ set_default_whitespace_mode(state);
+ if (read_stdin) {
+ res = apply_patch(state, 0, "<stdin>", options);
+ if (res < 0)
+ goto end;
+ errs |= res;
+ }
+
+ if (state->whitespace_error) {
+ if (state->squelch_whitespace_errors &&
+ state->squelch_whitespace_errors < state->whitespace_error) {
+ int squelched =
+ state->whitespace_error - state->squelch_whitespace_errors;
+ warning(Q_("squelched %d whitespace error",
+ "squelched %d whitespace errors",
+ squelched),
+ squelched);
+ }
+ if (state->ws_error_action == die_on_ws_error) {
+ error(Q_("%d line adds whitespace errors.",
+ "%d lines add whitespace errors.",
+ state->whitespace_error),
+ state->whitespace_error);
+ res = -128;
+ goto end;
+ }
+ if (state->applied_after_fixing_ws && state->apply)
+ warning("%d line%s applied after"
+ " fixing whitespace errors.",
+ state->applied_after_fixing_ws,
+ state->applied_after_fixing_ws == 1 ? "" : "s");
+ else if (state->whitespace_error)
+ warning(Q_("%d line adds whitespace errors.",
+ "%d lines add whitespace errors.",
+ state->whitespace_error),
+ state->whitespace_error);
+ }
+
+ if (state->update_index) {
+ res = write_locked_index(&the_index, state->lock_file, COMMIT_LOCK);
+ if (res) {
+ error(_("Unable to write new index file"));
+ res = -128;
+ goto end;
+ }
+ state->newfd = -1;
+ }
+
+ res = !!errs;
+
+end:
+ if (state->newfd >= 0) {
+ rollback_lock_file(state->lock_file);
+ state->newfd = -1;
+ }
+
+ if (state->apply_verbosity <= verbosity_silent) {
+ set_error_routine(state->saved_error_routine);
+ set_warn_routine(state->saved_warn_routine);
+ }
+
+ if (res > -1)
+ return res;
+ return (res == -1 ? 1 : 128);
+}
+
+int apply_parse_options(int argc, const char **argv,
+ struct apply_state *state,
+ int *force_apply, int *options,
+ const char * const *apply_usage)
+{
+ struct option builtin_apply_options[] = {
+ { OPTION_CALLBACK, 0, "exclude", state, N_("path"),
+ N_("don't apply changes matching the given path"),
+ 0, apply_option_parse_exclude },
+ { OPTION_CALLBACK, 0, "include", state, N_("path"),
+ N_("apply changes matching the given path"),
+ 0, apply_option_parse_include },
+ { OPTION_CALLBACK, 'p', NULL, state, N_("num"),
+ N_("remove <num> leading slashes from traditional diff paths"),
+ 0, apply_option_parse_p },
+ OPT_BOOL(0, "no-add", &state->no_add,
+ N_("ignore additions made by the patch")),
+ OPT_BOOL(0, "stat", &state->diffstat,
+ N_("instead of applying the patch, output diffstat for the input")),
+ OPT_NOOP_NOARG(0, "allow-binary-replacement"),
+ OPT_NOOP_NOARG(0, "binary"),
+ OPT_BOOL(0, "numstat", &state->numstat,
+ N_("show number of added and deleted lines in decimal notation")),
+ OPT_BOOL(0, "summary", &state->summary,
+ N_("instead of applying the patch, output a summary for the input")),
+ OPT_BOOL(0, "check", &state->check,
+ N_("instead of applying the patch, see if the patch is applicable")),
+ OPT_BOOL(0, "index", &state->check_index,
+ N_("make sure the patch is applicable to the current index")),
+ OPT_BOOL(0, "cached", &state->cached,
+ N_("apply a patch without touching the working tree")),
+ OPT_BOOL(0, "unsafe-paths", &state->unsafe_paths,
+ N_("accept a patch that touches outside the working area")),
+ OPT_BOOL(0, "apply", force_apply,
+ N_("also apply the patch (use with --stat/--summary/--check)")),
+ OPT_BOOL('3', "3way", &state->threeway,
+ N_( "attempt three-way merge if a patch does not apply")),
+ OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor,
+ N_("build a temporary index based on embedded index information")),
+ /* Think twice before adding "--nul" synonym to this */
+ OPT_SET_INT('z', NULL, &state->line_termination,
+ N_("paths are separated with NUL character"), '\0'),
+ OPT_INTEGER('C', NULL, &state->p_context,
+ N_("ensure at least <n> lines of context match")),
+ { OPTION_CALLBACK, 0, "whitespace", state, N_("action"),
+ N_("detect new or modified lines that have whitespace errors"),
+ 0, apply_option_parse_whitespace },
+ { OPTION_CALLBACK, 0, "ignore-space-change", state, NULL,
+ N_("ignore changes in whitespace when finding context"),
+ PARSE_OPT_NOARG, apply_option_parse_space_change },
+ { OPTION_CALLBACK, 0, "ignore-whitespace", state, NULL,
+ N_("ignore changes in whitespace when finding context"),
+ PARSE_OPT_NOARG, apply_option_parse_space_change },
+ OPT_BOOL('R', "reverse", &state->apply_in_reverse,
+ N_("apply the patch in reverse")),
+ OPT_BOOL(0, "unidiff-zero", &state->unidiff_zero,
+ N_("don't expect at least one line of context")),
+ OPT_BOOL(0, "reject", &state->apply_with_reject,
+ N_("leave the rejected hunks in corresponding *.rej files")),
+ OPT_BOOL(0, "allow-overlap", &state->allow_overlap,
+ N_("allow overlapping hunks")),
+ OPT__VERBOSE(&state->apply_verbosity, N_("be verbose")),
+ OPT_BIT(0, "inaccurate-eof", options,
+ N_("tolerate incorrectly detected missing new-line at the end of file"),
+ APPLY_OPT_INACCURATE_EOF),
+ OPT_BIT(0, "recount", options,
+ N_("do not trust the line counts in the hunk headers"),
+ APPLY_OPT_RECOUNT),
+ { OPTION_CALLBACK, 0, "directory", state, N_("root"),
+ N_("prepend <root> to all filenames"),
+ 0, apply_option_parse_directory },
+ OPT_END()
+ };
+
+ return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+}
diff --git a/apply.h b/apply.h
new file mode 100644
index 0000000..b3d6783
--- /dev/null
+++ b/apply.h
@@ -0,0 +1,137 @@
+#ifndef APPLY_H
+#define APPLY_H
+
+enum apply_ws_error_action {
+ nowarn_ws_error,
+ warn_on_ws_error,
+ die_on_ws_error,
+ correct_ws_error
+};
+
+enum apply_ws_ignore {
+ ignore_ws_none,
+ ignore_ws_change
+};
+
+enum apply_verbosity {
+ verbosity_silent = -1,
+ verbosity_normal = 0,
+ verbosity_verbose = 1
+};
+
+/*
+ * We need to keep track of how symlinks in the preimage are
+ * manipulated by the patches. A patch to add a/b/c where a/b
+ * is a symlink should not be allowed to affect the directory
+ * the symlink points at, but if the same patch removes a/b,
+ * it is perfectly fine, as the patch removes a/b to make room
+ * to create a directory a/b so that a/b/c can be created.
+ *
+ * See also "struct string_list symlink_changes" in "struct
+ * apply_state".
+ */
+#define APPLY_SYMLINK_GOES_AWAY 01
+#define APPLY_SYMLINK_IN_RESULT 02
+
+struct apply_state {
+ const char *prefix;
+ int prefix_length;
+
+ /* These are lock_file related */
+ struct lock_file *lock_file;
+ int newfd;
+
+ /* These control what gets looked at and modified */
+ int apply; /* this is not a dry-run */
+ int cached; /* apply to the index only */
+ int check; /* preimage must match working tree, don't actually apply */
+ int check_index; /* preimage must match the indexed version */
+ int update_index; /* check_index && apply */
+
+ /* These control cosmetic aspect of the output */
+ int diffstat; /* just show a diffstat, and don't actually apply */
+ int numstat; /* just show a numeric diffstat, and don't actually apply */
+ int summary; /* just report creation, deletion, etc, and don't actually apply */
+
+ /* These boolean parameters control how the apply is done */
+ int allow_overlap;
+ int apply_in_reverse;
+ int apply_with_reject;
+ int no_add;
+ int threeway;
+ int unidiff_zero;
+ int unsafe_paths;
+
+ /* Other non boolean parameters */
+ const char *index_file;
+ enum apply_verbosity apply_verbosity;
+ const char *fake_ancestor;
+ const char *patch_input_file;
+ int line_termination;
+ struct strbuf root;
+ int p_value;
+ int p_value_known;
+ unsigned int p_context;
+
+ /* Exclude and include path parameters */
+ struct string_list limit_by_name;
+ int has_include;
+
+ /* Various "current state" */
+ int linenr; /* current line number */
+ struct string_list symlink_changes; /* we have to track symlinks */
+
+ /*
+ * For "diff-stat" like behaviour, we keep track of the biggest change
+ * we've seen, and the longest filename. That allows us to do simple
+ * scaling.
+ */
+ int max_change;
+ int max_len;
+
+ /*
+ * Records filenames that have been touched, in order to handle
+ * the case where more than one patches touch the same file.
+ */
+ struct string_list fn_table;
+
+ /*
+ * This is to save reporting routines before using
+ * set_error_routine() or set_warn_routine() to install muting
+ * routines when in verbosity_silent mode.
+ */
+ void (*saved_error_routine)(const char *err, va_list params);
+ void (*saved_warn_routine)(const char *warn, va_list params);
+
+ /* These control whitespace errors */
+ enum apply_ws_error_action ws_error_action;
+ enum apply_ws_ignore ws_ignore_action;
+ const char *whitespace_option;
+ int whitespace_error;
+ int squelch_whitespace_errors;
+ int applied_after_fixing_ws;
+};
+
+extern int apply_parse_options(int argc, const char **argv,
+ struct apply_state *state,
+ int *force_apply, int *options,
+ const char * const *apply_usage);
+extern int init_apply_state(struct apply_state *state,
+ const char *prefix,
+ struct lock_file *lock_file);
+extern void clear_apply_state(struct apply_state *state);
+extern int check_apply_state(struct apply_state *state, int force_apply);
+
+/*
+ * Some aspects of the apply behavior are controlled by the following
+ * bits in the "options" parameter passed to apply_all_patches().
+ */
+#define APPLY_OPT_INACCURATE_EOF (1<<0) /* accept inaccurate eof */
+#define APPLY_OPT_RECOUNT (1<<1) /* accept inaccurate line count */
+
+extern int apply_all_patches(struct apply_state *state,
+ int argc,
+ const char **argv,
+ int options);
+
+#endif
diff --git a/archive-tar.c b/archive-tar.c
index cb99df2..380e3ae 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -18,6 +18,21 @@ static int tar_umask = 002;
static int write_tar_filter_archive(const struct archiver *ar,
struct archiver_args *args);
+/*
+ * This is the max value that a ustar size header can specify, as it is fixed
+ * at 11 octal digits. POSIX specifies that we switch to extended headers at
+ * this size.
+ *
+ * Likewise for the mtime (which happens to use a buffer of the same size).
+ */
+#if ULONG_MAX == 0xFFFFFFFF
+#define USTAR_MAX_SIZE ULONG_MAX
+#define USTAR_MAX_MTIME ULONG_MAX
+#else
+#define USTAR_MAX_SIZE 077777777777UL
+#define USTAR_MAX_MTIME 077777777777UL
+#endif
+
/* writes out the whole block, but only if it is full */
static void write_if_needed(void)
{
@@ -137,6 +152,20 @@ static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
strbuf_addch(sb, '\n');
}
+/*
+ * Like strbuf_append_ext_header, but for numeric values.
+ */
+static void strbuf_append_ext_header_uint(struct strbuf *sb,
+ const char *keyword,
+ uintmax_t value)
+{
+ char buf[40]; /* big enough for 2^128 in decimal, plus NUL */
+ int len;
+
+ len = xsnprintf(buf, sizeof(buf), "%"PRIuMAX, value);
+ strbuf_append_ext_header(sb, keyword, buf, len);
+}
+
static unsigned int ustar_header_chksum(const struct ustar_header *header)
{
const unsigned char *p = (const unsigned char *)header;
@@ -184,9 +213,9 @@ static void prepare_header(struct archiver_args *args,
xsnprintf(header->chksum, sizeof(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)
+static void write_extended_header(struct archiver_args *args,
+ const unsigned char *sha1,
+ const void *buffer, unsigned long size)
{
struct ustar_header header;
unsigned int mode;
@@ -197,7 +226,6 @@ static int write_extended_header(struct archiver_args *args,
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,
@@ -208,7 +236,7 @@ static int write_tar_entry(struct archiver_args *args,
struct ustar_header header;
struct strbuf ext_header = STRBUF_INIT;
unsigned int old_mode = mode;
- unsigned long size;
+ unsigned long size, size_in_header;
void *buffer;
int err = 0;
@@ -267,15 +295,17 @@ static int write_tar_entry(struct archiver_args *args,
memcpy(header.linkname, buffer, size);
}
- prepare_header(args, &header, mode, size);
+ size_in_header = size;
+ if (S_ISREG(mode) && size > USTAR_MAX_SIZE) {
+ size_in_header = 0;
+ strbuf_append_ext_header_uint(&ext_header, "size", size);
+ }
+
+ prepare_header(args, &header, mode, size_in_header);
if (ext_header.len > 0) {
- err = write_extended_header(args, sha1, ext_header.buf,
- ext_header.len);
- if (err) {
- free(buffer);
- return err;
- }
+ write_extended_header(args, sha1, ext_header.buf,
+ ext_header.len);
}
strbuf_release(&ext_header);
write_blocked(&header, sizeof(header));
@@ -289,15 +319,25 @@ static int write_tar_entry(struct archiver_args *args,
return err;
}
-static int write_global_extended_header(struct archiver_args *args)
+static void write_global_extended_header(struct archiver_args *args)
{
const unsigned char *sha1 = args->commit_sha1;
struct strbuf ext_header = STRBUF_INIT;
struct ustar_header header;
unsigned int mode;
- int err = 0;
- strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
+ if (sha1)
+ strbuf_append_ext_header(&ext_header, "comment",
+ sha1_to_hex(sha1), 40);
+ if (args->time > USTAR_MAX_MTIME) {
+ strbuf_append_ext_header_uint(&ext_header, "mtime",
+ args->time);
+ args->time = USTAR_MAX_MTIME;
+ }
+
+ if (!ext_header.len)
+ return;
+
memset(&header, 0, sizeof(header));
*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
mode = 0100666;
@@ -306,7 +346,6 @@ static int write_global_extended_header(struct archiver_args *args)
write_blocked(&header, sizeof(header));
write_blocked(ext_header.buf, ext_header.len);
strbuf_release(&ext_header);
- return err;
}
static struct archiver **tar_filters;
@@ -382,10 +421,8 @@ static int write_tar_archive(const struct archiver *ar,
{
int err = 0;
- if (args->commit_sha1)
- err = write_global_extended_header(args);
- if (!err)
- err = write_archive_entries(args, write_tar_entry);
+ write_global_extended_header(args);
+ err = write_archive_entries(args, write_tar_entry);
if (!err)
write_trailer();
return err;
diff --git a/archive.c b/archive.c
index 5d735ae..dde1ab4 100644
--- a/archive.c
+++ b/archive.c
@@ -322,7 +322,7 @@ static int path_exists(struct tree *tree, const char *path)
pathspec.recursive = 1;
ret = read_tree_recursive(tree, "", 0, 0, &pathspec,
reject_entry, &pathspec);
- free_pathspec(&pathspec);
+ clear_pathspec(&pathspec);
return ret != 0;
}
@@ -458,11 +458,11 @@ static int parse_archive_args(int argc, const char **argv,
argc = parse_options(argc, argv, NULL, opts, archive_usage, 0);
if (remote)
- die("Unexpected option --remote");
+ die(_("Unexpected option --remote"));
if (exec)
- die("Option --exec can only be used together with --remote");
+ die(_("Option --exec can only be used together with --remote"));
if (output)
- die("Unexpected option --output");
+ die(_("Unexpected option --output"));
if (!base)
base = "";
@@ -484,14 +484,14 @@ static int parse_archive_args(int argc, const char **argv,
usage_with_options(archive_usage, opts);
*ar = lookup_archiver(format);
if (!*ar || (is_remote && !((*ar)->flags & ARCHIVER_REMOTE)))
- die("Unknown archive format '%s'", format);
+ die(_("Unknown archive format '%s'"), format);
args->compression_level = Z_DEFAULT_COMPRESSION;
if (compression_level != -1) {
if ((*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS)
args->compression_level = compression_level;
else {
- die("Argument not supported for format '%s': -%d",
+ die(_("Argument not supported for format '%s': -%d"),
format, compression_level);
}
}
diff --git a/bisect.c b/bisect.c
index dc13319..21bc6da 100644
--- a/bisect.c
+++ b/bisect.c
@@ -215,7 +215,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
array[cnt].distance = distance;
cnt++;
}
- qsort(array, cnt, sizeof(*array), compare_commit_dist);
+ QSORT(array, cnt, compare_commit_dist);
for (p = list, i = 0; i < cnt; i++) {
char buf[100]; /* enough for dist=%d */
struct object *obj = &(array[i].commit->object);
@@ -438,12 +438,12 @@ static void read_bisect_paths(struct argv_array *array)
FILE *fp = fopen(filename, "r");
if (!fp)
- die_errno("Could not open file '%s'", filename);
+ die_errno(_("Could not open file '%s'"), filename);
while (strbuf_getline_lf(&str, fp) != EOF) {
strbuf_trim(&str);
if (sq_dequote_to_argv_array(str.buf, array))
- die("Badly quoted content in file '%s': %s",
+ die(_("Badly quoted content in file '%s': %s"),
filename, str.buf);
}
@@ -646,10 +646,13 @@ static void exit_if_skipped_commits(struct commit_list *tried,
printf("There are only 'skip'ped commits left to test.\n"
"The first %s commit could be any of:\n", term_bad);
- print_commit_list(tried, "%s\n", "%s\n");
+
+ for ( ; tried; tried = tried->next)
+ printf("%s\n", oid_to_hex(&tried->item->object.oid));
+
if (bad)
printf("%s\n", oid_to_hex(bad));
- printf("We cannot bisect more!\n");
+ printf(_("We cannot bisect more!\n"));
exit(2);
}
@@ -702,7 +705,7 @@ static struct commit *get_commit_reference(const unsigned char *sha1)
{
struct commit *r = lookup_commit_reference(sha1);
if (!r)
- die("Not a valid commit name %s", sha1_to_hex(sha1));
+ die(_("Not a valid commit name %s"), sha1_to_hex(sha1));
return r;
}
@@ -726,27 +729,27 @@ static void handle_bad_merge_base(void)
char *bad_hex = oid_to_hex(current_bad_oid);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
- fprintf(stderr, "The merge base %s is bad.\n"
+ fprintf(stderr, _("The merge base %s is bad.\n"
"This means the bug has been fixed "
- "between %s and [%s].\n",
+ "between %s and [%s].\n"),
bad_hex, bad_hex, good_hex);
} else if (!strcmp(term_bad, "new") && !strcmp(term_good, "old")) {
- fprintf(stderr, "The merge base %s is new.\n"
+ fprintf(stderr, _("The merge base %s is new.\n"
"The property has changed "
- "between %s and [%s].\n",
+ "between %s and [%s].\n"),
bad_hex, bad_hex, good_hex);
} else {
- fprintf(stderr, "The merge base %s is %s.\n"
+ fprintf(stderr, _("The merge base %s is %s.\n"
"This means the first '%s' commit is "
- "between %s and [%s].\n",
+ "between %s and [%s].\n"),
bad_hex, term_bad, term_good, bad_hex, good_hex);
}
exit(3);
}
- fprintf(stderr, "Some %s revs are not ancestor of the %s rev.\n"
+ fprintf(stderr, _("Some %s revs are not ancestor of the %s rev.\n"
"git bisect cannot work properly in this case.\n"
- "Maybe you mistook %s and %s revs?\n",
+ "Maybe you mistook %s and %s revs?\n"),
term_good, term_bad, term_good, term_bad);
exit(1);
}
@@ -754,14 +757,14 @@ static void handle_bad_merge_base(void)
static void handle_skipped_merge_base(const unsigned char *mb)
{
char *mb_hex = sha1_to_hex(mb);
- char *bad_hex = sha1_to_hex(current_bad_oid->hash);
+ char *bad_hex = oid_to_hex(current_bad_oid);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
- warning("the merge base between %s and [%s] "
+ warning(_("the merge base between %s and [%s] "
"must be skipped.\n"
"So we cannot be sure the first %s commit is "
"between %s and %s.\n"
- "We continue anyway.",
+ "We continue anyway."),
bad_hex, good_hex, term_bad, mb_hex, bad_hex);
free(good_hex);
}
@@ -792,7 +795,7 @@ static void check_merge_bases(int no_checkout)
} else if (0 <= sha1_array_lookup(&skipped_revs, mb)) {
handle_skipped_merge_base(mb);
} else {
- printf("Bisecting: a merge base must be tested\n");
+ printf(_("Bisecting: a merge base must be tested\n"));
exit(bisect_checkout(mb, no_checkout));
}
}
@@ -843,7 +846,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
int fd;
if (!current_bad_oid)
- die("a %s revision is needed", term_bad);
+ die(_("a %s revision is needed"), term_bad);
/* Check if file BISECT_ANCESTORS_OK exists. */
if (!stat(filename, &st) && S_ISREG(st.st_mode))
@@ -860,7 +863,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
/* Create file BISECT_ANCESTORS_OK. */
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
- warning_errno("could not create file '%s'",
+ warning_errno(_("could not create file '%s'"),
filename);
else
close(fd);
@@ -911,7 +914,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
*read_good = "good";
return;
} else {
- die_errno("could not read file '%s'", filename);
+ die_errno(_("could not read file '%s'"), filename);
}
} else {
strbuf_getline_lf(&str, fp);
@@ -937,10 +940,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
struct commit_list *tried;
int reaches = 0, all = 0, nr, steps;
const unsigned char *bisect_rev;
+ char steps_msg[32];
read_bisect_terms(&term_bad, &term_good);
if (read_bisect_refs())
- die("reading bisect refs failed");
+ die(_("reading bisect refs failed"));
check_good_are_ancestors_of_bad(prefix, no_checkout);
@@ -960,7 +964,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
*/
exit_if_skipped_commits(tried, NULL);
- printf("%s was both %s and %s\n",
+ printf(_("%s was both %s and %s\n"),
oid_to_hex(current_bad_oid),
term_good,
term_bad);
@@ -968,8 +972,8 @@ int bisect_next_all(const char *prefix, int no_checkout)
}
if (!all) {
- fprintf(stderr, "No testable commit found.\n"
- "Maybe you started with bad path parameters?\n");
+ fprintf(stderr, _("No testable commit found.\n"
+ "Maybe you started with bad path parameters?\n"));
exit(4);
}
@@ -986,9 +990,14 @@ int bisect_next_all(const char *prefix, int no_checkout)
nr = all - reaches - 1;
steps = estimate_bisect_steps(all);
- printf("Bisecting: %d revision%s left to test after this "
- "(roughly %d step%s)\n", nr, (nr == 1 ? "" : "s"),
- steps, (steps == 1 ? "" : "s"));
+ xsnprintf(steps_msg, sizeof(steps_msg),
+ Q_("(roughly %d step)", "(roughly %d steps)", steps),
+ steps);
+ /* TRANSLATORS: the last %s will be replaced with
+ "(roughly %d steps)" translation */
+ printf(Q_("Bisecting: %d revision left to test after this %s\n",
+ "Bisecting: %d revisions left to test after this %s\n",
+ nr), nr, steps_msg);
return bisect_checkout(bisect_rev, no_checkout);
}
diff --git a/builtin.h b/builtin.h
index 6b95006..b9122bc 100644
--- a/builtin.h
+++ b/builtin.h
@@ -25,7 +25,7 @@ struct fmt_merge_msg_opts {
extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct fmt_merge_msg_opts *);
-extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const struct object_id *oid, int oid_valid, char **buf, unsigned long *buf_size);
extern int is_builtin(const char *s);
diff --git a/builtin/add.c b/builtin/add.c
index b1dddb4..e8fb80b 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -26,10 +26,25 @@ static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
struct update_callback_data {
- int flags, force_mode;
+ int flags;
int add_errors;
};
+static void chmod_pathspec(struct pathspec *pathspec, int force_mode)
+{
+ int i;
+
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+
+ if (pathspec && !ce_path_match(ce, pathspec, NULL))
+ continue;
+
+ if (chmod_cache_entry(ce, force_mode) < 0)
+ fprintf(stderr, "cannot chmod '%s'", ce->name);
+ }
+}
+
static int fix_unmerged_status(struct diff_filepair *p,
struct update_callback_data *data)
{
@@ -65,8 +80,7 @@ static void update_callback(struct diff_queue_struct *q,
die(_("unexpected diff status %c"), p->status);
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
- if (add_file_to_index(&the_index, path,
- data->flags, data->force_mode)) {
+ if (add_file_to_index(&the_index, path, data->flags)) {
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
die(_("updating files failed"));
data->add_errors++;
@@ -84,15 +98,14 @@ static void update_callback(struct diff_queue_struct *q,
}
}
-int add_files_to_cache(const char *prefix, const struct pathspec *pathspec,
- int flags, int force_mode)
+int add_files_to_cache(const char *prefix,
+ const struct pathspec *pathspec, int flags)
{
struct update_callback_data data;
struct rev_info rev;
memset(&data, 0, sizeof(data));
data.flags = flags;
- data.force_mode = force_mode;
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
@@ -281,7 +294,7 @@ static int add_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-static int add_files(struct dir_struct *dir, int flags, int force_mode)
+static int add_files(struct dir_struct *dir, int flags)
{
int i, exit_status = 0;
@@ -294,8 +307,7 @@ static int add_files(struct dir_struct *dir, int flags, int force_mode)
}
for (i = 0; i < dir->nr; i++)
- if (add_file_to_index(&the_index, dir->entries[i]->name,
- flags, force_mode)) {
+ if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
if (!ignore_add_errors)
die(_("adding files failed"));
exit_status = 1;
@@ -308,7 +320,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int exit_status = 0;
struct pathspec pathspec;
struct dir_struct dir;
- int flags, force_mode;
+ int flags;
int add_new_files;
int require_pathspec;
char *seen = NULL;
@@ -342,13 +354,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));
- if (!chmod_arg)
- force_mode = 0;
- else if (!strcmp(chmod_arg, "-x"))
- force_mode = 0666;
- else if (!strcmp(chmod_arg, "+x"))
- force_mode = 0777;
- else
+ if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
+ chmod_arg[1] != 'x' || chmod_arg[2]))
die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
add_new_files = !take_worktree_changes && !refresh_only;
@@ -441,11 +448,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
plug_bulk_checkin();
- exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode);
+ exit_status |= add_files_to_cache(prefix, &pathspec, flags);
if (add_new_files)
- exit_status |= add_files(&dir, flags, force_mode);
+ exit_status |= add_files(&dir, flags);
+ if (chmod_arg && pathspec.nr)
+ chmod_pathspec(&pathspec, chmod_arg[0]);
unplug_bulk_checkin();
finish:
diff --git a/builtin/am.c b/builtin/am.c
index 00e4a09..6981f42 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -28,6 +28,8 @@
#include "rerere.h"
#include "prompt.h"
#include "mailinfo.h"
+#include "apply.h"
+#include "string-list.h"
/**
* Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -70,7 +72,8 @@ enum patch_format {
PATCH_FORMAT_MBOX,
PATCH_FORMAT_STGIT,
PATCH_FORMAT_STGIT_SERIES,
- PATCH_FORMAT_HG
+ PATCH_FORMAT_HG,
+ PATCH_FORMAT_MBOXRD
};
enum keep_type {
@@ -107,7 +110,7 @@ struct am_state {
size_t msg_len;
/* when --rebasing, records the original commit the patch came from */
- unsigned char orig_commit[GIT_SHA1_RAWSZ];
+ struct object_id orig_commit;
/* number of digits in patch filename */
int prec;
@@ -183,22 +186,22 @@ static inline const char *am_path(const struct am_state *state, const char *path
/**
* For convenience to call write_file()
*/
-static int write_state_text(const struct am_state *state,
- const char *name, const char *string)
+static void write_state_text(const struct am_state *state,
+ const char *name, const char *string)
{
- return write_file(am_path(state, name), "%s", string);
+ write_file(am_path(state, name), "%s", string);
}
-static int write_state_count(const struct am_state *state,
- const char *name, int value)
+static void write_state_count(const struct am_state *state,
+ const char *name, int value)
{
- return write_file(am_path(state, name), "%d", value);
+ write_file(am_path(state, name), "%d", value);
}
-static int write_state_bool(const struct am_state *state,
- const char *name, int value)
+static void write_state_bool(const struct am_state *state,
+ const char *name, int value)
{
- return write_state_text(state, name, value ? "t" : "f");
+ write_state_text(state, name, value ? "t" : "f");
}
/**
@@ -257,38 +260,29 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state,
}
/**
- * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE
- * as a newly-allocated string. VALUE must be a quoted string, and the KEY must
- * match `key`. Returns NULL on failure.
- *
- * This is used by read_author_script() to read the GIT_AUTHOR_* variables from
- * the author-script.
+ * Take a series of KEY='VALUE' lines where VALUE part is
+ * sq-quoted, and append <KEY, VALUE> at the end of the string list
*/
-static char *read_shell_var(FILE *fp, const char *key)
+static int parse_key_value_squoted(char *buf, struct string_list *list)
{
- struct strbuf sb = STRBUF_INIT;
- const char *str;
-
- if (strbuf_getline_lf(&sb, fp))
- goto fail;
-
- if (!skip_prefix(sb.buf, key, &str))
- goto fail;
-
- if (!skip_prefix(str, "=", &str))
- goto fail;
-
- strbuf_remove(&sb, 0, str - sb.buf);
-
- str = sq_dequote(sb.buf);
- if (!str)
- goto fail;
-
- return strbuf_detach(&sb, NULL);
-
-fail:
- strbuf_release(&sb);
- return NULL;
+ while (*buf) {
+ struct string_list_item *item;
+ char *np;
+ char *cp = strchr(buf, '=');
+ if (!cp)
+ return -1;
+ np = strchrnul(cp, '\n');
+ *cp++ = '\0';
+ item = string_list_append(list, buf);
+
+ buf = np + (*np == '\n');
+ *np = '\0';
+ cp = sq_dequote(cp);
+ if (!cp)
+ return -1;
+ item->util = xstrdup(cp);
+ }
+ return 0;
}
/**
@@ -310,44 +304,39 @@ fail:
static int read_author_script(struct am_state *state)
{
const char *filename = am_path(state, "author-script");
- FILE *fp;
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list kv = STRING_LIST_INIT_DUP;
+ int retval = -1; /* assume failure */
+ int fd;
assert(!state->author_name);
assert(!state->author_email);
assert(!state->author_date);
- fp = fopen(filename, "r");
- if (!fp) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
if (errno == ENOENT)
return 0;
die_errno(_("could not open '%s' for reading"), filename);
}
+ strbuf_read(&buf, fd, 0);
+ close(fd);
+ if (parse_key_value_squoted(buf.buf, &kv))
+ goto finish;
- state->author_name = read_shell_var(fp, "GIT_AUTHOR_NAME");
- if (!state->author_name) {
- fclose(fp);
- return -1;
- }
-
- state->author_email = read_shell_var(fp, "GIT_AUTHOR_EMAIL");
- if (!state->author_email) {
- fclose(fp);
- return -1;
- }
-
- state->author_date = read_shell_var(fp, "GIT_AUTHOR_DATE");
- if (!state->author_date) {
- fclose(fp);
- return -1;
- }
-
- if (fgetc(fp) != EOF) {
- fclose(fp);
- return -1;
- }
-
- fclose(fp);
- return 0;
+ if (kv.nr != 3 ||
+ strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") ||
+ strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") ||
+ strcmp(kv.items[2].string, "GIT_AUTHOR_DATE"))
+ goto finish;
+ state->author_name = kv.items[0].util;
+ state->author_email = kv.items[1].util;
+ state->author_date = kv.items[2].util;
+ retval = 0;
+finish:
+ string_list_clear(&kv, !!retval);
+ strbuf_release(&buf);
+ return retval;
}
/**
@@ -402,13 +391,8 @@ static int read_commit_msg(struct am_state *state)
*/
static void write_commit_msg(const struct am_state *state)
{
- int fd;
const char *filename = am_path(state, "final-commit");
-
- fd = xopen(filename, O_WRONLY | O_CREAT, 0666);
- if (write_in_full(fd, state->msg, state->msg_len) < 0)
- die_errno(_("could not write to %s"), filename);
- close(fd);
+ write_file_buf(filename, state->msg, state->msg_len);
}
/**
@@ -432,8 +416,8 @@ static void am_load(struct am_state *state)
read_commit_msg(state);
if (read_state_file(&sb, state, "original-commit", 1) < 0)
- hashclr(state->orig_commit);
- else if (get_sha1_hex(sb.buf, state->orig_commit) < 0)
+ oidclr(&state->orig_commit);
+ else if (get_oid_hex(sb.buf, &state->orig_commit) < 0)
die(_("could not parse %s"), am_path(state, "original-commit"));
read_state_file(&sb, state, "threeway", 1);
@@ -559,14 +543,14 @@ static int copy_notes_for_rebase(const struct am_state *state)
fp = xfopen(am_path(state, "rewritten"), "r");
while (!strbuf_getline_lf(&sb, fp)) {
- unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];
+ struct object_id from_obj, to_obj;
if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {
ret = error(invalid_line, sb.buf);
goto finish;
}
- if (get_sha1_hex(sb.buf, from_obj)) {
+ if (get_oid_hex(sb.buf, &from_obj)) {
ret = error(invalid_line, sb.buf);
goto finish;
}
@@ -576,14 +560,14 @@ static int copy_notes_for_rebase(const struct am_state *state)
goto finish;
}
- if (get_sha1_hex(sb.buf + GIT_SHA1_HEXSZ + 1, to_obj)) {
+ if (get_oid_hex(sb.buf + GIT_SHA1_HEXSZ + 1, &to_obj)) {
ret = error(invalid_line, sb.buf);
goto finish;
}
- if (copy_note_for_rewrite(c, from_obj, to_obj))
+ if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash))
ret = error(_("Failed to copy notes from '%s' to '%s'"),
- sha1_to_hex(from_obj), sha1_to_hex(to_obj));
+ oid_to_hex(&from_obj), oid_to_hex(&to_obj));
}
finish:
@@ -712,7 +696,8 @@ done:
* Splits out individual email patches from `paths`, where each path is either
* a mbox file or a Maildir. Returns 0 on success, -1 on failure.
*/
-static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
+static int split_mail_mbox(struct am_state *state, const char **paths,
+ int keep_cr, int mboxrd)
{
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf last = STRBUF_INIT;
@@ -724,6 +709,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_
argv_array_push(&cp.args, "-b");
if (keep_cr)
argv_array_push(&cp.args, "--keep-cr");
+ if (mboxrd)
+ argv_array_push(&cp.args, "--mboxrd");
argv_array_push(&cp.args, "--");
argv_array_pushv(&cp.args, paths);
@@ -965,13 +952,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
switch (patch_format) {
case PATCH_FORMAT_MBOX:
- return split_mail_mbox(state, paths, keep_cr);
+ return split_mail_mbox(state, paths, keep_cr, 0);
case PATCH_FORMAT_STGIT:
return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
case PATCH_FORMAT_STGIT_SERIES:
return split_mail_stgit_series(state, paths, keep_cr);
case PATCH_FORMAT_HG:
return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
+ case PATCH_FORMAT_MBOXRD:
+ return split_mail_mbox(state, paths, keep_cr, 1);
default:
die("BUG: invalid patch_format");
}
@@ -984,7 +973,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
static void am_setup(struct am_state *state, enum patch_format patch_format,
const char **paths, int keep_cr)
{
- unsigned char curr_head[GIT_SHA1_RAWSZ];
+ struct object_id curr_head;
const char *str;
struct strbuf sb = STRBUF_INIT;
@@ -1052,10 +1041,10 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
else
write_state_text(state, "applying", "");
- if (!get_sha1("HEAD", curr_head)) {
- write_state_text(state, "abort-safety", sha1_to_hex(curr_head));
+ if (!get_oid("HEAD", &curr_head)) {
+ write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
- update_ref("am", "ORIG_HEAD", curr_head, NULL, 0,
+ update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
} else {
write_state_text(state, "abort-safety", "");
@@ -1080,7 +1069,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
*/
static void am_next(struct am_state *state)
{
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
free(state->author_name);
state->author_name = NULL;
@@ -1098,11 +1087,11 @@ static void am_next(struct am_state *state)
unlink(am_path(state, "author-script"));
unlink(am_path(state, "final-commit"));
- hashclr(state->orig_commit);
+ oidclr(&state->orig_commit);
unlink(am_path(state, "original-commit"));
- if (!get_sha1("HEAD", head))
- write_state_text(state, "abort-safety", sha1_to_hex(head));
+ if (!get_oid("HEAD", &head))
+ write_state_text(state, "abort-safety", oid_to_hex(&head));
else
write_state_text(state, "abort-safety", "");
@@ -1144,17 +1133,17 @@ static void refresh_and_write_cache(void)
*/
static int index_has_changes(struct strbuf *sb)
{
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
int i;
- if (!get_sha1_tree("HEAD", head)) {
+ if (!get_sha1_tree("HEAD", head.hash)) {
struct diff_options opt;
diff_setup(&opt);
DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
if (!sb)
DIFF_OPT_SET(&opt, QUICK);
- do_diff_cache(head, &opt);
+ do_diff_cache(head.hash, &opt);
diffcore_std(&opt);
for (i = 0; sb && i < diff_queued_diff.nr; i++) {
if (i)
@@ -1361,7 +1350,7 @@ finish:
* Sets commit_id to the commit hash where the mail was generated from.
* Returns 0 on success, -1 on failure.
*/
-static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
+static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
{
struct strbuf sb = STRBUF_INIT;
FILE *fp = xfopen(mail, "r");
@@ -1373,7 +1362,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
if (!skip_prefix(sb.buf, "From ", &x))
return -1;
- if (get_sha1_hex(x, commit_id) < 0)
+ if (get_oid_hex(x, commit_id) < 0)
return -1;
strbuf_release(&sb);
@@ -1463,12 +1452,12 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
static void write_index_patch(const struct am_state *state)
{
struct tree *tree;
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
struct rev_info rev_info;
FILE *fp;
- if (!get_sha1_tree("HEAD", head))
- tree = lookup_tree(head);
+ if (!get_sha1_tree("HEAD", head.hash))
+ tree = lookup_tree(head.hash);
else
tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
@@ -1498,19 +1487,19 @@ static void write_index_patch(const struct am_state *state)
static int parse_mail_rebase(struct am_state *state, const char *mail)
{
struct commit *commit;
- unsigned char commit_sha1[GIT_SHA1_RAWSZ];
+ struct object_id commit_oid;
- if (get_mail_commit_sha1(commit_sha1, mail) < 0)
+ if (get_mail_commit_oid(&commit_oid, mail) < 0)
die(_("could not parse %s"), mail);
- commit = lookup_commit_or_die(commit_sha1, mail);
+ commit = lookup_commit_or_die(commit_oid.hash, mail);
get_commit_info(state, commit);
write_commit_patch(state, commit);
- hashcpy(state->orig_commit, commit_sha1);
- write_state_text(state, "original-commit", sha1_to_hex(commit_sha1));
+ oidcpy(&state->orig_commit, &commit_oid);
+ write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
return 0;
}
@@ -1521,39 +1510,59 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
*/
static int run_apply(const struct am_state *state, const char *index_file)
{
- struct child_process cp = CHILD_PROCESS_INIT;
-
- cp.git_cmd = 1;
-
- if (index_file)
- argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", index_file);
+ struct argv_array apply_paths = ARGV_ARRAY_INIT;
+ struct argv_array apply_opts = ARGV_ARRAY_INIT;
+ struct apply_state apply_state;
+ int res, opts_left;
+ static struct lock_file lock_file;
+ int force_apply = 0;
+ int options = 0;
+
+ if (init_apply_state(&apply_state, NULL, &lock_file))
+ die("BUG: init_apply_state() failed");
+
+ argv_array_push(&apply_opts, "apply");
+ argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
+
+ opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv,
+ &apply_state, &force_apply, &options,
+ NULL);
+
+ if (opts_left != 0)
+ die("unknown option passed through to git apply");
+
+ if (index_file) {
+ apply_state.index_file = index_file;
+ apply_state.cached = 1;
+ } else
+ apply_state.check_index = 1;
/*
* If we are allowed to fall back on 3-way merge, don't give false
* errors during the initial attempt.
*/
- if (state->threeway && !index_file) {
- cp.no_stdout = 1;
- cp.no_stderr = 1;
- }
+ if (state->threeway && !index_file)
+ apply_state.apply_verbosity = verbosity_silent;
- argv_array_push(&cp.args, "apply");
+ if (check_apply_state(&apply_state, force_apply))
+ die("BUG: check_apply_state() failed");
- argv_array_pushv(&cp.args, state->git_apply_opts.argv);
+ argv_array_push(&apply_paths, am_path(state, "patch"));
- if (index_file)
- argv_array_push(&cp.args, "--cached");
- else
- argv_array_push(&cp.args, "--index");
+ res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);
- argv_array_push(&cp.args, am_path(state, "patch"));
+ argv_array_clear(&apply_paths);
+ argv_array_clear(&apply_opts);
+ clear_apply_state(&apply_state);
- if (run_command(&cp))
- return -1;
+ if (res)
+ return res;
- /* Reload index as git-apply will have modified it. */
- discard_cache();
- read_cache_from(index_file ? index_file : get_index_file());
+ if (index_file) {
+ /* Reload index as apply_all_patches() will have modified it. */
+ discard_cache();
+ read_cache_from(index_file);
+ }
return 0;
}
@@ -1578,47 +1587,18 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f
}
/**
- * Do the three-way merge using fake ancestor, their tree constructed
- * from the fake ancestor and the postimage of the patch, and our
- * state.
- */
-static int run_fallback_merge_recursive(const struct am_state *state,
- unsigned char *orig_tree,
- unsigned char *our_tree,
- unsigned char *their_tree)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
- int status;
-
- cp.git_cmd = 1;
-
- argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s",
- sha1_to_hex(their_tree), linelen(state->msg), state->msg);
- if (state->quiet)
- argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0");
-
- argv_array_push(&cp.args, "merge-recursive");
- argv_array_push(&cp.args, sha1_to_hex(orig_tree));
- argv_array_push(&cp.args, "--");
- argv_array_push(&cp.args, sha1_to_hex(our_tree));
- argv_array_push(&cp.args, sha1_to_hex(their_tree));
-
- status = run_command(&cp) ? (-1) : 0;
- discard_cache();
- read_cache();
- return status;
-}
-
-/**
* Attempt a threeway merge, using index_path as the temporary index.
*/
static int fall_back_threeway(const struct am_state *state, const char *index_path)
{
- unsigned char orig_tree[GIT_SHA1_RAWSZ], their_tree[GIT_SHA1_RAWSZ],
- our_tree[GIT_SHA1_RAWSZ];
+ struct object_id orig_tree, their_tree, our_tree;
+ const struct object_id *bases[1] = { &orig_tree };
+ struct merge_options o;
+ struct commit *result;
+ char *their_tree_name;
- if (get_sha1("HEAD", our_tree) < 0)
- hashcpy(our_tree, EMPTY_TREE_SHA1_BIN);
+ if (get_oid("HEAD", &our_tree) < 0)
+ hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);
if (build_fake_ancestor(state, index_path))
return error("could not build fake ancestor");
@@ -1626,7 +1606,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
discard_cache();
read_cache_from(index_path);
- if (write_index_as_tree(orig_tree, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL))
return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
say(state, stdout, _("Using index info to reconstruct a base tree..."));
@@ -1642,7 +1622,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
init_revisions(&rev_info, NULL);
rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
- add_pending_sha1(&rev_info, "HEAD", our_tree, 0);
+ add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0);
diff_setup_done(&rev_info.diffopt);
run_diff_index(&rev_info, 1);
}
@@ -1651,7 +1631,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
return error(_("Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."));
- if (write_index_as_tree(their_tree, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(their_tree.hash, &the_index, index_path, 0, NULL))
return error("could not write tree");
say(state, stdout, _("Falling back to patching base and 3-way merge..."));
@@ -1667,11 +1647,22 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
* changes.
*/
- if (run_fallback_merge_recursive(state, orig_tree, our_tree, their_tree)) {
+ init_merge_options(&o);
+
+ o.branch1 = "HEAD";
+ their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
+ o.branch2 = their_tree_name;
+
+ if (state->quiet)
+ o.verbosity = 0;
+
+ if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) {
rerere(state->allow_rerere_autoupdate);
+ free(their_tree_name);
return error(_("Failed to merge in the changes."));
}
+ free(their_tree_name);
return 0;
}
@@ -1682,9 +1673,8 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
*/
static void do_commit(const struct am_state *state)
{
- unsigned char tree[GIT_SHA1_RAWSZ], parent[GIT_SHA1_RAWSZ],
- commit[GIT_SHA1_RAWSZ];
- unsigned char *ptr;
+ struct object_id tree, parent, commit;
+ const struct object_id *old_oid;
struct commit_list *parents = NULL;
const char *reflog_msg, *author;
struct strbuf sb = STRBUF_INIT;
@@ -1692,14 +1682,14 @@ static void do_commit(const struct am_state *state)
if (run_hook_le(NULL, "pre-applypatch", NULL))
exit(1);
- if (write_cache_as_tree(tree, 0, NULL))
+ if (write_cache_as_tree(tree.hash, 0, NULL))
die(_("git write-tree failed to write a tree"));
- if (!get_sha1_commit("HEAD", parent)) {
- ptr = parent;
- commit_list_insert(lookup_commit(parent), &parents);
+ if (!get_sha1_commit("HEAD", parent.hash)) {
+ old_oid = &parent;
+ commit_list_insert(lookup_commit(parent.hash), &parents);
} else {
- ptr = NULL;
+ old_oid = NULL;
say(state, stderr, _("applying to an empty history"));
}
@@ -1711,7 +1701,7 @@ static void do_commit(const struct am_state *state)
setenv("GIT_COMMITTER_DATE",
state->ignore_date ? "" : state->author_date, 1);
- if (commit_tree(state->msg, state->msg_len, tree, parents, commit,
+ if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
author, state->sign_commit))
die(_("failed to write commit object"));
@@ -1722,14 +1712,15 @@ static void do_commit(const struct am_state *state)
strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
state->msg);
- update_ref(sb.buf, "HEAD", commit, ptr, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (state->rebasing) {
FILE *fp = xfopen(am_path(state, "rewritten"), "a");
- assert(!is_null_sha1(state->orig_commit));
- fprintf(fp, "%s ", sha1_to_hex(state->orig_commit));
- fprintf(fp, "%s\n", sha1_to_hex(commit));
+ assert(!is_null_oid(&state->orig_commit));
+ fprintf(fp, "%s ", oid_to_hex(&state->orig_commit));
+ fprintf(fp, "%s\n", oid_to_hex(&commit));
fclose(fp);
}
@@ -2050,30 +2041,30 @@ static int merge_tree(struct tree *tree)
* Clean the index without touching entries that are not modified between
* `head` and `remote`.
*/
-static int clean_index(const unsigned char *head, const unsigned char *remote)
+static int clean_index(const struct object_id *head, const struct object_id *remote)
{
struct tree *head_tree, *remote_tree, *index_tree;
- unsigned char index[GIT_SHA1_RAWSZ];
+ struct object_id index;
- head_tree = parse_tree_indirect(head);
+ head_tree = parse_tree_indirect(head->hash);
if (!head_tree)
- return error(_("Could not parse object '%s'."), sha1_to_hex(head));
+ return error(_("Could not parse object '%s'."), oid_to_hex(head));
- remote_tree = parse_tree_indirect(remote);
+ remote_tree = parse_tree_indirect(remote->hash);
if (!remote_tree)
- return error(_("Could not parse object '%s'."), sha1_to_hex(remote));
+ return error(_("Could not parse object '%s'."), oid_to_hex(remote));
read_cache_unmerged();
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_cache_as_tree(index, 0, NULL))
+ if (write_cache_as_tree(index.hash, 0, NULL))
return -1;
- index_tree = parse_tree_indirect(index);
+ index_tree = parse_tree_indirect(index.hash);
if (!index_tree)
- return error(_("Could not parse object '%s'."), sha1_to_hex(index));
+ return error(_("Could not parse object '%s'."), oid_to_hex(&index));
if (fast_forward_to(index_tree, remote_tree, 0))
return -1;
@@ -2101,14 +2092,14 @@ static void am_rerere_clear(void)
*/
static void am_skip(struct am_state *state)
{
- unsigned char head[GIT_SHA1_RAWSZ];
+ struct object_id head;
am_rerere_clear();
- if (get_sha1("HEAD", head))
- hashcpy(head, EMPTY_TREE_SHA1_BIN);
+ if (get_oid("HEAD", &head))
+ hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);
- if (clean_index(head, head))
+ if (clean_index(&head, &head))
die(_("failed to clean index"));
am_next(state);
@@ -2126,21 +2117,21 @@ static void am_skip(struct am_state *state)
static int safe_to_abort(const struct am_state *state)
{
struct strbuf sb = STRBUF_INIT;
- unsigned char abort_safety[GIT_SHA1_RAWSZ], head[GIT_SHA1_RAWSZ];
+ struct object_id abort_safety, head;
if (file_exists(am_path(state, "dirtyindex")))
return 0;
if (read_state_file(&sb, state, "abort-safety", 1) > 0) {
- if (get_sha1_hex(sb.buf, abort_safety))
+ if (get_oid_hex(sb.buf, &abort_safety))
die(_("could not parse %s"), am_path(state, "abort_safety"));
} else
- hashclr(abort_safety);
+ oidclr(&abort_safety);
- if (get_sha1("HEAD", head))
- hashclr(head);
+ if (get_oid("HEAD", &head))
+ oidclr(&head);
- if (!hashcmp(head, abort_safety))
+ if (!oidcmp(&head, &abort_safety))
return 1;
error(_("You seem to have moved HEAD since the last 'am' failure.\n"
@@ -2154,7 +2145,7 @@ static int safe_to_abort(const struct am_state *state)
*/
static void am_abort(struct am_state *state)
{
- unsigned char curr_head[GIT_SHA1_RAWSZ], orig_head[GIT_SHA1_RAWSZ];
+ struct object_id curr_head, orig_head;
int has_curr_head, has_orig_head;
char *curr_branch;
@@ -2165,20 +2156,20 @@ static void am_abort(struct am_state *state)
am_rerere_clear();
- curr_branch = resolve_refdup("HEAD", 0, curr_head, NULL);
- has_curr_head = !is_null_sha1(curr_head);
+ curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+ has_curr_head = !is_null_oid(&curr_head);
if (!has_curr_head)
- hashcpy(curr_head, EMPTY_TREE_SHA1_BIN);
+ hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
- has_orig_head = !get_sha1("ORIG_HEAD", orig_head);
+ has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
if (!has_orig_head)
- hashcpy(orig_head, EMPTY_TREE_SHA1_BIN);
+ hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);
- clean_index(curr_head, orig_head);
+ clean_index(&curr_head, &orig_head);
if (has_orig_head)
- update_ref("am --abort", "HEAD", orig_head,
- has_curr_head ? curr_head : NULL, 0,
+ update_ref_oid("am --abort", "HEAD", &orig_head,
+ has_curr_head ? &curr_head : NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
delete_ref(curr_branch, NULL, REF_NODEREF);
@@ -2203,6 +2194,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
*opt_value = PATCH_FORMAT_STGIT_SERIES;
else if (!strcmp(arg, "hg"))
*opt_value = PATCH_FORMAT_HG;
+ else if (!strcmp(arg, "mboxrd"))
+ *opt_value = PATCH_FORMAT_MBOXRD;
else
return error(_("Invalid value for --patch-format: %s"), arg);
return 0;
@@ -2237,7 +2230,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
int in_progress;
const char * const usage[] = {
- N_("git am [<options>] [(<mbox>|<Maildir>)...]"),
+ N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
N_("git am [<options>] (--continue | --skip | --abort)"),
NULL
};
diff --git a/builtin/apply.c b/builtin/apply.c
index c770d7d..81b9a61 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,4665 +1,36 @@
-/*
- * apply.c
- *
- * Copyright (C) Linus Torvalds, 2005
- *
- * This applies patches on top of some (arbitrary) version of the SCM.
- *
- */
#include "cache.h"
-#include "lockfile.h"
-#include "cache-tree.h"
-#include "quote.h"
-#include "blob.h"
-#include "delta.h"
#include "builtin.h"
-#include "string-list.h"
-#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
- * files that are being modified, but doesn't apply the patch
- * --stat does just a diffstat, and doesn't actually apply
- * --numstat does numeric diffstat, and doesn't actually apply
- * --index-info shows the old and new index info for paths if available.
- * --index updates the cache as well.
- * --cached updates only the cache without ever touching the working tree.
- */
-static const char *prefix;
-static int prefix_length = -1;
-static int newfd = -1;
+#include "lockfile.h"
+#include "apply.h"
-static int unidiff_zero;
-static int p_value = 1;
-static int p_value_known;
-static int check_index;
-static int update_index;
-static int cached;
-static int diffstat;
-static int numstat;
-static int summary;
-static int check;
-static int apply = 1;
-static int apply_in_reverse;
-static int apply_with_reject;
-static int apply_verbosely;
-static int allow_overlap;
-static int no_add;
-static int threeway;
-static int unsafe_paths;
-static const char *fake_ancestor;
-static int line_termination = '\n';
-static unsigned int p_context = UINT_MAX;
static const char * const apply_usage[] = {
N_("git apply [<options>] [<patch>...]"),
NULL
};
-static enum ws_error_action {
- nowarn_ws_error,
- warn_on_ws_error,
- die_on_ws_error,
- correct_ws_error
-} ws_error_action = warn_on_ws_error;
-static int whitespace_error;
-static int squelch_whitespace_errors = 5;
-static int applied_after_fixing_ws;
-
-static enum ws_ignore {
- ignore_ws_none,
- ignore_ws_change
-} ws_ignore_action = ignore_ws_none;
-
-
-static const char *patch_input_file;
-static struct strbuf root = STRBUF_INIT;
-static int read_stdin = 1;
-static int options;
-
-static void parse_whitespace_option(const char *option)
-{
- if (!option) {
- ws_error_action = warn_on_ws_error;
- return;
- }
- if (!strcmp(option, "warn")) {
- ws_error_action = warn_on_ws_error;
- return;
- }
- if (!strcmp(option, "nowarn")) {
- ws_error_action = nowarn_ws_error;
- return;
- }
- if (!strcmp(option, "error")) {
- ws_error_action = die_on_ws_error;
- return;
- }
- if (!strcmp(option, "error-all")) {
- ws_error_action = die_on_ws_error;
- squelch_whitespace_errors = 0;
- return;
- }
- if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
- ws_error_action = correct_ws_error;
- return;
- }
- die(_("unrecognized whitespace option '%s'"), option);
-}
-
-static void parse_ignorewhitespace_option(const char *option)
-{
- if (!option || !strcmp(option, "no") ||
- !strcmp(option, "false") || !strcmp(option, "never") ||
- !strcmp(option, "none")) {
- ws_ignore_action = ignore_ws_none;
- return;
- }
- if (!strcmp(option, "change")) {
- ws_ignore_action = ignore_ws_change;
- return;
- }
- die(_("unrecognized whitespace ignore option '%s'"), option);
-}
-
-static void set_default_whitespace_mode(const char *whitespace_option)
-{
- if (!whitespace_option && !apply_default_whitespace)
- ws_error_action = (apply ? warn_on_ws_error : nowarn_ws_error);
-}
-
-/*
- * For "diff-stat" like behaviour, we keep track of the biggest change
- * we've seen, and the longest filename. That allows us to do simple
- * scaling.
- */
-static int max_change, max_len;
-
-/*
- * Various "current state", notably line numbers and what
- * file (and how) we're patching right now.. The "is_xxxx"
- * things are flags, where -1 means "don't know yet".
- */
-static int linenr = 1;
-
-/*
- * This represents one "hunk" from a patch, starting with
- * "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
- * patch text is pointed at by patch, and its byte length
- * is stored in size. leading and trailing are the number
- * of context lines.
- */
-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 linenr;
- struct fragment *next;
-};
-
-/*
- * When dealing with a binary patch, we reuse "leading" field
- * to store the type of the binary hunk, either deflated "delta"
- * or deflated "literal".
- */
-#define binary_patch_method leading
-#define BINARY_DELTA_DEFLATED 1
-#define BINARY_LITERAL_DEFLATED 2
-
-/*
- * This represents a "patch" to a file, both metainfo changes
- * such as creation/deletion, filemode and content changes represented
- * as a series of fragments.
- */
-struct patch {
- char *new_name, *old_name, *def_name;
- unsigned int old_mode, new_mode;
- int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */
- int rejected;
- unsigned ws_rule;
- int lines_added, lines_deleted;
- int score;
- unsigned int is_toplevel_relative:1;
- unsigned int inaccurate_eof:1;
- unsigned int is_binary:1;
- 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 */
- struct object_id threeway_stage[3];
-};
-
-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
- * one), and its contents hashes to 'hash'.
- */
-struct line {
- size_t len;
- unsigned hash : 24;
- unsigned flag : 8;
-#define LINE_COMMON 1
-#define LINE_PATCHED 2
-};
-
-/*
- * This represents a "file", which is an array of "lines".
- */
-struct image {
- char *buf;
- size_t len;
- size_t nr;
- size_t alloc;
- struct line *line_allocated;
- struct line *line;
-};
-
-/*
- * Records filenames that have been touched, in order to handle
- * the case where more than one patches touch the same file.
- */
-
-static struct string_list fn_table;
-
-static uint32_t hash_line(const char *cp, size_t len)
-{
- size_t i;
- uint32_t h;
- for (i = 0, h = 0; i < len; i++) {
- if (!isspace(cp[i])) {
- h = h * 3 + (cp[i] & 0xff);
- }
- }
- return h;
-}
-
-/*
- * Compare lines s1 of length n1 and s2 of length n2, ignoring
- * whitespace difference. Returns 1 if they match, 0 otherwise
- */
-static int fuzzy_matchlines(const char *s1, size_t n1,
- const char *s2, size_t n2)
-{
- const char *last1 = s1 + n1 - 1;
- const char *last2 = s2 + n2 - 1;
- int result = 0;
-
- /* ignore line endings */
- while ((*last1 == '\r') || (*last1 == '\n'))
- last1--;
- while ((*last2 == '\r') || (*last2 == '\n'))
- last2--;
-
- /* skip leading whitespaces, if both begin with whitespace */
- if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) {
- while (isspace(*s1) && (s1 <= last1))
- s1++;
- while (isspace(*s2) && (s2 <= last2))
- s2++;
- }
- /* early return if both lines are empty */
- if ((s1 > last1) && (s2 > last2))
- return 1;
- while (!result) {
- result = *s1++ - *s2++;
- /*
- * Skip whitespace inside. We check for whitespace on
- * both buffers because we don't want "a b" to match
- * "ab"
- */
- if (isspace(*s1) && isspace(*s2)) {
- while (isspace(*s1) && s1 <= last1)
- s1++;
- while (isspace(*s2) && s2 <= last2)
- s2++;
- }
- /*
- * If we reached the end on one side only,
- * lines don't match
- */
- if (
- ((s2 > last2) && (s1 <= last1)) ||
- ((s1 > last1) && (s2 <= last2)))
- return 0;
- if ((s1 > last1) && (s2 > last2))
- break;
- }
-
- return !result;
-}
-
-static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)
-{
- ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);
- img->line_allocated[img->nr].len = len;
- img->line_allocated[img->nr].hash = hash_line(bol, len);
- img->line_allocated[img->nr].flag = flag;
- 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)
-{
- const char *cp, *ep;
-
- memset(image, 0, sizeof(*image));
- image->buf = buf;
- image->len = len;
-
- if (!prepare_linetable)
- return;
-
- ep = image->buf + image->len;
- cp = image->buf;
- while (cp < ep) {
- const char *next;
- for (next = cp; next < ep && *next != '\n'; next++)
- ;
- if (next < ep)
- next++;
- add_line_info(image, cp, next - cp, 0);
- cp = next;
- }
- image->line = image->line_allocated;
-}
-
-static void clear_image(struct image *image)
-{
- free(image->buf);
- free(image->line_allocated);
- memset(image, 0, sizeof(*image));
-}
-
-/* fmt must contain _one_ %s and no other substitution */
-static void say_patch_name(FILE *output, const char *fmt, struct patch *patch)
-{
- 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, &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, &sb, NULL, 0);
- }
- fprintf(output, fmt, sb.buf);
- fputc('\n', output);
- strbuf_release(&sb);
-}
-
-#define SLOP (16)
-
-static void read_patch_file(struct strbuf *sb, int fd)
-{
- if (strbuf_read(sb, fd, 0) < 0)
- die_errno("git apply: failed to read");
-
- /*
- * Make sure that we have some slop in the buffer
- * so that we can do speculative "memcmp" etc, and
- * see to it that it is NUL-filled.
- */
- strbuf_grow(sb, SLOP);
- memset(sb->buf + sb->len, 0, SLOP);
-}
-
-static unsigned long linelen(const char *buffer, unsigned long size)
-{
- unsigned long len = 0;
- while (size--) {
- len++;
- if (*buffer++ == '\n')
- break;
- }
- return len;
-}
-
-static int is_dev_null(const char *str)
-{
- return skip_prefix(str, "/dev/null", &str) && isspace(*str);
-}
-
-#define TERM_SPACE 1
-#define TERM_TAB 2
-
-static int name_terminate(int c, int terminate)
-{
- if (c == ' ' && !(terminate & TERM_SPACE))
- return 0;
- if (c == '\t' && !(terminate & TERM_TAB))
- return 0;
-
- return 1;
-}
-
-/* remove double slashes to make --index work with such filenames */
-static char *squash_slash(char *name)
-{
- int i = 0, j = 0;
-
- if (!name)
- return NULL;
-
- while (name[i]) {
- if ((name[j++] = name[i++]) == '/')
- while (name[i] == '/')
- i++;
- }
- name[j] = '\0';
- return name;
-}
-
-static char *find_name_gnu(const char *line, const char *def, int p_value)
-{
- struct strbuf name = STRBUF_INIT;
- char *cp;
-
- /*
- * Proposed "new-style" GNU patch/diff format; see
- * http://marc.info/?l=git&m=112927316408690&w=2
- */
- if (unquote_c_style(&name, line, NULL)) {
- strbuf_release(&name);
- return NULL;
- }
-
- for (cp = name.buf; p_value; p_value--) {
- cp = strchr(cp, '/');
- if (!cp) {
- strbuf_release(&name);
- return NULL;
- }
- cp++;
- }
-
- strbuf_remove(&name, 0, cp - name.buf);
- if (root.len)
- strbuf_insert(&name, 0, root.buf, root.len);
- return squash_slash(strbuf_detach(&name, NULL));
-}
-
-static size_t sane_tz_len(const char *line, size_t len)
-{
- const char *tz, *p;
-
- if (len < strlen(" +0500") || line[len-strlen(" +0500")] != ' ')
- return 0;
- tz = line + len - strlen(" +0500");
-
- if (tz[1] != '+' && tz[1] != '-')
- return 0;
-
- for (p = tz + 2; p != line + len; p++)
- if (!isdigit(*p))
- return 0;
-
- return line + len - tz;
-}
-
-static size_t tz_with_colon_len(const char *line, size_t len)
-{
- const char *tz, *p;
-
- if (len < strlen(" +08:00") || line[len - strlen(":00")] != ':')
- return 0;
- tz = line + len - strlen(" +08:00");
-
- if (tz[0] != ' ' || (tz[1] != '+' && tz[1] != '-'))
- return 0;
- p = tz + 2;
- if (!isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
- !isdigit(*p++) || !isdigit(*p++))
- return 0;
-
- return line + len - tz;
-}
-
-static size_t date_len(const char *line, size_t len)
-{
- const char *date, *p;
-
- if (len < strlen("72-02-05") || line[len-strlen("-05")] != '-')
- return 0;
- p = date = line + len - strlen("72-02-05");
-
- if (!isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
- !isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
- !isdigit(*p++) || !isdigit(*p++)) /* Not a date. */
- return 0;
-
- if (date - line >= strlen("19") &&
- isdigit(date[-1]) && isdigit(date[-2])) /* 4-digit year */
- date -= strlen("19");
-
- return line + len - date;
-}
-
-static size_t short_time_len(const char *line, size_t len)
-{
- const char *time, *p;
-
- if (len < strlen(" 07:01:32") || line[len-strlen(":32")] != ':')
- return 0;
- p = time = line + len - strlen(" 07:01:32");
-
- /* Permit 1-digit hours? */
- if (*p++ != ' ' ||
- !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
- !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
- !isdigit(*p++) || !isdigit(*p++)) /* Not a time. */
- return 0;
-
- return line + len - time;
-}
-
-static size_t fractional_time_len(const char *line, size_t len)
-{
- const char *p;
- size_t n;
-
- /* Expected format: 19:41:17.620000023 */
- if (!len || !isdigit(line[len - 1]))
- return 0;
- p = line + len - 1;
-
- /* Fractional seconds. */
- while (p > line && isdigit(*p))
- p--;
- if (*p != '.')
- return 0;
-
- /* Hours, minutes, and whole seconds. */
- n = short_time_len(line, p - line);
- if (!n)
- return 0;
-
- return line + len - p + n;
-}
-
-static size_t trailing_spaces_len(const char *line, size_t len)
-{
- const char *p;
-
- /* Expected format: ' ' x (1 or more) */
- if (!len || line[len - 1] != ' ')
- return 0;
-
- p = line + len;
- while (p != line) {
- p--;
- if (*p != ' ')
- return line + len - (p + 1);
- }
-
- /* All spaces! */
- return len;
-}
-
-static size_t diff_timestamp_len(const char *line, size_t len)
-{
- const char *end = line + len;
- size_t n;
-
- /*
- * Posix: 2010-07-05 19:41:17
- * GNU: 2010-07-05 19:41:17.620000023 -0500
- */
-
- if (!isdigit(end[-1]))
- return 0;
-
- n = sane_tz_len(line, end - line);
- if (!n)
- n = tz_with_colon_len(line, end - line);
- end -= n;
-
- n = short_time_len(line, end - line);
- if (!n)
- n = fractional_time_len(line, end - line);
- end -= n;
-
- n = date_len(line, end - line);
- if (!n) /* No date. Too bad. */
- return 0;
- end -= n;
-
- if (end == line) /* No space before date. */
- return 0;
- if (end[-1] == '\t') { /* Success! */
- end--;
- return line + len - end;
- }
- if (end[-1] != ' ') /* No space before date. */
- return 0;
-
- /* Whitespace damage. */
- end -= trailing_spaces_len(line, end - line);
- return line + len - end;
-}
-
-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;
-
- if (p_value == 0)
- start = line;
- while (line != end) {
- char c = *line;
-
- if (!end && isspace(c)) {
- if (c == '\n')
- break;
- if (name_terminate(c, terminate))
- break;
- }
- line++;
- if (c == '/' && !--p_value)
- start = line;
- }
- if (!start)
- return squash_slash(xstrdup_or_null(def));
- len = line - start;
- if (!len)
- return squash_slash(xstrdup_or_null(def));
-
- /*
- * Generally we prefer the shorter name, especially
- * if the other one is just a variation of that with
- * something else tacked on to the end (ie "file.orig"
- * or "file~").
- */
- if (def) {
- int deflen = strlen(def);
- if (deflen < len && !strncmp(start, def, deflen))
- return squash_slash(xstrdup(def));
- }
-
- if (root.len) {
- char *ret = xstrfmt("%s%.*s", root.buf, len, start);
- return squash_slash(ret);
- }
-
- return squash_slash(xmemdupz(start, len));
-}
-
-static char *find_name(const char *line, char *def, int p_value, int terminate)
-{
- if (*line == '"') {
- char *name = find_name_gnu(line, def, p_value);
- if (name)
- return name;
- }
-
- return find_name_common(line, def, p_value, NULL, terminate);
-}
-
-static char *find_name_traditional(const char *line, char *def, int p_value)
-{
- size_t len;
- size_t date_len;
-
- if (*line == '"') {
- char *name = find_name_gnu(line, def, p_value);
- if (name)
- return name;
- }
-
- len = strchrnul(line, '\n') - line;
- date_len = diff_timestamp_len(line, len);
- if (!date_len)
- return find_name_common(line, def, p_value, NULL, TERM_TAB);
- len -= date_len;
-
- return find_name_common(line, def, p_value, line + len, 0);
-}
-
-static int count_slashes(const char *cp)
-{
- int cnt = 0;
- char ch;
-
- while ((ch = *cp++))
- if (ch == '/')
- cnt++;
- return cnt;
-}
-
-/*
- * Given the string after "--- " or "+++ ", guess the appropriate
- * p_value for the given patch.
- */
-static int guess_p_value(const char *nameline)
-{
- char *name, *cp;
- int val = -1;
-
- if (is_dev_null(nameline))
- return -1;
- name = find_name_traditional(nameline, NULL, 0);
- if (!name)
- return -1;
- cp = strchr(name, '/');
- if (!cp)
- val = 0;
- else if (prefix) {
- /*
- * Does it begin with "a/$our-prefix" and such? Then this is
- * very likely to apply to our directory.
- */
- if (!strncmp(name, prefix, prefix_length))
- val = count_slashes(prefix);
- else {
- cp++;
- if (!strncmp(cp, prefix, prefix_length))
- val = count_slashes(prefix) + 1;
- }
- }
- free(name);
- return val;
-}
-
-/*
- * Does the ---/+++ line have the POSIX timestamp after the last HT?
- * GNU diff puts epoch there to signal a creation/deletion event. Is
- * this such a timestamp?
- */
-static int has_epoch_timestamp(const char *nameline)
-{
- /*
- * We are only interested in epoch timestamp; any non-zero
- * fraction cannot be one, hence "(\.0+)?" in the regexp below.
- * For the same reason, the date must be either 1969-12-31 or
- * 1970-01-01, and the seconds part must be "00".
- */
- const char stamp_regexp[] =
- "^(1969-12-31|1970-01-01)"
- " "
- "[0-2][0-9]:[0-5][0-9]:00(\\.0+)?"
- " "
- "([-+][0-2][0-9]:?[0-5][0-9])\n";
- const char *timestamp = NULL, *cp, *colon;
- static regex_t *stamp;
- regmatch_t m[10];
- int zoneoffset;
- int hourminute;
- int status;
-
- for (cp = nameline; *cp != '\n'; cp++) {
- if (*cp == '\t')
- timestamp = cp + 1;
- }
- if (!timestamp)
- return 0;
- if (!stamp) {
- stamp = xmalloc(sizeof(*stamp));
- if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
- warning(_("Cannot prepare timestamp regexp %s"),
- stamp_regexp);
- return 0;
- }
- }
-
- status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
- if (status) {
- if (status != REG_NOMATCH)
- warning(_("regexec returned %d for input: %s"),
- status, timestamp);
- return 0;
- }
-
- zoneoffset = strtol(timestamp + m[3].rm_so + 1, (char **) &colon, 10);
- if (*colon == ':')
- zoneoffset = zoneoffset * 60 + strtol(colon + 1, NULL, 10);
- else
- zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
- if (timestamp[m[3].rm_so] == '-')
- zoneoffset = -zoneoffset;
-
- /*
- * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
- * (west of GMT) or 1970-01-01 (east of GMT)
- */
- if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) ||
- (0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10)))
- return 0;
-
- hourminute = (strtol(timestamp + 11, NULL, 10) * 60 +
- strtol(timestamp + 14, NULL, 10) -
- zoneoffset);
-
- return ((zoneoffset < 0 && hourminute == 1440) ||
- (0 <= zoneoffset && !hourminute));
-}
-
-/*
- * Get the name etc info from the ---/+++ lines of a traditional patch header
- *
- * FIXME! The end-of-filename heuristics are kind of screwy. For existing
- * files, we can happily check the index for a match, but for creating a
- * new file we should try to match whatever "patch" does. I have no idea.
- */
-static void parse_traditional_patch(const char *first, const char *second, struct patch *patch)
-{
- char *name;
-
- first += 4; /* skip "--- " */
- second += 4; /* skip "+++ " */
- if (!p_value_known) {
- int p, q;
- p = guess_p_value(first);
- q = guess_p_value(second);
- if (p < 0) p = q;
- if (0 <= p && p == q) {
- p_value = p;
- p_value_known = 1;
- }
- }
- if (is_dev_null(first)) {
- patch->is_new = 1;
- patch->is_delete = 0;
- name = find_name_traditional(second, NULL, p_value);
- patch->new_name = name;
- } else if (is_dev_null(second)) {
- patch->is_new = 0;
- patch->is_delete = 1;
- name = find_name_traditional(first, NULL, p_value);
- patch->old_name = name;
- } else {
- 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;
- patch->new_name = name;
- } else if (has_epoch_timestamp(second)) {
- patch->is_new = 0;
- patch->is_delete = 1;
- patch->old_name = name;
- } else {
- patch->old_name = name;
- patch->new_name = xstrdup_or_null(name);
- }
- }
- if (!name)
- die(_("unable to find filename in patch at line %d"), linenr);
-}
-
-static int gitdiff_hdrend(const char *line, struct patch *patch)
-{
- return -1;
-}
-
-/*
- * We're anal about diff header consistency, to make
- * sure that we don't end up having strange ambiguous
- * patches floating around.
- *
- * As a result, gitdiff_{old|new}name() will check
- * their names against any previous information, just
- * to make sure..
- */
-#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);
-
- if (orig_name) {
- int len = strlen(orig_name);
- char *another;
- if (isnull)
- die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
- orig_name, linenr);
- another = find_name(line, NULL, p_value, TERM_TAB);
- if (!another || memcmp(another, orig_name, len + 1))
- 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);
- 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,
- DIFF_OLD_NAME);
- 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,
- DIFF_NEW_NAME);
- return 0;
-}
-
-static int gitdiff_oldmode(const char *line, struct patch *patch)
-{
- patch->old_mode = strtoul(line, NULL, 8);
- return 0;
-}
-
-static int gitdiff_newmode(const char *line, struct patch *patch)
-{
- patch->new_mode = strtoul(line, NULL, 8);
- return 0;
-}
-
-static int gitdiff_delete(const char *line, struct patch *patch)
-{
- patch->is_delete = 1;
- free(patch->old_name);
- patch->old_name = xstrdup_or_null(patch->def_name);
- return gitdiff_oldmode(line, patch);
-}
-
-static int gitdiff_newfile(const char *line, struct patch *patch)
-{
- patch->is_new = 1;
- free(patch->new_name);
- patch->new_name = xstrdup_or_null(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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-static int gitdiff_similarity(const char *line, struct patch *patch)
-{
- unsigned long val = strtoul(line, NULL, 10);
- if (val <= 100)
- patch->score = val;
- return 0;
-}
-
-static int gitdiff_dissimilarity(const char *line, struct patch *patch)
-{
- unsigned long val = strtoul(line, NULL, 10);
- if (val <= 100)
- patch->score = val;
- return 0;
-}
-
-static int gitdiff_index(const char *line, struct patch *patch)
-{
- /*
- * index line is N hexadecimal, "..", N hexadecimal,
- * and optional space with octal mode.
- */
- const char *ptr, *eol;
- int len;
-
- ptr = strchr(line, '.');
- if (!ptr || ptr[1] != '.' || 40 < ptr - line)
- return 0;
- len = ptr - line;
- memcpy(patch->old_sha1_prefix, line, len);
- patch->old_sha1_prefix[len] = 0;
-
- line = ptr + 2;
- ptr = strchr(line, ' ');
- eol = strchrnul(line, '\n');
-
- if (!ptr || eol < ptr)
- ptr = eol;
- len = ptr - line;
-
- if (40 < len)
- return 0;
- memcpy(patch->new_sha1_prefix, line, len);
- patch->new_sha1_prefix[len] = 0;
- if (*ptr == ' ')
- patch->old_mode = strtoul(ptr+1, NULL, 8);
- return 0;
-}
-
-/*
- * This is normal for a diff that doesn't change anything: we'll fall through
- * into the next diff. Tell the parser to break out.
- */
-static int gitdiff_unrecognized(const char *line, struct patch *patch)
-{
- return -1;
-}
-
-/*
- * Skip p_value leading components from "line"; as we do not accept
- * absolute paths, return NULL in that case.
- */
-static const char *skip_tree_prefix(const char *line, int llen)
-{
- int nslash;
- int i;
-
- if (!p_value)
- return (llen && line[0] == '/') ? NULL : line;
-
- nslash = p_value;
- for (i = 0; i < llen; i++) {
- int ch = line[i];
- if (ch == '/' && --nslash <= 0)
- return (i == 0) ? NULL : &line[i + 1];
- }
- return NULL;
-}
-
-/*
- * This is to extract the same name that appears on "diff --git"
- * line. We do not find and return anything if it is a rename
- * patch, and it is OK because we will find the name elsewhere.
- * We need to reliably find name only when it is mode-change only,
- * 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(const char *line, int llen)
-{
- const char *name;
- const char *second = NULL;
- size_t len, line_len;
-
- line += strlen("diff --git ");
- llen -= strlen("diff --git ");
-
- if (*line == '"') {
- const char *cp;
- struct strbuf first = STRBUF_INIT;
- struct strbuf sp = STRBUF_INIT;
-
- if (unquote_c_style(&first, line, &second))
- goto free_and_fail1;
-
- /* strip the a/b prefix including trailing slash */
- cp = skip_tree_prefix(first.buf, first.len);
- if (!cp)
- goto free_and_fail1;
- strbuf_remove(&first, 0, cp - first.buf);
-
- /*
- * second points at one past closing dq of name.
- * find the second name.
- */
- while ((second < line + llen) && isspace(*second))
- second++;
-
- if (line + llen <= second)
- goto free_and_fail1;
- if (*second == '"') {
- if (unquote_c_style(&sp, second, NULL))
- goto free_and_fail1;
- cp = skip_tree_prefix(sp.buf, sp.len);
- if (!cp)
- goto free_and_fail1;
- /* They must match, otherwise ignore */
- if (strcmp(cp, first.buf))
- goto free_and_fail1;
- strbuf_release(&sp);
- return strbuf_detach(&first, NULL);
- }
-
- /* unquoted second */
- cp = skip_tree_prefix(second, line + llen - second);
- if (!cp)
- goto free_and_fail1;
- if (line + llen - cp != first.len ||
- memcmp(first.buf, cp, first.len))
- goto free_and_fail1;
- return strbuf_detach(&first, NULL);
-
- free_and_fail1:
- strbuf_release(&first);
- strbuf_release(&sp);
- return NULL;
- }
-
- /* unquoted first name */
- name = skip_tree_prefix(line, llen);
- if (!name)
- return NULL;
-
- /*
- * since the first name is unquoted, a dq if exists must be
- * the beginning of the second name.
- */
- for (second = name; second < line + llen; second++) {
- if (*second == '"') {
- struct strbuf sp = STRBUF_INIT;
- const char *np;
-
- if (unquote_c_style(&sp, second, NULL))
- goto free_and_fail2;
-
- np = skip_tree_prefix(sp.buf, sp.len);
- if (!np)
- goto free_and_fail2;
-
- len = sp.buf + sp.len - np;
- if (len < second - name &&
- !strncmp(np, name, len) &&
- isspace(name[len])) {
- /* Good */
- strbuf_remove(&sp, 0, np - sp.buf);
- return strbuf_detach(&sp, NULL);
- }
-
- free_and_fail2:
- strbuf_release(&sp);
- return NULL;
- }
- }
-
- /*
- * Accept a name only if it shows up twice, exactly the same
- * form.
- */
- second = strchr(name, '\n');
- if (!second)
- return NULL;
- line_len = second - name;
- for (len = 0 ; ; len++) {
- switch (name[len]) {
- default:
- continue;
- case '\n':
- return NULL;
- case '\t': case ' ':
- /*
- * Is this the separator between the preimage
- * and the postimage pathname? Again, we are
- * only interested in the case where there is
- * no rename, as this is only to set def_name
- * and a rename patch has the names elsewhere
- * in an unambiguous form.
- */
- if (!name[len + 1])
- return NULL; /* no postimage name */
- second = skip_tree_prefix(name + len + 1,
- line_len - (len + 1));
- if (!second)
- return NULL;
- /*
- * Does len bytes starting at "name" and "second"
- * (that are separated by one HT or SP we just
- * found) exactly match?
- */
- if (second[len] == '\n' && !strncmp(name, second, len))
- return xmemdupz(name, len);
- }
- }
-}
-
-/* Verify that we recognize the lines following a git header */
-static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
-{
- unsigned long offset;
-
- /* A git diff has explicit new/delete information, so we don't guess */
- patch->is_new = 0;
- patch->is_delete = 0;
-
- /*
- * Some things may not have the old name in the
- * rest of the headers anywhere (pure mode changes,
- * or removing or adding empty files), so we get
- * the default name from the header.
- */
- patch->def_name = git_header_name(line, len);
- if (patch->def_name && root.len) {
- char *s = xstrfmt("%s%s", root.buf, patch->def_name);
- free(patch->def_name);
- patch->def_name = s;
- }
-
- line += len;
- size -= len;
- linenr++;
- for (offset = len ; size > 0 ; offset += len, size -= len, line += len, linenr++) {
- static const struct opentry {
- const char *str;
- int (*fn)(const char *, struct patch *);
- } optable[] = {
- { "@@ -", gitdiff_hdrend },
- { "--- ", gitdiff_oldname },
- { "+++ ", gitdiff_newname },
- { "old mode ", gitdiff_oldmode },
- { "new mode ", gitdiff_newmode },
- { "deleted file mode ", gitdiff_delete },
- { "new file mode ", gitdiff_newfile },
- { "copy from ", gitdiff_copysrc },
- { "copy to ", gitdiff_copydst },
- { "rename old ", gitdiff_renamesrc },
- { "rename new ", gitdiff_renamedst },
- { "rename from ", gitdiff_renamesrc },
- { "rename to ", gitdiff_renamedst },
- { "similarity index ", gitdiff_similarity },
- { "dissimilarity index ", gitdiff_dissimilarity },
- { "index ", gitdiff_index },
- { "", gitdiff_unrecognized },
- };
- int i;
-
- len = linelen(line, size);
- if (!len || line[len-1] != '\n')
- break;
- for (i = 0; i < ARRAY_SIZE(optable); i++) {
- const struct opentry *p = optable + i;
- int oplen = strlen(p->str);
- if (len < oplen || memcmp(p->str, line, oplen))
- continue;
- if (p->fn(line + oplen, patch) < 0)
- return offset;
- break;
- }
- }
-
- return offset;
-}
-
-static int parse_num(const char *line, unsigned long *p)
-{
- char *ptr;
-
- if (!isdigit(*line))
- return 0;
- *p = strtoul(line, &ptr, 10);
- return ptr - line;
-}
-
-static int parse_range(const char *line, int len, int offset, const char *expect,
- unsigned long *p1, unsigned long *p2)
-{
- int digits, ex;
-
- if (offset < 0 || offset >= len)
- return -1;
- line += offset;
- len -= offset;
-
- digits = parse_num(line, p1);
- if (!digits)
- return -1;
-
- offset += digits;
- line += digits;
- len -= digits;
-
- *p2 = 1;
- if (*line == ',') {
- digits = parse_num(line+1, p2);
- if (!digits)
- return -1;
-
- offset += digits+1;
- line += digits+1;
- len -= digits+1;
- }
-
- ex = strlen(expect);
- if (ex > len)
- return -1;
- if (memcmp(line, expect, ex))
- return -1;
-
- return offset + ex;
-}
-
-static void recount_diff(const char *line, int size, struct fragment *fragment)
-{
- int oldlines = 0, newlines = 0, ret = 0;
-
- if (size < 1) {
- warning("recount: ignore empty hunk");
- return;
- }
-
- for (;;) {
- int len = linelen(line, size);
- size -= len;
- line += len;
-
- if (size < 1)
- break;
-
- switch (*line) {
- case ' ': case '\n':
- newlines++;
- /* fall through */
- case '-':
- oldlines++;
- continue;
- case '+':
- newlines++;
- continue;
- case '\\':
- continue;
- case '@':
- ret = size < 3 || !starts_with(line, "@@ ");
- break;
- case 'd':
- ret = size < 5 || !starts_with(line, "diff ");
- break;
- default:
- ret = -1;
- break;
- }
- if (ret) {
- warning(_("recount: unexpected line: %.*s"),
- (int)linelen(line, size), line);
- return;
- }
- break;
- }
- fragment->oldlines = oldlines;
- fragment->newlines = newlines;
-}
-
-/*
- * Parse a unified diff fragment header of the
- * form "@@ -a,b +c,d @@"
- */
-static int parse_fragment_header(const char *line, int len, struct fragment *fragment)
-{
- int offset;
-
- if (!len || line[len-1] != '\n')
- return -1;
-
- /* Figure out the number of lines in a fragment */
- offset = parse_range(line, len, 4, " +", &fragment->oldpos, &fragment->oldlines);
- offset = parse_range(line, len, offset, " @@", &fragment->newpos, &fragment->newlines);
-
- return offset;
-}
-
-static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
-{
- unsigned long offset, len;
-
- patch->is_toplevel_relative = 0;
- patch->is_rename = patch->is_copy = 0;
- patch->is_new = patch->is_delete = -1;
- patch->old_mode = patch->new_mode = 0;
- patch->old_name = patch->new_name = NULL;
- for (offset = 0; size > 0; offset += len, size -= len, line += len, linenr++) {
- unsigned long nextlen;
-
- len = linelen(line, size);
- if (!len)
- break;
-
- /* Testing this early allows us to take a few shortcuts.. */
- if (len < 6)
- continue;
-
- /*
- * Make sure we don't find any unconnected patch fragments.
- * That's a sign that we didn't find a header, and that a
- * patch has become corrupted/broken up.
- */
- if (!memcmp("@@ -", line, 4)) {
- struct fragment dummy;
- if (parse_fragment_header(line, len, &dummy) < 0)
- continue;
- die(_("patch fragment without header at line %d: %.*s"),
- linenr, (int)len-1, line);
- }
-
- if (size < len + 6)
- break;
-
- /*
- * Git patch? It might not have a real patch, just a rename
- * or mode change, so we handle that specially
- */
- if (!memcmp("diff --git ", line, 11)) {
- int git_hdr_len = parse_git_header(line, len, size, patch);
- if (git_hdr_len <= len)
- continue;
- if (!patch->old_name && !patch->new_name) {
- if (!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 "
- "(line %d)", linenr);
- patch->is_toplevel_relative = 1;
- *hdrsize = git_hdr_len;
- return offset;
- }
-
- /* --- followed by +++ ? */
- if (memcmp("--- ", line, 4) || memcmp("+++ ", line + len, 4))
- continue;
-
- /*
- * We only accept unified patches, so we want it to
- * at least have "@@ -a,b +c,d @@\n", which is 14 chars
- * minimum ("@@ -0,0 +1 @@\n" is the shortest).
- */
- nextlen = linelen(line + len, size - len);
- if (size < nextlen + 14 || memcmp("@@ -", line + len + nextlen, 4))
- continue;
-
- /* Ok, we'll consider it a patch */
- parse_traditional_patch(line, line+len, patch);
- *hdrsize = len + nextlen;
- linenr += 2;
- return offset;
- }
- return -1;
-}
-
-static void record_ws_error(unsigned result, const char *line, int len, int linenr)
-{
- char *err;
-
- if (!result)
- return;
-
- whitespace_error++;
- if (squelch_whitespace_errors &&
- squelch_whitespace_errors < whitespace_error)
- return;
-
- err = whitespace_error_string(result);
- fprintf(stderr, "%s:%d: %s.\n%.*s\n",
- patch_input_file, linenr, err, len, line);
- free(err);
-}
-
-static void check_whitespace(const char *line, int len, unsigned ws_rule)
-{
- unsigned result = ws_check(line + 1, len - 1, ws_rule);
-
- record_ws_error(result, line + 1, len - 2, linenr);
-}
-
-/*
- * Parse a unified diff. Note that this really needs to parse each
- * fragment separately, since the only way to know the difference
- * 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(const char *line, unsigned long size,
- struct patch *patch, struct fragment *fragment)
-{
- int added, deleted;
- int len = linelen(line, size), offset;
- unsigned long oldlines, newlines;
- unsigned long leading, trailing;
-
- offset = parse_fragment_header(line, len, fragment);
- if (offset < 0)
- return -1;
- if (offset > 0 && patch->recount)
- recount_diff(line + offset, size - offset, fragment);
- oldlines = fragment->oldlines;
- newlines = fragment->newlines;
- leading = 0;
- trailing = 0;
-
- /* Parse the thing.. */
- line += len;
- size -= len;
- linenr++;
- added = deleted = 0;
- for (offset = len;
- 0 < size;
- offset += len, size -= len, line += len, linenr++) {
- if (!oldlines && !newlines)
- break;
- len = linelen(line, size);
- if (!len || line[len-1] != '\n')
- return -1;
- switch (*line) {
- default:
- return -1;
- case '\n': /* newer GNU diff, an empty context line */
- case ' ':
- oldlines--;
- newlines--;
- if (!deleted && !added)
- leading++;
- trailing++;
- if (!apply_in_reverse &&
- ws_error_action == correct_ws_error)
- check_whitespace(line, len, patch->ws_rule);
- break;
- case '-':
- if (apply_in_reverse &&
- ws_error_action != nowarn_ws_error)
- check_whitespace(line, len, patch->ws_rule);
- deleted++;
- oldlines--;
- trailing = 0;
- break;
- case '+':
- if (!apply_in_reverse &&
- ws_error_action != nowarn_ws_error)
- check_whitespace(line, len, patch->ws_rule);
- added++;
- newlines--;
- trailing = 0;
- break;
-
- /*
- * We allow "\ No newline at end of file". Depending
- * on locale settings when the patch was produced we
- * don't know what this line looks like. The only
- * thing we do know is that it begins with "\ ".
- * Checking for 12 is just for sanity check -- any
- * l10n of "\ No newline..." is at least that long.
- */
- case '\\':
- if (len < 12 || memcmp(line, "\\ ", 2))
- return -1;
- break;
- }
- }
- if (oldlines || newlines)
- return -1;
- if (!deleted && !added)
- return -1;
-
- fragment->leading = leading;
- fragment->trailing = trailing;
-
- /*
- * If a fragment ends with an incomplete line, we failed to include
- * it in the above loop because we hit oldlines == newlines == 0
- * before seeing it.
- */
- if (12 < size && !memcmp(line, "\\ ", 2))
- offset += linelen(line, size);
-
- patch->lines_added += added;
- patch->lines_deleted += deleted;
-
- if (0 < patch->is_new && oldlines)
- return error(_("new file depends on old contents"));
- if (0 < patch->is_delete && newlines)
- return error(_("deleted file still has contents"));
- return offset;
-}
-
-/*
- * 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;
- struct fragment **fragp = &patch->fragments;
-
- while (size > 4 && !memcmp(line, "@@ -", 4)) {
- struct fragment *fragment;
- int len;
-
- fragment = xcalloc(1, sizeof(*fragment));
- fragment->linenr = linenr;
- len = parse_fragment(line, size, patch, fragment);
- if (len <= 0)
- die(_("corrupt patch at line %d"), linenr);
- fragment->patch = line;
- fragment->size = len;
- oldlines += fragment->oldlines;
- newlines += fragment->newlines;
- context += fragment->leading + fragment->trailing;
-
- *fragp = fragment;
- fragp = &fragment->next;
-
- offset += len;
- line += len;
- size -= len;
- }
-
- /*
- * If something was removed (i.e. we have old-lines) it cannot
- * be creation, and if something was added it cannot be
- * deletion. However, the reverse is not true; --unified=0
- * patches that only add are not necessarily creation even
- * though they do not have any old lines, and ones that only
- * delete are not necessarily deletion.
- *
- * Unfortunately, a real creation/deletion patch do _not_ have
- * any context line by definition, so we cannot safely tell it
- * apart with --unified=0 insanity. At least if the patch has
- * more than one hunk it is not creation or deletion.
- */
- if (patch->is_new < 0 &&
- (oldlines || (patch->fragments && patch->fragments->next)))
- patch->is_new = 0;
- if (patch->is_delete < 0 &&
- (newlines || (patch->fragments && patch->fragments->next)))
- patch->is_delete = 0;
-
- if (0 < patch->is_new && oldlines)
- 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);
- if (!patch->is_delete && !newlines && context)
- fprintf_ln(stderr,
- _("** warning: "
- "file %s becomes empty but is not deleted"),
- patch->new_name);
-
- return offset;
-}
-
-static inline int metadata_changes(struct patch *patch)
-{
- return patch->is_rename > 0 ||
- patch->is_copy > 0 ||
- patch->is_new > 0 ||
- patch->is_delete ||
- (patch->old_mode && patch->new_mode &&
- patch->old_mode != patch->new_mode);
-}
-
-static char *inflate_it(const void *data, unsigned long size,
- unsigned long inflated_size)
-{
- git_zstream stream;
- void *out;
- int st;
-
- memset(&stream, 0, sizeof(stream));
-
- stream.next_in = (unsigned char *)data;
- stream.avail_in = size;
- stream.next_out = out = xmalloc(inflated_size);
- stream.avail_out = inflated_size;
- git_inflate_init(&stream);
- st = git_inflate(&stream, Z_FINISH);
- git_inflate_end(&stream);
- if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
- free(out);
- return NULL;
- }
- 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,
- int *used_p)
-{
- /*
- * Expect a line that begins with binary patch method ("literal"
- * or "delta"), followed by the length of data before deflating.
- * a sequence of 'length-byte' followed by base-85 encoded data
- * should follow, terminated by a newline.
- *
- * Each 5-byte sequence of base-85 encodes up to 4 bytes,
- * and we would limit the patch line to 66 characters,
- * so one line can fit up to 13 groups that would decode
- * to 52 bytes max. The length byte 'A'-'Z' corresponds
- * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
- */
- int llen, used;
- unsigned long size = *sz_p;
- char *buffer = *buf_p;
- int patch_method;
- unsigned long origlen;
- char *data = NULL;
- int hunk_size = 0;
- struct fragment *frag;
-
- llen = linelen(buffer, size);
- used = llen;
-
- *status_p = 0;
-
- if (starts_with(buffer, "delta ")) {
- patch_method = BINARY_DELTA_DEFLATED;
- origlen = strtoul(buffer + 6, NULL, 10);
- }
- else if (starts_with(buffer, "literal ")) {
- patch_method = BINARY_LITERAL_DEFLATED;
- origlen = strtoul(buffer + 8, NULL, 10);
- }
- else
- return NULL;
-
- linenr++;
- buffer += llen;
- while (1) {
- int byte_length, max_byte_length, newsize;
- llen = linelen(buffer, size);
- used += llen;
- linenr++;
- if (llen == 1) {
- /* consume the blank line */
- buffer++;
- size--;
- break;
- }
- /*
- * Minimum line is "A00000\n" which is 7-byte long,
- * and the line length must be multiple of 5 plus 2.
- */
- if ((llen < 7) || (llen-2) % 5)
- goto corrupt;
- max_byte_length = (llen - 2) / 5 * 4;
- byte_length = *buffer;
- if ('A' <= byte_length && byte_length <= 'Z')
- byte_length = byte_length - 'A' + 1;
- else if ('a' <= byte_length && byte_length <= 'z')
- byte_length = byte_length - 'a' + 27;
- else
- goto corrupt;
- /* if the input length was not multiple of 4, we would
- * have filler at the end but the filler should never
- * exceed 3 bytes
- */
- if (max_byte_length < byte_length ||
- byte_length <= max_byte_length - 4)
- goto corrupt;
- newsize = hunk_size + byte_length;
- data = xrealloc(data, newsize);
- if (decode_85(data + hunk_size, buffer + 1, byte_length))
- goto corrupt;
- hunk_size = newsize;
- buffer += llen;
- size -= llen;
- }
-
- frag = xcalloc(1, sizeof(*frag));
- frag->patch = inflate_it(data, hunk_size, origlen);
- frag->free_patch = 1;
- if (!frag->patch)
- goto corrupt;
- free(data);
- frag->size = origlen;
- *buf_p = buffer;
- *sz_p = size;
- *used_p = used;
- frag->binary_patch_method = patch_method;
- return frag;
-
- corrupt:
- free(data);
- *status_p = -1;
- error(_("corrupt binary patch at line %d: %.*s"),
- linenr-1, llen-1, buffer);
- return NULL;
-}
-
-/*
- * Returns:
- * -1 in case of error,
- * the length of the parsed binary patch otherwise
- */
-static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
-{
- /*
- * We have read "GIT binary patch\n"; what follows is a line
- * that says the patch method (currently, either "literal" or
- * "delta") and the length of data before deflating; a
- * sequence of 'length-byte' followed by base-85 encoded data
- * follows.
- *
- * When a binary patch is reversible, there is another binary
- * hunk in the same format, starting with patch method (either
- * "literal" or "delta") with the length of data, and a sequence
- * of length-byte + base-85 encoded data, terminated with another
- * empty line. This data, when applied to the postimage, produces
- * the preimage.
- */
- struct fragment *forward;
- struct fragment *reverse;
- int status;
- int used, used_1;
-
- 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);
- if (status)
- /* otherwise we already gave an error message */
- return status;
-
- reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
- if (reverse)
- used += used_1;
- else if (status) {
- /*
- * Not having reverse hunk is not an error, but having
- * a corrupt reverse hunk is.
- */
- free((void*) forward->patch);
- free(forward);
- return status;
- }
- forward->next = reverse;
- patch->fragments = forward;
- patch->is_binary = 1;
- return used;
-}
-
-static void prefix_one(char **name)
-{
- char *old_name = *name;
- if (!old_name)
- return;
- *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
- free(old_name);
-}
-
-static void prefix_patch(struct patch *p)
-{
- if (!prefix || p->is_toplevel_relative)
- return;
- prefix_one(&p->new_name);
- prefix_one(&p->old_name);
-}
-
-/*
- * include/exclude
- */
-
-static struct string_list limit_by_name;
-static int has_include;
-static void add_name_limit(const char *name, int exclude)
-{
- struct string_list_item *it;
-
- it = string_list_append(&limit_by_name, name);
- it->util = exclude ? NULL : (void *) 1;
-}
-
-static int use_patch(struct patch *p)
-{
- const char *pathname = p->new_name ? p->new_name : p->old_name;
- int i;
-
- /* Paths outside are not touched regardless of "--include" */
- if (0 < prefix_length) {
- int pathlen = strlen(pathname);
- if (pathlen <= prefix_length ||
- memcmp(prefix, pathname, prefix_length))
- return 0;
- }
-
- /* See if it matches any of exclude/include rule */
- for (i = 0; i < limit_by_name.nr; i++) {
- struct string_list_item *it = &limit_by_name.items[i];
- if (!wildmatch(it->string, pathname, 0, NULL))
- return (it->util != NULL);
- }
-
- /*
- * If we had any include, a path that does not match any rule is
- * not used. Otherwise, we saw bunch of exclude rules (or none)
- * and such a path is used.
- */
- return !has_include;
-}
-
-
-/*
- * Read the patch text in "buffer" that 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;
- int offset = find_header(buffer, size, &hdrsize, patch);
-
- if (offset < 0)
- return offset;
-
- prefix_patch(patch);
-
- if (!use_patch(patch))
- patch->ws_rule = 0;
- else
- patch->ws_rule = whitespace_rule(patch->new_name
- ? patch->new_name
- : patch->old_name);
-
- patchsize = parse_single_patch(buffer + offset + hdrsize,
- size - offset - hdrsize, patch);
-
- if (!patchsize) {
- static const char git_binary[] = "GIT binary patch\n";
- int hd = hdrsize + offset;
- unsigned long llen = linelen(buffer + hd, size - hd);
-
- if (llen == sizeof(git_binary) - 1 &&
- !memcmp(git_binary, buffer + hd, llen)) {
- int used;
- linenr++;
- used = parse_binary(buffer + hd + llen,
- size - hd - llen, patch);
- if (used < 0)
- return -1;
- if (used)
- patchsize = used + llen;
- else
- patchsize = 0;
- }
- else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
- static const char *binhdr[] = {
- "Binary files ",
- "Files ",
- NULL,
- };
- int i;
- for (i = 0; binhdr[i]; i++) {
- int len = strlen(binhdr[i]);
- if (len < size - hd &&
- !memcmp(binhdr[i], buffer + hd, len)) {
- linenr++;
- patch->is_binary = 1;
- patchsize = llen;
- break;
- }
- }
- }
-
- /* Empty patch cannot be applied if it is a text patch
- * without metadata change. A binary patch appears
- * empty to us here.
- */
- if ((apply || check) &&
- (!patch->is_binary && !metadata_changes(patch)))
- die(_("patch with only garbage at line %d"), linenr);
- }
-
- return offset + hdrsize + patchsize;
-}
-
-#define swap(a,b) myswap((a),(b),sizeof(a))
-
-#define myswap(a, b, size) do { \
- unsigned char mytmp[size]; \
- memcpy(mytmp, &a, size); \
- memcpy(&a, &b, size); \
- memcpy(&b, mytmp, size); \
-} while (0)
-
-static void reverse_patches(struct patch *p)
-{
- for (; p; p = p->next) {
- struct fragment *frag = p->fragments;
-
- swap(p->new_name, p->old_name);
- swap(p->new_mode, p->old_mode);
- swap(p->is_new, p->is_delete);
- swap(p->lines_added, p->lines_deleted);
- swap(p->old_sha1_prefix, p->new_sha1_prefix);
-
- for (; frag; frag = frag->next) {
- swap(frag->newpos, frag->oldpos);
- swap(frag->newlines, frag->oldlines);
- }
- }
-}
-
-static const char pluses[] =
-"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
-static const char minuses[]=
-"----------------------------------------------------------------------";
-
-static void show_stats(struct patch *patch)
-{
- struct strbuf qname = STRBUF_INIT;
- char *cp = patch->new_name ? patch->new_name : patch->old_name;
- int max, add, del;
-
- quote_c_style(cp, &qname, NULL, 0);
-
- /*
- * "scale" the filename
- */
- max = max_len;
- if (max > 50)
- max = 50;
-
- if (qname.len > max) {
- cp = strchr(qname.buf + qname.len + 3 - max, '/');
- if (!cp)
- cp = qname.buf + qname.len + 3 - max;
- strbuf_splice(&qname, 0, cp - qname.buf, "...", 3);
- }
-
- if (patch->is_binary) {
- printf(" %-*s | Bin\n", max, qname.buf);
- strbuf_release(&qname);
- return;
- }
-
- printf(" %-*s |", max, qname.buf);
- strbuf_release(&qname);
-
- /*
- * scale the add/delete
- */
- max = max + max_change > 70 ? 70 - max : max_change;
- add = patch->lines_added;
- del = patch->lines_deleted;
-
- if (max_change > 0) {
- int total = ((add + del) * max + max_change / 2) / max_change;
- add = (add * max + max_change / 2) / max_change;
- del = total - add;
- }
- printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
- add, pluses, del, minuses);
-}
-
-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 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);
- convert_to_git(path, buf->buf, buf->len, buf, 0);
- return 0;
- default:
- return -1;
- }
-}
-
-/*
- * Update the preimage, and the common lines in postimage,
- * from buffer buf of length len. If postlen is 0 the postimage
- * is updated in place, otherwise it's updated on a new buffer
- * of length postlen
- */
-
-static void update_pre_post_images(struct image *preimage,
- struct image *postimage,
- char *buf,
- size_t len, size_t postlen)
-{
- int i, ctx, reduced;
- char *new, *old, *fixed;
- struct image fixed_preimage;
-
- /*
- * Update the preimage with whitespace fixes. Note that we
- * are not losing preimage->buf -- apply_one_fragment() will
- * free "oldlines".
- */
- prepare_image(&fixed_preimage, buf, len, 1);
- assert(postlen
- ? fixed_preimage.nr == preimage->nr
- : fixed_preimage.nr <= preimage->nr);
- for (i = 0; i < fixed_preimage.nr; i++)
- fixed_preimage.line[i].flag = preimage->line[i].flag;
- free(preimage->line_allocated);
- *preimage = fixed_preimage;
-
- /*
- * Adjust the common context lines in postimage. This can be
- * done in-place when we are shrinking it with whitespace
- * fixing, but needs a new buffer when ignoring whitespace or
- * expanding leading tabs to spaces.
- *
- * We trust the caller to tell us if the update can be done
- * in place (postlen==0) or not.
- */
- old = postimage->buf;
- if (postlen)
- new = postimage->buf = xmalloc(postlen);
- else
- new = old;
- fixed = preimage->buf;
-
- for (i = reduced = ctx = 0; i < postimage->nr; i++) {
- size_t len = postimage->line[i].len;
- if (!(postimage->line[i].flag & LINE_COMMON)) {
- /* an added line -- no counterparts in preimage */
- memmove(new, old, len);
- old += len;
- new += len;
- continue;
- }
-
- /* a common context -- skip it in the original postimage */
- old += len;
-
- /* and find the corresponding one in the fixed preimage */
- while (ctx < preimage->nr &&
- !(preimage->line[ctx].flag & LINE_COMMON)) {
- fixed += preimage->line[ctx].len;
- ctx++;
- }
-
- /*
- * preimage is expected to run out, if the caller
- * fixed addition of trailing blank lines.
- */
- if (preimage->nr <= ctx) {
- reduced++;
- continue;
- }
-
- /* and copy it in, while fixing the line length */
- len = preimage->line[ctx].len;
- memcpy(new, fixed, len);
- new += len;
- fixed += len;
- postimage->line[i].len = len;
- ctx++;
- }
-
- if (postlen
- ? postlen < new - postimage->buf
- : postimage->len < new - postimage->buf)
- die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
- (int)postlen, (int) postimage->len, (int)(new - postimage->buf));
-
- /* Fix the length of the whole thing */
- postimage->len = new - postimage->buf;
- postimage->nr -= reduced;
-}
-
-static int match_fragment(struct image *img,
- struct image *preimage,
- struct image *postimage,
- unsigned long try,
- int try_lno,
- unsigned ws_rule,
- int match_beginning, int match_end)
-{
- int i;
- char *fixed_buf, *buf, *orig, *target;
- struct strbuf fixed;
- size_t fixed_len, postlen;
- int preimage_limit;
-
- if (preimage->nr + try_lno <= img->nr) {
- /*
- * The hunk falls within the boundaries of img.
- */
- preimage_limit = preimage->nr;
- if (match_end && (preimage->nr + try_lno != img->nr))
- return 0;
- } else if (ws_error_action == correct_ws_error &&
- (ws_rule & WS_BLANK_AT_EOF)) {
- /*
- * This hunk extends beyond the end of img, and we are
- * removing blank lines at the end of the file. This
- * many lines from the beginning of the preimage must
- * match with img, and the remainder of the preimage
- * must be blank.
- */
- preimage_limit = img->nr - try_lno;
- } else {
- /*
- * The hunk extends beyond the end of the img and
- * we are not removing blanks at the end, so we
- * should reject the hunk at this position.
- */
- return 0;
- }
-
- if (match_beginning && try_lno)
- return 0;
-
- /* Quick hash check */
- for (i = 0; i < preimage_limit; i++)
- if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
- (preimage->line[i].hash != img->line[try_lno + i].hash))
- return 0;
-
- if (preimage_limit == preimage->nr) {
- /*
- * Do we have an exact match? If we were told to match
- * at the end, size must be exactly at try+fragsize,
- * otherwise try+fragsize must be still within the preimage,
- * and either case, the old piece should match the preimage
- * exactly.
- */
- if ((match_end
- ? (try + preimage->len == img->len)
- : (try + preimage->len <= img->len)) &&
- !memcmp(img->buf + try, preimage->buf, preimage->len))
- return 1;
- } else {
- /*
- * The preimage extends beyond the end of img, so
- * there cannot be an exact match.
- *
- * There must be one non-blank context line that match
- * a line before the end of img.
- */
- char *buf_end;
-
- buf = preimage->buf;
- buf_end = buf;
- for (i = 0; i < preimage_limit; i++)
- buf_end += preimage->line[i].len;
-
- for ( ; buf < buf_end; buf++)
- if (!isspace(*buf))
- break;
- if (buf == buf_end)
- return 0;
- }
-
- /*
- * No exact match. If we are ignoring whitespace, run a line-by-line
- * fuzzy matching. We collect all the line length information because
- * we need it to adjust whitespace if we match.
- */
- if (ws_ignore_action == ignore_ws_change) {
- size_t imgoff = 0;
- size_t preoff = 0;
- size_t postlen = postimage->len;
- size_t extra_chars;
- char *preimage_eof;
- char *preimage_end;
- for (i = 0; i < preimage_limit; i++) {
- size_t prelen = preimage->line[i].len;
- size_t imglen = img->line[try_lno+i].len;
-
- if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
- preimage->buf + preoff, prelen))
- return 0;
- if (preimage->line[i].flag & LINE_COMMON)
- postlen += imglen - prelen;
- imgoff += imglen;
- preoff += prelen;
- }
-
- /*
- * Ok, the preimage matches with whitespace fuzz.
- *
- * imgoff now holds the true length of the target that
- * matches the preimage before the end of the file.
- *
- * Count the number of characters in the preimage that fall
- * beyond the end of the file and make sure that all of them
- * are whitespace characters. (This can only happen if
- * we are removing blank lines at the end of the file.)
- */
- buf = preimage_eof = preimage->buf + preoff;
- for ( ; i < preimage->nr; i++)
- preoff += preimage->line[i].len;
- preimage_end = preimage->buf + preoff;
- for ( ; buf < preimage_end; buf++)
- if (!isspace(*buf))
- return 0;
-
- /*
- * Update the preimage and the common postimage context
- * lines to use the same whitespace as the target.
- * If whitespace is missing in the target (i.e.
- * if the preimage extends beyond the end of the file),
- * use the whitespace from the preimage.
- */
- extra_chars = preimage_end - preimage_eof;
- strbuf_init(&fixed, imgoff + extra_chars);
- strbuf_add(&fixed, img->buf + try, imgoff);
- strbuf_add(&fixed, preimage_eof, extra_chars);
- fixed_buf = strbuf_detach(&fixed, &fixed_len);
- update_pre_post_images(preimage, postimage,
- fixed_buf, fixed_len, postlen);
- return 1;
- }
-
- if (ws_error_action != correct_ws_error)
- return 0;
-
- /*
- * The hunk does not apply byte-by-byte, but the hash says
- * it might with whitespace fuzz. We weren't asked to
- * ignore whitespace, we were asked to correct whitespace
- * errors, so let's try matching after whitespace correction.
- *
- * While checking the preimage against the target, whitespace
- * errors in both fixed, we count how large the corresponding
- * postimage needs to be. The postimage prepared by
- * apply_one_fragment() has whitespace errors fixed on added
- * lines already, but the common lines were propagated as-is,
- * which may become longer when their whitespace errors are
- * fixed.
- */
-
- /* First count added lines in postimage */
- postlen = 0;
- for (i = 0; i < postimage->nr; i++) {
- if (!(postimage->line[i].flag & LINE_COMMON))
- postlen += postimage->line[i].len;
- }
-
- /*
- * The preimage may extend beyond the end of the file,
- * but in this loop we will only handle the part of the
- * preimage that falls within the file.
- */
- strbuf_init(&fixed, preimage->len + 1);
- orig = preimage->buf;
- target = img->buf + try;
- for (i = 0; i < preimage_limit; i++) {
- size_t oldlen = preimage->line[i].len;
- size_t tgtlen = img->line[try_lno + i].len;
- size_t fixstart = fixed.len;
- struct strbuf tgtfix;
- int match;
-
- /* Try fixing the line in the preimage */
- ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
-
- /* Try fixing the line in the target */
- strbuf_init(&tgtfix, tgtlen);
- ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
-
- /*
- * If they match, either the preimage was based on
- * a version before our tree fixed whitespace breakage,
- * or we are lacking a whitespace-fix patch the tree
- * the preimage was based on already had (i.e. target
- * has whitespace breakage, the preimage doesn't).
- * In either case, we are fixing the whitespace breakages
- * so we might as well take the fix together with their
- * real change.
- */
- match = (tgtfix.len == fixed.len - fixstart &&
- !memcmp(tgtfix.buf, fixed.buf + fixstart,
- fixed.len - fixstart));
-
- /* Add the length if this is common with the postimage */
- if (preimage->line[i].flag & LINE_COMMON)
- postlen += tgtfix.len;
-
- strbuf_release(&tgtfix);
- if (!match)
- goto unmatch_exit;
-
- orig += oldlen;
- target += tgtlen;
- }
-
-
- /*
- * Now handle the lines in the preimage that falls beyond the
- * end of the file (if any). They will only match if they are
- * empty or only contain whitespace (if WS_BLANK_AT_EOL is
- * false).
- */
- for ( ; i < preimage->nr; i++) {
- size_t fixstart = fixed.len; /* start of the fixed preimage */
- size_t oldlen = preimage->line[i].len;
- int j;
-
- /* Try fixing the line in the preimage */
- ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
-
- for (j = fixstart; j < fixed.len; j++)
- if (!isspace(fixed.buf[j]))
- goto unmatch_exit;
-
- orig += oldlen;
- }
-
- /*
- * Yes, the preimage is based on an older version that still
- * has whitespace breakages unfixed, and fixing them makes the
- * hunk match. Update the context lines in the postimage.
- */
- fixed_buf = strbuf_detach(&fixed, &fixed_len);
- if (postlen < postimage->len)
- postlen = 0;
- update_pre_post_images(preimage, postimage,
- fixed_buf, fixed_len, postlen);
- return 1;
-
- unmatch_exit:
- strbuf_release(&fixed);
- return 0;
-}
-
-static int find_pos(struct image *img,
- struct image *preimage,
- struct image *postimage,
- int line,
- unsigned ws_rule,
- int match_beginning, int match_end)
-{
- int i;
- unsigned long backwards, forwards, try;
- int backwards_lno, forwards_lno, try_lno;
-
- /*
- * If match_beginning or match_end is specified, there is no
- * point starting from a wrong line that will never match and
- * wander around and wait for a match at the specified end.
- */
- if (match_beginning)
- line = 0;
- else if (match_end)
- line = img->nr - preimage->nr;
-
- /*
- * Because the comparison is unsigned, the following test
- * will also take care of a negative line number that can
- * result when match_end and preimage is larger than the target.
- */
- if ((size_t) line > img->nr)
- line = img->nr;
-
- try = 0;
- for (i = 0; i < line; i++)
- try += img->line[i].len;
-
- /*
- * There's probably some smart way to do this, but I'll leave
- * that to the smart and beautiful people. I'm simple and stupid.
- */
- backwards = try;
- backwards_lno = line;
- forwards = try;
- forwards_lno = line;
- try_lno = line;
-
- for (i = 0; ; i++) {
- if (match_fragment(img, preimage, postimage,
- try, try_lno, ws_rule,
- match_beginning, match_end))
- return try_lno;
-
- again:
- if (backwards_lno == 0 && forwards_lno == img->nr)
- break;
-
- if (i & 1) {
- if (backwards_lno == 0) {
- i++;
- goto again;
- }
- backwards_lno--;
- backwards -= img->line[backwards_lno].len;
- try = backwards;
- try_lno = backwards_lno;
- } else {
- if (forwards_lno == img->nr) {
- i++;
- goto again;
- }
- forwards += img->line[forwards_lno].len;
- forwards_lno++;
- try = forwards;
- try_lno = forwards_lno;
- }
-
- }
- return -1;
-}
-
-static void remove_first_line(struct image *img)
-{
- img->buf += img->line[0].len;
- img->len -= img->line[0].len;
- img->line++;
- img->nr--;
-}
-
-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,
- struct image *postimage)
-{
- /*
- * remove the copy of preimage at offset in img
- * and replace it with postimage
- */
- int i, nr;
- size_t remove_count, insert_count, applied_at = 0;
- char *result;
- int preimage_limit;
-
- /*
- * If we are removing blank lines at the end of img,
- * the preimage may extend beyond the end.
- * If that is the case, we must be careful only to
- * remove the part of the preimage that falls within
- * the boundaries of img. Initialize preimage_limit
- * to the number of lines in the preimage that falls
- * within the boundaries.
- */
- preimage_limit = preimage->nr;
- if (preimage_limit > img->nr - applied_pos)
- preimage_limit = img->nr - applied_pos;
-
- for (i = 0; i < applied_pos; i++)
- applied_at += img->line[i].len;
-
- remove_count = 0;
- for (i = 0; i < preimage_limit; i++)
- remove_count += img->line[applied_pos + i].len;
- insert_count = postimage->len;
-
- /* Adjust the contents */
- result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));
- memcpy(result, img->buf, applied_at);
- memcpy(result + applied_at, postimage->buf, postimage->len);
- memcpy(result + applied_at + postimage->len,
- img->buf + (applied_at + remove_count),
- img->len - (applied_at + remove_count));
- free(img->buf);
- img->buf = result;
- img->len += insert_count - remove_count;
- result[img->len] = '\0';
-
- /* Adjust the line table */
- nr = img->nr + postimage->nr - preimage_limit;
- if (preimage_limit < postimage->nr) {
- /*
- * NOTE: this knows that we never call remove_first_line()
- * on anything other than pre/post image.
- */
- REALLOC_ARRAY(img->line, nr);
- img->line_allocated = img->line;
- }
- if (preimage_limit != postimage->nr)
- memmove(img->line + applied_pos + postimage->nr,
- img->line + applied_pos + preimage_limit,
- (img->nr - (applied_pos + preimage_limit)) *
- sizeof(*img->line));
- memcpy(img->line + applied_pos,
- postimage->line,
- postimage->nr * sizeof(*img->line));
- if (!allow_overlap)
- for (i = 0; i < postimage->nr; i++)
- img->line[applied_pos + i].flag |= LINE_PATCHED;
- 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)
-{
- int match_beginning, match_end;
- const char *patch = frag->patch;
- int size = frag->size;
- char *old, *oldlines;
- struct strbuf newlines;
- int new_blank_lines_at_end = 0;
- int found_new_blank_lines_at_end = 0;
- int hunk_linenr = frag->linenr;
- unsigned long leading, trailing;
- int pos, applied_pos;
- struct image preimage;
- struct image postimage;
-
- memset(&preimage, 0, sizeof(preimage));
- memset(&postimage, 0, sizeof(postimage));
- oldlines = xmalloc(size);
- strbuf_init(&newlines, size);
-
- old = oldlines;
- while (size > 0) {
- char first;
- int len = linelen(patch, size);
- int plen;
- int added_blank_line = 0;
- int is_blank_context = 0;
- size_t start;
-
- if (!len)
- break;
-
- /*
- * "plen" is how much of the line we should use for
- * the actual patch data. Normally we just remove the
- * first character on the line, but if the line is
- * followed by "\ No newline", then we also remove the
- * last one (which is the newline, of course).
- */
- plen = len - 1;
- if (len < size && patch[len] == '\\')
- plen--;
- first = *patch;
- if (apply_in_reverse) {
- if (first == '-')
- first = '+';
- else if (first == '+')
- first = '-';
- }
-
- switch (first) {
- case '\n':
- /* Newer GNU diff, empty context line */
- if (plen < 0)
- /* ... followed by '\No newline'; nothing */
- break;
- *old++ = '\n';
- strbuf_addch(&newlines, '\n');
- add_line_info(&preimage, "\n", 1, LINE_COMMON);
- add_line_info(&postimage, "\n", 1, LINE_COMMON);
- is_blank_context = 1;
- break;
- case ' ':
- if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
- ws_blank_line(patch + 1, plen, ws_rule))
- is_blank_context = 1;
- case '-':
- memcpy(old, patch + 1, plen);
- add_line_info(&preimage, old, plen,
- (first == ' ' ? LINE_COMMON : 0));
- old += plen;
- if (first == '-')
- break;
- /* Fall-through for ' ' */
- case '+':
- /* --no-add does not add new lines */
- if (first == '+' && no_add)
- break;
-
- start = newlines.len;
- if (first != '+' ||
- !whitespace_error ||
- ws_error_action != correct_ws_error) {
- strbuf_add(&newlines, patch + 1, plen);
- }
- else {
- ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
- }
- add_line_info(&postimage, newlines.buf + start, newlines.len - start,
- (first == '+' ? 0 : LINE_COMMON));
- if (first == '+' &&
- (ws_rule & WS_BLANK_AT_EOF) &&
- ws_blank_line(patch + 1, plen, ws_rule))
- added_blank_line = 1;
- break;
- case '@': case '\\':
- /* Ignore it, we already handled it */
- break;
- default:
- if (apply_verbosely)
- error(_("invalid start of line: '%c'"), first);
- applied_pos = -1;
- goto out;
- }
- if (added_blank_line) {
- if (!new_blank_lines_at_end)
- found_new_blank_lines_at_end = hunk_linenr;
- new_blank_lines_at_end++;
- }
- else if (is_blank_context)
- ;
- else
- new_blank_lines_at_end = 0;
- patch += len;
- size -= len;
- hunk_linenr++;
- }
- if (inaccurate_eof &&
- old > oldlines && old[-1] == '\n' &&
- newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
- old--;
- strbuf_setlen(&newlines, newlines.len - 1);
- }
-
- leading = frag->leading;
- trailing = frag->trailing;
-
- /*
- * A hunk to change lines at the beginning would begin with
- * @@ -1,L +N,M @@
- * but we need to be careful. -U0 that inserts before the second
- * line also has this pattern.
- *
- * And a hunk to add to an empty file would begin with
- * @@ -0,0 +N,M @@
- *
- * In other words, a hunk that is (frag->oldpos <= 1) with or
- * without leading context must match at the beginning.
- */
- match_beginning = (!frag->oldpos ||
- (frag->oldpos == 1 && !unidiff_zero));
-
- /*
- * A hunk without trailing lines must match at the end.
- * However, we simply cannot tell if a hunk must match end
- * from the lack of trailing lines if the patch was generated
- * with unidiff without any context.
- */
- match_end = !unidiff_zero && !trailing;
-
- pos = frag->newpos ? (frag->newpos - 1) : 0;
- preimage.buf = oldlines;
- preimage.len = old - oldlines;
- postimage.buf = newlines.buf;
- postimage.len = newlines.len;
- preimage.line = preimage.line_allocated;
- postimage.line = postimage.line_allocated;
-
- for (;;) {
-
- applied_pos = find_pos(img, &preimage, &postimage, pos,
- ws_rule, match_beginning, match_end);
-
- if (applied_pos >= 0)
- break;
-
- /* Am I at my context limits? */
- if ((leading <= p_context) && (trailing <= p_context))
- break;
- if (match_beginning || match_end) {
- match_beginning = match_end = 0;
- continue;
- }
-
- /*
- * Reduce the number of context lines; reduce both
- * leading and trailing if they are equal otherwise
- * just reduce the larger context.
- */
- if (leading >= trailing) {
- remove_first_line(&preimage);
- remove_first_line(&postimage);
- pos--;
- leading--;
- }
- if (trailing > leading) {
- remove_last_line(&preimage);
- remove_last_line(&postimage);
- trailing--;
- }
- }
-
- if (applied_pos >= 0) {
- if (new_blank_lines_at_end &&
- preimage.nr + applied_pos >= img->nr &&
- (ws_rule & WS_BLANK_AT_EOF) &&
- ws_error_action != nowarn_ws_error) {
- record_ws_error(WS_BLANK_AT_EOF, "+", 1,
- found_new_blank_lines_at_end);
- if (ws_error_action == correct_ws_error) {
- while (new_blank_lines_at_end--)
- remove_last_line(&postimage);
- }
- /*
- * We would want to prevent write_out_results()
- * from taking place in apply_patch() that follows
- * the callchain led us here, which is:
- * apply_patch->check_patch_list->check_patch->
- * apply_data->apply_fragments->apply_one_fragment
- */
- if (ws_error_action == die_on_ws_error)
- apply = 0;
- }
-
- if (apply_verbosely && applied_pos != pos) {
- int offset = applied_pos - pos;
- if (apply_in_reverse)
- offset = 0 - 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);
- }
-
- /*
- * Warn if it was necessary to reduce the number
- * of context lines.
- */
- if ((leading != frag->leading) ||
- (trailing != frag->trailing))
- 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"),
- (int)(old - oldlines), oldlines);
- }
-
-out:
- free(oldlines);
- strbuf_release(&newlines);
- free(preimage.line_allocated);
- free(postimage.line_allocated);
-
- return (applied_pos < 0);
-}
-
-static int apply_binary_fragment(struct image *img, struct patch *patch)
-{
- struct fragment *fragment = patch->fragments;
- unsigned long len;
- void *dst;
-
- if (!fragment)
- return error(_("missing binary patch data for '%s'"),
- patch->new_name ?
- patch->new_name :
- patch->old_name);
-
- /* Binary patch is irreversible without the optional second hunk */
- if (apply_in_reverse) {
- if (!fragment->next)
- return error("cannot reverse-apply a binary patch "
- "without the reverse hunk to '%s'",
- patch->new_name
- ? patch->new_name : patch->old_name);
- fragment = fragment->next;
- }
- switch (fragment->binary_patch_method) {
- case BINARY_DELTA_DEFLATED:
- dst = patch_delta(img->buf, img->len, fragment->patch,
- fragment->size, &len);
- if (!dst)
- return -1;
- clear_image(img);
- img->buf = dst;
- img->len = len;
- return 0;
- case BINARY_LITERAL_DEFLATED:
- clear_image(img);
- img->len = fragment->size;
- img->buf = xmemdupz(fragment->patch, img->len);
- return 0;
- }
- 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;
- unsigned char sha1[20];
-
- /*
- * For safety, we require patch index line to contain
- * full 40-byte textual SHA1 for old and new, at least for now.
- */
- if (strlen(patch->old_sha1_prefix) != 40 ||
- strlen(patch->new_sha1_prefix) != 40 ||
- get_sha1_hex(patch->old_sha1_prefix, sha1) ||
- get_sha1_hex(patch->new_sha1_prefix, sha1))
- return error("cannot apply binary patch to '%s' "
- "without full index line", name);
-
- if (patch->old_name) {
- /*
- * See if the old one matches what the patch
- * applies to.
- */
- hash_sha1_file(img->buf, img->len, blob_type, sha1);
- if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
- return error("the patch applies to '%s' (%s), "
- "which does not match the "
- "current contents.",
- name, sha1_to_hex(sha1));
- }
- else {
- /* Otherwise, the old one must be empty. */
- if (img->len)
- return error("the patch applies to an empty "
- "'%s' but it is not empty", name);
- }
-
- get_sha1_hex(patch->new_sha1_prefix, sha1);
- if (is_null_sha1(sha1)) {
- clear_image(img);
- return 0; /* deletion patch */
- }
-
- if (has_sha1_file(sha1)) {
- /* We already have the postimage */
- enum object_type type;
- unsigned long size;
- char *result;
-
- result = read_sha1_file(sha1, &type, &size);
- if (!result)
- return error("the necessary postimage %s for "
- "'%s' cannot be read",
- patch->new_sha1_prefix, name);
- clear_image(img);
- img->buf = result;
- img->len = size;
- } else {
- /*
- * We have verified buf matches the preimage;
- * apply the patch data to it, which is stored
- * in the patch->fragments->{patch,size}.
- */
- if (apply_binary_fragment(img, patch))
- 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)"),
- name, patch->new_sha1_prefix, sha1_to_hex(sha1));
- }
-
- return 0;
-}
-
-static int apply_fragments(struct image *img, struct patch *patch)
-{
- struct fragment *frag = patch->fragments;
- const char *name = patch->old_name ? patch->old_name : patch->new_name;
- unsigned ws_rule = patch->ws_rule;
- unsigned inaccurate_eof = patch->inaccurate_eof;
- int nth = 0;
-
- if (patch->is_binary)
- return apply_binary(img, patch);
-
- while (frag) {
- nth++;
- if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
- error(_("patch failed: %s:%ld"), name, frag->oldpos);
- if (!apply_with_reject)
- return -1;
- frag->rejected = 1;
- }
- frag = frag->next;
- }
- return 0;
-}
-
-static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
-{
- if (S_ISGITLINK(mode)) {
- strbuf_grow(buf, 100);
- 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(sha1, &type, &sz);
- if (!result)
- return -1;
- /* XXX read_sha1_file NUL-terminates */
- strbuf_attach(buf, result, sz, sz + 1);
- }
- return 0;
-}
-
-static int read_file_or_gitlink(const 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;
-
- if (name == NULL)
- return NULL;
-
- item = string_list_lookup(&fn_table, name);
- if (item != NULL)
- return (struct patch *)item->util;
-
- return NULL;
-}
-
-/*
- * item->util in the filename table records the status of the path.
- * Usually it points at a patch (whose result records the contents
- * of it after applying it), but it could be PATH_WAS_DELETED for a
- * path that a previously applied patch has already removed, 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 presence of B as we
- * will remove it in a later patch.
- */
-#define PATH_TO_BE_DELETED ((struct patch *) -2)
-#define PATH_WAS_DELETED ((struct patch *) -1)
-
-static int to_be_deleted(struct patch *patch)
-{
- return patch == PATH_TO_BE_DELETED;
-}
-
-static int was_deleted(struct patch *patch)
-{
- return patch == PATH_WAS_DELETED;
-}
-
-static void add_to_fn_table(struct patch *patch)
-{
- struct string_list_item *item;
-
- /*
- * Always add new_name unless patch is a deletion
- * This should cover the cases for normal diffs,
- * file creations and copies
- */
- if (patch->new_name != NULL) {
- item = string_list_insert(&fn_table, patch->new_name);
- item->util = patch;
- }
-
- /*
- * store a failure on rename/deletion cases because
- * later chunks shouldn't patch old names
- */
- if ((patch->new_name == NULL) || (patch->is_rename)) {
- item = string_list_insert(&fn_table, patch->old_name);
- item->util = PATH_WAS_DELETED;
- }
-}
-
-static void prepare_fn_table(struct patch *patch)
-{
- /*
- * store information about incoming file deletion
- */
- while (patch) {
- if ((patch->new_name == NULL) || (patch->is_rename)) {
- struct string_list_item *item;
- item = string_list_insert(&fn_table, patch->old_name);
- item->util = PATH_TO_BE_DELETED;
- }
- patch = patch->next;
- }
-}
-
-static int checkout_target(struct index_state *istate,
- struct cache_entry *ce, struct stat *st)
-{
- struct checkout costate;
-
- memset(&costate, 0, sizeof(costate));
- costate.base_dir = "";
- costate.refresh_cache = 1;
- costate.istate = istate;
- 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(const 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,
- const struct cache_entry *ce,
- struct stat *st,
- const char *name,
- unsigned expected_mode)
-{
- if (cached || check_index) {
- 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 (has_symlink_leading_path(name, strlen(name))) {
- return error(_("reading from '%s' beyond a symbolic link"), name);
- } 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,
- const struct cache_entry *ce)
-{
- struct strbuf buf = STRBUF_INIT;
- size_t len;
- char *img;
- struct patch *previous;
- int status;
-
- 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);
- return 0;
-}
-
-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;
-
- 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(&the_index, 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 try_threeway(struct image *image, struct patch *patch,
- struct stat *st, const struct cache_entry *ce)
-{
- 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");
-
- 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)
- oidclr(&patch->threeway_stage[0]);
- else
- hashcpy(patch->threeway_stage[0].hash, pre_sha1);
- hashcpy(patch->threeway_stage[1].hash, our_sha1);
- hashcpy(patch->threeway_stage[2].hash, 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);
- }
- return 0;
-}
-
-static int apply_data(struct patch *patch, struct stat *st, const struct cache_entry *ce)
-{
- 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;
- }
- 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 *previous = NULL;
- int stat_ret = 0, status;
- unsigned st_mode = 0;
-
- if (!old_name)
- return 0;
-
- assert(patch->is_new <= 0);
- previous = previous_patch(patch, &status);
-
- 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));
- }
-
- 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);
- }
- *ce = active_cache[pos];
- if (stat_ret < 0) {
- if (checkout_target(&the_index, *ce, st))
- return -1;
- }
- if (!cached && verify_index_match(*ce, st))
- 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));
- }
-
- if (!cached && !previous)
- st_mode = ce_mode_from_stat(*ce, st->st_mode);
-
- if (patch->is_new < 0)
- patch->is_new = 0;
- if (!patch->old_mode)
- patch->old_mode = st_mode;
- if ((st_mode ^ patch->old_mode) & S_IFMT)
- return error(_("%s: wrong type"), old_name);
- if (st_mode != patch->old_mode)
- 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;
- return 0;
-
- 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;
-}
-
-/*
- * We need to keep track of how symlinks in the preimage are
- * manipulated by the patches. A patch to add a/b/c where a/b
- * is a symlink should not be allowed to affect the directory
- * the symlink points at, but if the same patch removes a/b,
- * it is perfectly fine, as the patch removes a/b to make room
- * to create a directory a/b so that a/b/c can be created.
- */
-static struct string_list symlink_changes;
-#define SYMLINK_GOES_AWAY 01
-#define SYMLINK_IN_RESULT 02
-
-static uintptr_t register_symlink_changes(const char *path, uintptr_t what)
-{
- struct string_list_item *ent;
-
- ent = string_list_lookup(&symlink_changes, path);
- if (!ent) {
- ent = string_list_insert(&symlink_changes, path);
- ent->util = (void *)0;
- }
- ent->util = (void *)(what | ((uintptr_t)ent->util));
- return (uintptr_t)ent->util;
-}
-
-static uintptr_t check_symlink_changes(const char *path)
-{
- struct string_list_item *ent;
-
- ent = string_list_lookup(&symlink_changes, path);
- if (!ent)
- return 0;
- return (uintptr_t)ent->util;
-}
-
-static void prepare_symlink_changes(struct patch *patch)
-{
- for ( ; patch; patch = patch->next) {
- if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
- (patch->is_rename || patch->is_delete))
- /* the symlink at patch->old_name is removed */
- register_symlink_changes(patch->old_name, SYMLINK_GOES_AWAY);
-
- if (patch->new_name && S_ISLNK(patch->new_mode))
- /* the symlink at patch->new_name is created or remains */
- register_symlink_changes(patch->new_name, SYMLINK_IN_RESULT);
- }
-}
-
-static int path_is_beyond_symlink_1(struct strbuf *name)
-{
- do {
- unsigned int change;
-
- while (--name->len && name->buf[name->len] != '/')
- ; /* scan backwards */
- if (!name->len)
- break;
- name->buf[name->len] = '\0';
- change = check_symlink_changes(name->buf);
- if (change & SYMLINK_IN_RESULT)
- return 1;
- if (change & SYMLINK_GOES_AWAY)
- /*
- * This cannot be "return 0", because we may
- * see a new one created at a higher level.
- */
- continue;
-
- /* otherwise, check the preimage */
- if (check_index) {
- struct cache_entry *ce;
-
- ce = cache_file_exists(name->buf, name->len, ignore_case);
- if (ce && S_ISLNK(ce->ce_mode))
- return 1;
- } else {
- struct stat st;
- if (!lstat(name->buf, &st) && S_ISLNK(st.st_mode))
- return 1;
- }
- } while (1);
- return 0;
-}
-
-static int path_is_beyond_symlink(const char *name_)
-{
- int ret;
- struct strbuf name = STRBUF_INIT;
-
- assert(*name_ != '\0');
- strbuf_addstr(&name, name_);
- ret = path_is_beyond_symlink_1(&name);
- strbuf_release(&name);
-
- return ret;
-}
-
-static void die_on_unsafe_path(struct patch *patch)
-{
- const char *old_name = NULL;
- const char *new_name = NULL;
- if (patch->is_delete)
- old_name = patch->old_name;
- else if (!patch->is_new && !patch->is_copy)
- old_name = patch->old_name;
- if (!patch->is_delete)
- new_name = patch->new_name;
-
- if (old_name && !verify_path(old_name))
- die(_("invalid path '%s'"), old_name);
- if (new_name && !verify_path(new_name))
- die(_("invalid path '%s'"), new_name);
-}
-
-/*
- * 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;
- const char *old_name = patch->old_name;
- const char *new_name = patch->new_name;
- const char *name = old_name ? old_name : new_name;
- struct cache_entry *ce = NULL;
- struct patch *tpatch;
- int ok_if_exists;
- int status;
-
- patch->rejected = 1; /* we will drop this after we succeed */
-
- status = check_preimage(patch, &ce, &st);
- if (status)
- 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 presence 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)))
- ok_if_exists = 1;
- else
- ok_if_exists = 0;
-
- if (new_name &&
- ((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
- 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;
- else
- patch->new_mode = patch->old_mode;
- }
- }
-
- if (new_name && old_name) {
- 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) {
- 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 (!unsafe_paths)
- die_on_unsafe_path(patch);
-
- /*
- * An attempt to read from or delete a path that is beyond a
- * symbolic link will be prevented by load_patch_target() that
- * is called at the beginning of apply_data() so we do not
- * have to worry about a patch marked with "is_delete" bit
- * here. We however need to make sure that the patch result
- * is not deposited to a path that is beyond a symbolic link
- * here.
- */
- if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
- return error(_("affected file '%s' is beyond a symbolic link"),
- patch->new_name);
-
- if (apply_data(patch, &st, ce) < 0)
- return error(_("%s: patch does not apply"), name);
- patch->rejected = 0;
- return 0;
-}
-
-static int check_patch_list(struct patch *patch)
-{
- int err = 0;
-
- prepare_symlink_changes(patch);
- prepare_fn_table(patch);
- while (patch) {
- if (apply_verbosely)
- say_patch_name(stderr,
- _("Checking patch %s..."), patch);
- err |= check_patch(patch);
- patch = patch->next;
- }
- return err;
-}
-
-/* This function tries to read the sha1 from the current index */
-static int get_current_sha1(const char *path, unsigned char *sha1)
-{
- int pos;
-
- if (read_cache() < 0)
- return -1;
- pos = cache_name_pos(path, strlen(path));
- if (pos < 0)
- return -1;
- hashcpy(sha1, active_cache[pos]->sha1);
- return 0;
-}
-
-static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20])
-{
- /*
- * A usable gitlink patch has only one fragment (hunk) that looks like:
- * @@ -1 +1 @@
- * -Subproject commit <old sha1>
- * +Subproject commit <new sha1>
- * or
- * @@ -1 +0,0 @@
- * -Subproject commit <old sha1>
- * for a removal patch.
- */
- struct fragment *hunk = p->fragments;
- static const char heading[] = "-Subproject commit ";
- char *preimage;
-
- if (/* does the patch have only one hunk? */
- hunk && !hunk->next &&
- /* is its preimage one line? */
- hunk->oldpos == 1 && hunk->oldlines == 1 &&
- /* does preimage begin with the heading? */
- (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
- starts_with(++preimage, heading) &&
- /* does it record full SHA-1? */
- !get_sha1_hex(preimage + sizeof(heading) - 1, sha1) &&
- preimage[sizeof(heading) + 40 - 1] == '\n' &&
- /* does the abbreviated name on the index line agree with it? */
- starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
- return 0; /* it all looks fine */
-
- /* we may have full object name on the index line */
- return get_sha1_hex(p->old_sha1_prefix, sha1);
-}
-
-/* Build an index that contains the just the files needed for a 3way merge */
-static void build_fake_ancestor(struct patch *list, const char *filename)
-{
- struct patch *patch;
- struct index_state result = { NULL };
- static struct lock_file lock;
-
- /* Once we start supporting the reverse patch, it may be
- * worth showing the new sha1 prefix, but until then...
- */
- for (patch = list; patch; patch = patch->next) {
- unsigned char sha1[20];
- struct cache_entry *ce;
- const char *name;
-
- name = patch->old_name ? patch->old_name : patch->new_name;
- if (0 < patch->is_new)
- continue;
-
- if (S_ISGITLINK(patch->old_mode)) {
- if (!preimage_sha1_in_gitlink_patch(patch, sha1))
- ; /* ok, the textual part looks sane */
- else
- die("sha1 information is lacking or useless for submodule %s",
- name);
- } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
- ; /* ok */
- } else if (!patch->lines_added && !patch->lines_deleted) {
- /* mode-only change: update the current */
- if (get_current_sha1(patch->old_name, sha1))
- die("mode change for %s, which is not "
- "in current HEAD", name);
- } else
- die("sha1 information is lacking or useless "
- "(%s).", name);
-
- ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);
- if (!ce)
- 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);
- }
-
- hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
- if (write_locked_index(&result, &lock, COMMIT_LOCK))
- die ("Could not write temporary index to %s", filename);
-
- discard_index(&result);
-}
-
-static void stat_patch_list(struct patch *patch)
-{
- int files, adds, dels;
-
- for (files = adds = dels = 0 ; patch ; patch = patch->next) {
- files++;
- adds += patch->lines_added;
- dels += patch->lines_deleted;
- show_stats(patch);
- }
-
- print_stat_summary(stdout, files, adds, dels);
-}
-
-static void numstat_patch_list(struct patch *patch)
-{
- for ( ; patch; patch = patch->next) {
- const char *name;
- name = patch->new_name ? patch->new_name : patch->old_name;
- if (patch->is_binary)
- printf("-\t-\t");
- else
- printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
- write_name_quoted(name, stdout, line_termination);
- }
-}
-
-static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
-{
- if (mode)
- printf(" %s mode %06o %s\n", newdelete, mode, name);
- else
- printf(" %s %s\n", newdelete, name);
-}
-
-static void show_mode_change(struct patch *p, int show_name)
-{
- if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
- if (show_name)
- printf(" mode change %06o => %06o %s\n",
- p->old_mode, p->new_mode, p->new_name);
- else
- printf(" mode change %06o => %06o\n",
- p->old_mode, p->new_mode);
- }
-}
-
-static void show_rename_copy(struct patch *p)
-{
- const char *renamecopy = p->is_rename ? "rename" : "copy";
- const char *old, *new;
-
- /* Find common prefix */
- old = p->old_name;
- new = p->new_name;
- while (1) {
- const char *slash_old, *slash_new;
- slash_old = strchr(old, '/');
- slash_new = strchr(new, '/');
- if (!slash_old ||
- !slash_new ||
- slash_old - old != slash_new - new ||
- memcmp(old, new, slash_new - new))
- break;
- old = slash_old + 1;
- new = slash_new + 1;
- }
- /* p->old_name thru old is the common prefix, and old and new
- * through the end of names are renames
- */
- if (old != p->old_name)
- printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
- (int)(old - p->old_name), p->old_name,
- old, new, p->score);
- else
- printf(" %s %s => %s (%d%%)\n", renamecopy,
- p->old_name, p->new_name, p->score);
- show_mode_change(p, 0);
-}
-
-static void summary_patch_list(struct patch *patch)
-{
- struct patch *p;
-
- for (p = patch; p; p = p->next) {
- if (p->is_new)
- show_file_mode_name("create", p->new_mode, p->new_name);
- else if (p->is_delete)
- show_file_mode_name("delete", p->old_mode, p->old_name);
- else {
- if (p->is_rename || p->is_copy)
- show_rename_copy(p);
- else {
- if (p->score) {
- printf(" rewrite %s (%d%%)\n",
- p->new_name, p->score);
- show_mode_change(p, 0);
- }
- else
- show_mode_change(p, 1);
- }
- }
- }
-}
-
-static void patch_stats(struct patch *patch)
-{
- int lines = patch->lines_added + patch->lines_deleted;
-
- if (lines > max_change)
- max_change = lines;
- if (patch->old_name) {
- int len = quote_c_style(patch->old_name, NULL, NULL, 0);
- if (!len)
- len = strlen(patch->old_name);
- if (len > max_len)
- max_len = len;
- }
- if (patch->new_name) {
- int len = quote_c_style(patch->new_name, NULL, NULL, 0);
- if (!len)
- len = strlen(patch->new_name);
- if (len > max_len)
- max_len = len;
- }
-}
-
-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);
- }
- if (!cached) {
- if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
- remove_path(patch->old_name);
- }
- }
-}
-
-static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
-{
- struct stat st;
- struct cache_entry *ce;
- int namelen = strlen(path);
- unsigned ce_size = cache_entry_size(namelen);
-
- if (!update_index)
- return;
-
- ce = xcalloc(1, ce_size);
- memcpy(ce->name, path, namelen);
- ce->ce_mode = create_ce_mode(mode);
- ce->ce_flags = create_ce_flags(0);
- ce->ce_namelen = namelen;
- if (S_ISGITLINK(mode)) {
-