]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'rs/line-log-until' into master
authorJunio C Hamano <gitster@pobox.com>
Thu, 9 Jul 2020 21:00:42 +0000 (14:00 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 9 Jul 2020 21:00:42 +0000 (14:00 -0700)
"git log -Lx,y:path --before=date" lost track of where the range
should be because it didn't take the changes made by the youngest
commits that are omitted from the output into account.

* rs/line-log-until:
  revision: disable min_age optimization with line-log

191 files changed:
Documentation/MyFirstContribution.txt
Documentation/RelNotes/2.28.0.txt
Documentation/SubmittingPatches
Documentation/config/init.txt
Documentation/git-branch.txt
Documentation/git-cat-file.txt
Documentation/git-clone.txt
Documentation/git-fast-export.txt
Documentation/git-fetch.txt
Documentation/git-index-pack.txt
Documentation/git-init.txt
Documentation/git-ls-remote.txt
Documentation/git-show-index.txt
Documentation/git-submodule.txt
Documentation/giteveryday.txt
Documentation/githooks.txt
Documentation/gitmodules.txt
Documentation/gitremote-helpers.txt
Documentation/gitworkflows.txt
Documentation/howto/maintain-git.txt
Documentation/howto/rebase-from-internal-branch.txt
Documentation/howto/revert-branch-rebase.txt
Documentation/howto/update-hook-example.txt
Documentation/pretty-formats.txt
Documentation/technical/protocol-capabilities.txt
Documentation/technical/protocol-v2.txt
Documentation/user-manual.txt
alloc.c
alloc.h
blame.c
blob.c
bloom.c
branch.c
builtin/branch.c
builtin/cat-file.c
builtin/clone.c
builtin/commit-graph.c
builtin/config.c
builtin/fast-export.c
builtin/fsck.c
builtin/index-pack.c
builtin/init-db.c
builtin/ls-remote.c
builtin/pull.c
builtin/receive-pack.c
builtin/reflog.c
builtin/show-index.c
builtin/submodule--helper.c
builtin/worktree.c
bundle.c
bundle.h
cache.h
command-list.txt
commit-graph.c
commit-graph.h
commit-reach.c
commit-reach.h
commit.c
commit.h
connect.c
connect.h
contrib/coccinelle/commit.cocci
contrib/completion/git-completion.bash
contrib/completion/git-prompt.sh
contrib/subtree/t/t7900-subtree.sh
diff-lib.c
fetch-pack.c
fmt-merge-msg.c
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-send-email.perl
git-svn.perl
git.c
http-push.c
object-store.h
object.c
object.h
packfile.c
perl/Git/IndexInfo.pm
perl/Git/SVN.pm
perl/Git/SVN/Editor.pm
perl/Git/SVN/Fetcher.pm
perl/Git/SVN/Log.pm
perl/Git/SVN/Ra.pm
pkt-line.c
pkt-line.h
ref-filter.c
refs.c
refs.h
remote-curl.c
remote-testsvn.c
remote.c
revision.c
revision.h
send-pack.c
serve.c
setup.c
t/helper/test-oid-array.c
t/helper/test-reach.c
t/helper/test-ref-store.c
t/lib-git-svn.sh
t/lib-submodule-update.sh
t/perf/p1400-update-ref.sh [new file with mode: 0755]
t/t0001-init.sh
t/t1013-read-tree-submodule.sh
t/t1050-large.sh
t/t1302-repo-version.sh
t/t1416-ref-transaction-hooks.sh [new file with mode: 0755]
t/t1507-rev-parse-upstream.sh
t/t2013-checkout-submodule.sh
t/t2203-add-intent.sh
t/t3200-branch.sh
t/t3426-rebase-submodule.sh
t/t3512-cherry-pick-submodule.sh
t/t3513-revert-submodule.sh
t/t3906-stash-submodule.sh
t/t4013-diff-various.sh
t/t4013/diff.log_--decorate=full_--all
t/t4013/diff.log_--decorate_--all
t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
t/t4013/diff.log_--patch-with-stat_master
t/t4013/diff.log_--patch-with-stat_master_--_dir_
t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
t/t4013/diff.log_--root_--patch-with-stat_--summary_master
t/t4013/diff.log_--root_--patch-with-stat_master
t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
t/t4013/diff.log_--root_-p_master
t/t4013/diff.log_--root_master
t/t4013/diff.log_-m_-p_--first-parent_master
t/t4013/diff.log_-m_-p_master
t/t4013/diff.log_-p_--first-parent_master
t/t4013/diff.log_-p_master
t/t4013/diff.log_master
t/t4013/diff.show_--first-parent_master
t/t4013/diff.show_-c_master
t/t4013/diff.show_-m_master
t/t4013/diff.show_master
t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
t/t4137-apply-submodule.sh
t/t4202-log.sh
t/t4255-am-submodule.sh
t/t5300-pack-object.sh
t/t5302-pack-index.sh
t/t5500-fetch-pack.sh
t/t5505-remote.sh
t/t5516-fetch-push.sh
t/t5528-push-default.sh
t/t5540-http-push-webdav.sh
t/t5550-http-fetch-dumb.sh
t/t5562-http-backend-content-length.sh
t/t5572-pull-submodule.sh
t/t5606-clone-options.sh
t/t5701-git-serve.sh
t/t5702-protocol-v2.sh
t/t5703-upload-pack-ref-in-want.sh
t/t5704-protocol-violations.sh
t/t5801/git-remote-testgit
t/t6041-bisect-submodule.sh
t/t6200-fmt-merge-msg.sh
t/t7112-reset-submodule.sh
t/t7406-submodule-update.sh
t/t7419-submodule-set-branch.sh
t/t7600-merge.sh
t/t7608-merge-messages.sh
t/t7613-merge-submodule.sh
t/t7800-difftool.sh
t/t9001-send-email.sh
t/t9020-remote-svn.sh
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9104-git-svn-follow-parent.sh
t/t9108-git-svn-glob.sh
t/t9109-git-svn-multi-glob.sh
t/t9168-git-svn-partially-globbed-names.sh
t/t9351-fast-export-anonymize.sh
t/t9902-completion.sh
t/test-lib.sh
tag.c
transport-helper.c
transport.c
transport.h
tree.c
upload-pack.c
worktree.c
worktree.h
wrapper.c
wt-status.c
wt-status.h

index 427274df4d9233e61001e478b3c299dd20439a73..d85c9b5143cec2f315c33886c497576e0c5591b8 100644 (file)
@@ -1179,8 +1179,8 @@ look at the section below this one for some context.)
 [[after-approval]]
 === After Review Approval
 
-The Git project has four integration branches: `pu`, `next`, `master`, and
-`maint`. Your change will be placed into `pu` fairly early on by the maintainer
+The Git project has four integration branches: `seen`, `next`, `master`, and
+`maint`. Your change will be placed into `seen` fairly early on by the maintainer
 while it is still in the review process; from there, when it is ready for wider
 testing, it will be merged into `next`. Plenty of early testers use `next` and
 may report issues. Eventually, changes in `next` will make it to `master`,
index 02e150efcb1701714ced358f88f8abd9e2a95d60..94ddbd92068df52bf7c8c4a6964afd534c03c005 100644 (file)
@@ -41,6 +41,14 @@ UI, Workflows & Features
  * "git diff-files" has been taught to say paths that are marked as
    intent-to-add are new files, not modified from an empty blob.
 
+ * "git status" learned to report the status of sparse checkout.
+
+ * "git difftool" has trouble dealing with paths added to the index
+   with the intent-to-add bit.
+
+ * "git fast-export --anonymize" learned to take customized mapping to
+   allow its users to tweak its output more usable for debugging.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -90,6 +98,22 @@ Performance, Internal Implementation, Development Support etc.
 
  * A misdesigned strbuf_write_fd() function has been retired.
 
+ * SHA-256 migration work continues, including CVS/SVN interface.
+
+ * A few fields in "struct commit" that do not have to always be
+   present have been moved to commit slabs.
+
+ * API cleanup for get_worktrees()
+
+ * By renumbering object flag bits, "struct object" managed to lose
+   bloated inter-field padding.
+
+ * The name of the primary branch in existing repositories, and the
+   default name used for the first branch in newly created
+   repositories, is made configurable, so that we can eventually wean
+   ourselves off of the hardcoded 'master'.
+
+ * The effort to avoid using test_must_fail on non-git command continues.
 
 
 Fixes since v2.27
@@ -158,6 +182,15 @@ Fixes since v2.27
  * An in-code comment in "git diff" has been updated.
    (merge c592fd4c83 dl/diff-usage-comment-update later to maint).
 
+ * The documentation and some tests have been adjusted for the recent
+   renaming of "pu" branch to "seen".
+   (merge 6dca5dbf93 js/pu-to-seen later to maint).
+
+ * The code to push changes over "dumb" HTTP had a bad interaction
+   with the commit reachability code due to incorrect allocation of
+   object flag bits, which has been corrected.
+   (merge 64472d15e9 bc/http-push-flagsfix later to maint).
+
  * Other code cleanup, docfix, build fix, etc.
    (merge 2c31a7aa44 jx/pkt-line-doc-count-fix later to maint).
    (merge d63ae31962 cb/t5608-cleanup later to maint).
@@ -166,3 +199,5 @@ Fixes since v2.27
    (merge b75a219904 es/advertise-contribution-doc later to maint).
    (merge 0c9a4f638a rs/pull-leakfix later to maint).
    (merge d546fe2874 rs/commit-reach-leakfix later to maint).
+   (merge 087bf5409c mk/pb-pretty-email-without-domain-part-fix later to maint).
+   (merge 5f4ee57ad9 es/worktree-code-cleanup later to maint).
index ecf9438cf08069bc66150633e79bfb2bead1853a..291b61e2621321e30277cd426fc842982c845ca6 100644 (file)
@@ -19,7 +19,7 @@ change is relevant to.
   base your work on the tip of the topic.
 
 * A new feature should be based on `master` in general. If the new
-  feature depends on a topic that is in `pu`, but not in `master`,
+  feature depends on a topic that is in `seen`, but not in `master`,
   base your work on the tip of that topic.
 
 * Corrections and enhancements to a topic not yet in `master` should
@@ -28,7 +28,7 @@ change is relevant to.
   into the series.
 
 * In the exceptional case that a new feature depends on several topics
-  not in `master`, start working on `next` or `pu` privately and send
+  not in `master`, start working on `next` or `seen` privately and send
   out patches for discussion. Before the final merge, you may have to
   wait until some of the dependent topics graduate to `master`, and
   rebase your work.
@@ -38,7 +38,7 @@ change is relevant to.
   these parts should be based on their trees.
 
 To find the tip of a topic branch, run `git log --first-parent
-master..pu` and look for the merge commit. The second parent of this
+master..seen` and look for the merge commit. The second parent of this
 commit is the tip of the topic branch.
 
 [[separate-commits]]
@@ -424,7 +424,7 @@ help you find out who they are.
   and cooked further and eventually graduates to `master`.
 
 In any time between the (2)-(3) cycle, the maintainer may pick it up
-from the list and queue it to `pu`, in order to make it easier for
+from the list and queue it to `seen`, in order to make it easier for
 people play with it without having to pick up and apply the patch to
 their trees themselves.
 
@@ -435,7 +435,7 @@ their trees themselves.
   master. `git pull --rebase` will automatically skip already-applied
   patches, and will let you know. This works only if you rebase on top
   of the branch in which your patch has been merged (i.e. it will not
-  tell you if your patch is merged in pu if you rebase on top of
+  tell you if your patch is merged in `seen` if you rebase on top of
   master).
 
 * Read the Git mailing list, the maintainer regularly posts messages
index 46fa8c6a0827abbd41bcaca49cf494f6b59db814..dc77f8c8446801fddbce2dff1ef4e678f431e202 100644 (file)
@@ -1,3 +1,7 @@
 init.templateDir::
        Specify the directory from which templates will be copied.
        (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+
+init.defaultBranch::
+       Allows overriding the default branch name e.g. when initializing
+       a new repository or when cloning an empty repository.
index 135206ff4aba651f9f40f307fdabaec91ae86555..03c0824d528a0132b1d1eb2d7ac3eb7ddc461d21 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
        [-v [--abbrev=<length> | --no-abbrev]]
        [--column[=<options>] | --no-column] [--sort=<key>]
        [(--merged | --no-merged) [<commit>]]
-       [--contains [<commit]] [--no-contains [<commit>]]
+       [--contains [<commit>]] [--no-contains [<commit>]]
        [--points-at <object>] [--format=<format>]
        [(-r | --remotes) | (-a | --all)]
        [--list] [<pattern>...]
index 8eca671b8278cfe02692605b80a9121bc5717567..8e192d87db4c6f8114d591e99f48c8783336d83d 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 '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]
+'git cat-file' (--batch[=<format>] | --batch-check[=<format>]) [ --textconv | --filters ] [--follow-symlinks]
 
 DESCRIPTION
 -----------
index 08d6045c4a835dd5032c594dfc112b4adf4c6d5e..c898310099895f92e884b7852af28786c6564c8b 100644 (file)
@@ -259,7 +259,7 @@ maintain a branch with no references other than a single cloned
 branch. This is useful e.g. to maintain minimal clones of the default
 branch of some repository for search indexing.
 
---recurse-submodules[=<pathspec]::
+--recurse-submodules[=<pathspec>]::
        After the clone is created, initialize and clone submodules
        within based on the provided pathspec.  If no pathspec is
        provided, all submodules are initialized and cloned.
index e8950de3ba40b9b2ff6587150a7fd4b3309752d3..1978dbdc6add12c87fd73673816219968f29dedf 100644 (file)
@@ -119,6 +119,11 @@ by keeping the marks the same across runs.
        the shape of the history and stored tree.  See the section on
        `ANONYMIZING` below.
 
+--anonymize-map=<from>[:<to>]::
+       Convert token `<from>` to `<to>` in the anonymized output. If
+       `<to>` is omitted, map `<from>` to itself (i.e., do not
+       anonymize it). See the section on `ANONYMIZING` below.
+
 --reference-excluded-parents::
        By default, running a command such as `git fast-export
        master~5..master` will not include the commit master{tilde}5
@@ -238,6 +243,30 @@ collapse "User 0", "User 1", etc into "User X"). This produces a much
 smaller output, and it is usually easy to quickly confirm that there is
 no private data in the stream.
 
+Reproducing some bugs may require referencing particular commits or
+paths, which becomes challenging after refnames and paths have been
+anonymized. You can ask for a particular token to be left as-is or
+mapped to a new value. For example, if you have a bug which reproduces
+with `git rev-list sensitive -- secret.c`, you can run:
+
+---------------------------------------------------
+$ git fast-export --anonymize --all \
+      --anonymize-map=sensitive:foo \
+      --anonymize-map=secret.c:bar.c \
+      >stream
+---------------------------------------------------
+
+After importing the stream, you can then run `git rev-list foo -- bar.c`
+in the anonymized repository.
+
+Note that paths and refnames are split into tokens at slash boundaries.
+The command above would anonymize `subdir/secret.c` as something like
+`path123/bar.c`; you could then search for `bar.c` in the anonymized
+repository to determine the final pathname.
+
+To make referencing the final pathname simpler, you can map each path
+component; so if you also anonymize `subdir` to `publicdir`, then the
+final pathname would be `publicdir/bar.c`.
 
 LIMITATIONS
 -----------
index 5b1909fdf4ffcf00d52997eb1a1c2b42385689a7..45b6d8e633ccf20675349b1a23072b90c0a46709 100644 (file)
@@ -255,14 +255,14 @@ refspec.
 * Using refspecs explicitly:
 +
 ------------------------------------------------
-$ git fetch origin +pu:pu maint:tmp
+$ git fetch origin +seen:seen maint:tmp
 ------------------------------------------------
 +
-This updates (or creates, as necessary) branches `pu` and `tmp` in
+This updates (or creates, as necessary) branches `seen` and `tmp` in
 the local repository by fetching from the branches (respectively)
-`pu` and `maint` from the remote repository.
+`seen` and `maint` from the remote repository.
 +
-The `pu` branch will be updated even if it does not fast-forward,
+The `seen` branch will be updated even if it does not fast-forward,
 because it is prefixed with a plus sign; `tmp` will not be.
 
 * Peek at a remote's branch, without configuring the remote in your local
index d5b7560bfe2d51370c313ee006a9f0ed4388eda4..9316d9a80b0d7bb5f83f80400585fe7cb22dc723 100644 (file)
@@ -93,6 +93,14 @@ OPTIONS
 --max-input-size=<size>::
        Die, if the pack is larger than <size>.
 
+--object-format=<hash-algorithm>::
+       Specify the given object format (hash algorithm) for the pack.  The valid
+       values are 'sha1' and (if enabled) 'sha256'.  The default is the algorithm for
+       the current repository (set by `extensions.objectFormat`), or 'sha1' if no
+       value is set or outside a repository.
++
+This option cannot be used with --stdin.
+
 NOTES
 -----
 
index adc6adfd380beb88cfc9e95ad9be39d874b4890e..ddfe265da5b6524f30d972bfea990bb2a89b5611 100644 (file)
@@ -10,7 +10,8 @@ SYNOPSIS
 --------
 [verse]
 'git init' [-q | --quiet] [--bare] [--template=<template_directory>]
-         [--separate-git-dir <git dir>] [--object-format=<format]
+         [--separate-git-dir <git dir>] [--object-format=<format>]
+         [-b <branch-name> | --initial-branch=<branch-name>]
          [--shared[=<permissions>]] [directory]
 
 
@@ -67,6 +68,12 @@ repository.
 +
 If this is reinitialization, the repository will be moved to the specified path.
 
+-b <branch-name::
+--initial-branch=<branch-name>::
+
+Use the specified name for the initial branch in the newly created repository.
+If not specified, fall back to the default name: `master`.
+
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
 Specify that the Git repository is to be shared amongst several users.  This
index 0a5c8b7d493efd0162774790b4ba1cab67e4c7db..492e573856f24f6444fefb842e8ee733fa95be25 100644 (file)
@@ -101,9 +101,9 @@ f25a265a342aed6041ab0cc484224d9ca54b6f41    refs/tags/v0.99.1
 7ceca275d047c90c0c7d5afb13ab97efdf51bd6e       refs/tags/v0.99.3
 c5db5456ae3b0873fc659c19fafdde22313cc441       refs/tags/v0.99.2
 0918385dbd9656cab0d1d81ba7453d49bbc16250       refs/tags/junio-gpg-pub
-$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master pu rc
+$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
 5fe978a5381f1fbad26a80e682ddd2a401966740       refs/heads/master
-c781a84b5204fb294c9ccc79f8b3baceeb32c061       refs/heads/pu
+c781a84b5204fb294c9ccc79f8b3baceeb32c061       refs/heads/seen
 $ git remote add korg http://www.kernel.org/pub/scm/git/git.git
 $ git ls-remote --tags korg v\*
 d6602ec5194c87b0fc87103ca4d67251c76f233a       refs/tags/v0.99
index 424e4ba84cf9b0444a41f0a163de0a58a6ac378a..39b1d8eaa1456f60af07de2e30f0653f9d5efd64 100644 (file)
@@ -9,7 +9,7 @@ git-show-index - Show packed archive index
 SYNOPSIS
 --------
 [verse]
-'git show-index'
+'git show-index' [--object-format=<hash-algorithm>]
 
 
 DESCRIPTION
@@ -36,6 +36,15 @@ Note that you can get more information on a packfile by calling
 linkgit:git-verify-pack[1]. However, as this command considers only the
 index file itself, it's both faster and more flexible.
 
+OPTIONS
+-------
+
+--object-format=<hash-algorithm>::
+       Specify the given object format (hash algorithm) for the index file.  The
+       valid values are 'sha1' and (if enabled) 'sha256'.  The default is the
+       algorithm for the current repository (set by `extensions.objectFormat`), or
+       'sha1' if no value is set or outside a repository..
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index c9ed2bf3d5c5681e26cd408125f489f358294a7c..7e5f995f77e48cdc8e9c1b6b58dec8f2896b32cf 100644 (file)
@@ -183,7 +183,7 @@ set-branch (-d|--default) [--] <path>::
        Sets the default remote tracking branch for the submodule. The
        `--branch` option allows the remote branch to be specified. The
        `--default` option removes the submodule.<name>.branch configuration
-       key, which causes the tracking branch to default to 'master'.
+       key, which causes the tracking branch to default to the remote 'HEAD'.
 
 set-url [--] <path> <newurl>::
        Sets the URL of the specified submodule to <newurl>. Then, it will
@@ -284,7 +284,7 @@ OPTIONS
        `.gitmodules` for `update --remote`.  A special value of `.` is used to
        indicate that the name of the branch in the submodule should be the
        same name as the current branch in the current repository.  If the
-       option is not specified, it defaults to 'master'.
+       option is not specified, it defaults to the remote 'HEAD'.
 
 -f::
 --force::
@@ -322,10 +322,10 @@ OPTIONS
        the superproject's recorded SHA-1 to update the submodule, use the
        status of the submodule's remote-tracking branch.  The remote used
        is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
-       The remote branch used defaults to `master`, but the branch name may
-       be overridden by setting the `submodule.<name>.branch` option in
-       either `.gitmodules` or `.git/config` (with `.git/config` taking
-       precedence).
+       The remote branch used defaults to the remote `HEAD`, but the branch
+       name may be overridden by setting the `submodule.<name>.branch`
+       option in either `.gitmodules` or `.git/config` (with `.git/config`
+       taking precedence).
 +
 This works for any of the supported update procedures (`--checkout`,
 `--rebase`, etc.).  The only change is the source of the target SHA-1.
index 1bd919f92bdd053cdfde7678ae6528f91513bc45..faba2ef0881c52e8c6c2e5ec0f5702c0b1ba5028 100644 (file)
@@ -278,13 +278,13 @@ $ git am -3 -i -s ./+to-apply <4>
 $ compile/test
 $ git switch -c hold/linus && git am -3 -i -s ./+hold-linus <5>
 $ git switch topic/one && git rebase master <6>
-$ git switch -C pu next <7>
+$ git switch -C seen next <7>
 $ git merge topic/one topic/two && git merge hold/linus <8>
 $ git switch maint
 $ git cherry-pick master~4 <9>
 $ compile/test
 $ git tag -s -m "GIT 0.99.9x" v0.99.9x <10>
-$ git fetch ko && for branch in master maint next pu <11>
+$ git fetch ko && for branch in master maint next seen <11>
     do
        git show-branch ko/$branch $branch <12>
     done
@@ -294,14 +294,14 @@ $ git push --follow-tags ko <13>
 <1> see what you were in the middle of doing, if anything.
 <2> see which branches haven't been merged into `master` yet.
 Likewise for any other integration branches e.g. `maint`, `next`
-and `pu` (potential updates).
+and `seen`.
 <3> read mails, save ones that are applicable, and save others
 that are not quite ready (other mail readers are available).
 <4> apply them, interactively, with your sign-offs.
 <5> create topic branch as needed and apply, again with sign-offs.
 <6> rebase internal topic branch that has not been merged to the
 master or exposed as a part of a stable branch.
-<7> restart `pu` every time from the next.
+<7> restart `seen` every time from the next.
 <8> and bundle topic branches still cooking.
 <9> backport a critical fix.
 <10> create a signed tag.
@@ -323,7 +323,7 @@ repository at kernel.org, and looks like this:
        fetch = refs/heads/*:refs/remotes/ko/*
        push = refs/heads/master
        push = refs/heads/next
-       push = +refs/heads/pu
+       push = +refs/heads/seen
        push = refs/heads/maint
 ------------
 
index 81f2a87e88ba5fee51419b615a60352a8dd3c999..642471109f70c202ce214b4b3dd2b3fd7aa98c69 100644 (file)
@@ -404,6 +404,35 @@ 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.
 
+ref-transaction
+~~~~~~~~~~~~~~~
+
+This hook is invoked by any Git command that performs reference
+updates. It executes whenever a reference transaction is prepared,
+committed or aborted and may thus get called multiple times.
+
+The hook takes exactly one argument, which is the current state the
+given reference transaction is in:
+
+    - "prepared": All reference updates have been queued to the
+      transaction and references were locked on disk.
+
+    - "committed": The reference transaction was committed and all
+      references now have their respective new value.
+
+    - "aborted": The reference transaction was aborted, no changes
+      were performed and the locks have been released.
+
+For each reference update that was added to the transaction, the hook
+receives on standard input a line of the format:
+
+  <old-value> SP <new-value> SP <ref-name> LF
+
+The exit status of the hook is ignored for any state except for the
+"prepared" state. In the "prepared" state, a non-zero exit status will
+cause the transaction to be aborted. The hook will not be called with
+"aborted" state in that case.
+
 push-to-checkout
 ~~~~~~~~~~~~~~~~
 
index 67275fd187f0f8f60f608e17334da12b6272394f..539b4e1997e62c741ba4cd68ab28fcab534380ec 100644 (file)
@@ -49,9 +49,9 @@ submodule.<name>.update::
 
 submodule.<name>.branch::
        A remote branch name for tracking updates in the upstream submodule.
-       If the option is not specified, it defaults to 'master'.  A special
-       value of `.` is used to indicate that the name of the branch in the
-       submodule should be the same name as the current branch in the
+       If the option is not specified, it defaults to the remote 'HEAD'.
+       A special value of `.` is used to indicate that the name of the branch
+       in the submodule should be the same name as the current branch in the
        current repository.  See the `--remote` documentation in
        linkgit:git-submodule[1] for details.
 
index 93baeeb0295824ca90bf3ba81635e3d0b4470eb1..6f1e269ae43e00d631feb8798a2a95aef48e8287 100644 (file)
@@ -238,6 +238,9 @@ the remote repository.
        `--signed-tags=verbatim` to linkgit:git-fast-export[1].  In the
        absence of this capability, Git will use `--signed-tags=warn-strip`.
 
+'object-format'::
+       This indicates that the helper is able to interact with the remote
+       side using an explicit hash algorithm extension.
 
 
 COMMANDS
@@ -257,12 +260,14 @@ Support for this command is mandatory.
 'list'::
        Lists the refs, one per line, in the format "<value> <name>
        [<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
-       a symref, or "?" to indicate that the helper could not get the
-       value of the ref. A space-separated list of attributes follows
-       the name; unrecognized attributes are ignored. The list ends
-       with a blank line.
+       a symref, ":<keyword> <value>" for a key-value pair, or
+       "?" to indicate that the helper could not get the value of the
+       ref. A space-separated list of attributes follows the name;
+       unrecognized attributes are ignored. The list ends with a
+       blank line.
 +
 See REF LIST ATTRIBUTES for a list of currently defined attributes.
+See REF LIST KEYWORDS for a list of currently defined keywords.
 +
 Supported if the helper has the "fetch" or "import" capability.
 
@@ -432,6 +437,18 @@ attributes are defined.
        This ref is unchanged since the last import or fetch, although
        the helper cannot necessarily determine what value that produced.
 
+REF LIST KEYWORDS
+-----------------
+
+The 'list' command may produce a list of key-value pairs.
+The following keys are defined.
+
+'object-format'::
+       The refs are using the given hash algorithm.  This keyword is only
+       used if the server and client both support the object-format
+       extension.
+
+
 OPTIONS
 -------
 
@@ -516,6 +533,14 @@ set by Git if the remote helper has the 'option' capability.
        transaction.  If successful, all refs will be updated, or none will.  If the
        remote side does not support this capability, the push will fail.
 
+'option object-format' {'true'|algorithm}::
+       If 'true', indicate that the caller wants hash algorithm information
+       to be passed back from the remote.  This mode is used when fetching
+       refs.
++
+If set to an algorithm, indicate that the caller wants to interact with
+the remote side using that algorithm.
+
 SEE ALSO
 --------
 linkgit:git-remote[1]
index abc0dc6bc79bfaf088202114ecee1dbe1f704dc9..2db7ba78424ead3b35d7df33bfcbdab63ec0a83a 100644 (file)
@@ -85,15 +85,15 @@ As a given feature goes from experimental to stable, it also
 
 There is a fourth official branch that is used slightly differently:
 
-* 'pu' (proposed updates) is an integration branch for things that are
-  not quite ready for inclusion yet (see "Integration Branches"
-  below).
+* 'seen' (patches seen by the maintainer) is an integration branch for
+  things that are not quite ready for inclusion yet (see "Integration
+  Branches" below).
 
 Each of the four branches is usually a direct descendant of the one
 above it.
 
 Conceptually, the feature enters at an unstable branch (usually 'next'
-or 'pu'), and "graduates" to 'master' for the next release once it is
+or 'seen'), and "graduates" to 'master' for the next release once it is
 considered stable enough.
 
 
@@ -207,7 +207,7 @@ If you make it (very) clear that this branch is going to be deleted
 right after the testing, you can even publish this branch, for example
 to give the testers a chance to work with it, or other developers a
 chance to see if their in-progress work will be compatible.  `git.git`
-has such an official throw-away integration branch called 'pu'.
+has such an official throw-away integration branch called 'seen'.
 
 
 Branch management for a release
@@ -291,7 +291,7 @@ This will not happen if the content of the branches was verified as
 described in the previous section.
 
 
-Branch management for next and pu after a feature release
+Branch management for next and seen after a feature release
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 After a feature release, the integration branch 'next' may optionally be
@@ -319,8 +319,8 @@ so.
 If you do this, then you should make a public announcement indicating
 that 'next' was rewound and rebuilt.
 
-The same rewind and rebuild process may be followed for 'pu'. A public
-announcement is not necessary since 'pu' is a throw-away branch, as
+The same rewind and rebuild process may be followed for 'seen'. A public
+announcement is not necessary since 'seen' is a throw-away branch, as
 described above.
 
 
index 73be8b49f8495a04dbbba0813638abefe4c6b2b0..a67130debb63dc99cbd860fd7b31fb187b1f9571 100644 (file)
@@ -66,7 +66,7 @@ this mailing list after each feature release is made.
    demonstrated to be regression free.  New changes are tested
    in 'next' before merged to 'master'.
 
- - 'pu' branch is used to publish other proposed changes that do
+ - 'seen' branch is used to publish other proposed changes that do
    not yet pass the criteria set for 'next'.
 
  - The tips of 'master' and 'maint' branches will not be rewound to
@@ -76,7 +76,7 @@ this mailing list after each feature release is made.
    of the cycle.
 
  - Usually 'master' contains all of 'maint' and 'next' contains all
-   of 'master'.  'pu' contains all the topics merged to 'next', but
+   of 'master'.  'seen' contains all the topics merged to 'next', but
    is rebuilt directly on 'master'.
 
  - The tip of 'master' is meant to be more stable than any
@@ -229,12 +229,12 @@ by doing the following:
    series?)
 
  - Prepare 'jch' branch, which is used to represent somewhere
-   between 'master' and 'pu' and often is slightly ahead of 'next'.
+   between 'master' and 'seen' and often is slightly ahead of 'next'.
 
-     $ Meta/Reintegrate master..pu >Meta/redo-jch.sh
+     $ Meta/Reintegrate master..seen >Meta/redo-jch.sh
 
    The result is a script that lists topics to be merged in order to
-   rebuild 'pu' as the input to Meta/Reintegrate script.  Remove
+   rebuild 'seen' as the input to Meta/Reintegrate script.  Remove
    later topics that should not be in 'jch' yet.  Add a line that
    consists of '### match next' before the name of the first topic
    in the output that should be in 'jch' but not in 'next' yet.
@@ -291,29 +291,29 @@ by doing the following:
    merged to 'master'.  This may lose '### match next' marker;
    add it again to the appropriate place when it happens.
 
- - Rebuild 'pu'.
+ - Rebuild 'seen'.
 
-     $ Meta/Reintegrate master..pu >Meta/redo-pu.sh
+     $ Meta/Reintegrate master..seen >Meta/redo-seen.sh
 
-   Edit the result by adding new topics that are not still in 'pu'
+   Edit the result by adding new topics that are not still in 'seen'
    in the script.  Then
 
-     $ git checkout -B pu jch
-     $ sh Meta/redo-pu.sh
+     $ git checkout -B seen jch
+     $ sh Meta/redo-seen.sh
 
-   When all is well, clean up the redo-pu.sh script with
+   When all is well, clean up the redo-seen.sh script with
 
-     $ sh Meta/redo-pu.sh -u
+     $ sh Meta/redo-seen.sh -u
 
    Double check by running
 
-     $ git branch --no-merged pu
+     $ git branch --no-merged seen
 
    to see there is no unexpected leftover topics.
 
    At this point, build-test the result for semantic conflicts, and
    if there are, prepare an appropriate merge-fix first (see
-   appendix), and rebuild the 'pu' branch from scratch, starting at
+   appendix), and rebuild the 'seen' branch from scratch, starting at
    the tip of 'jch'.
 
  - Update "What's cooking" message to review the updates to
@@ -323,14 +323,14 @@ by doing the following:
 
      $ Meta/cook
 
-   This script inspects the history between master..pu, finds tips
+   This script inspects the history between master..seen, finds tips
    of topic branches, compares what it found with the current
    contents in Meta/whats-cooking.txt, and updates that file.
-   Topics not listed in the file but are found in master..pu are
+   Topics not listed in the file but are found in master..seen are
    added to the "New topics" section, topics listed in the file that
-   are no longer found in master..pu are moved to the "Graduated to
+   are no longer found in master..seen are moved to the "Graduated to
    master" section, and topics whose commits changed their states
-   (e.g. used to be only in 'pu', now merged to 'next') are updated
+   (e.g. used to be only in 'seen', now merged to 'next') are updated
    with change markers "<<" and ">>".
 
    Look for lines enclosed in "<<" and ">>"; they hold contents from
@@ -360,7 +360,7 @@ Observations
 Some observations to be made.
 
  * Each topic is tested individually, and also together with other
-   topics cooking first in 'pu', then in 'jch' and then in 'next'.
+   topics cooking first in 'seen', then in 'jch' and then in 'next'.
    Until it matures, no part of it is merged to 'master'.
 
  * A topic already in 'next' can get fixes while still in
@@ -411,7 +411,7 @@ new use of the variable under its old name. When these two topics
 are merged together, the reference to the variable newly added by
 the latter topic will still use the old name in the result.
 
-The Meta/Reintegrate script that is used by redo-jch and redo-pu
+The Meta/Reintegrate script that is used by redo-jch and redo-seen
 scripts implements a crude but usable way to work this issue around.
 When the script merges branch $X, it checks if "refs/merge-fix/$X"
 exists, and if so, the effect of it is squashed into the result of
@@ -431,14 +431,14 @@ commit that can be squashed into a result of mechanical merge to
 correct semantic conflicts.
 
 After finding that the result of merging branch "ai/topic" to an
-integration branch had such a semantic conflict, say pu~4, check the
+integration branch had such a semantic conflict, say seen~4, check the
 problematic merge out on a detached HEAD, edit the working tree to
 fix the semantic conflict, and make a separate commit to record the
 fix-up:
 
-     $ git checkout pu~4
+     $ git checkout seen~4
      $ git show -s --pretty=%s ;# double check
-     Merge branch 'ai/topic' to pu
+     Merge branch 'ai/topic' to seen
      $ edit
      $ git commit -m 'merge-fix/ai/topic' -a
 
@@ -450,9 +450,9 @@ result:
 Then double check the result by asking Meta/Reintegrate to redo the
 merge:
 
-     $ git checkout pu~5 ;# the parent of the problem merge
+     $ git checkout seen~5 ;# the parent of the problem merge
      $ echo ai/topic | Meta/Reintegrate
-     $ git diff pu~4
+     $ git diff seen~4
 
 This time, because you prepared refs/merge-fix/ai/topic, the
 resulting merge should have been tweaked to include the fix for the
@@ -464,7 +464,7 @@ branch needs this merge-fix is because another branch merged earlier
 to the integration branch changed the underlying assumption ai/topic
 branch made (e.g. ai/topic branch added a site to refer to a
 variable, while the other branch renamed that variable and adjusted
-existing use sites), and if you changed redo-jch (or redo-pu) script
+existing use sites), and if you changed redo-jch (or redo-seen) script
 to merge ai/topic branch before the other branch, then the above
 merge-fix should not be applied while merging ai/topic, but should
 instead be applied while merging the other branch.  You would need
index 02cb5f758d6f65c61e216c89fa758f7345526f96..f2e10a7ec88664be4c31db7ae9770281db343a74 100644 (file)
@@ -4,7 +4,7 @@ Cc:     Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org>
 Subject: Re: sending changesets from the middle of a git tree
 Date:  Sun, 14 Aug 2005 18:37:39 -0700
 Abstract: In this article, JC talks about how he rebases the
- public "pu" branch using the core Git tools when he updates
+ public "seen" branch using the core Git tools when he updates
  the "master" branch, and how "rebase" works.  Also discussed
  is how this applies to individual developers who sends patches
  upstream.
@@ -20,8 +20,8 @@ Petr Baudis <pasky@suse.cz> writes:
 > where Junio C Hamano <junkio@cox.net> told me that...
 >> Linus Torvalds <torvalds@osdl.org> writes:
 >>
->> > Junio, maybe you want to talk about how you move patches from your "pu"
->> > branch to the real branches.
+>> > Junio, maybe you want to talk about how you move patches from your
+>> > "seen" branch to the real branches.
 >>
 > Actually, wouldn't this be also precisely for what StGIT is intended to?
 --------------------------------------
@@ -33,12 +33,12 @@ the kind of task StGIT is designed to do.
 I just have done a simpler one, this time using only the core
 Git tools.
 
-I had a handful of commits that were ahead of master in pu, and I
+I had a handful of commits that were ahead of master in 'seen', and I
 wanted to add some documentation bypassing my usual habit of
-placing new things in pu first.  At the beginning, the commit
+placing new things in 'seen' first.  At the beginning, the commit
 ancestry graph looked like this:
 
-                             *"pu" head
+                            *"seen" head
     master --> #1 --> #2 --> #3
 
 So I started from master, made a bunch of edits, and committed:
@@ -50,7 +50,7 @@ So I started from master, made a bunch of edits, and committed:
 
 After the commit, the ancestry graph would look like this:
 
-                              *"pu" head
+                             *"seen" head
     master^ --> #1 --> #2 --> #3
           \
             \---> master
@@ -58,31 +58,31 @@ After the commit, the ancestry graph would look like this:
 The old master is now master^ (the first parent of the master).
 The new master commit holds my documentation updates.
 
-Now I have to deal with "pu" branch.
+Now I have to deal with "seen" branch.
 
 This is the kind of situation I used to have all the time when
 Linus was the maintainer and I was a contributor, when you look
-at "master" branch being the "maintainer" branch, and "pu"
+at "master" branch being the "maintainer" branch, and "seen"
 branch being the "contributor" branch.  Your work started at the
 tip of the "maintainer" branch some time ago, you made a lot of
 progress in the meantime, and now the maintainer branch has some
 other commits you do not have yet.  And "git rebase" was written
 with the explicit purpose of helping to maintain branches like
-"pu".  You _could_ merge master to pu and keep going, but if you
+"seen".  You _could_ merge master to 'seen' and keep going, but if you
 eventually want to cherrypick and merge some but not necessarily
 all changes back to the master branch, it often makes later
 operations for _you_ easier if you rebase (i.e. carry forward
-your changes) "pu" rather than merge.  So I ran "git rebase":
+your changes) "seen" rather than merge.  So I ran "git rebase":
 
-    $ git checkout pu
-    $ git rebase master pu
+    $ git checkout seen
+    $ git rebase master seen
 
 What this does is to pick all the commits since the current
-branch (note that I now am on "pu" branch) forked from the
+branch (note that I now am on "seen" branch) forked from the
 master branch, and forward port these changes.
 
     master^ --> #1 --> #2 --> #3
-          \                                  *"pu" head
+         \                                  *"seen" head
             \---> master --> #1' --> #2' --> #3'
 
 The diff between master^ and #1 is applied to master and
@@ -92,7 +92,7 @@ commits are made similarly out of #2 and #3 commits.
 
 Old #3 is not recorded in any of the .git/refs/heads/ file
 anymore, so after doing this you will have dangling commit if
-you ran fsck-cache, which is normal.  After testing "pu", you
+you ran fsck-cache, which is normal.  After testing "seen", you
 can run "git prune" to get rid of those original three commits.
 
 While I am talking about "git rebase", I should talk about how
index 149508e13bdacf70488b1a7049bf6aef502c36e3..a3e5595a569a91b7f15d001aee756c82b3c8008d 100644 (file)
@@ -15,7 +15,7 @@ One of the changes I pulled into the 'master' branch turns out to
 break building Git with GCC 2.95.  While they were well-intentioned
 portability fixes, keeping things working with gcc-2.95 was also
 important.  Here is what I did to revert the change in the 'master'
-branch and to adjust the 'pu' branch, using core Git tools and
+branch and to adjust the 'seen' branch, using core Git tools and
 barebone Porcelain.
 
 First, prepare a throw-away branch in case I screw things up.
@@ -104,11 +104,11 @@ $ git diff master..revert-c99
 
 says nothing.
 
-Then we rebase the 'pu' branch as usual.
+Then we rebase the 'seen' branch as usual.
 
 ------------------------------------------------
-$ git checkout pu
-$ git tag pu-anchor pu
+$ git checkout seen
+$ git tag seen-anchor seen
 $ git rebase master
 * Applying: Redo "revert" using three-way merge machinery.
 First trying simple merge strategy to cherry-pick.
@@ -127,11 +127,11 @@ First trying simple merge strategy to cherry-pick.
 First trying simple merge strategy to cherry-pick.
 ------------------------------------------------
 
-The temporary tag 'pu-anchor' is me just being careful, in case 'git
+The temporary tag 'seen-anchor' is me just being careful, in case 'git
 rebase' screws up.  After this, I can do these for sanity check:
 
 ------------------------------------------------
-$ git diff pu-anchor..pu ;# make sure we got the master fix.
+$ git diff seen-anchor..seen ;# make sure we got the master fix.
 $ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
 $ make clean test ;# make sure it did not cause other breakage.
 ------------------------------------------------
@@ -140,7 +140,7 @@ Everything is in the good order.  I do not need the temporary branch
 or tag anymore, so remove them:
 
 ------------------------------------------------
-$ rm -f .git/refs/tags/pu-anchor
+$ rm -f .git/refs/tags/seen-anchor
 $ git branch -d revert-c99
 ------------------------------------------------
 
@@ -168,18 +168,18 @@ Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
 And the final repository status looks like this:
 
 ------------------------------------------------
-$ git show-branch --more=1 master pu rc
+$ git show-branch --more=1 master seen rc
 ! [master] Revert "Replace zero-length array decls with []."
- ! [pu] git-repack: Add option to repack all objects.
+ ! [seen] git-repack: Add option to repack all objects.
   * [rc] Merge refs/heads/master from .
 ---
- +  [pu] git-repack: Add option to repack all objects.
- +  [pu~1] More documentation updates.
- +  [pu~2] Show commits in topo order and name all commits.
- +  [pu~3] mailinfo and applymbox updates
- +  [pu~4] Document "git cherry-pick" and "git revert"
- +  [pu~5] Remove git-apply-patch-script.
- +  [pu~6] Redo "revert" using three-way merge machinery.
+ +  [seen] git-repack: Add option to repack all objects.
+ +  [seen~1] More documentation updates.
+ +  [seen~2] Show commits in topo order and name all commits.
+ +  [seen~3] mailinfo and applymbox updates
+ +  [seen~4] Document "git cherry-pick" and "git revert"
+ +  [seen~5] Remove git-apply-patch-script.
+ +  [seen~6] Redo "revert" using three-way merge machinery.
   - [rc] Merge refs/heads/master from .
 ++* [master] Revert "Replace zero-length array decls with []."
   - [rc~1] Merge refs/heads/master from .
index 89821ec74fe1d71764bcb320d1ac1021bd06201f..151ee84cebcef3ca549f3150e69e91b29cc2f372 100644 (file)
@@ -179,7 +179,7 @@ allowed-groups, to describe which heads can be pushed into by
 whom.  The format of each file would look like this:
 
     refs/heads/master   junio
-    +refs/heads/pu      junio
+    +refs/heads/seen    junio
     refs/heads/cogito$  pasky
     refs/heads/bw/.*    linus
     refs/heads/tmp/.*   .*
@@ -187,6 +187,6 @@ whom.  The format of each file would look like this:
 
 With this, Linus can push or create "bw/penguin" or "bw/zebra"
 or "bw/panda" branches, Pasky can do only "cogito", and JC can
-do master and pu branches and make versioned tags.  And anybody
-can do tmp/blah branches. The '+' sign at the pu record means
+do master and "seen" branches and make versioned tags.  And anybody
+can do tmp/blah branches. The '+' sign at the "seen" record means
 that JC can make non-fast-forward pushes on it.
index 547a55246302f91d6673db79228e08c6de95a286..84bbc7439a601b2e18a7ea48af9cfcdd62353e64 100644 (file)
@@ -196,8 +196,8 @@ The placeholders are:
 '%ce':: committer email
 '%cE':: committer email (respecting .mailmap, see
        linkgit:git-shortlog[1] or linkgit:git-blame[1])
-'%cl':: author email local-part (the part before the '@' sign)
-'%cL':: author local-part (see '%cl') respecting .mailmap, see
+'%cl':: committer email local-part (the part before the '@' sign)
+'%cL':: committer local-part (see '%cl') respecting .mailmap, see
        linkgit:git-shortlog[1] or linkgit:git-blame[1])
 '%cd':: committer date (format respects --date= option)
 '%cD':: committer date, RFC2822 style
index 2b267c0da6b2d88c8ab9425745b7239e3f867b6e..36ccd14f97ed4631078fbac5cf65940840d3e197 100644 (file)
@@ -176,6 +176,21 @@ agent strings are purely informative for statistics and debugging
 purposes, and MUST NOT be used to programmatically assume the presence
 or absence of particular features.
 
+object-format
+-------------
+
+This capability, which takes a hash algorithm as an argument, indicates
+that the server supports the given hash algorithms.  It may be sent
+multiple times; if so, the first one given is the one used in the ref
+advertisement.
+
+When provided by the client, this indicates that it intends to use the
+given hash algorithm to communicate.  The algorithm provided must be one
+that the server supports.
+
+If this capability is not provided, it is assumed that the only
+supported algorithm is SHA-1.
+
 symref
 ------
 
index 5852f499a64f831ab8fb9dce6681db44606e958c..e597b74da39d82b4b6bff621dda10b27d72da5d0 100644 (file)
@@ -483,3 +483,12 @@ included in a request.  This is done by sending each option as a
 a request.
 
 The provided options must not contain a NUL or LF character.
+
+ object-format
+~~~~~~~~~~~~~~~
+
+The server can advertise the `object-format` capability with a value `X` (in the
+form `object-format=X`) to notify the client that the server is able to deal
+with objects using hash algorithm X.  If not specified, the server is assumed to
+only handle SHA-1.  If the client would like to use a hash algorithm other than
+SHA-1, it should specify its object-format string.
index 833652983fa64080dfb1319181b2d676b2b93660..fd480b864526dbe33762358a68046d79ecdb0883 100644 (file)
@@ -347,7 +347,7 @@ $ git branch -r
   origin/man
   origin/master
   origin/next
-  origin/pu
+  origin/seen
   origin/todo
 ------------------------------------------------
 
diff --git a/alloc.c b/alloc.c
index 1c64c4dd1629c63a8bb2fff6e580ee0c648a0730..957a0af3626432b0c9c2dd1301f20c4ff339a0a4 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -99,23 +99,27 @@ void *alloc_object_node(struct repository *r)
        return obj;
 }
 
-static unsigned int alloc_commit_index(struct repository *r)
+/*
+ * The returned count is to be used as an index into commit slabs,
+ * that are *NOT* maintained per repository, and that is why a single
+ * global counter is used.
+ */
+static unsigned int alloc_commit_index(void)
 {
-       return r->parsed_objects->commit_count++;
+       static unsigned int parsed_commits_count;
+       return parsed_commits_count++;
 }
 
-void init_commit_node(struct repository *r, struct commit *c)
+void init_commit_node(struct commit *c)
 {
        c->object.type = OBJ_COMMIT;
-       c->index = alloc_commit_index(r);
-       c->graph_pos = COMMIT_NOT_FROM_GRAPH;
-       c->generation = GENERATION_NUMBER_INFINITY;
+       c->index = alloc_commit_index();
 }
 
 void *alloc_commit_node(struct repository *r)
 {
        struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
-       init_commit_node(r, c);
+       init_commit_node(c);
        return c;
 }
 
diff --git a/alloc.h b/alloc.h
index ed1071c11ea3a6d0f7d55da46df4acf524a32565..371d388b552fb01824b4ec208abe7fdf11d95eec 100644 (file)
--- a/alloc.h
+++ b/alloc.h
@@ -9,7 +9,7 @@ struct repository;
 
 void *alloc_blob_node(struct repository *r);
 void *alloc_tree_node(struct repository *r);
-void init_commit_node(struct repository *r, struct commit *c);
+void init_commit_node(struct commit *c);
 void *alloc_commit_node(struct repository *r);
 void *alloc_tag_node(struct repository *r);
 void *alloc_object_node(struct repository *r);
diff --git a/blame.c b/blame.c
index da7e28800e7eb8c13b1200ed6207d2fe077ae66f..82fa16d6585b90e3635d87f6adc1e4856524f7d6 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -1272,7 +1272,7 @@ static int maybe_changed_path(struct repository *r,
        if (!bd)
                return 1;
 
-       if (origin->commit->generation == GENERATION_NUMBER_INFINITY)
+       if (commit_graph_generation(origin->commit) == GENERATION_NUMBER_INFINITY)
                return 1;
 
        filter = get_bloom_filter(r, origin->commit, 0);
diff --git a/blob.c b/blob.c
index 36f9abda19ec1095a903aa138bdf53ce18a86b10..182718aba9fe320f1064a12fb5baf1969f563b29 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -10,7 +10,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
        struct object *obj = lookup_object(r, oid);
        if (!obj)
                return create_object(r, oid, alloc_blob_node(r));
-       return object_as_type(r, obj, OBJ_BLOB, 0);
+       return object_as_type(obj, OBJ_BLOB, 0);
 }
 
 int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
diff --git a/bloom.c b/bloom.c
index 6c7611847ad05cb95103177ca00e7824f42b63c1..6a7f2f2bdc13031f2861a5cd8c8417bafaed503f 100644 (file)
--- a/bloom.c
+++ b/bloom.c
@@ -33,15 +33,16 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
                                        struct commit *c)
 {
        uint32_t lex_pos, start_index, end_index;
+       uint32_t graph_pos = commit_graph_position(c);
 
-       while (c->graph_pos < g->num_commits_in_base)
+       while (graph_pos < g->num_commits_in_base)
                g = g->base_graph;
 
        /* The commit graph commit 'c' lives in doesn't carry bloom filters. */
        if (!g->chunk_bloom_indexes)
                return 0;
 
-       lex_pos = c->graph_pos - g->num_commits_in_base;
+       lex_pos = graph_pos - g->num_commits_in_base;
 
        end_index = get_be32(g->chunk_bloom_indexes + 4 * lex_pos);
 
@@ -193,7 +194,7 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
 
        if (!filter->data) {
                load_commit_graph_info(r, c);
-               if (c->graph_pos != COMMIT_NOT_FROM_GRAPH &&
+               if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH &&
                        r->objects->commit_graph->chunk_bloom_indexes) {
                        if (load_bloom_filter_from_graph(r->objects->commit_graph, filter, c))
                                return filter;
index 2d9e7675a6ed24bd70165a78386ad5a6589a3b50..7095f7805869811c07aa25d9fbfd9c68ddc7d08d 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -370,7 +370,7 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref,
                                      const char *logmsg)
 {
        int ret = 0;
-       struct worktree **worktrees = get_worktrees(0);
+       struct worktree **worktrees = get_worktrees();
        int i;
 
        for (i = 0; worktrees[i]; i++) {
index 99633ad004dca39cdfee5dce3ff3a668c7e75ad9..e82301fb1bc03b31e18d83f7fc6d4dcfe6986742 100644 (file)
@@ -468,7 +468,7 @@ static void print_current_branch_name(void)
 
 static void reject_rebase_or_bisect_branch(const char *target)
 {
-       struct worktree **worktrees = get_worktrees(0);
+       struct worktree **worktrees = get_worktrees();
        int i;
 
        for (i = 0; worktrees[i]; i++) {
index ae18e20a7c96fd1b20660ba9aa1079bcebe8d2af..5ebf13359e839ac71c3afccd17340e9e970b32a3 100644 (file)
@@ -596,7 +596,7 @@ static int batch_objects(struct batch_options *opt)
 
 static const char * const cat_file_usage[] = {
        N_("git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -p | <type> | --textconv | --filters) [--path=<path>] <object>"),
-       N_("git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv | --filters]"),
+       N_("git cat-file (--batch[=<format>] | --batch-check[=<format>]) [--follow-symlinks] [--textconv | --filters]"),
        NULL
 };
 
index 2a8e3aaaed367cc094d8277bd2d1aa6ccb9210c4..bef70745c09a260442685eef111c9914b4a78d0a 100644 (file)
@@ -1111,7 +1111,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                }
        }
 
-       init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
+       init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
+               INIT_DB_QUIET);
 
        if (real_git_dir)
                git_dir = real_git_dir;
@@ -1220,6 +1221,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        refs = transport_get_remote_refs(transport, &ref_prefixes);
 
        if (refs) {
+               int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+
+               /*
+                * Now that we know what algorithm the remote side is using,
+                * let's set ours to the same thing.
+                */
+               initialize_repository_version(hash_algo);
+               repo_set_hash_algo(the_repository, hash_algo);
+
                mapped_refs = wanted_peer_refs(refs, &remote->fetch);
                /*
                 * transport_get_remote_refs() may return refs with null sha-1
@@ -1266,9 +1276,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                remote_head_points_at = NULL;
                remote_head = NULL;
                option_no_checkout = 1;
-               if (!option_bare)
-                       install_branch_config(0, "master", option_origin,
-                                             "refs/heads/master");
+               if (!option_bare) {
+                       const char *branch = git_default_branch_name();
+                       char *ref = xstrfmt("refs/heads/%s", branch);
+
+                       install_branch_config(0, branch, option_origin, ref);
+                       free(ref);
+               }
        }
 
        write_refspec_config(src_ref_prefix, our_head_points_at,
index 75455da138d5f6efae26eb5d5280050aa351dee3..f6797e2a9fb3210192dc65a044b084458ab632d6 100644 (file)
@@ -154,7 +154,7 @@ static int read_one_commit(struct oidset *commits, struct progress *progress,
                           NULL, 0);
        if (!result)
                return error(_("invalid object: %s"), hash);
-       else if (object_as_type(the_repository, result, OBJ_COMMIT, 1))
+       else if (object_as_type(result, OBJ_COMMIT, 1))
                oidset_insert(commits, &result->oid);
 
        display_progress(progress, oidset_size(commits));
index ee4aef6a3555765a9ed74263d68c765ba8431f85..5e39f6188542bb28cd859e52b883d13fcbd281fe 100644 (file)
@@ -672,7 +672,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                given_config_source.file = git_pathdup("config");
                given_config_source.scope = CONFIG_SCOPE_LOCAL;
        } else if (use_worktree_config) {
-               struct worktree **worktrees = get_worktrees(0);
+               struct worktree **worktrees = get_worktrees();
                if (repository_format_worktree_config)
                        given_config_source.file = git_pathdup("config.worktree");
                else if (worktrees[0] && worktrees[1])
index 85868162eec9b0080ab30e7b1b8de1560c5ce5f2..9f37895d4cf2ecb01c62e490be7a100ce5256398 100644 (file)
@@ -45,6 +45,7 @@ static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
 static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
 static struct refspec refspecs = REFSPEC_INIT_FETCH;
 static int anonymize;
+static struct hashmap anonymized_seeds;
 static struct revision_sources revision_sources;
 
 static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -119,25 +120,34 @@ static int has_unshown_parent(struct commit *commit)
 }
 
 struct anonymized_entry {
+       struct hashmap_entry hash;
+       const char *anon;
+       const char orig[FLEX_ARRAY];
+};
+
+struct anonymized_entry_key {
        struct hashmap_entry hash;
        const char *orig;
        size_t orig_len;
-       const char *anon;
-       size_t anon_len;
 };
 
 static int anonymized_entry_cmp(const void *unused_cmp_data,
                                const struct hashmap_entry *eptr,
                                const struct hashmap_entry *entry_or_key,
-                               const void *unused_keydata)
+                               const void *keydata)
 {
        const struct anonymized_entry *a, *b;
 
        a = container_of(eptr, const struct anonymized_entry, hash);
-       b = container_of(entry_or_key, const struct anonymized_entry, hash);
+       if (keydata) {
+               const struct anonymized_entry_key *key = keydata;
+               int equal = !strncmp(a->orig, key->orig, key->orig_len) &&
+                           !a->orig[key->orig_len];
+               return !equal;
+       }
 
-       return a->orig_len != b->orig_len ||
-               memcmp(a->orig, b->orig, a->orig_len);
+       b = container_of(entry_or_key, const struct anonymized_entry, hash);
+       return strcmp(a->orig, b->orig);
 }
 
 /*
@@ -145,31 +155,39 @@ static int anonymized_entry_cmp(const void *unused_cmp_data,
  * the same anonymized string with another. The actual generation
  * is farmed out to the generate function.
  */
-static const void *anonymize_mem(struct hashmap *map,
-                                void *(*generate)(const void *, size_t *),
-                                const void *orig, size_t *len)
+static const char *anonymize_str(struct hashmap *map,
+                                char *(*generate)(void *),
+                                const char *orig, size_t len,
+                                void *data)
 {
-       struct anonymized_entry key, *ret;
+       struct anonymized_entry_key key;
+       struct anonymized_entry *ret;
 
        if (!map->cmpfn)
                hashmap_init(map, anonymized_entry_cmp, NULL, 0);
 
-       hashmap_entry_init(&key.hash, memhash(orig, *len));
+       hashmap_entry_init(&key.hash, memhash(orig, len));
        key.orig = orig;
-       key.orig_len = *len;
-       ret = hashmap_get_entry(map, &key, hash, NULL);
+       key.orig_len = len;
+
+       /* First check if it's a token the user configured manually... */
+       if (anonymized_seeds.cmpfn)
+               ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
+       else
+               ret = NULL;
+
+       /* ...otherwise check if we've already seen it in this context... */
+       if (!ret)
+               ret = hashmap_get_entry(map, &key, hash, &key);
 
+       /* ...and finally generate a new mapping if necessary */
        if (!ret) {
-               ret = xmalloc(sizeof(*ret));
+               FLEX_ALLOC_MEM(ret, orig, orig, len);
                hashmap_entry_init(&ret->hash, key.hash.hash);
-               ret->orig = xstrdup(orig);
-               ret->orig_len = *len;
-               ret->anon = generate(orig, len);
-               ret->anon_len = *len;
+               ret->anon = generate(data);
                hashmap_put(map, &ret->hash);
        }
 
-       *len = ret->anon_len;
        return ret->anon;
 }
 
@@ -181,13 +199,13 @@ static const void *anonymize_mem(struct hashmap *map,
  */
 static void anonymize_path(struct strbuf *out, const char *path,
                           struct hashmap *map,
-                          void *(*generate)(const void *, size_t *))
+                          char *(*generate)(void *))
 {
        while (*path) {
                const char *end_of_component = strchrnul(path, '/');
                size_t len = end_of_component - path;
-               const char *c = anonymize_mem(map, generate, path, &len);
-               strbuf_add(out, c, len);
+               const char *c = anonymize_str(map, generate, path, len, NULL);
+               strbuf_addstr(out, c);
                path = end_of_component;
                if (*path)
                        strbuf_addch(out, *path++);
@@ -361,12 +379,12 @@ static void print_path_1(const char *path)
                printf("%s", path);
 }
 
-static void *anonymize_path_component(const void *path, size_t *len)
+static char *anonymize_path_component(void *data)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
        strbuf_addf(&out, "path%d", counter++);
-       return strbuf_detach(&out, len);
+       return strbuf_detach(&out, NULL);
 }
 
 static void print_path(const char *path)
@@ -383,20 +401,23 @@ static void print_path(const char *path)
        }
 }
 
-static void *generate_fake_oid(const void *old, size_t *len)
+static char *generate_fake_oid(void *data)
 {
        static uint32_t counter = 1; /* avoid null oid */
        const unsigned hashsz = the_hash_algo->rawsz;
-       unsigned char *out = xcalloc(hashsz, 1);
+       unsigned char out[GIT_MAX_RAWSZ];
+       char *hex = xmallocz(GIT_MAX_HEXSZ);
+
+       hashclr(out);
        put_be32(out + hashsz - 4, counter++);
-       return out;
+       return hash_to_hex_algop_r(hex, out, the_hash_algo);
 }
 
-static const struct object_id *anonymize_oid(const struct object_id *oid)
+static const char *anonymize_oid(const char *oid_hex)
 {
        static struct hashmap objs;
-       size_t len = the_hash_algo->rawsz;
-       return anonymize_mem(&objs, generate_fake_oid, oid, &len);
+       size_t len = strlen(oid_hex);
+       return anonymize_str(&objs, generate_fake_oid, oid_hex, len, NULL);
 }
 
 static void show_filemodify(struct diff_queue_struct *q,
@@ -455,9 +476,9 @@ static void show_filemodify(struct diff_queue_struct *q,
                         */
                        if (no_data || S_ISGITLINK(spec->mode))
                                printf("M %06o %s ", spec->mode,
-                                      oid_to_hex(anonymize ?
-                                                 anonymize_oid(&spec->oid) :
-                                                 &spec->oid));
+                                      anonymize ?
+                                      anonymize_oid(oid_to_hex(&spec->oid)) :
+                                      oid_to_hex(&spec->oid));
                        else {
                                struct object *object = lookup_object(the_repository,
                                                                      &spec->oid);
@@ -493,12 +514,12 @@ static const char *find_encoding(const char *begin, const char *end)
        return bol;
 }
 
-static void *anonymize_ref_component(const void *old, size_t *len)
+static char *anonymize_ref_component(void *data)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
        strbuf_addf(&out, "ref%d", counter++);
-       return strbuf_detach(&out, len);
+       return strbuf_detach(&out, NULL);
 }
 
 static const char *anonymize_refname(const char *refname)
@@ -517,13 +538,6 @@ static const char *anonymize_refname(const char *refname)
        static struct strbuf anon = STRBUF_INIT;
        int i;
 
-       /*
-        * We also leave "master" as a special case, since it does not reveal
-        * anything interesting.
-        */
-       if (!strcmp(refname, "refs/heads/master"))
-               return refname;
-
        strbuf_reset(&anon);
        for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
                if (skip_prefix(refname, prefixes[i], &refname)) {
@@ -546,14 +560,13 @@ static char *anonymize_commit_message(const char *old)
        return xstrfmt("subject %d\n\nbody\n", counter++);
 }
 
-static struct hashmap idents;
-static void *anonymize_ident(const void *old, size_t *len)
+static char *anonymize_ident(void *data)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
        strbuf_addf(&out, "User %d <user%d@example.com>", counter, counter);
        counter++;
-       return strbuf_detach(&out, len);
+       return strbuf_detach(&out, NULL);
 }
 
 /*
@@ -563,6 +576,7 @@ static void *anonymize_ident(const void *old, size_t *len)
  */
 static void anonymize_ident_line(const char **beg, const char **end)
 {
+       static struct hashmap idents;
        static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
        static unsigned which_buffer;
 
@@ -588,9 +602,9 @@ static void anonymize_ident_line(const char **beg, const char **end)
                size_t len;
 
                len = split.mail_end - split.name_begin;
-               ident = anonymize_mem(&idents, anonymize_ident,
-                                     split.name_begin, &len);
-               strbuf_add(out, ident, len);
+               ident = anonymize_str(&idents, anonymize_ident,
+                                     split.name_begin, len, NULL);
+               strbuf_addstr(out, ident);
                strbuf_addch(out, ' ');
                strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
        } else {
@@ -712,9 +726,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
                if (mark)
                        printf(":%d\n", mark);
                else
-                       printf("%s\n", oid_to_hex(anonymize ?
-                                                 anonymize_oid(&obj->oid) :
-                                                 &obj->oid));
+                       printf("%s\n",
+                              anonymize ?
+                              anonymize_oid(oid_to_hex(&obj->oid)) :
+                              oid_to_hex(&obj->oid));
                i++;
        }
 
@@ -729,12 +744,12 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
        show_progress();
 }
 
-static void *anonymize_tag(const void *old, size_t *len)
+static char *anonymize_tag(void *data)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
        strbuf_addf(&out, "tag message %d", counter++);
-       return strbuf_detach(&out, len);
+       return strbuf_detach(&out, NULL);
 }
 
 static void handle_tail(struct object_array *commits, struct rev_info *revs,
@@ -804,8 +819,8 @@ static void handle_tag(const char *name, struct tag *tag)
                name = anonymize_refname(name);
                if (message) {
                        static struct hashmap tags;
-                       message = anonymize_mem(&tags, anonymize_tag,
-                                               message, &message_size);
+                       message = anonymize_str(&tags, anonymize_tag,
+                                               message, message_size, NULL);
                }
        }
 
@@ -1136,6 +1151,37 @@ static void handle_deletes(void)
        }
 }
 
+static char *anonymize_seed(void *data)
+{
+       return xstrdup(data);
+}
+
+static int parse_opt_anonymize_map(const struct option *opt,
+                                  const char *arg, int unset)
+{
+       struct hashmap *map = opt->value;
+       const char *delim, *value;
+       size_t keylen;
+
+       BUG_ON_OPT_NEG(unset);
+
+       delim = strchr(arg, ':');
+       if (delim) {
+               keylen = delim - arg;
+               value = delim + 1;
+       } else {
+               keylen = strlen(arg);
+               value = arg;
+       }
+
+       if (!keylen || !*value)
+               return error(_("--anonymize-map token cannot be empty"));
+
+       anonymize_str(map, anonymize_seed, arg, keylen, (void *)value);
+
+       return 0;
+}
+
 int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
@@ -1177,6 +1223,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
                             N_("Apply refspec to exported refs")),
                OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
+               OPT_CALLBACK_F(0, "anonymize-map", &anonymized_seeds, N_("from:to"),
+                              N_("convert <from> to <to> in anonymized output"),
+                              PARSE_OPT_NONEG, parse_opt_anonymize_map),
                OPT_BOOL(0, "reference-excluded-parents",
                         &reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
                OPT_BOOL(0, "show-original-ids", &show_original_ids,
@@ -1204,6 +1253,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        if (argc > 1)
                usage_with_options (fast_export_usage, options);
 
+       if (anonymized_seeds.cmpfn && !anonymize)
+               die(_("--anonymize-map without --anonymize does not make sense"));
+
        if (refspecs_list.nr) {
                int i;
 
index f02cbdb439b210f973c06588da8a29f87fe23350..37aa07da78ebe9130c4d48865810bfc87d9f4ea0 100644 (file)
@@ -241,7 +241,7 @@ static void mark_unreachable_referents(const struct object_id *oid)
                enum object_type type = oid_object_info(the_repository,
                                                        &obj->oid, NULL);
                if (type > 0)
-                       object_as_type(the_repository, obj, type, 0);
+                       object_as_type(obj, type, 0);
        }
 
        options.walk = mark_used;
@@ -577,7 +577,7 @@ static void get_default_heads(void)
 
        for_each_rawref(fsck_handle_ref, NULL);
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        for (p = worktrees; *p; p++) {
                struct worktree *wt = *p;
                struct strbuf ref = STRBUF_INIT;
index f176dd28c870d5e417b373f2bb0d39b4fa1a0c29..f865666db9ee62ba0b1dd60111912b233df47d7c 100644 (file)
@@ -1555,13 +1555,9 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
 {
        const uint32_t *idx1, *idx2;
        uint32_t i;
-       const uint32_t hashwords = the_hash_algo->rawsz / sizeof(uint32_t);
 
        /* The address of the 4-byte offset table */
-       idx1 = (((const uint32_t *)p->index_data)
-               + 2 /* 8-byte header */
-               + 256 /* fan out */
-               + hashwords * p->num_objects /* object ID table */
+       idx1 = (((const uint32_t *)((const uint8_t *)p->index_data + p->crc_offset))
                + p->num_objects /* CRC32 table */
                );
 
@@ -1671,6 +1667,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        unsigned char pack_hash[GIT_MAX_RAWSZ];
        unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
        int report_end_of_input = 0;
+       int hash_algo = 0;
 
        /*
         * index-pack never needs to fetch missing objects except when
@@ -1764,6 +1761,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                        die(_("bad %s"), arg);
                        } else if (skip_prefix(arg, "--max-input-size=", &arg)) {
                                max_input_size = strtoumax(arg, NULL, 10);
+                       } else if (skip_prefix(arg, "--object-format=", &arg)) {
+                               hash_algo = hash_algo_by_name(arg);
+                               if (hash_algo == GIT_HASH_UNKNOWN)
+                                       die(_("unknown hash algorithm '%s'"), arg);
+                               repo_set_hash_algo(the_repository, hash_algo);
                        } else
                                usage(index_pack_usage);
                        continue;
@@ -1780,6 +1782,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                die(_("--fix-thin cannot be used without --stdin"));
        if (from_stdin && !startup_info->have_repository)
                die(_("--stdin requires a git repository"));
+       if (from_stdin && hash_algo)
+               die(_("--object-format cannot be used with --stdin"));
        if (!index_name && pack_name)
                index_name = derive_filename(pack_name, "idx", &index_name_buf);
 
index 0b7222e7188858a7c820e870dce4c2dd0370f443..cee64823cbb500a8df0f19f486a2d3593492b1e6 100644 (file)
@@ -203,6 +203,7 @@ void initialize_repository_version(int hash_algo)
 
 static int create_default_files(const char *template_path,
                                const char *original_git_dir,
+                               const char *initial_branch,
                                const struct repository_format *fmt)
 {
        struct stat st1;
@@ -258,15 +259,26 @@ static int create_default_files(const char *template_path,
                die("failed to set up refs db: %s", err.buf);
 
        /*
-        * Create the default symlink from ".git/HEAD" to the "master"
-        * branch, if it does not exist yet.
+        * Point the HEAD symref to the initial branch with if HEAD does
+        * not yet exist.
         */
        path = git_path_buf(&buf, "HEAD");
        reinit = (!access(path, R_OK)
                  || readlink(path, junk, sizeof(junk)-1) != -1);
        if (!reinit) {
-               if (create_symref("HEAD", "refs/heads/master", NULL) < 0)
+               char *ref;
+
+               if (!initial_branch)
+                       initial_branch = git_default_branch_name();
+
+               ref = xstrfmt("refs/heads/%s", initial_branch);
+               if (check_refname_format(ref, 0) < 0)
+                       die(_("invalid initial branch name: '%s'"),
+                           initial_branch);
+
+               if (create_symref("HEAD", ref, NULL) < 0)
                        exit(1);
+               free(ref);
        }
 
        initialize_repository_version(fmt->hash_algo);
@@ -383,7 +395,8 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
 }
 
 int init_db(const char *git_dir, const char *real_git_dir,
-           const char *template_dir, int hash, unsigned int flags)
+           const char *template_dir, int hash, const char *initial_branch,
+           unsigned int flags)
 {
        int reinit;
        int exist_ok = flags & INIT_DB_EXIST_OK;
@@ -425,7 +438,11 @@ int init_db(const char *git_dir, const char *real_git_dir,
 
        validate_hash_algorithm(&repo_fmt, hash);
 
-       reinit = create_default_files(template_dir, original_git_dir, &repo_fmt);
+       reinit = create_default_files(template_dir, original_git_dir,
+                                     initial_branch, &repo_fmt);
+       if (reinit && initial_branch)
+               warning(_("re-init: ignored --initial-branch=%s"),
+                       initial_branch);
 
        create_object_directory();
 
@@ -528,6 +545,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        const char *template_dir = NULL;
        unsigned int flags = 0;
        const char *object_format = NULL;
+       const char *initial_branch = NULL;
        int hash_algo = GIT_HASH_UNKNOWN;
        const struct option init_db_options[] = {
                OPT_STRING(0, "template", &template_dir, N_("template-directory"),
@@ -541,6 +559,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
                OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
                           N_("separate git dir from working tree")),
+               OPT_STRING('b', "initial-branch", &initial_branch, N_("name"),
+                          N_("override the name of the initial branch")),
                OPT_STRING(0, "object-format", &object_format, N_("hash"),
                           N_("specify the hash algorithm to use")),
                OPT_END()
@@ -652,5 +672,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        UNLEAK(work_tree);
 
        flags |= INIT_DB_EXIST_OK;
-       return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
+       return init_db(git_dir, real_git_dir, template_dir, hash_algo,
+                      initial_branch, flags);
 }
index 6ef519514bd1a4dfc39b149967ee60dcf14dfbaa..3a4dd12903206ae47fd4683e3bef1a7371d67d55 100644 (file)
@@ -118,6 +118,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                transport->server_options = &server_options;
 
        ref = transport_get_remote_refs(transport, &ref_prefixes);
+       if (ref) {
+               int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+               repo_set_hash_algo(the_repository, hash_algo);
+       }
        if (transport_disconnect(transport)) {
                UNLEAK(sorting);
                return 1;
index 8e6572d305ec3fac23af491a14e1a9612bedba64..8159c5d7c9651497a658b3880fef26b67089bd29 100644 (file)
@@ -1025,7 +1025,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                        commit_list_insert(head, &list);
                        merge_head = lookup_commit_reference(the_repository,
                                                             &merge_heads.oid[0]);
-                       if (is_descendant_of(merge_head, list)) {
+                       if (repo_is_descendant_of(the_repository,
+                                                 merge_head, list)) {
                                /* we can fast-forward this without invoking rebase */
                                opt_ff = "--ff-only";
                                ran_ff = 1;
index ea3d0f01af3b7cfd90e1e235ee4e8694dabf8791..d43663bb0a9e8f410371ac06a34794060101578f 100644 (file)
@@ -249,6 +249,7 @@ static void show_ref(const char *path, const struct object_id *oid)
                        strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
                if (advertise_push_options)
                        strbuf_addstr(&cap, " push-options");
+               strbuf_addf(&cap, " object-format=%s", the_hash_algo->name);
                strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
                packet_write_fmt(1, "%s %s%c%s\n",
                             oid_to_hex(oid), path, 0, cap.buf);
@@ -1624,6 +1625,8 @@ static struct command *read_head_info(struct packet_reader *reader,
                linelen = strlen(reader->line);
                if (linelen < reader->pktlen) {
                        const char *feature_list = reader->line + linelen + 1;
+                       const char *hash = NULL;
+                       int len = 0;
                        if (parse_feature_request(feature_list, "report-status"))
                                report_status = 1;
                        if (parse_feature_request(feature_list, "side-band-64k"))
@@ -1636,6 +1639,13 @@ static struct command *read_head_info(struct packet_reader *reader,
                        if (advertise_push_options
                            && parse_feature_request(feature_list, "push-options"))
                                use_push_options = 1;
+                       hash = parse_feature_value(feature_list, "object-format", &len, NULL);
+                       if (!hash) {
+                               hash = hash_algos[GIT_HASH_SHA1].name;
+                               len = strlen(hash);
+                       }
+                       if (xstrncmpz(the_hash_algo->name, hash, len))
+                               die("error: unsupported object format '%s'", hash);
                }
 
                if (!strcmp(reader->line, "push-cert")) {
index 52ecf6d43c1010e431c2f408a4acb79a31a1543e..ca1d8079f320e6d6b93767110520dcdcd1fa0a97 100644 (file)
@@ -615,7 +615,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                int i;
 
                memset(&collected, 0, sizeof(collected));
-               worktrees = get_worktrees(0);
+               worktrees = get_worktrees();
                for (p = worktrees; *p; p++) {
                        if (!all_worktrees && !(*p)->is_current)
                                continue;
index 0826f6a5a2c2207d1a17070f0f246cc999f31104..8106b03a6b3243c4d8c5e86e9b668727598696ed 100644 (file)
@@ -1,9 +1,12 @@
 #include "builtin.h"
 #include "cache.h"
 #include "pack.h"
+#include "parse-options.h"
 
-static const char show_index_usage[] =
-"git show-index";
+static const char *const show_index_usage[] = {
+       "git show-index [--object-format=<hash-algorithm>]",
+       NULL
+};
 
 int cmd_show_index(int argc, const char **argv, const char *prefix)
 {
@@ -11,10 +14,26 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
        unsigned nr;
        unsigned int version;
        static unsigned int top_index[256];
-       const unsigned hashsz = the_hash_algo->rawsz;
+       unsigned hashsz;
+       const char *hash_name = NULL;
+       int hash_algo;
+       const struct option show_index_options[] = {
+               OPT_STRING(0, "object-format", &hash_name, N_("hash-algorithm"),
+                          N_("specify the hash algorithm to use")),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, show_index_options, show_index_usage, 0);
+
+       if (hash_name) {
+               hash_algo = hash_algo_by_name(hash_name);
+               if (hash_algo == GIT_HASH_UNKNOWN)
+                       die(_("Unknown hash algorithm"));
+               repo_set_hash_algo(the_repository, hash_algo);
+       }
+
+       hashsz = the_hash_algo->rawsz;
 
-       if (argc != 1)
-               usage(show_index_usage);
        if (fread(top_index, 2 * 4, 1, stdin) != 1)
                die("unable to read header");
        if (top_index[0] == htonl(PACK_IDX_SIGNATURE)) {
index 59c1e1217c95a2aef1ef59b7d29de1b37ce4b082..a1c75607c72e190a10cc7af0184a41b04f5e77b5 100644 (file)
@@ -1981,7 +1981,7 @@ static const char *remote_submodule_branch(const char *path)
        free(key);
 
        if (!branch)
-               return "master";
+               return "HEAD";
 
        if (!strcmp(branch, ".")) {
                const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
index 1238b6bab1f34d11121f9c55e0af955386e86b69..f0cbdef718215d1ff71a2a71204c10d296a9b2c8 100644 (file)
@@ -325,7 +325,7 @@ static int add_worktree(const char *path, const char *refname,
        struct strbuf sb_name = STRBUF_INIT;
        struct worktree **worktrees;
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        check_candidate_path(path, opts->force, worktrees, "add");
        free_worktrees(worktrees);
        worktrees = NULL;
@@ -697,6 +697,23 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
        }
 }
 
+static int pathcmp(const void *a_, const void *b_)
+{
+       const struct worktree *const *a = a_;
+       const struct worktree *const *b = b_;
+       return fspathcmp((*a)->path, (*b)->path);
+}
+
+static void pathsort(struct worktree **wt)
+{
+       int n = 0;
+       struct worktree **p = wt;
+
+       while (*p++)
+               n++;
+       QSORT(wt, n, pathcmp);
+}
+
 static int list(int ac, const char **av, const char *prefix)
 {
        int porcelain = 0;
@@ -710,9 +727,12 @@ static int list(int ac, const char **av, const char *prefix)
        if (ac)
                usage_with_options(worktree_usage, options);
        else {
-               struct worktree **worktrees = get_worktrees(GWT_SORT_LINKED);
+               struct worktree **worktrees = get_worktrees();
                int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
 
+               /* sort worktrees by path but keep main worktree at top */
+               pathsort(worktrees + 1);
+
                if (!porcelain)
                        measure_widths(worktrees, &abbrev, &path_maxlen);
 
@@ -741,7 +761,7 @@ static int lock_worktree(int ac, const char **av, const char *prefix)
        if (ac != 1)
                usage_with_options(worktree_usage, options);
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        wt = find_worktree(worktrees, prefix, av[0]);
        if (!wt)
                die(_("'%s' is not a working tree"), av[0]);
@@ -774,7 +794,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
        if (ac != 1)
                usage_with_options(worktree_usage, options);
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        wt = find_worktree(worktrees, prefix, av[0]);
        if (!wt)
                die(_("'%s' is not a working tree"), av[0]);
@@ -848,7 +868,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
        strbuf_addstr(&dst, path);
        free(path);
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        wt = find_worktree(worktrees, prefix, av[0]);
        if (!wt)
                die(_("'%s' is not a working tree"), av[0]);
@@ -974,7 +994,7 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
        if (ac != 1)
                usage_with_options(worktree_usage, options);
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        wt = find_worktree(worktrees, prefix, av[0]);
        if (!wt)
                die(_("'%s' is not a working tree"), av[0]);
index 99439e07a1064ae6420ca9c5a821ecec8022aef7..2a0d744d3fa51b2bbbb307a04f7e32a45b1b690d 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -23,6 +23,17 @@ static void add_to_ref_list(const struct object_id *oid, const char *name,
        list->nr++;
 }
 
+static const struct git_hash_algo *detect_hash_algo(struct strbuf *buf)
+{
+       size_t len = strcspn(buf->buf, " \n");
+       int algo;
+
+       algo = hash_algo_by_length(len / 2);
+       if (algo == GIT_HASH_UNKNOWN)
+               return NULL;
+       return &hash_algos[algo];
+}
+
 static int parse_bundle_header(int fd, struct bundle_header *header,
                               const char *report_path)
 {
@@ -52,12 +63,21 @@ static int parse_bundle_header(int fd, struct bundle_header *header,
                }
                strbuf_rtrim(&buf);
 
+               if (!header->hash_algo) {
+                       header->hash_algo = detect_hash_algo(&buf);
+                       if (!header->hash_algo) {
+                               error(_("unknown hash algorithm length"));
+                               status = -1;
+                               break;
+                       }
+               }
+
                /*
                 * Tip lines have object name, SP, and refname.
                 * Prerequisites have object name that is optionally
                 * followed by SP and subject line.
                 */
-               if (parse_oid_hex(buf.buf, &oid, &p) ||
+               if (parse_oid_hex_algop(buf.buf, &oid, &p, header->hash_algo) ||
                    (*p && !isspace(*p)) ||
                    (!is_prereq && !*p)) {
                        if (report_path)
index ceab0c747578e5c5ec7835e3d62c4521914fe7ce..2dc9442024fa27f775e25bbfa9dc8ba04ca1967c 100644 (file)
--- a/bundle.h
+++ b/bundle.h
@@ -15,6 +15,7 @@ struct ref_list {
 struct bundle_header {
        struct ref_list prerequisites;
        struct ref_list references;
+       const struct git_hash_algo *hash_algo;
 };
 
 int is_bundle(const char *path, int quiet);
diff --git a/cache.h b/cache.h
index e5885cc9ead57a4eba10ad5263f58b94439feb85..126ec56c7f33b4f90439363848504263ea48d3f0 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -628,7 +628,7 @@ int path_inside_repo(const char *prefix, const char *path);
 
 int init_db(const char *git_dir, const char *real_git_dir,
            const char *template_dir, int hash_algo,
-           unsigned int flags);
+           const char *initial_branch, unsigned int flags);
 void initialize_repository_version(int hash_algo);
 
 void sanitize_stdfds(void);
index cbb960c843668ad75b6497f8f661687a7e5dc45e..89aa60cde7e0659e955fdcfb963a8859bf69a567 100644 (file)
@@ -136,7 +136,7 @@ git-pack-redundant                      plumbinginterrogators
 git-pack-refs                           ancillarymanipulators
 git-parse-remote                        synchelpers
 git-patch-id                            purehelpers
-git-prune                               ancillarymanipulators
+git-prune                               ancillarymanipulators   complete
 git-prune-packed                        plumbingmanipulators
 git-pull                                mainporcelain           remote
 git-push                                mainporcelain           remote
index 2ff042fbf4f732f63b6317f9430e1e589df67ef2..fdd1c4fa7c54510006fb9eb7722b822470897fd3 100644 (file)
@@ -87,15 +87,69 @@ static int commit_pos_cmp(const void *va, const void *vb)
               commit_pos_at(&commit_pos, b);
 }
 
+define_commit_slab(commit_graph_data_slab, struct commit_graph_data);
+static struct commit_graph_data_slab commit_graph_data_slab =
+       COMMIT_SLAB_INIT(1, commit_graph_data_slab);
+
+uint32_t commit_graph_position(const struct commit *c)
+{
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       return data ? data->graph_pos : COMMIT_NOT_FROM_GRAPH;
+}
+
+uint32_t commit_graph_generation(const struct commit *c)
+{
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       if (!data)
+               return GENERATION_NUMBER_INFINITY;
+       else if (data->graph_pos == COMMIT_NOT_FROM_GRAPH)
+               return GENERATION_NUMBER_INFINITY;
+
+       return data->generation;
+}
+
+static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
+{
+       unsigned int i, nth_slab;
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       if (data)
+               return data;
+
+       nth_slab = c->index / commit_graph_data_slab.slab_size;
+       data = commit_graph_data_slab_at(&commit_graph_data_slab, c);
+
+       /*
+        * commit-slab initializes elements with zero, overwrite this with
+        * COMMIT_NOT_FROM_GRAPH for graph_pos.
+        *
+        * We avoid initializing generation with checking if graph position
+        * is not COMMIT_NOT_FROM_GRAPH.
+        */
+       for (i = 0; i < commit_graph_data_slab.slab_size; i++) {
+               commit_graph_data_slab.slab[nth_slab][i].graph_pos =
+                       COMMIT_NOT_FROM_GRAPH;
+       }
+
+       return data;
+}
+
 static int commit_gen_cmp(const void *va, const void *vb)
 {
        const struct commit *a = *(const struct commit **)va;
        const struct commit *b = *(const struct commit **)vb;
 
+       uint32_t generation_a = commit_graph_generation(a);
+       uint32_t generation_b = commit_graph_generation(b);
        /* lower generation commits first */
-       if (a->generation < b->generation)
+       if (generation_a < generation_b)
                return -1;
-       else if (a->generation > b->generation)
+       else if (generation_a > generation_b)
                return 1;
 
        /* use date as a heuristic when generations are equal */
@@ -670,13 +724,14 @@ static struct commit_list **insert_parent_or_die(struct repository *r,
        c = lookup_commit(r, &oid);
        if (!c)
                die(_("could not find commit %s"), oid_to_hex(&oid));
-       c->graph_pos = pos;
+       commit_graph_data_at(c)->graph_pos = pos;
        return &commit_list_insert(c, pptr)->next;
 }
 
 static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, uint32_t pos)
 {
        const unsigned char *commit_data;
+       struct commit_graph_data *graph_data;
        uint32_t lex_index;
 
        while (pos < g->num_commits_in_base)
@@ -684,8 +739,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
 
        lex_index = pos - g->num_commits_in_base;
        commit_data = g->chunk_commit_data + GRAPH_DATA_WIDTH * lex_index;
-       item->graph_pos = pos;
-       item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
+
+       graph_data = commit_graph_data_at(item);
+       graph_data->graph_pos = pos;
+       graph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
 }
 
 static inline void set_commit_tree(struct commit *c, struct tree *t)
@@ -701,6 +758,7 @@ static int fill_commit_in_graph(struct repository *r,
        uint32_t *parent_data_ptr;
        uint64_t date_low, date_high;
        struct commit_list **pptr;
+       struct commit_graph_data *graph_data;
        const unsigned char *commit_data;
        uint32_t lex_index;
 
@@ -714,7 +772,8 @@ static int fill_commit_in_graph(struct repository *r,
         * Store the "full" position, but then use the
         * "local" position for the rest of the calculation.
         */
-       item->graph_pos = pos;
+       graph_data = commit_graph_data_at(item);
+       graph_data->graph_pos = pos;
        lex_index = pos - g->num_commits_in_base;
 
        commit_data = g->chunk_commit_data + (g->hash_len + 16) * lex_index;
@@ -727,7 +786,7 @@ static int fill_commit_in_graph(struct repository *r,
        date_low = get_be32(commit_data + g->hash_len + 12);
        item->date = (timestamp_t)((date_high << 32) | date_low);
 
-       item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
+       graph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
 
        pptr = &item->parents;
 
@@ -759,8 +818,9 @@ static int fill_commit_in_graph(struct repository *r,
 
 static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t *pos)
 {
-       if (item->graph_pos != COMMIT_NOT_FROM_GRAPH) {
-               *pos = item->graph_pos;
+       uint32_t graph_pos = commit_graph_position(item);
+       if (graph_pos != COMMIT_NOT_FROM_GRAPH) {
+               *pos = graph_pos;
                return 1;
        } else {
                struct commit_graph *cur_g = g;
@@ -815,12 +875,13 @@ static struct tree *load_tree_for_commit(struct repository *r,
 {
        struct object_id oid;
        const unsigned char *commit_data;
+       uint32_t graph_pos = commit_graph_position(c);
 
-       while (c->graph_pos < g->num_commits_in_base)
+       while (graph_pos < g->num_commits_in_base)
                g = g->base_graph;
 
        commit_data = g->chunk_commit_data +
-                       GRAPH_DATA_WIDTH * (c->graph_pos - g->num_commits_in_base);
+                       GRAPH_DATA_WIDTH * (graph_pos - g->num_commits_in_base);
 
        hashcpy(oid.hash, commit_data);
        set_commit_tree(c, lookup_tree(r, &oid));
@@ -834,7 +895,7 @@ static struct tree *get_commit_tree_in_graph_one(struct repository *r,
 {
        if (c->maybe_tree)
                return c->maybe_tree;
-       if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
+       if (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)
                BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
 
        return load_tree_for_commit(r, g, (struct commit *)c);
@@ -1020,7 +1081,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                else
                        packedDate[0] = 0;
 
-               packedDate[0] |= htonl((*list)->generation << 2);
+               packedDate[0] |= htonl(commit_graph_data_at(*list)->generation << 2);
 
                packedDate[1] = htonl((*list)->date);
                hashwrite(f, packedDate, 8);
@@ -1219,7 +1280,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
                        continue;
                if (ctx->split) {
                        if ((!parse_commit(commit) &&
-                            commit->graph_pos == COMMIT_NOT_FROM_GRAPH) ||
+                            commit_graph_position(commit) == COMMIT_NOT_FROM_GRAPH) ||
                            flags == COMMIT_GRAPH_SPLIT_REPLACE)
                                add_missing_parents(ctx, commit);
                } else if (!parse_commit_no_graph(commit))
@@ -1251,9 +1312,11 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                                        _("Computing commit graph generation numbers"),
                                        ctx->commits.nr);
        for (i = 0; i < ctx->commits.nr; i++) {
+               uint32_t generation = commit_graph_data_at(ctx->commits.list[i])->generation;
+
                display_progress(ctx->progress, i + 1);
-               if (ctx->commits.list[i]->generation != GENERATION_NUMBER_INFINITY &&
-                   ctx->commits.list[i]->generation != GENERATION_NUMBER_ZERO)
+               if (generation != GENERATION_NUMBER_INFINITY &&
+                   generation != GENERATION_NUMBER_ZERO)
                        continue;
 
                commit_list_insert(ctx->commits.list[i], &list);
@@ -1264,22 +1327,26 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                        uint32_t max_generation = 0;
 
                        for (parent = current->parents; parent; parent = parent->next) {
-                               if (parent->item->generation == GENERATION_NUMBER_INFINITY ||
-                                   parent->item->generation == GENERATION_NUMBER_ZERO) {
+                               generation = commit_graph_data_at(parent->item)->generation;
+
+                               if (generation == GENERATION_NUMBER_INFINITY ||
+                                   generation == GENERATION_NUMBER_ZERO) {
                                        all_parents_computed = 0;
                                        commit_list_insert(parent->item, &list);
                                        break;
-                               } else if (parent->item->generation > max_generation) {
-                                       max_generation = parent->item->generation;
+                               } else if (generation > max_generation) {
+                                       max_generation = generation;
                                }
                        }
 
                        if (all_parents_computed) {
-                               current->generation = max_generation + 1;
+                               struct commit_graph_data *data = commit_graph_data_at(current);
+
+                               data->generation = max_generation + 1;
                                pop_commit(&list);
 
-                               if (current->generation > GENERATION_NUMBER_MAX)
-                                       current->generation = GENERATION_NUMBER_MAX;
+                               if (data->generation > GENERATION_NUMBER_MAX)
+                                       data->generation = GENERATION_NUMBER_MAX;
                        }
                }
        }
@@ -1458,7 +1525,7 @@ static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
                        if (ctx->split) {
                                struct commit *c = lookup_commit(ctx->r, &ctx->oids.list[i]);
 
-                               if (!c || c->graph_pos != COMMIT_NOT_FROM_GRAPH)
+                               if (!c || commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH)
                                        continue;
                        }
 
@@ -1492,7 +1559,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
                ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.list[i]);
 
                if (ctx->split && flags != COMMIT_GRAPH_SPLIT_REPLACE &&
-                   ctx->commits.list[ctx->commits.nr]->graph_pos != COMMIT_NOT_FROM_GRAPH)
+                   commit_graph_position(ctx->commits.list[ctx->commits.nr]) != COMMIT_NOT_FROM_GRAPH)
                        continue;
 
                if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE)
@@ -2241,6 +2308,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                struct commit *graph_commit, *odb_commit;
                struct commit_list *graph_parents, *odb_parents;
                uint32_t max_generation = 0;
+               uint32_t generation;
 
                display_progress(progress, i + 1);
                hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
@@ -2279,8 +2347,9 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                                             oid_to_hex(&graph_parents->item->object.oid),
                                             oid_to_hex(&odb_parents->item->object.oid));
 
-                       if (graph_parents->item->generation > max_generation)
-                               max_generation = graph_parents->item->generation;
+                       generation = commit_graph_generation(graph_parents->item);
+                       if (generation > max_generation)
+                               max_generation = generation;
 
                        graph_parents = graph_parents->next;
                        odb_parents = odb_parents->next;
@@ -2290,7 +2359,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                        graph_report(_("commit-graph parent list for commit %s terminates early"),
                                     oid_to_hex(&cur_oid));
 
-               if (!graph_commit->generation) {
+               if (!commit_graph_generation(graph_commit)) {
                        if (generation_zero == GENERATION_NUMBER_EXISTS)
                                graph_report(_("commit-graph has generation number zero for commit %s, but non-zero elsewhere"),
                                             oid_to_hex(&cur_oid));
@@ -2310,10 +2379,11 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                if (max_generation == GENERATION_NUMBER_MAX)
                        max_generation--;
 
-               if (graph_commit->generation != max_generation + 1)
+               generation = commit_graph_generation(graph_commit);
+               if (generation != max_generation + 1)
                        graph_report(_("commit-graph generation for commit %s is %u != %u"),
                                     oid_to_hex(&cur_oid),
-                                    graph_commit->generation,
+                                    generation,
                                     max_generation + 1);
 
                if (graph_commit->date != odb_commit->date)
index 3ba0da1e5f4738823670ba560a34e156946b1b8a..28f89cdf3e577582261c2261698bdd051b530edb 100644 (file)
@@ -135,4 +135,14 @@ void free_commit_graph(struct commit_graph *);
  */
 void disable_commit_graph(struct repository *r);
 
+struct commit_graph_data {
+       uint32_t graph_pos;
+       uint32_t generation;
+};
+
+/*
+ * Commits should be parsed before accessing generation, graph positions.
+ */
+uint32_t commit_graph_generation(const struct commit *);
+uint32_t commit_graph_position(const struct commit *);
 #endif
index 176121766335b8dcdcad0db76591407cf9db7a60..efd5925cbb826e563c1a2040b506f9d9148d1d18 100644 (file)
@@ -58,14 +58,15 @@ static struct commit_list *paint_down_to_common(struct repository *r,
                struct commit *commit = prio_queue_get(&queue);
                struct commit_list *parents;
                int flags;
+               uint32_t generation = commit_graph_generation(commit);
 
-               if (min_generation && commit->generation > last_gen)
+               if (min_generation && generation > last_gen)
                        BUG("bad generation skip %8x > %8x at %s",
-                           commit->generation, last_gen,
+                           generation, last_gen,
                            oid_to_hex(&commit->object.oid));
-               last_gen = commit->generation;
+               last_gen = generation;
 
-               if (commit->generation < min_generation)
+               if (generation < min_generation)
                        break;
 
                flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
@@ -176,18 +177,20 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
                repo_parse_commit(r, array[i]);
        for (i = 0; i < cnt; i++) {
                struct commit_list *common;
-               uint32_t min_generation = array[i]->generation;
+               uint32_t min_generation = commit_graph_generation(array[i]);
 
                if (redundant[i])
                        continue;
                for (j = filled = 0; j < cnt; j++) {
+                       uint32_t curr_generation;
                        if (i == j || redundant[j])
                                continue;
                        filled_index[filled] = j;
                        work[filled++] = array[j];
 
-                       if (array[j]->generation < min_generation)
-                               min_generation = array[j]->generation;
+                       curr_generation = commit_graph_generation(array[j]);
+                       if (curr_generation < min_generation)
+                               min_generation = curr_generation;
                }
                common = paint_down_to_common(r, array[i], filled,
                                              work, min_generation);
@@ -283,9 +286,9 @@ struct commit_list *repo_get_merge_bases(struct repository *r,
 /*
  * Is "commit" a descendant of one of the elements on the "with_commit" list?
  */
-static int repo_is_descendant_of(struct repository *r,
-                                struct commit *commit,
-                                struct commit_list *with_commit)
+int repo_is_descendant_of(struct repository *r,
+                         struct commit *commit,
+                         struct commit_list *with_commit)
 {
        if (!with_commit)
                return 1;
@@ -310,11 +313,6 @@ static int repo_is_descendant_of(struct repository *r,
        }
 }
 
-int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
-{
-       return repo_is_descendant_of(the_repository, commit, with_commit);
-}
-
 /*
  * Is "commit" an ancestor of one of the "references"?
  */
@@ -323,23 +321,26 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
 {
        struct commit_list *bases;
        int ret = 0, i;
-       uint32_t min_generation = GENERATION_NUMBER_INFINITY;
+       uint32_t generation, min_generation = GENERATION_NUMBER_INFINITY;
 
        if (repo_parse_commit(r, commit))
                return ret;
        for (i = 0; i < nr_reference; i++) {
                if (repo_parse_commit(r, reference[i]))
                        return ret;
-               if (reference[i]->generation < min_generation)
-                       min_generation = reference[i]->generation;
+
+               generation = commit_graph_generation(reference[i]);
+               if (generation < min_generation)
+                       min_generation = generation;
        }
 
-       if (commit->generation > min_generation)
+       generation = commit_graph_generation(commit);
+       if (generation > min_generation)
                return ret;
 
        bases = paint_down_to_common(r, commit,
                                     nr_reference, reference,
-                                    commit->generation);
+                                    generation);
        if (commit->object.flags & PARENT2)
                ret = 1;
        clear_commit_marks(commit, all_flags);
@@ -433,7 +434,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
                return 0;
 
        commit_list_insert(old_commit, &old_commit_list);
-       ret = is_descendant_of(new_commit, old_commit_list);
+       ret = repo_is_descendant_of(the_repository,
+                                   new_commit, old_commit_list);
        free_commit_list(old_commit_list);
        return ret;
 }
@@ -485,7 +487,7 @@ static enum contains_result contains_test(struct commit *candidate,
        /* Otherwise, we don't know; prepare to recurse */
        parse_commit_or_die(candidate);
 
-       if (candidate->generation < cutoff)
+       if (commit_graph_generation(candidate) < cutoff)
                return CONTAINS_NO;
 
        return CONTAINS_UNKNOWN;
@@ -508,10 +510,12 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
        const struct commit_list *p;
 
        for (p = want; p; p = p->next) {
+               uint32_t generation;
                struct commit *c = p->item;
                load_commit_graph_info(the_repository, c);
-               if (c->generation < cutoff)
-                       cutoff = c->generation;
+               generation = commit_graph_generation(c);
+               if (generation < cutoff)
+                       cutoff = generation;
        }
 
        result = contains_test(candidate, want, cache, cutoff);
@@ -554,7 +558,7 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
 {
        if (filter->with_commit_tag_algo)
                return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
-       return is_descendant_of(commit, list);
+       return repo_is_descendant_of(the_repository, commit, list);
 }
 
 static int compare_commits_by_gen(const void *_a, const void *_b)
@@ -562,9 +566,12 @@ static int compare_commits_by_gen(const void *_a, const void *_b)
        const struct commit *a = *(const struct commit * const *)_a;
        const struct commit *b = *(const struct commit * const *)_b;
 
-       if (a->generation < b->generation)
+       uint32_t generation_a = commit_graph_generation(a);
+       uint32_t generation_b = commit_graph_generation(b);
+
+       if (generation_a < generation_b)
                return -1;
-       if (a->generation > b->generation)
+       if (generation_a > generation_b)
                return 1;
        return 0;
 }
@@ -603,7 +610,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
 
                list[nr_commits] = (struct commit *)from_one;
                if (parse_commit(list[nr_commits]) ||
-                   list[nr_commits]->generation < min_generation) {
+                   commit_graph_generation(list[nr_commits]) < min_generation) {
                        result = 0;
                        goto cleanup;
                }
@@ -639,7 +646,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
 
                                        if (parse_commit(parent->item) ||
                                            parent->item->date < min_commit_date ||
-                                           parent->item->generation < min_generation)
+                                           commit_graph_generation(parent->item) < min_generation)
                                                continue;
 
                                        commit_list_insert(parent->item, &stack);
@@ -680,11 +687,13 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
                add_object_array(&from_iter->item->object, NULL, &from_objs);
 
                if (!parse_commit(from_iter->item)) {
+                       uint32_t generation;
                        if (from_iter->item->date < min_commit_date)
                                min_commit_date = from_iter->item->date;
 
-                       if (from_iter->item->generation < min_generation)
-                               min_generation = from_iter->item->generation;
+                       generation = commit_graph_generation(from_iter->item);
+                       if (generation < min_generation)
+                               min_generation = generation;
                }
 
                from_iter = from_iter->next;
@@ -692,11 +701,13 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
 
        while (to_iter) {
                if (!parse_commit(to_iter->item)) {
+                       uint32_t generation;
                        if (to_iter->item->date < min_commit_date)
                                min_commit_date = to_iter->item->date;
 
-                       if (to_iter->item->generation < min_generation)
-                               min_generation = to_iter->item->generation;
+                       generation = commit_graph_generation(to_iter->item);
+                       if (generation < min_generation)
+                               min_generation = generation;
                }
 
                to_iter->item->object.flags |= PARENT2;
@@ -736,11 +747,13 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
        struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
 
        for (item = to; item < to_last; item++) {
+               uint32_t generation;
                struct commit *c = *item;
 
                parse_commit(c);
-               if (c->generation < min_generation)
-                       min_generation = c->generation;
+               generation = commit_graph_generation(c);
+               if (generation < min_generation)
+                       min_generation = generation;
 
                if (!(c->object.flags & PARENT1)) {
                        c->object.flags |= PARENT1;
@@ -773,7 +786,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
 
                        parse_commit(p);
 
-                       if (p->generation < min_generation)
+                       if (commit_graph_generation(p) < min_generation)
                                continue;
 
                        if (p->object.flags & PARENT2)
index 99a43e8b64fc803d7b7f4d09d11c2ec31fdb0a76..b49ad71a3177f7dfb670fedd272e68cc89a03e77 100644 (file)
@@ -27,7 +27,9 @@ struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
 
 struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 
-int is_descendant_of(struct commit *commit, struct commit_list *with_commit);
+int repo_is_descendant_of(struct repository *r,
+                         struct commit *commit,
+                         struct commit_list *with_commit);
 int repo_in_merge_bases(struct repository *r,
                        struct commit *commit,
                        struct commit *reference);
index 87686a7055bc5c502de88032d1c474e32539e6a0..43d29a800d73f3df330fa61f5214ec5259025827 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -37,7 +37,7 @@ struct commit *lookup_commit_reference_gently(struct repository *r,
 
        if (!obj)
                return NULL;
-       return object_as_type(r, obj, OBJ_COMMIT, quiet);
+       return object_as_type(obj, OBJ_COMMIT, quiet);
 }
 
 struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)
@@ -62,7 +62,7 @@ struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
        struct object *obj = lookup_object(r, oid);
        if (!obj)
                return create_object(r, oid, alloc_commit_node(r));
-       return object_as_type(r, obj, OBJ_COMMIT, 0);
+       return object_as_type(obj, OBJ_COMMIT, 0);
 }
 
 struct commit *lookup_commit_reference_by_name(const char *name)
@@ -339,7 +339,7 @@ struct tree *repo_get_commit_tree(struct repository *r,
        if (commit->maybe_tree || !commit->object.parsed)
                return commit->maybe_tree;
 
-       if (commit->graph_pos != COMMIT_NOT_FROM_GRAPH)
+       if (commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
                return get_commit_tree_in_graph(r, commit);
 
        return NULL;
@@ -729,11 +729,13 @@ int compare_commits_by_author_date(const void *a_, const void *b_,
 int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
 {
        const struct commit *a = a_, *b = b_;
+       const uint32_t generation_a = commit_graph_generation(a),
+                      generation_b = commit_graph_generation(b);
 
        /* newer commits first */
-       if (a->generation < b->generation)
+       if (generation_a < generation_b)
                return 1;
-       else if (a->generation > b->generation)
+       else if (generation_a > generation_b)
                return -1;
 
        /* use date as a heuristic when generations are equal */
index 1b2dea5d85ebe52c8e5f32f1e5e26ff33e0c566c..e90153890954a458fa83671dea14b07a76621747 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -36,8 +36,6 @@ struct commit {
         * or get_commit_tree_oid().
         */
        struct tree *maybe_tree;
-       uint32_t graph_pos;
-       uint32_t generation;
        unsigned int index;
 };
 
index 0df45a110888e53e4d6f3f86bafc76abcd096297..e0d5b9fee05fc5db4c329d4825600020dce8910a 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -18,7 +18,7 @@
 
 static char *server_capabilities_v1;
 static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
-static const char *parse_feature_value(const char *, const char *, int *);
+static const char *next_server_feature_value(const char *feature, int *len, int *offset);
 
 static int check_ref(const char *name, unsigned int flags)
 {
@@ -83,6 +83,21 @@ int server_supports_v2(const char *c, int die_on_error)
        return 0;
 }
 
+int server_feature_v2(const char *c, const char **v)
+{
+       int i;
+
+       for (i = 0; i < server_capabilities_v2.argc; i++) {
+               const char *out;
+               if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
+                   (*out == '=')) {
+                       *v = out + 1;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 int server_supports_feature(const char *c, const char *feature,
                            int die_on_error)
 {
@@ -181,17 +196,16 @@ reject:
 static void annotate_refs_with_symref_info(struct ref *ref)
 {
        struct string_list symref = STRING_LIST_INIT_DUP;
-       const char *feature_list = server_capabilities_v1;
+       int offset = 0;
 
-       while (feature_list) {
+       while (1) {
                int len;
                const char *val;
 
-               val = parse_feature_value(feature_list, "symref", &len);
+               val = next_server_feature_value("symref", &len, &offset);
                if (!val)
                        break;
                parse_one_symref_info(&symref, val, len);
-               feature_list = val + 1;
        }
        string_list_sort(&symref);
 
@@ -205,21 +219,36 @@ static void annotate_refs_with_symref_info(struct ref *ref)
        string_list_clear(&symref, 0);
 }
 
-static void process_capabilities(const char *line, int *len)
+static void process_capabilities(struct packet_reader *reader, int *linelen)
 {
+       const char *feat_val;
+       int feat_len;
+       const char *line = reader->line;
        int nul_location = strlen(line);
-       if (nul_location == *len)
+       if (nul_location == *linelen)
                return;
        server_capabilities_v1 = xstrdup(line + nul_location + 1);
-       *len = nul_location;
+       *linelen = nul_location;
+
+       feat_val = server_feature_value("object-format", &feat_len);
+       if (feat_val) {
+               char *hash_name = xstrndup(feat_val, feat_len);
+               int hash_algo = hash_algo_by_name(hash_name);
+               if (hash_algo != GIT_HASH_UNKNOWN)
+                       reader->hash_algo = &hash_algos[hash_algo];
+               free(hash_name);
+       } else {
+               reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
+       }
 }
 
-static int process_dummy_ref(const char *line)
+static int process_dummy_ref(const struct packet_reader *reader)
 {
+       const char *line = reader->line;
        struct object_id oid;
        const char *name;
 
-       if (parse_oid_hex(line, &oid, &name))
+       if (parse_oid_hex_algop(line, &oid, &name, reader->hash_algo))
                return 0;
        if (*name != ' ')
                return 0;
@@ -235,13 +264,15 @@ static void check_no_capabilities(const char *line, int len)
                        line + strlen(line));
 }
 
-static int process_ref(const char *line, int len, struct ref ***list,
-                      unsigned int flags, struct oid_array *extra_have)
+static int process_ref(const struct packet_reader *reader, int len,
+                      struct ref ***list, unsigned int flags,
+                      struct oid_array *extra_have)
 {
+       const char *line = reader->line;
        struct object_id old_oid;
        const char *name;
 
-       if (parse_oid_hex(line, &old_oid, &name))
+       if (parse_oid_hex_algop(line, &old_oid, &name, reader->hash_algo))
                return 0;
        if (*name != ' ')
                return 0;
@@ -261,16 +292,17 @@ static int process_ref(const char *line, int len, struct ref ***list,
        return 1;
 }
 
-static int process_shallow(const char *line, int len,
+static int process_shallow(const struct packet_reader *reader, int len,
                           struct oid_array *shallow_points)
 {
+       const char *line = reader->line;
        const char *arg;
        struct object_id old_oid;
 
        if (!skip_prefix(line, "shallow ", &arg))
                return 0;
 
-       if (get_oid_hex(arg, &old_oid))
+       if (get_oid_hex_algop(arg, &old_oid, reader->hash_algo))
                die(_("protocol error: expected shallow sha-1, got '%s'"), arg);
        if (!shallow_points)
                die(_("repository on the other end cannot be shallow"));
@@ -317,20 +349,20 @@ struct ref **get_remote_heads(struct packet_reader *reader,
 
                switch (state) {
                case EXPECTING_FIRST_REF:
-                       process_capabilities(reader->line, &len);
-                       if (process_dummy_ref(reader->line)) {
+                       process_capabilities(reader, &len);
+                       if (process_dummy_ref(reader)) {
                                state = EXPECTING_SHALLOW;
                                break;
                        }
                        state = EXPECTING_REF;
                        /* fallthrough */
                case EXPECTING_REF:
-                       if (process_ref(reader->line, len, &list, flags, extra_have))
+                       if (process_ref(reader, len, &list, flags, extra_have))
                                break;
                        state = EXPECTING_SHALLOW;
                        /* fallthrough */
                case EXPECTING_SHALLOW:
-                       if (process_shallow(reader->line, len, shallow_points))
+                       if (process_shallow(reader, len, shallow_points))
                                break;
                        die(_("protocol error: unexpected '%s'"), reader->line);
                case EXPECTING_DONE:
@@ -344,7 +376,7 @@ struct ref **get_remote_heads(struct packet_reader *reader,
 }
 
 /* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
-static int process_ref_v2(const char *line, struct ref ***list)
+static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
 {
        int ret = 1;
        int i = 0;
@@ -352,6 +384,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
        struct ref *ref;
        struct string_list line_sections = STRING_LIST_INIT_DUP;
        const char *end;
+       const char *line = reader->line;
 
        /*
         * Ref lines have a number of fields which are space deliminated.  The
@@ -364,7 +397,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
                goto out;
        }
 
-       if (parse_oid_hex(line_sections.items[i++].string, &old_oid, &end) ||
+       if (parse_oid_hex_algop(line_sections.items[i++].string, &old_oid, &end, reader->hash_algo) ||
            *end) {
                ret = 0;
                goto out;
@@ -372,7 +405,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
 
        ref = alloc_ref(line_sections.items[i++].string);
 
-       oidcpy(&ref->old_oid, &old_oid);
+       memcpy(ref->old_oid.hash, old_oid.hash, reader->hash_algo->rawsz);
        **list = ref;
        *list = &ref->next;
 
@@ -385,7 +418,8 @@ static int process_ref_v2(const char *line, struct ref ***list)
                        struct object_id peeled_oid;
                        char *peeled_name;
                        struct ref *peeled;
-                       if (parse_oid_hex(arg, &peeled_oid, &end) || *end) {
+                       if (parse_oid_hex_algop(arg, &peeled_oid, &end,
+                                               reader->hash_algo) || *end) {
                                ret = 0;
                                goto out;
                        }
@@ -393,7 +427,8 @@ static int process_ref_v2(const char *line, struct ref ***list)
                        peeled_name = xstrfmt("%s^{}", ref->name);
                        peeled = alloc_ref(peeled_name);
 
-                       oidcpy(&peeled->old_oid, &peeled_oid);
+                       memcpy(peeled->old_oid.hash, peeled_oid.hash,
+                              reader->hash_algo->rawsz);
                        **list = peeled;
                        *list = &peeled->next;
 
@@ -423,6 +458,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
                             int stateless_rpc)
 {
        int i;
+       const char *hash_name;
        *list = NULL;
 
        if (server_supports_v2("ls-refs", 1))
@@ -431,6 +467,16 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
        if (server_supports_v2("agent", 0))
                packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
 
+       if (server_feature_v2("object-format", &hash_name)) {
+               int hash_algo = hash_algo_by_name(hash_name);
+               if (hash_algo == GIT_HASH_UNKNOWN)
+                       die(_("unknown object format '%s' specified by server"), hash_name);
+               reader->hash_algo = &hash_algos[hash_algo];
+               packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name);
+       } else {
+               reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
+       }
+
        if (server_options && server_options->nr &&
            server_supports_v2("server-option", 1))
                for (i = 0; i < server_options->nr; i++)
@@ -450,7 +496,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
 
        /* Process response from server */
        while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
-               if (!process_ref_v2(reader->line, &list))
+               if (!process_ref_v2(reader, &list))
                        die(_("invalid ls-refs response: %s"), reader->line);
        }
 
@@ -463,7 +509,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
        return list;
 }
 
-static const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
 {
        int len;
 
@@ -471,6 +517,8 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
                return NULL;
 
        len = strlen(feature);
+       if (offset)
+               feature_list += *offset;
        while (*feature_list) {
                const char *found = strstr(feature_list, feature);
                if (!found)
@@ -485,9 +533,14 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
                        }
                        /* feature with a value (e.g., "agent=git/1.2.3") */
                        else if (*value == '=') {
+                               int end;
+
                                value++;
+                               end = strcspn(value, " \t\n");
                                if (lenp)
-                                       *lenp = strcspn(value, " \t\n");
+                                       *lenp = end;
+                               if (offset)
+                                       *offset = value + end - feature_list;
                                return value;
                        }
                        /*
@@ -500,14 +553,41 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
        return NULL;
 }
 
+int server_supports_hash(const char *desired, int *feature_supported)
+{
+       int offset = 0;
+       int len;
+       const char *hash;
+
+       hash = next_server_feature_value("object-format", &len, &offset);
+       if (feature_supported)
+               *feature_supported = !!hash;
+       if (!hash) {
+               hash = hash_algos[GIT_HASH_SHA1].name;
+               len = strlen(hash);
+       }
+       while (hash) {
+               if (!xstrncmpz(desired, hash, len))
+                       return 1;
+
+               hash = next_server_feature_value("object-format", &len, &offset);
+       }
+       return 0;
+}
+
 int parse_feature_request(const char *feature_list, const char *feature)
 {
-       return !!parse_feature_value(feature_list, feature, NULL);
+       return !!parse_feature_value(feature_list, feature, NULL, NULL);
+}
+
+static const char *next_server_feature_value(const char *feature, int *len, int *offset)
+{
+       return parse_feature_value(server_capabilities_v1, feature, len, offset);
 }
 
 const char *server_feature_value(const char *feature, int *len)
 {
-       return parse_feature_value(server_capabilities_v1, feature, len);
+       return parse_feature_value(server_capabilities_v1, feature, len, NULL);
 }
 
 int server_supports(const char *feature)
index 235bc66254d4a0b8760cd828339fccee7fac1bd0..c53586e929e8b6f11194d9aeb9934e0fbecd5983 100644 (file)
--- a/connect.h
+++ b/connect.h
@@ -18,7 +18,10 @@ int url_is_local_not_ssh(const char *url);
 struct packet_reader;
 enum protocol_version discover_version(struct packet_reader *reader);
 
+int server_supports_hash(const char *desired, int *feature_supported);
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset);
 int server_supports_v2(const char *c, int die_on_error);
+int server_feature_v2(const char *c, const char **v);
 int server_supports_feature(const char *c, const char *feature,
                            int die_on_error);
 
index 778e4704f6a2baa8484a13fea3a0cf4d2b35f44b..af6dd4c20cae87d3364b59cedac80936f8ff3355 100644 (file)
@@ -32,3 +32,21 @@ expression c;
 - c->maybe_tree
 + repo_get_commit_tree(specify_the_right_repo_here, c)
   ...>}
+
+@@
+struct commit *c;
+expression E;
+@@
+(
+- c->generation = E;
++ commit_graph_data_at(c)->generation = E;
+|
+- c->graph_pos = E;
++ commit_graph_data_at(c)->graph_pos = E;
+|
+- c->generation
++ commit_graph_generation(c)
+|
+- c->graph_pos
++ commit_graph_position(c)
+)
index de5d0fbbd1dccaf2db571ba6e442249d0b35995e..ee468ea3b041ca573eb412739443230211cc6043 100644 (file)
@@ -50,7 +50,7 @@ esac
 # variable.
 __git_find_repo_path ()
 {
-       if [ -n "$__git_repo_path" ]; then
+       if [ -n "${__git_repo_path-}" ]; then
                # we already know where it is
                return
        fi
@@ -404,12 +404,12 @@ __gitcomp_builtin ()
        # spaces must be replaced with underscore for multi-word
        # commands, e.g. "git remote add" becomes remote_add.
        local cmd="$1"
-       local incl="$2"
-       local excl="$3"
+       local incl="${2-}"
+       local excl="${3-}"
 
        local var=__gitcomp_builtin_"${cmd/-/_}"
        local options
-       eval "options=\$$var"
+       eval "options=\${$var-}"
 
        if [ -z "$options" ]; then
                # leading and trailing spaces are significant to make
@@ -801,7 +801,7 @@ __git_refs ()
 #                --remote is only compatible with --mode=refs.
 __git_complete_refs ()
 {
-       local remote dwim pfx cur_="$cur" sfx=" " mode="refs"
+       local remote= dwim= pfx= cur_="$cur" sfx=" " mode="refs"
 
        while test $# != 0; do
                case "$1" in
@@ -1152,7 +1152,7 @@ __git_find_on_cmdline ()
        while [ $c -lt $cword ]; do
                for word in $wordlist; do
                        if [ "$word" = "${words[c]}" ]; then
-                               if [ -n "$show_idx" ]; then
+                               if [ -n "${show_idx-}" ]; then
                                        echo "$c $word"
                                else
                                        echo "$word"
@@ -1468,7 +1468,7 @@ __git_checkout_default_dwim_mode ()
 {
        local last_option dwim_opt="--dwim"
 
-       if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ]; then
+       if [ "${GIT_COMPLETION_CHECKOUT_NO_GUESS-}" = "1" ]; then
                dwim_opt=""
        fi
 
@@ -3350,7 +3350,7 @@ __git_main ()
                ((c++))
        done
 
-       if [ -z "$command" ]; then
+       if [ -z "${command-}" ]; then
                case "$prev" in
                --git-dir|-C|--work-tree)
                        # these need a path argument, let's fall back to
@@ -3385,7 +3385,7 @@ __git_main ()
                        "
                        ;;
                *)
-                       if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
+                       if test -n "${GIT_TESTING_PORCELAIN_COMMAND_LIST-}"
                        then
                                __gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
                        else
index 014cd7c3cfcc99f837b0bd1a3086b2d32272caf0..e6cd5464e5cad86f92deddea111dae8744b159aa 100644 (file)
 # state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
 # is SP.
 #
+# When there is an in-progress operation such as a merge, rebase,
+# revert, cherry-pick, or bisect, the prompt will include information
+# related to the operation, often in the form "|<OPERATION-NAME>".
+#
+# When the repository has a sparse-checkout, a notification of the form
+# "|SPARSE" will be included in the prompt.  This can be shortened to a
+# single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
+# by setting GIT_PS1_OMITSPARSESTATE.
+#
 # By default, __git_ps1 will compare HEAD to your SVN upstream if it can
 # find one, or @{upstream} otherwise.  Once you have set
 # GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
@@ -421,6 +430,13 @@ __git_ps1 ()
                return $exit
        fi
 
+       local sparse=""
+       if [ -z "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
+          [ -z "${GIT_PS1_OMITSPARSESTATE}" ] &&
+          [ "$(git config --bool core.sparseCheckout)" == "true" ]; then
+               sparse="|SPARSE"
+       fi
+
        local r=""
        local b=""
        local step=""
@@ -492,6 +508,7 @@ __git_ps1 ()
        local i=""
        local s=""
        local u=""
+       local h=""
        local c=""
        local p=""
 
@@ -524,6 +541,11 @@ __git_ps1 ()
                        u="%${ZSH_VERSION+%}"
                fi
 
+               if [ -n "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
+                  [ "$(git config --bool core.sparseCheckout)" == "true" ]; then
+                       h="?"
+               fi
+
                if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
                        __git_ps1_show_upstream
                fi
@@ -542,8 +564,8 @@ __git_ps1 ()
                b="\${__git_ps1_branch_name}"
        fi
 
-       local f="$w$i$s$u"
-       local gitstring="$c$b${f:+$z$f}$r$p"
+       local f="$h$w$i$s$u"
+       local gitstring="$c$b${f:+$z$f}${sparse}$r$p"
 
        if [ $pcmode = yes ]; then
                if [ "${__git_printf_supports_v-}" != yes ]; then
index 57ff4b25c17e5479e9dc058fd723d44faa23877b..53d7accf949fef1882f051805570a4797e46de3f 100755 (executable)
@@ -196,7 +196,8 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
                cd "$subtree_test_count" &&
                git fetch ./"sub proj" master &&
                git subtree merge --prefix="sub dir" FETCH_HEAD &&
-               check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+               check_equal "$(last_commit_message)" \
+                       "Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into master"
        )
 '
 
@@ -273,7 +274,8 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
                cd "$test_count" &&
                git fetch ./subproj master &&
                git subtree merge --prefix=subdir/ FETCH_HEAD &&
-               check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+               check_equal "$(last_commit_message)" \
+                       "Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into master"
        )
 '
 
index 61812f48c2737a4702e604962e97f5c00d394b16..25fd2dee19c4a8f6408d768d44d8dc92aeaf0ed3 100644 (file)
@@ -220,8 +220,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        } else if (revs->diffopt.ita_invisible_in_index &&
                                   ce_intent_to_add(ce)) {
                                diff_addremove(&revs->diffopt, '+', ce->ce_mode,
-                                              the_hash_algo->empty_tree, 0,
-                                              ce->name, 0);
+                                              &null_oid, 0, ce->name, 0);
                                continue;
                        }
 
index acd55ba6e82a860eeb973d9d255c8d7efc13bddc..80fb3bd89987671c1c696c72b84cb25e946882b9 100644 (file)
@@ -1050,6 +1050,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                print_verbose(args, _("Server supports %s"), "deepen-relative");
        else if (args->deepen_relative)
                die(_("Server does not support --deepen"));
+       if (!server_supports_hash(the_hash_algo->name, NULL))
+               die(_("Server does not support this repository's object format"));
 
        if (!args->no_dependents) {
                mark_complete_and_common_ref(negotiator, args, &ref);
@@ -1188,6 +1190,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
                              int sideband_all, int seen_ack)
 {
        int ret = 0;
+       const char *hash_name;
        struct strbuf req_buf = STRBUF_INIT;
 
        if (server_supports_v2("fetch", 1))
@@ -1202,6 +1205,17 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
                                         args->server_options->items[i].string);
        }
 
+       if (server_feature_v2("object-format", &hash_name)) {
+               int hash_algo = hash_algo_by_name(hash_name);
+               if (hash_algo_by_ptr(the_hash_algo) != hash_algo)
+                       die(_("mismatched algorithms: client %s; server %s"),
+                           the_hash_algo->name, hash_name);
+               packet_write_fmt(fd_out, "object-format=%s", the_hash_algo->name);
+       } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) {
+               die(_("the server does not support algorithm '%s'"),
+                   the_hash_algo->name);
+       }
+
        packet_buf_delim(&req_buf);
        if (args->use_thin_pack)
                packet_buf_write(&req_buf, "thin-pack");
index 72d32bd73b11ddf7291f5e80b7e6afb6df5fdd33..cfb8ff2f33f9f325bfae1fba78bf9312b5ba9cbe 100644 (file)
@@ -451,10 +451,7 @@ static void fmt_merge_msg_title(struct strbuf *out,
                        strbuf_addf(out, " of %s", srcs.items[i].string);
        }
 
-       if (!strcmp("master", current_branch))
-               strbuf_addch(out, '\n');
-       else
-               strbuf_addf(out, " into %s\n", current_branch);
+       strbuf_addf(out, " into %s\n", current_branch);
 }
 
 static void fmt_tag_signature(struct strbuf *tagbuf,
index a73632e8e43ce997f4bb2abf9c4e5520d2b078e2..5637114b8dcf41a2ab09a8f1787de53fc5a3a443 100644 (file)
@@ -868,6 +868,12 @@ char *xgetcwd(void);
 FILE *fopen_for_writing(const char *path);
 FILE *fopen_or_warn(const char *path, const char *mode);
 
+/*
+ * Like strncmp, but only return zero if s is NUL-terminated and exactly len
+ * characters long.  If it is not, consider it greater than t.
+ */
+int xstrncmpz(const char *s, const char *t, size_t len);
+
 /*
  * FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
  * that ptr is used twice, so don't pass e.g. ptr++.
index fc00d5946af68e536876d42a1463b21924edefa5..6483d792d337f6c0c0aa1dc0074df230bff8f378 100755 (executable)
@@ -22,6 +22,10 @@ die "Need at least one commit identifier!" unless @ARGV;
 my $repo = Git->repository();
 $opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
 
+my $tmpdir = File::Temp->newdir;
+my $hash_algo = $repo->config('extensions.objectformat') || 'sha1';
+my $hexsz = $hash_algo eq 'sha256' ? 64 : 40;
+
 if ($opt_w || $opt_W) {
        # Remember where GIT_DIR is before changing to CVS checkout
        unless ($ENV{GIT_DIR}) {
@@ -96,7 +100,7 @@ foreach my $line (@commit) {
     }
 
     if ($stage eq 'headers') {
-       if ($line =~ m/^parent (\w{40})$/) { # found a parent
+       if ($line =~ m/^parent ([0-9a-f]{$hexsz})$/) { # found a parent
            push @parents, $1;
        } elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) {
            $author = $1;
@@ -111,7 +115,7 @@ foreach my $line (@commit) {
     }
 }
 
-my $noparent = "0000000000000000000000000000000000000000";
+my $noparent = "0" x $hexsz;
 if ($parent) {
     my $found;
     # double check that it's a valid parent
@@ -174,7 +178,7 @@ my $context = $opt_p ? '' : '-C1';
 print "Checking if patch will apply\n";
 
 my @stat;
-open APPLY, "GIT_DIR= git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
+open APPLY, "GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
 @stat=<APPLY>;
 close APPLY || die "Cannot patch";
 my (@bfiles,@files,@afiles,@dfiles);
@@ -329,7 +333,7 @@ print "Applying\n";
 if ($opt_W) {
     system("git checkout -q $commit^0") && die "cannot patch";
 } else {
-    `GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
+    `GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
 }
 
 print "Patch applied successfully. Adding new files and directories to CVS\n";
@@ -407,7 +411,7 @@ unlink(".cvsexportcommit.diff");
 
 if ($opt_W) {
     system("git checkout $go_back_to") && die "cannot move back to $go_back_to";
-    if (!($go_back_to =~ /^[0-9a-fA-F]{40}$/)) {
+    if (!($go_back_to =~ /^[0-9a-fA-F]{$hexsz}$/)) {
        system("git symbolic-ref HEAD $go_back_to") &&
            die "cannot move back to $go_back_to";
     }
index 1057f389d3b299f47d9575f254df7dc9305b0d30..7bf3c12d6789741fc33a9a9032c697bb89dc2fc0 100755 (executable)
@@ -637,9 +637,9 @@ sub getwd() {
        return $pwd;
 }
 
-sub is_sha1 {
+sub is_oid {
        my $s = shift;
-       return $s =~ /^[a-f0-9]{40}$/;
+       return $s =~ /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/;
 }
 
 sub get_headref ($) {
@@ -810,7 +810,7 @@ sub write_tree () {
        open(my $fh, '-|', qw(git write-tree))
                or die "unable to open git write-tree: $!";
        chomp(my $tree = <$fh>);
-       is_sha1($tree)
+       is_oid($tree)
                or die "Cannot get tree id ($tree): $!";
        close($fh)
                or die "Error running git write-tree: $?\n";
@@ -896,7 +896,7 @@ sub commit {
 
        print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
        chomp(my $cid = <$commit_read>);
-       is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
+       is_oid($cid) or die "Cannot get commit id ($cid): $!\n";
        print "Commit ID $cid\n" if $opt_v;
        close($commit_read);
 
index ae1044273d01125af96a06f1d68cbbd3d0e25c41..f6f3fc192c8713555fa0752c29b0c45146d6ed6c 100755 (executable)
@@ -365,7 +365,7 @@ sub req_Root
     }
     foreach my $line ( @gitvars )
     {
-        next unless ( $line =~ /^(gitcvs)\.(?:(ext|pserver)\.)?([\w-]+)=(.*)$/ );
+        next unless ( $line =~ /^(gitcvs|extensions)\.(?:(ext|pserver)\.)?([\w-]+)=(.*)$/ );
         unless ($2) {
             $cfg->{$1}{$3} = $4;
         } else {
@@ -392,6 +392,9 @@ sub req_Root
         $log->nofile();
     }
 
+    $state->{rawsz} = ($cfg->{'extensions'}{'objectformat'} || 'sha1') eq 'sha256' ? 32 : 20;
+    $state->{hexsz} = $state->{rawsz} * 2;
+
     return 1;
 }
 
@@ -1581,7 +1584,7 @@ sub req_ci
 
             $parenthash = safe_pipe_capture('git', 'show-ref', '-s', $branchRef);
             chomp $parenthash;
-            if ($parenthash !~ /^[0-9a-f]{40}$/)
+            if ($parenthash !~ /^[0-9a-f]{$state->{hexsz}}$/)
             {
                 if ( defined($stickyInfo) && defined($stickyInfo->{tag}) )
                 {
@@ -1708,7 +1711,7 @@ sub req_ci
     chomp($commithash);
     $log->info("Commit hash : $commithash");
 
-    unless ( $commithash =~ /[a-zA-Z0-9]{40}/ )
+    unless ( $commithash =~ /[a-zA-Z0-9]{$state->{hexsz}}/ )
     {
         $log->warn("Commit failed (Invalid commit hash)");
         print "error 1 Commit failed (unknown reason)\n";
@@ -2375,7 +2378,7 @@ sub req_annotate
         print "E ***************\n";
         while ( <ANNOTATE> )
         {
-            if (m/^([a-zA-Z0-9]{40})\t\([^\)]*\)(.*)$/i)
+            if (m/^([a-zA-Z0-9]{$state->{hexsz}})\t\([^\)]*\)(.*)$/i)
             {
                 my $commithash = $1;
                 my $data = $2;
@@ -2852,7 +2855,7 @@ sub transmitfile
         return;
     }
 
-    die "Need filehash" unless ( defined ( $filehash ) and $filehash =~ /^[a-zA-Z0-9]{40}$/ );
+    die "Need filehash" unless ( defined ( $filehash ) and $filehash =~ /^[a-zA-Z0-9]{$state->{hexsz}}$/ );
 
     my $type = safe_pipe_capture('git', 'cat-file', '-t', $filehash);
     chomp $type;
@@ -3042,7 +3045,7 @@ sub ensureWorkTree
 
     my $ver = safe_pipe_capture('git', 'show-ref', '-s', "refs/heads/$state->{module}");
     chomp $ver;
-    if ($ver !~ /^[0-9a-f]{40}$/)
+    if ($ver !~ /^[0-9a-f]{$state->{hexsz}}$/)
     {
         $log->warn("Error from git show-ref -s refs/head$state->{module}");
         print "error 1 cannot find the current HEAD of module";
@@ -3281,7 +3284,7 @@ sub open_blob_or_die
     }
     elsif( $srcType eq "sha1" )
     {
-        unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{40}$/ )
+        unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{$state->{hexsz}}$/ )
         {
             $log->warn("Need filehash");
             die "Need filehash\n";
@@ -3817,7 +3820,7 @@ sub update
     chomp $commitsha1;
 
     my $commitinfo = ::safe_pipe_capture('git', 'cat-file', 'commit', $self->{module});
-    unless ( $commitinfo =~ /tree\s+[a-zA-Z0-9]{40}/ )
+    unless ( $commitinfo =~ /tree\s+[a-zA-Z0-9]{$state->{hexsz}}/ )
     {
         die("Invalid module '$self->{module}'");
     }
@@ -3957,7 +3960,7 @@ sub update
             while ( <FILELIST> )
             {
                chomp;
-                unless ( /^:\d{6}\s+([0-7]{6})\s+[a-f0-9]{40}\s+([a-f0-9]{40})\s+(\w)$/o )
+                unless ( /^:\d{6}\s+([0-7]{6})\s+[a-f0-9]{$state->{hexsz}}\s+([a-f0-9]{$state->{hexsz}})\s+(\w)$/o )
                 {
                     die("Couldn't process git-diff-tree line : $_");
                 }
@@ -4625,11 +4628,11 @@ sub getmeta
             $db_query->execute($filename, $intRev);
             $meta = $db_query->fetchrow_hashref;
         }
-        elsif ( $revision =~ /^2\.1\.1\.2000(\.[1-3][0-9][0-9]){20}$/ )
+        elsif ( $revision =~ /^2\.1\.1\.2000(\.[1-3][0-9][0-9]){$state->{rawsz}}$/ )
         {
             my ($commitHash)=($revision=~/^2\.1\.1\.2000(.*)$/);
             $commitHash=~s/\.([0-9]+)/sprintf("%02x",$1-100)/eg;
-            if($commitHash=~/^[0-9a-f]{40}$/)
+            if($commitHash=~/^[0-9a-f]{$state->{hexsz}}$/)
             {
                 return $self->getMetaFromCommithash($filename,$commitHash);
             }
@@ -4639,7 +4642,7 @@ sub getmeta
             $log->warning("failed get $revision with commithash=$commitHash");
             undef $revision;
         }
-        elsif ( $revision =~ /^[0-9a-f]{40}$/ )
+        elsif ( $revision =~ /^[0-9a-f]{$state->{hexsz}}$/ )
         {
             # Try DB first.  This is mostly only useful for req_annotate(),
             # which only calls this for stuff that should already be in
@@ -4658,7 +4661,7 @@ sub getmeta
             if(! $meta)
             {
                 my($revCommit)=$self->lookupCommitRef($revision);
-                if($revCommit=~/^[0-9a-f]{40}$/)
+                if($revCommit=~/^[0-9a-f]{$state->{hexsz}}$/)
                 {
                     return $self->getMetaFromCommithash($filename,$revCommit);
                 }
@@ -4672,7 +4675,7 @@ sub getmeta
         else
         {
             my($revCommit)=$self->lookupCommitRef($revision);
-            if($revCommit=~/^[0-9a-f]{40}$/)
+            if($revCommit=~/^[0-9a-f]{$state->{hexsz}}$/)
             {
                 return $self->getMetaFromCommithash($filename,$revCommit);
             }
@@ -4767,7 +4770,7 @@ sub getMetaFromCommithash
 
     my($fileHash) = ::safe_pipe_capture("git","rev-parse","$revCommit:$filename");
     chomp $fileHash;
-    if(!($fileHash=~/^[0-9a-f]{40}$/))
+    if(!($fileHash=~/^[0-9a-f]{$state->{hexsz}}$/))
     {
         die "Invalid fileHash '$fileHash' looking up"
                     ." '$revCommit:$filename'\n";
@@ -4863,7 +4866,7 @@ sub lookupCommitRef
     $commitHash = ::safe_pipe_capture("git","rev-parse","--verify","--quiet",
                                      $self->unescapeRefName($ref));
     $commitHash=~s/\s*$//;
-    if(!($commitHash=~/^[0-9a-f]{40}$/))
+    if(!($commitHash=~/^[0-9a-f]{$state->{hexsz}}$/))
     {
         $commitHash=undef;
     }
@@ -4909,7 +4912,7 @@ sub commitmessage
     my $commithash = shift;
     my $tablename = $self->tablename("commitmsgs");
 
-    die("Need commithash") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{40}$/ );
+    die("Need commithash") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{$state->{hexsz}}$/ );
 
     my $db_query;
     $db_query = $self->{dbh}->prepare_cached("SELECT value FROM $tablename WHERE key=?",{},1);
index dc95656f75c1c4a066665b91d31b387936998961..36c47bae1d1f1a0d3558fe43dcdbd5eb49a3d27c 100755 (executable)
@@ -1699,10 +1699,14 @@ sub process_file {
                                $xfer_encoding = $1 if not defined $xfer_encoding;
                        }
                        elsif (/^In-Reply-To: (.*)/i) {
-                               $in_reply_to = $1;
+                               if (!$initial_in_reply_to || $thread) {
+                                       $in_reply_to = $1;
+                               }
                        }
                        elsif (/^References: (.*)/i) {
-                               $references = $1;
+                               if (!$initial_in_reply_to || $thread) {
+                                       $references = $1;
+                               }
                        }
                        elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
                                push @xh, $_;
index 4aa208ff5ffb713ebde9f33cdbbbb4f0015c537d..58f5a7ac8f80ac609fe1b35a558f936c7af42b98 100755 (executable)
@@ -5,7 +5,8 @@ use 5.008;
 use warnings;
 use strict;
 use vars qw/   $AUTHOR $VERSION
-               $sha1 $sha1_short $_revision $_repository
+               $oid $oid_short $oid_length
+               $_revision $_repository
                $_q $_authors $_authors_prog %users/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';
@@ -103,8 +104,9 @@ sub _req_svn {
        }
 }
 
-$sha1 = qr/[a-f\d]{40}/;
-$sha1_short = qr/[a-f\d]{4,40}/;
+$oid = qr/(?:[a-f\d]{40}(?:[a-f\d]{24})?)/;
+$oid_short = qr/[a-f\d]{4,64}/;
+$oid_length = 40;
 my ($_stdin, $_help, $_edit,
        $_message, $_file, $_branch_dest,
        $_template, $_shared,
@@ -498,6 +500,7 @@ sub do_git_init_db {
                command_noisy('config', "$pfx.preserve-empty-dirs", 'true');
                command_noisy('config', "$pfx.placeholder-filename", $$fname);
        }
+       load_object_format();
 }
 
 sub init_subdir {
@@ -582,7 +585,7 @@ sub cmd_set_tree {
                print "Reading from stdin...\n";
                @commits = ();
                while (<STDIN>) {
-                       if (/\b($sha1_short)\b/o) {
+                       if (/\b($oid_short)\b/o) {
                                unshift @commits, $1;
                        }
                }
@@ -1831,7 +1834,7 @@ sub get_tree_from_treeish {
        if ($type eq 'commit') {
                $expected = (grep /^tree /, command(qw/cat-file commit/,
                                                    $treeish))[0];
-               ($expected) = ($expected =~ /^tree ($sha1)$/o);
+               ($expected) = ($expected =~ /^tree ($oid)$/o);
                die "Unable to get tree from $treeish\n" unless $expected;
        } elsif ($type eq 'tree') {
                $expected = $treeish;
@@ -1975,9 +1978,15 @@ sub read_git_config {
                        }
                }
        }
+       load_object_format();
        delete @$opts{@config_only} if @config_only;
 }
 
+sub load_object_format {
+       chomp(my $hash = `git config --get extensions.objectformat`);
+       $::oid_length = 64 if $hash eq 'sha256';
+}
+
 sub extract_metadata {
        my $id = shift or return (undef, undef, undef);
        my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+)
@@ -2006,10 +2015,10 @@ sub cmt_sha2rev_batch {
                print $out $sha, "\n";
 
                while (my $line = <$in>) {
-                       if ($first && $line =~ /^[[:xdigit:]]{40}\smissing$/) {
+                       if ($first && $line =~ /^$::oid\smissing$/) {
                                last;
                        } elsif ($first &&
-                              $line =~ /^[[:xdigit:]]{40}\scommit\s(\d+)$/) {
+                              $line =~ /^$::oid\scommit\s(\d+)$/) {
                                $first = 0;
                                $size = $1;
                                next;
@@ -2036,7 +2045,7 @@ sub working_head_info {
        my $hash;
        my %max;
        while (<$fh>) {
-               if ( m{^commit ($::sha1)$} ) {
+               if ( m{^commit ($::oid)$} ) {
                        unshift @$refs, $hash if $hash and $refs;
                        $hash = $1;
                        next;
diff --git a/git.c b/git.c
index a2d337eed77c13bf43ffde57642af9c1ea68b2db..2f021b97f344c668ba1753c66f015567f122a378 100644 (file)
--- a/git.c
+++ b/git.c
@@ -574,7 +574,7 @@ static struct cmd_struct commands[] = {
        { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
        { "show", cmd_show, RUN_SETUP },
        { "show-branch", cmd_show_branch, RUN_SETUP },
-       { "show-index", cmd_show_index },
+       { "show-index", cmd_show_index, RUN_SETUP_GENTLY },
        { "show-ref", cmd_show_ref, RUN_SETUP },
        { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
        { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
index ac7868ffeef5151a9dcc9fa2382d882f88e71aa6..1ff1883cdd9fdb537d52b1c2c25f780378de5e7c 100644 (file)
@@ -70,10 +70,10 @@ enum XML_Status {
 #define LOCK_REFRESH 30
 
 /* Remember to update object flag allocation in object.h */
-#define LOCAL    (1u<<16)
-#define REMOTE   (1u<<17)
-#define FETCHING (1u<<18)
-#define PUSHING  (1u<<19)
+#define LOCAL    (1u<<11)
+#define REMOTE   (1u<<12)
+#define FETCHING (1u<<13)
+#define PUSHING  (1u<<14)
 
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
index d1e490f2035d2f48583a30eb7a44cc4613a662fd..f439d47af81d1b8772b181cead999bba28980e21 100644 (file)
@@ -70,6 +70,7 @@ struct packed_git {
        size_t index_size;
        uint32_t num_objects;
        uint32_t num_bad_objects;
+       uint32_t crc_offset;
        unsigned char *bad_object_sha1;
        int index_version;
        time_t mtime;
index 794c86650e9a976a0667cb8103a4ae0a9a0deaf2..32575186562507b2774c6abf097df7810e9cce5e 100644 (file)
--- a/object.c
+++ b/object.c
@@ -157,13 +157,13 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)
        return obj;
 }
 
-void *object_as_type(struct repository *r, struct object *obj, enum object_type type, int quiet)
+void *object_as_type(struct object *obj, enum object_type type, int quiet)
 {
        if (obj->type == type)
                return obj;
        else if (obj->type == OBJ_NONE) {
                if (type == OBJ_COMMIT)
-                       init_commit_node(r, (struct commit *) obj);
+                       init_commit_node((struct commit *) obj);
                else
                        obj->type = type;
                return obj;
index b22328b8383ef026df6ad05decb62c9af60ec6d5..38dc2d5a6c4c908733724791806d612833b0dbe6 100644 (file)
--- a/object.h
+++ b/object.h
@@ -15,7 +15,6 @@ struct parsed_object_pool {
        struct alloc_state *commit_state;
        struct alloc_state *tag_state;
        struct alloc_state *object_state;
-       unsigned commit_count;
 
        /* parent substitutions from .git/info/grafts and .git/shallow */
        struct commit_graft **grafts;
@@ -59,7 +58,7 @@ struct object_array {
 
 /*
  * object flag allocation:
- * revision.h:               0---------10         15                   25----28
+ * revision.h:               0---------10         15             23------26
  * fetch-pack.c:             01
  * negotiator/default.c:       2--5
  * walker.c:                 0-2
@@ -67,7 +66,7 @@ struct object_array {
  * builtin/blame.c:                        12-13
  * bisect.c:                                        16
  * bundle.c:                                        16
- * http-push.c:                                     16-----19
+ * http-push.c:                          11-----14
  * commit-graph.c:                                15
  * commit-reach.c:                                  16-----19
  * sha1-name.c:                                              20
@@ -79,7 +78,7 @@ struct object_array {
  * builtin/show-branch.c:    0-------------------------------------------26
  * builtin/unpack-objects.c:                                 2021
  */
-#define FLAG_BITS  29
+#define FLAG_BITS  28
 
 /*
  * The object type is stored in 3 bits.
@@ -121,7 +120,7 @@ struct object *lookup_object(struct repository *r, const struct object_id *oid);
 
 void *create_object(struct repository *r, const struct object_id *oid, void *obj);
 
-void *object_as_type(struct repository *r, struct object *obj, enum object_type type, int quiet);
+void *object_as_type(struct object *obj, enum object_type type, int quiet);
 
 /*
  * Returns the object, having parsed it to find out what it is.
index f4e752996dbcca3778c42de1d55d856a28be974d..6ab5233613e2417f8ee9ce0991ae532726b59b20 100644 (file)
@@ -178,6 +178,7 @@ int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
                     */
                    (sizeof(off_t) <= 4))
                        return error("pack too large for current definition of off_t in %s", path);
+               p->crc_offset = 8 + 4 * 256 + nr * hashsz;
        }
 
        p->index_version = version;
index a43108c985440db24688d7b053b94d428e6dd1bb..2a7b4908f3e637d3e93462799c91cd75a8221354 100644 (file)
@@ -5,13 +5,15 @@ use Git qw/command_input_pipe command_close_pipe/;
 
 sub new {
        my ($class) = @_;
+       my $hash_algo = Git::config('extensions.objectformat') || 'sha1';
        my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
-       bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
+       bless { gui => $gui, ctx => $ctx, nr => 0, hash_algo => $hash_algo}, $class;
 }
 
 sub remove {
        my ($self, $path) = @_;
-       if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
+       my $length = $self->{hash_algo} eq 'sha256' ? 64 : 40;
+       if (print { $self->{gui} } '0 ', 0 x $length, "\t", $path, "\0") {
                return ++$self->{nr};
        }
        undef;
index 4b28b8778474bec673dd7f82fde0aba7afcafab4..d1c352f92b58392961b8e958c5539cba65458856 100644 (file)
@@ -2,7 +2,7 @@ package Git::SVN;
 use strict;
 use warnings;
 use Fcntl qw/:DEFAULT :seek/;
-use constant rev_map_fmt => 'NH40';
+use constant rev_map_fmt => 'NH*';
 use vars qw/$_no_metadata
             $_repack $_repack_flags $_use_svm_props $_head
             $_use_svnsync_props $no_reuse_existing
@@ -874,7 +874,7 @@ sub assert_index_clean {
                command_noisy('read-tree', $treeish) unless -e $self->{index};
                my $x = command_oneline('write-tree');
                my ($y) = (command(qw/cat-file commit/, $treeish) =~
-                          /^tree ($::sha1)/mo);
+                          /^tree ($::oid)/mo);
                return if $y eq $x;
 
                warn "Index mismatch: $y != $x\nrereading $treeish\n";
@@ -1020,7 +1020,7 @@ sub do_git_commit {
                $tree = $self->tmp_index_do(sub {
                                            command_oneline('write-tree') });
        }
-       die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o;
+       die "Tree is not a valid oid $tree\n" if $tree !~ /^$::oid$/o;
 
        my @exec = ('git', 'commit-tree', $tree);
        foreach ($self->get_commit_parents($log_entry)) {
@@ -1048,8 +1048,8 @@ sub do_git_commit {
        close $out_fh or croak $!;
        waitpid $pid, 0;
        croak $? if $?;
-       if ($commit !~ /^$::sha1$/o) {
-               die "Failed to commit, invalid sha1: $commit\n";
+       if ($commit !~ /^$::oid$/o) {
+               die "Failed to commit, invalid oid: $commit\n";
        }
 
        $self->rev_map_set($log_entry->{revision}, $commit, 1);
@@ -2087,10 +2087,10 @@ sub rebuild_from_rev_db {
        open my $fh, '<', $path or croak "open: $!";
        binmode $fh or croak "binmode: $!";
        while (<$fh>) {
-               length($_) == 41 or croak "inconsistent size in ($_) != 41";
+               length($_) == $::oid_length + 1 or croak "inconsistent size in ($_)";
                chomp($_);
                ++$r;
-               next if $_ eq ('0' x 40);
+               next if $_ eq ('0' x $::oid_length);
                $self->rev_map_set($r, $_);
                print "r$r = $_\n";
        }
@@ -2150,7 +2150,7 @@ sub rebuild {
        my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid;
        my $c;
        while (<$log>) {
-               if ( m{^commit ($::sha1)$} ) {
+               if ( m{^commit ($::oid)$} ) {
                        $c = $1;
                        next;
                }
@@ -2196,9 +2196,9 @@ sub rebuild {
 # (mainly tags)
 #
 # The format is this:
-#   - 24 bytes for every record,
+#   - 24 or 36 bytes for every record,
 #     * 4 bytes for the integer representing an SVN revision number
-#     * 20 bytes representing the sha1 of a git commit
+#     * 20 or 32 bytes representing the oid of a git commit
 #   - No empty padding records like the old format
 #     (except the last record, which can be overwritten)
 #   - new records are written append-only since SVN revision numbers
@@ -2207,7 +2207,7 @@ sub rebuild {
 #   - Piping the file to xxd -c24 is a good way of dumping it for
 #     viewing or editing (piped back through xxd -r), should the need
 #     ever arise.
-#   - The last record can be padding revision with an all-zero sha1
+#   - The last record can be padding revision with an all-zero oid
 #     This is used to optimize fetch performance when using multiple
 #     "fetch" directives in .git/config
 #
@@ -2215,38 +2215,39 @@ sub rebuild {
 
 sub _rev_map_set {
        my ($fh, $rev, $commit) = @_;
+       my $record_size = ($::oid_length / 2) + 4;
 
        binmode $fh or croak "binmode: $!";
        my $size = (stat($fh))[7];
-       ($size % 24) == 0 or croak "inconsistent size: $size";
+       ($size % $record_size) == 0 or croak "inconsistent size: $size";
 
        my $wr_offset = 0;
        if ($size > 0) {
-               sysseek($fh, -24, SEEK_END) or croak "seek: $!";
-               my $read = sysread($fh, my $buf, 24) or croak "read: $!";
-               $read == 24 or croak "read only $read bytes (!= 24)";
+               sysseek($fh, -$record_size, SEEK_END) or croak "seek: $!";
+               my $read = sysread($fh, my $buf, $record_size) or croak "read: $!";
+               $read == $record_size or croak "read only $read bytes (!= $record_size)";
                my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
-               if ($last_commit eq ('0' x40)) {
-                       if ($size >= 48) {
-                               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
-                               $read = sysread($fh, $buf, 24) or
+               if ($last_commit eq ('0' x $::oid_length)) {
+                       if ($size >= ($record_size * 2)) {
+                               sysseek($fh, -($record_size * 2), SEEK_END) or croak "seek: $!";
+                               $read = sysread($fh, $buf, $record_size) or
                                    croak "read: $!";
-                               $read == 24 or
-                                   croak "read only $read bytes (!= 24)";
+                               $read == $record_size or
+                                   croak "read only $read bytes (!= $record_size)";
                                ($last_rev, $last_commit) =
                                    unpack(rev_map_fmt, $buf);
-                               if ($last_commit eq ('0' x40)) {
+                               if ($last_commit eq ('0' x $::oid_length)) {
                                        croak "inconsistent .rev_map\n";
                                }
                        }
                        if ($last_rev >= $rev) {
                                croak "last_rev is higher!: $last_rev >= $rev";
                        }
-                       $wr_offset = -24;
+                       $wr_offset = -$record_size;
                }
        }
        sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
-       syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
+       syswrite($fh, pack(rev_map_fmt, $rev, $commit), $record_size) == $record_size or
          croak "write: $!";
 }
 
@@ -2271,7 +2272,7 @@ sub mkfile {
 sub rev_map_set {
        my ($self, $rev, $commit, $update_ref, $uuid) = @_;
        defined $commit or die "missing arg3\n";
-       length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
+       $commit =~ /^$::oid$/ or die "arg3 must be a full hex object ID\n";
        my $db = $self->map_path($uuid);
        my $db_lock = "$db.lock";
        my $sigmask;
@@ -2344,29 +2345,30 @@ sub rev_map_max {
 
 sub rev_map_max_norebuild {
        my ($self, $want_commit) = @_;
+       my $record_size = ($::oid_length / 2) + 4;
        my $map_path = $self->map_path;
        stat $map_path or return $want_commit ? (0, undef) : 0;
        sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
        binmode $fh or croak "binmode: $!";
        my $size = (stat($fh))[7];
-       ($size % 24) == 0 or croak "inconsistent size: $size";
+       ($size % $record_size) == 0 or croak "inconsistent size: $size";
 
        if ($size == 0) {
                close $fh or croak "close: $!";
                return $want_commit ? (0, undef) : 0;
        }
 
-       sysseek($fh, -24, SEEK_END) or croak "seek: $!";
-       sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+       sysseek($fh, -$record_size, SEEK_END) or croak "seek: $!";
+       sysread($fh, my $buf, $record_size) == $record_size or croak "read: $!";
        my ($r, $c) = unpack(rev_map_fmt, $buf);
-       if ($want_commit && $c eq ('0' x40)) {
-               if ($size < 48) {
+       if ($want_commit && $c eq ('0' x $::oid_length)) {
+               if ($size < $record_size * 2) {
                        return $want_commit ? (0, undef) : 0;
                }
-               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
-               sysread($fh, $buf, 24) == 24 or croak "read: $!";
+               sysseek($fh, -($record_size * 2), SEEK_END) or croak "seek: $!";
+               sysread($fh, $buf, $record_size) == $record_size or croak "read: $!";
                ($r, $c) = unpack(rev_map_fmt, $buf);
-               if ($c eq ('0'x40)) {
+               if ($c eq ('0' x $::oid_length)) {
                        croak "Penultimate record is all-zeroes in $map_path";
                }
        }
@@ -2387,30 +2389,31 @@ sub rev_map_get {
 
 sub _rev_map_get {
        my ($fh, $rev) = @_;
+       my $record_size = ($::oid_length / 2) + 4;
 
        binmode $fh or croak "binmode: $!";
        my $size = (stat($fh))[7];
-       ($size % 24) == 0 or croak "inconsistent size: $size";
+       ($size % $record_size) == 0 or croak "inconsistent size: $size";
 
        if ($size == 0) {
                return undef;
        }
 
-       my ($l, $u) = (0, $size - 24);
+       my ($l, $u) = (0, $size - $record_size);
        my ($r, $c, $buf);
 
        while ($l <= $u) {
-               my $i = int(($l/24 + $u/24) / 2) * 24;
+               my $i = int(($l/$record_size + $u/$record_size) / 2) * $record_size;
                sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
-               sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+               sysread($fh, my $buf, $record_size) == $record_size or croak "read: $!";
                my ($r, $c) = unpack(rev_map_fmt, $buf);
 
                if ($r < $rev) {
-                       $l = $i + 24;
+                       $l = $i + $record_size;
                } elsif ($r > $rev) {
-                       $u = $i - 24;
+                       $u = $i - $record_size;
                } else { # $r == $rev
-                       return $c eq ('0' x 40) ? undef : $c;
+                       return $c eq ('0' x $::oid_length) ? undef : $c;
                }
        }
        undef;
index 0df16ed72688f77058f471fddfdd25809d8926ae..c961444d4cbb622ea8045587c7294d50f2b655ef 100644 (file)
@@ -63,7 +63,7 @@ sub generate_diff {
        my @mods;
        while (defined($_ = get_record($diff_fh, "\0"))) {
                if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s
-                                       ($::sha1)\s($::sha1)\s
+                                       ($::oid)\s($::oid)\s
                                        ([MTCRAD])\d*$/xo) {
                        push @mods, {   mode_a => $1, mode_b => $2,
                                        sha1_a => $3, sha1_b => $4,
@@ -400,12 +400,12 @@ sub T {
            ($m->{mode_b} !~ /^120/ && $m->{mode_a} =~ /^120/)) {
                $self->D({
                        mode_a => $m->{mode_a}, mode_b => '000000',
-                       sha1_a => $m->{sha1_a}, sha1_b => '0' x 40,
+                       sha1_a => $m->{sha1_a}, sha1_b => '0' x $::oid_length,
                        chg => 'D', file_b => $m->{file_b}
                }, $deletions);
                $self->A({
                        mode_a => '000000', mode_b => $m->{mode_b},
-                       sha1_a => '0' x 40, sha1_b => $m->{sha1_b},
+                       sha1_a => '0' x $::oid_length, sha1_b => $m->{sha1_b},
                        chg => 'A', file_b => $m->{file_b}
                }, $deletions);
                return;
@@ -434,7 +434,7 @@ sub _chg_file_get_blob ($$$$) {
                $self->change_file_prop($fbat,'svn:special',undef);
        }
        my $blob = $m->{"sha1_$which"};
-       return ($fh,) if ($blob =~ /^0{40}$/);
+       return ($fh,) if ($blob =~ /^0+$/);
        my $size = $::_repository->cat_blob($blob, $fh);
        croak "Failed to read object $blob" if ($size < 0);
        $fh->flush == 0 or croak $!;
index 64e900a0e910eea63943dfd129e595697b81c542..729e5337df7accad3340f3a8f7411ba0ffd31085 100644 (file)
@@ -173,7 +173,7 @@ sub delete_entry {
 
        # remove entire directories.
        my ($tree) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
-                        =~ /\A040000 tree ([a-f\d]{40})\t\Q$gpath\E\0/);
+                        =~ /\A040000 tree ($::oid)\t\Q$gpath\E\0/);
        if ($tree) {
                my ($ls, $ctx) = command_output_pipe(qw/ls-tree
                                                     -r --name-only -z/,
@@ -203,7 +203,7 @@ sub open_file {
 
        my $gpath = $self->git_path($path);
        ($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
-                            =~ /\A(\d{6}) blob ([a-f\d]{40})\t\Q$gpath\E\0/);
+                            =~ /\A(\d{6}) blob ($::oid)\t\Q$gpath\E\0/);
        unless (defined $mode && defined $blob) {
                die "$path was not found in commit $self->{c} (r$rev)\n";
        }
@@ -413,7 +413,7 @@ sub close_file {
 
                $hash = $::_repository->hash_and_insert_object(
                                Git::temp_path($fh));
-               $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
+               $hash =~ /^$::oid$/ or die "not an object ID: $hash\n";
 
                Git::temp_release($fb->{base}, 1);
                Git::temp_release($fh, 1);
index 664105357c0031e869b3348a09d91777a42c1cdf..3858fcf27dee85c8d2b72ff96402d253c8ea1772 100644 (file)
@@ -285,7 +285,7 @@ sub cmd_show_log {
        my (@k, $c, $d, $stat);
        my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
        while (<$log>) {
-               if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
+               if (/^${esc_color}commit (?:- )?($::oid_short)/o) {
                        my $cmt = $1;
                        if ($c && cmt_showable($c) && $c->{r} != $r_last) {
                                $r_last = $c->{r};
index 56ad9870bcfdfae68bd0fb5b57aa73e208bcb0fd..2cfe055a9a04305ab5b248a6de0bab2a8abfcec0 100644 (file)
@@ -486,11 +486,11 @@ sub gs_fetch_loop_common {
                        $reload_ra->() if $ra_invalid;
                }
                # pre-fill the .rev_db since it'll eventually get filled in
-               # with '0' x40 if something new gets committed
+               # with '0' x $oid_length if something new gets committed
                foreach my $gs (@$gsv) {
                        next if $gs->rev_map_max >= $max;
                        next if defined $gs->rev_map_get($max);
-                       $gs->rev_map_set($max, 0 x40);
+                       $gs->rev_map_set($max, 0 x $::oid_length);
                }
                foreach my $g (@$globs) {
                        my $k = "svn-remote.$g->{remote}.$g->{t}-maxRev";
index 8f9bc68ee28ef46b2cd221a46a2049bf8a633511..844c253ccd9a9ee770fe494a0cce84f53dc8fed8 100644 (file)
@@ -490,6 +490,7 @@ void packet_reader_init(struct packet_reader *reader, int fd,
        reader->buffer_size = sizeof(packet_buffer);
        reader->options = options;
        reader->me = "git";
+       reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
 }
 
 enum packet_read_status packet_reader_read(struct packet_reader *reader)
index 5b373fe4cdaae2d1446fb86d4fb0762aaac764f5..8c90daa59ef0ca5f32202a1bcf52583b3f324e4f 100644 (file)
@@ -177,6 +177,9 @@ struct packet_reader {
 
        unsigned use_sideband : 1;
        const char *me;
+
+       /* hash algorithm in use */
+       const struct git_hash_algo *hash_algo;
 };
 
 /*
index bf7b70299b43b1145c22b353f78eed1ec372f023..8447cb09be0c2741b5a20426e6c0db104339fa7e 100644 (file)
@@ -1579,7 +1579,7 @@ static void lazy_init_worktree_map(void)
        if (ref_to_worktree_map.worktrees)
                return;
 
-       ref_to_worktree_map.worktrees = get_worktrees(0);
+       ref_to_worktree_map.worktrees = get_worktrees();
        hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
        populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
 }
diff --git a/refs.c b/refs.c
index 224ff66c7bb0ef587cf2b34763586f53ad73bd84..639cba93b4e0a78697a55995c926adc3e05d5126 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -9,6 +9,7 @@
 #include "iterator.h"
 #include "refs.h"
 #include "refs/refs-internal.h"
+#include "run-command.h"
 #include "object-store.h"
 #include "object.h"
 #include "tag.h"
@@ -16,6 +17,7 @@
 #include "worktree.h"
 #include "argv-array.h"
 #include "repository.h"
+#include "sigchain.h"
 
 /*
  * List of all available backends
@@ -339,7 +341,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid
 
        if (o->type == OBJ_NONE) {
                int type = oid_object_info(the_repository, name, NULL);
-               if (type < 0 || !object_as_type(the_repository, o, type, 0))
+               if (type < 0 || !object_as_type(o, type, 0))
                        return PEEL_INVALID;
        }
 
@@ -560,6 +562,36 @@ void expand_ref_prefix(struct argv_array *prefixes, const char *prefix)
                argv_array_pushf(prefixes, *p, len, prefix);
 }
 
+char *repo_default_branch_name(struct repository *r)
+{
+       const char *config_key = "init.defaultbranch";
+       const char *config_display_key = "init.defaultBranch";
+       char *ret = NULL, *full_ref;
+
+       if (repo_config_get_string(r, config_key, &ret) < 0)
+               die(_("could not retrieve `%s`"), config_display_key);
+
+       if (!ret)
+               ret = xstrdup("master");
+
+       full_ref = xstrfmt("refs/heads/%s", ret);
+       if (check_refname_format(full_ref, 0))
+               die(_("invalid branch name: %s = %s"), config_display_key, ret);
+       free(full_ref);
+
+       return ret;
+}
+
+const char *git_default_branch_name(void)
+{
+       static char *ret;
+
+       if (!ret)
+               ret = repo_default_branch_name(the_repository);
+
+       return ret;
+}
+
 /*
  * *string and *len will only be substituted, and *string returned (for
  * later free()ing) if the string passed in is a magic short-hand form
@@ -1986,10 +2018,65 @@ int ref_update_reject_duplicates(struct string_list *refnames,
        return 0;
 }
 
+static const char hook_not_found;
+static const char *hook;
+
+static int run_transaction_hook(struct ref_transaction *transaction,
+                               const char *state)
+{
+       struct child_process proc = CHILD_PROCESS_INIT;
+       struct strbuf buf = STRBUF_INIT;
+       int ret = 0, i;
+
+       if (hook == &hook_not_found)
+               return ret;
+       if (!hook)
+               hook = find_hook("reference-transaction");
+       if (!hook) {
+               hook = &hook_not_found;
+               return ret;
+       }
+
+       argv_array_pushl(&proc.args, hook, state, NULL);
+       proc.in = -1;
+       proc.stdout_to_stderr = 1;
+       proc.trace2_hook_name = "reference-transaction";
+
+       ret = start_command(&proc);
+       if (ret)
+               return ret;
+
+       sigchain_push(SIGPIPE, SIG_IGN);
+
+       for (i = 0; i < transaction->nr; i++) {
+               struct ref_update *update = transaction->updates[i];
+
+               strbuf_reset(&buf);
+               strbuf_addf(&buf, "%s %s %s\n",
+                           oid_to_hex(&update->old_oid),
+                           oid_to_hex(&update->new_oid),
+                           update->refname);
+
+               if (write_in_full(proc.in, buf.buf, buf.len) < 0) {
+                       if (errno != EPIPE)
+                               ret = -1;
+                       break;
+               }
+       }
+
+       close(proc.in);
+       sigchain_pop(SIGPIPE);
+       strbuf_release(&buf);
+
+       ret |= finish_command(&proc);
+       return ret;
+}
+
 int ref_transaction_prepare(struct ref_transaction *transaction,
                            struct strbuf *err)
 {
        struct ref_store *refs = transaction->ref_store;
+       int ret;
 
        switch (transaction->state) {
        case REF_TRANSACTION_OPEN:
@@ -2012,7 +2099,17 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
                return -1;
        }
 
-       return refs->be->transaction_prepare(refs, transaction, err);
+       ret = refs->be->transaction_prepare(refs, transaction, err);
+       if (ret)
+               return ret;
+
+       ret = run_transaction_hook(transaction, "prepared");
+       if (ret) {
+               ref_transaction_abort(transaction, err);
+               die(_("ref updates aborted by hook"));
+       }
+
+       return 0;
 }
 
 int ref_transaction_abort(struct ref_transaction *transaction,
@@ -2036,6 +2133,8 @@ int ref_transaction_abort(struct ref_transaction *transaction,
                break;
        }
 
+       run_transaction_hook(transaction, "aborted");
+
        ref_transaction_free(transaction);
        return ret;
 }
@@ -2064,7 +2163,10 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                break;
        }
 
-       return refs->be->transaction_finish(refs, transaction, err);
+       ret = refs->be->transaction_finish(refs, transaction, err);
+       if (!ret)
+               run_transaction_hook(transaction, "committed");
+       return ret;
 }
 
 int refs_verify_refname_available(struct ref_store *refs,
diff --git a/refs.h b/refs.h
index e010f8aec28aa47dddc5039178ac267d9aacfc5c..f212f8945e10a5a041a7f1c49a07f8f468589748 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -154,6 +154,15 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_
 int dwim_ref(const char *str, int len, struct object_id *oid, char **ref);
 int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
 
+/*
+ * Retrieves the default branch name for newly-initialized repositories.
+ *
+ * The return value of `repo_default_branch_name()` is an allocated string. The
+ * return value of `git_default_branch_name()` is a singleton.
+ */
+const char *git_default_branch_name(void);
+char *repo_default_branch_name(struct repository *r);
+
 /*
  * A ref_transaction represents a collection of reference updates that
  * should succeed or fail together.
index 75532a8baea8f20eb2c4aaa0f82c287a0dbaf617..5cbc6e50025b7cbf8b210cdd7bd6638fe2fa57fa 100644 (file)
@@ -41,7 +41,9 @@ struct options {
                deepen_relative : 1,
                from_promisor : 1,
                no_dependents : 1,
-               atomic : 1;
+               atomic : 1,
+               object_format : 1;
+       const struct git_hash_algo *hash_algo;
 };
 static struct options options;
 static struct string_list cas_options = STRING_LIST_INIT_DUP;
@@ -190,6 +192,16 @@ static int set_option(const char *name, const char *value)
        } else if (!strcmp(name, "filter")) {
                options.filter = xstrdup(value);
                return 0;
+       } else if (!strcmp(name, "object-format")) {
+               int algo;
+               options.object_format = 1;
+               if (strcmp(value, "true")) {
+                       algo = hash_algo_by_name(value);
+                       if (algo == GIT_HASH_UNKNOWN)
+                               die("unknown object format '%s'", value);
+                       options.hash_algo = &hash_algos[algo];
+               }
+               return 0;
        } else {
                return 1 /* unsupported */;
        }
@@ -231,6 +243,7 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
        case protocol_v0:
                get_remote_heads(&reader, &list, for_push ? REF_NORMAL : 0,
                                 NULL, &heads->shallow);
+               options.hash_algo = reader.hash_algo;
                break;
        case protocol_unknown_version:
                BUG("unknown protocol version");
@@ -239,6 +252,19 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
        return list;
 }
 
+static const struct git_hash_algo *detect_hash_algo(struct discovery *heads)
+{
+       const char *p = memchr(heads->buf, '\t', heads->len);
+       int algo;
+       if (!p)
+               return the_hash_algo;
+
+       algo = hash_algo_by_length((p - heads->buf) / 2);
+       if (algo == GIT_HASH_UNKNOWN)
+               return NULL;
+       return &hash_algos[algo];
+}
+
 static struct ref *parse_info_refs(struct discovery *heads)
 {
        char *data, *start, *mid;
@@ -249,6 +275,12 @@ static struct ref *parse_info_refs(struct discovery *heads)
        struct ref *ref = NULL;
        struct ref *last_ref = NULL;
 
+       options.hash_algo = detect_hash_algo(heads);
+       if (!options.hash_algo)
+               die("%sinfo/refs not valid: could not determine hash algorithm; "
+                   "is this a git repository?",
+                   transport_anonymize_url(url.buf));
+
        data = heads->buf;
        start = NULL;
        mid = data;
@@ -259,13 +291,13 @@ static struct ref *parse_info_refs(struct discovery *heads)
                if (data[i] == '\t')
                        mid = &data[i];
                if (data[i] == '\n') {
-                       if (mid - start != the_hash_algo->hexsz)
+                       if (mid - start != options.hash_algo->hexsz)
                                die(_("%sinfo/refs not valid: is this a git repository?"),
                                    transport_anonymize_url(url.buf));
                        data[i] = 0;
                        ref_name = mid + 1;
                        ref = alloc_ref(ref_name);
-                       get_oid_hex(start, &ref->old_oid);
+                       get_oid_hex_algop(start, &ref->old_oid, options.hash_algo);
                        if (!refs)
                                refs = ref;
                        if (last_ref)
@@ -509,11 +541,16 @@ static struct ref *get_refs(int for_push)
 static void output_refs(struct ref *refs)
 {
        struct ref *posn;
+       if (options.object_format && options.hash_algo) {
+               printf(":object-format %s\n", options.hash_algo->name);
+       }
        for (posn = refs; posn; posn = posn->next) {
                if (posn->symref)
                        printf("@%s %s\n", posn->symref, posn->name);
                else
-                       printf("%s %s\n", oid_to_hex(&posn->old_oid), posn->name);
+                       printf("%s %s\n", hash_to_hex_algop(posn->old_oid.hash,
+                                                           options.hash_algo),
+                                         posn->name);
        }
        printf("\n");
        fflush(stdout);
@@ -1499,6 +1536,7 @@ int cmd_main(int argc, const char **argv)
                        printf("option\n");
                        printf("push\n");
                        printf("check-connectivity\n");
+                       printf("object-format\n");
                        printf("\n");
                        fflush(stdout);
                } else if (skip_prefix(buf.buf, "stateless-connect ", &arg)) {
index 3af708c5b671920cff3d1888eb9c8ae724e0d648..cde39b94fb8439a9da3c57428a7f5e15056ae54a 100644 (file)
@@ -13,7 +13,7 @@
 static const char *url;
 static int dump_from_file;
 static const char *private_ref;
-static const char *remote_ref = "refs/heads/master";
+static char *remote_ref;
 static const char *marksfilename, *notes_ref;
 struct rev_note { unsigned int rev_nr; };
 
@@ -286,7 +286,7 @@ int cmd_main(int argc, const char **argv)
                        private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
                        notes_ref_sb = STRBUF_INIT;
        static struct remote *remote;
-       const char *url_in;
+       const char *url_in, *remote_ref_short;
 
        setup_git_directory();
        if (argc < 2 || argc > 3) {
@@ -294,6 +294,9 @@ int cmd_main(int argc, const char **argv)
                return 1;
        }
 
+       remote_ref_short = git_default_branch_name();
+       remote_ref = xstrfmt("refs/heads/%s", remote_ref_short);
+
        remote = remote_get(argv[1]);
        url_in = (argc == 3) ? argv[2] : remote->url[0];
 
@@ -306,7 +309,8 @@ int cmd_main(int argc, const char **argv)
                url = url_sb.buf;
        }
 
-       strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name);
+       strbuf_addf(&private_ref_sb, "refs/svn/%s/%s",
+                   remote->name, remote_ref_short);
        private_ref = private_ref_sb.buf;
 
        strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
index 534c6426f1e653e6fbb81bd7256a6b3f9d2dfb19..bc46413e6a75788da66b5c0c6bec9aa5a52c5403 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -276,7 +276,7 @@ static void read_branches_file(struct remote *remote)
 
        /*
         * The branches file would have URL and optionally
-        * #branch specified.  The "master" (or specified) branch is
+        * #branch specified.  The default (or specified) branch is
         * fetched and stored in the local branch matching the
         * remote name.
         */
@@ -284,7 +284,7 @@ static void read_branches_file(struct remote *remote)
        if (frag)
                *(frag++) = '\0';
        else
-               frag = "master";
+               frag = (char *)git_default_branch_name();
 
        add_url_alias(remote, strbuf_detach(&buf, NULL));
        strbuf_addf(&buf, "refs/heads/%s:refs/heads/%s",
@@ -2097,8 +2097,16 @@ struct ref *guess_remote_head(const struct ref *head,
        if (head->symref)
                return copy_ref(find_ref_by_name(refs, head->symref));
 
-       /* If refs/heads/master could be right, it is. */
+       /* If a remote branch exists with the default branch name, let's use it. */
        if (!all) {
+               char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+
+               r = find_ref_by_name(refs, ref);
+               free(ref);
+               if (r && oideq(&r->old_oid, &head->old_oid))
+                       return copy_ref(r);
+
+               /* Fall back to the hard-coded historical default */
                r = find_ref_by_name(refs, "refs/heads/master");
                if (r && oideq(&r->old_oid, &head->old_oid))
                        return copy_ref(r);
index 3bdc1bbf2ae5c137682e69c6502faa004493c36e..6aa7f4f56755bdc2b79455c61a9882085980f90a 100644 (file)
@@ -725,7 +725,7 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
        if (!revs->repo->objects->commit_graph)
                return -1;
 
-       if (commit->generation == GENERATION_NUMBER_INFINITY)
+       if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
                return -1;
 
        filter = get_bloom_filter(revs->repo, commit, 0);
@@ -1610,7 +1610,7 @@ static void add_other_reflogs_to_pending(struct all_refs_cb *cb)
 {
        struct worktree **worktrees, **p;
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        for (p = worktrees; *p; p++) {
                struct worktree *wt = *p;
 
@@ -1698,7 +1698,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
        if (revs->single_worktree)
                return;
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        for (p = worktrees; *p; p++) {
                struct worktree *wt = *p;
                struct index_state istate = { NULL };
@@ -3321,7 +3321,7 @@ static void explore_to_depth(struct rev_info *revs,
        struct topo_walk_info *info = revs->topo_walk_info;
        struct commit *c;
        while ((c = prio_queue_peek(&info->explore_queue)) &&
-              c->generation >= gen_cutoff)
+              commit_graph_generation(c) >= gen_cutoff)
                explore_walk_step(revs);
 }
 
@@ -3337,7 +3337,7 @@ static void indegree_walk_step(struct rev_info *revs)
        if (parse_commit_gently(c, 1) < 0)
                return;
 
-       explore_to_depth(revs, c->generation);
+       explore_to_depth(revs, commit_graph_generation(c));
 
        for (p = c->parents; p; p = p->next) {
                struct commit *parent = p->item;
@@ -3361,7 +3361,7 @@ static void compute_indegrees_to_depth(struct rev_info *revs,
        struct topo_walk_info *info = revs->topo_walk_info;
        struct commit *c;
        while ((c = prio_queue_peek(&info->indegree_queue)) &&
-              c->generation >= gen_cutoff)
+              commit_graph_generation(c) >= gen_cutoff)
                indegree_walk_step(revs);
 }
 
@@ -3414,6 +3414,7 @@ static void init_topo_walk(struct rev_info *revs)
        info->min_generation = GENERATION_NUMBER_INFINITY;
        for (list = revs->commits; list; list = list->next) {
                struct commit *c = list->item;
+               uint32_t generation;
 
                if (parse_commit_gently(c, 1))
                        continue;
@@ -3421,8 +3422,9 @@ static void init_topo_walk(struct rev_info *revs)
                test_flag_and_insert(&info->explore_queue, c, TOPO_WALK_EXPLORED);
                test_flag_and_insert(&info->indegree_queue, c, TOPO_WALK_INDEGREE);
 
-               if (c->generation < info->min_generation)
-                       info->min_generation = c->generation;
+               generation = commit_graph_generation(c);
+               if (generation < info->min_generation)
+                       info->min_generation = generation;
 
                *(indegree_slab_at(&info->indegree, c)) = 1;
 
@@ -3473,6 +3475,7 @@ static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
        for (p = commit->parents; p; p = p->next) {
                struct commit *parent = p->item;
                int *pi;
+               uint32_t generation;
 
                if (parent->object.flags & UNINTERESTING)
                        continue;
@@ -3480,8 +3483,9 @@ static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
                if (parse_commit_gently(parent, 1) < 0)
                        continue;
 
-               if (parent->generation < info->min_generation) {
-                       info->min_generation = parent->generation;
+               generation = commit_graph_generation(parent);
+               if (generation < info->min_generation) {
+                       info->min_generation = generation;
                        compute_indegrees_to_depth(revs, info->min_generation);
                }
 
index 93491b79d475adb32414008558d0d94ec9240d56..f412ae85ebafe0a1ecb8e2d7d2c56470682820ec 100644 (file)
 
 /* WARNING: This is also used as REACHABLE in commit-graph.c. */
 #define PULL_MERGE     (1u<<15)
+
+#define TOPO_WALK_EXPLORED     (1u<<23)
+#define TOPO_WALK_INDEGREE     (1u<<24)
+
 /*
  * Indicates object was reached by traversal. i.e. not given by user on
  * command-line or stdin.
@@ -48,9 +52,6 @@
 #define TRACK_LINEAR   (1u<<26)
 #define ALL_REV_FLAGS  (((1u<<11)-1) | NOT_USER_GIVEN | TRACK_LINEAR | PULL_MERGE)
 
-#define TOPO_WALK_EXPLORED     (1u<<27)
-#define TOPO_WALK_INDEGREE     (1u<<28)
-
 #define DECORATE_SHORT_REFS    1
 #define DECORATE_FULL_REFS     2
 
index 0abee22283dae8ceba42eb4b9b5ecb4842c98984..d671ab5d05c5dfd5acb1c597f68caf58d98dca9b 100644 (file)
@@ -363,6 +363,7 @@ int send_pack(struct send_pack_args *args,
        int atomic_supported = 0;
        int use_push_options = 0;
        int push_options_supported = 0;
+       int object_format_supported = 0;
        unsigned cmds_sent = 0;
        int ret;
        struct async demux;
@@ -389,6 +390,9 @@ int send_pack(struct send_pack_args *args,
        if (server_supports("push-options"))
                push_options_supported = 1;
 
+       if (!server_supports_hash(the_hash_algo->name, &object_format_supported))
+               die(_("the receiving end does not support this repository's hash algorithm"));
+
        if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
                int len;
                push_cert_nonce = server_feature_value("push-cert", &len);
@@ -406,7 +410,7 @@ int send_pack(struct send_pack_args *args,
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
-                       "Perhaps you should specify a branch such as 'master'.\n");
+                       "Perhaps you should specify a branch.\n");
                return 0;
        }
        if (args->atomic && !atomic_supported)
@@ -429,6 +433,8 @@ int send_pack(struct send_pack_args *args,
                strbuf_addstr(&cap_buf, " atomic");
        if (use_push_options)
                strbuf_addstr(&cap_buf, " push-options");
+       if (object_format_supported)
+               strbuf_addf(&cap_buf, " object-format=%s", the_hash_algo->name);
        if (agent_supported)
                strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
 
diff --git a/serve.c b/serve.c
index c046926ba141c76fc2a6b6fb1db80e31c1c28e8c..fbd2fcdfb52f7151e53bed7fdc182305bc015df2 100644 (file)
--- a/serve.c
+++ b/serve.c
@@ -22,6 +22,14 @@ static int agent_advertise(struct repository *r,
        return 1;
 }
 
+static int object_format_advertise(struct repository *r,
+                                  struct strbuf *value)
+{
+       if (value)
+               strbuf_addstr(value, r->hash_algo->name);
+       return 1;
+}
+
 struct protocol_capability {
        /*
         * The name of the capability.  The server uses this name when
@@ -57,6 +65,7 @@ static struct protocol_capability capabilities[] = {
        { "ls-refs", always_advertise, ls_refs },
        { "fetch", upload_pack_advertise, upload_pack_v2 },
        { "server-option", always_advertise, NULL },
+       { "object-format", object_format_advertise, NULL },
 };
 
 static void advertise_capabilities(void)
@@ -153,6 +162,22 @@ int has_capability(const struct argv_array *keys, const char *capability,
        return 0;
 }
 
+static void check_algorithm(struct repository *r, struct argv_array *keys)
+{
+       int client = GIT_HASH_SHA1, server = hash_algo_by_ptr(r->hash_algo);
+       const char *algo_name;
+
+       if (has_capability(keys, "object-format", &algo_name)) {
+               client = hash_algo_by_name(algo_name);
+               if (client == GIT_HASH_UNKNOWN)
+                       die("unknown object format '%s'", algo_name);
+       }
+
+       if (client != server)
+               die("mismatched object format: server %s; client %s\n",
+                   r->hash_algo->name, hash_algos[client].name);
+}
+
 enum request_state {
        PROCESS_REQUEST_KEYS,
        PROCESS_REQUEST_DONE,
@@ -225,6 +250,8 @@ static int process_request(void)
        if (!command)
                die("no command requested");
 
+       check_algorithm(the_repository, &keys);
+
        command->command(the_repository, &keys, &reader);
 
        argv_array_clear(&keys);
diff --git a/setup.c b/setup.c
index eb066db6d8c123da03e8992db84a3e562bed8fd3..dbac2eabe8fa4016ac4de415ba5c176155c07e12 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1308,6 +1308,7 @@ void check_repository_format(struct repository_format *fmt)
                fmt = &repo_fmt;
        check_repository_format_gently(get_git_dir(), fmt, NULL);
        startup_info->have_repository = 1;
+       repo_set_hash_algo(the_repository, fmt->hash_algo);
        clear_repository_format(&repo_fmt);
 }
 
index ce9fd5f0919f76ee3660cec5464b8a31c65eba07..b16cd0b11b147559e01f4413213148a70f4cb9e1 100644 (file)
@@ -12,6 +12,9 @@ int cmd__oid_array(int argc, const char **argv)
 {
        struct oid_array array = OID_ARRAY_INIT;
        struct strbuf line = STRBUF_INIT;
+       int nongit_ok;
+
+       setup_git_directory_gently(&nongit_ok);
 
        while (strbuf_getline(&line, stdin) != EOF) {
                const char *arg;
index a0272178b7791d4146cd196d402e666809753da1..14a3655442969268c4c15aa0c763a0feece5110b 100644 (file)
@@ -67,7 +67,7 @@ int cmd__reach(int ac, const char **av)
                        die("failed to load commit for input %s resulting in oid %s\n",
                            buf.buf, oid_to_hex(&oid));
 
-               c = object_as_type(r, peeled, OBJ_COMMIT, 0);
+               c = object_as_type(peeled, OBJ_COMMIT, 0);
 
                if (!c)
                        die("failed to load commit for input %s resulting in oid %s\n",
@@ -108,7 +108,7 @@ int cmd__reach(int ac, const char **av)
        else if (!strcmp(av[1], "in_merge_bases"))
                printf("%s(A,B):%d\n", av[1], in_merge_bases(A, B));
        else if (!strcmp(av[1], "is_descendant_of"))
-               printf("%s(A,X):%d\n", av[1], is_descendant_of(A, X));
+               printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
        else if (!strcmp(av[1], "get_merge_bases_many")) {
                struct commit_list *list = get_merge_bases_many(A, X_nr, X_array);
                printf("%s(A,X):\n", av[1]);
index 799fc00aa15b1e4cfe9fe8a6d32ebc2063003cb4..759e69dc549ea1d87343d9890b28066515858aea 100644 (file)
@@ -37,7 +37,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)
 
                *refs = get_submodule_ref_store(gitdir);
        } else if (skip_prefix(argv[0], "worktree:", &gitdir)) {
-               struct worktree **p, **worktrees = get_worktrees(0);
+               struct worktree **p, **worktrees = get_worktrees();
 
                for (p = worktrees; *p; p++) {
                        struct worktree *wt = *p;
index 7d248e6588063565596681e6e306f4f6b74f1177..547eb3c31a5a1ad7610f640bfccde823153bd283 100644 (file)
@@ -78,21 +78,24 @@ maybe_start_httpd () {
 }
 
 convert_to_rev_db () {
-       perl -w -- - "$@" <<\EOF
+       perl -w -- - "$(test_oid rawsz)" "$@" <<\EOF
 use strict;
+my $oidlen = shift;
 @ARGV == 2 or die "usage: convert_to_rev_db <input> <output>";
+my $record_size = $oidlen + 4;
+my $hexlen = $oidlen * 2;
 open my $wr, '+>', $ARGV[1] or die "$!: couldn't open: $ARGV[1]";
 open my $rd, '<', $ARGV[0] or die "$!: couldn't open: $ARGV[0]";
 my $size = (stat($rd))[7];
-($size % 24) == 0 or die "Inconsistent size: $size";
-while (sysread($rd, my $buf, 24) == 24) {
-       my ($r, $c) = unpack('NH40', $buf);
-       my $offset = $r * 41;
+($size % $record_size) == 0 or die "Inconsistent size: $size";
+while (sysread($rd, my $buf, $record_size) == $record_size) {
+       my ($r, $c) = unpack("NH$hexlen", $buf);
+       my $offset = $r * ($hexlen + 1);
        seek $wr, 0, 2 or die $!;
        my $pos = tell $wr;
        if ($pos < $offset) {
-               for (1 .. (($offset - $pos) / 41)) {
-                       print $wr (('0' x 40),"\n") or die $!;
+               for (1 .. (($offset - $pos) / ($hexlen + 1))) {
+                       print $wr (('0' x $hexlen),"\n") or die $!;
                }
        }
        seek $wr, $offset, 0 or die $!;
index 64fc6487dd97b2b81dfa4ee718912ee02a8cf496..07c822c8ff5f31eb8f0a81adffcec75ec752f737 100644 (file)
@@ -183,7 +183,7 @@ test_git_directory_is_unchanged () {
        )
 }
 
-test_git_directory_exists() {
+test_git_directory_exists () {
        test -e ".git/modules/$1" &&
        if test -f sub1/.git
        then
@@ -303,13 +303,17 @@ test_submodule_content () {
 # update" is run. And even then that command doesn't delete the work tree of
 # a removed submodule.
 #
+# The first argument of the callback function will be the name of the submodule.
+#
 # Removing a submodule containing a .git directory must fail even when forced
-# to protect the history!
+# to protect the history! If we are testing this case, the second argument of
+# the callback function will be 'test_must_fail', else it will be the empty
+# string.
 #
 
-# Internal function; use test_submodule_switch() or
-# test_submodule_forced_switch() instead.
-test_submodule_switch_common() {
+# Internal function; use test_submodule_switch_func(), test_submodule_switch(),
+# or test_submodule_forced_switch() instead.
+test_submodule_switch_common () {
        command="$1"
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear creates empty dir ...
@@ -443,7 +447,7 @@ test_submodule_switch_common() {
                (
                        cd submodule_update &&
                        git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
-                       test_must_fail $command replace_sub1_with_directory &&
+                       $command replace_sub1_with_directory test_must_fail &&
                        test_superproject_content origin/add_sub1 &&
                        test_submodule_content sub1 origin/add_sub1
                )
@@ -456,7 +460,7 @@ test_submodule_switch_common() {
                        cd submodule_update &&
                        git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
                        replace_gitfile_with_git_dir sub1 &&
-                       test_must_fail $command replace_sub1_with_directory &&
+                       $command replace_sub1_with_directory test_must_fail &&
                        test_superproject_content origin/add_sub1 &&
                        test_git_directory_is_unchanged sub1 &&
                        test_submodule_content sub1 origin/add_sub1
@@ -470,7 +474,7 @@ test_submodule_switch_common() {
                (
                        cd submodule_update &&
                        git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
-                       test_must_fail $command replace_sub1_with_file &&
+                       $command replace_sub1_with_file test_must_fail &&
                        test_superproject_content origin/add_sub1 &&
                        test_submodule_content sub1 origin/add_sub1
                )
@@ -484,7 +488,7 @@ test_submodule_switch_common() {
                        cd submodule_update &&
                        git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
                        replace_gitfile_with_git_dir sub1 &&
-                       test_must_fail $command replace_sub1_with_file &&
+                       $command replace_sub1_with_file test_must_fail &&
                        test_superproject_content origin/add_sub1 &&
                        test_git_directory_is_unchanged sub1 &&
                        test_submodule_content sub1 origin/add_sub1
@@ -559,15 +563,28 @@ test_submodule_switch_common() {
 # conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests
 # below to 1.
 #
-# Use as follows:
+# The first argument of the callback function will be the name of the submodule.
+#
+# Removing a submodule containing a .git directory must fail even when forced
+# to protect the history! If we are testing this case, the second argument of
+# the callback function will be 'test_must_fail', else it will be the empty
+# string.
+#
+# The following example uses `git some-command` as an example command to be
+# tested. It updates the worktree and index to match a target, but not any
+# submodule directories.
 #
 # my_func () {
-#   target=$1
-#   # Do something here that updates the worktree and index to match target,
-#   # but not any submodule directories.
+#   ...prepare for `git some-command` to be run...
+#   $2 git some-command "$1" &&
+#   if test -n "$2"
+#   then
+#     return
+#   fi &&
+#   ...check the state after git some-command is run...
 # }
-# test_submodule_switch "my_func"
-test_submodule_switch () {
+# test_submodule_switch_func "my_func"
+test_submodule_switch_func () {
        command="$1"
        test_submodule_switch_common "$command"
 
@@ -580,17 +597,33 @@ test_submodule_switch () {
                        cd submodule_update &&
                        git branch -t add_sub1 origin/add_sub1 &&
                        >sub1 &&
-                       test_must_fail $command add_sub1 &&
+                       $command add_sub1 test_must_fail &&
                        test_superproject_content origin/no_submodule &&
                        test_must_be_empty sub1
                )
        '
 }
 
+# Ensures that the that the arg either contains "test_must_fail" or is empty.
+may_only_be_test_must_fail () {
+       test -z "$1" || test "$1" = test_must_fail || die
+}
+
+git_test_func () {
+       may_only_be_test_must_fail "$2" &&
+       $2 git $gitcmd "$1"
+}
+
+test_submodule_switch () {
+       gitcmd="$1"
+       test_submodule_switch_func "git_test_func"
+}
+
 # Same as test_submodule_switch(), except that throwing away local changes in
 # the superproject is allowed.
 test_submodule_forced_switch () {
-       command="$1"
+       gitcmd="$1"
+       command="git_test_func"
        KNOWN_FAILURE_FORCED_SWITCH_TESTS=1
        test_submodule_switch_common "$command"
 
@@ -631,8 +664,8 @@ test_submodule_forced_switch () {
 
 # Internal function; use test_submodule_switch_recursing_with_args() or
 # test_submodule_forced_switch_recursing_with_args() instead.
-test_submodule_recursing_with_args_common() {
-       command="$1"
+test_submodule_recursing_with_args_common () {
+       command="$1 --recurse-submodules"
 
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear checks it out ...
@@ -840,7 +873,7 @@ test_submodule_recursing_with_args_common() {
 # test_submodule_switch_recursing_with_args "$GIT_COMMAND"
 test_submodule_switch_recursing_with_args () {
        cmd_args="$1"
-       command="git $cmd_args --recurse-submodules"
+       command="git $cmd_args"
        test_submodule_recursing_with_args_common "$command"
 
        RESULTDS=success
@@ -957,7 +990,7 @@ test_submodule_switch_recursing_with_args () {
 # away local changes in the superproject is allowed.
 test_submodule_forced_switch_recursing_with_args () {
        cmd_args="$1"
-       command="git $cmd_args --recurse-submodules"
+       command="git $cmd_args"
        test_submodule_recursing_with_args_common "$command"
 
        RESULT=success
diff --git a/t/perf/p1400-update-ref.sh b/t/perf/p1400-update-ref.sh
new file mode 100755 (executable)
index 0000000..d275a81
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+test_description="Tests performance of update-ref"
+
+. ./perf-lib.sh
+
+test_perf_fresh_repo
+
+test_expect_success "setup" '
+       test_commit PRE &&
+       test_commit POST &&
+       printf "create refs/heads/%d PRE\n" $(test_seq 1000) >create &&
+       printf "update refs/heads/%d POST PRE\n" $(test_seq 1000) >update &&
+       printf "delete refs/heads/%d POST\n" $(test_seq 1000) >delete
+'
+
+test_perf "update-ref" '
+       for i in $(test_seq 1000)
+       do
+               git update-ref refs/heads/branch PRE &&
+               git update-ref refs/heads/branch POST PRE &&
+               git update-ref -d refs/heads/branch
+       done
+'
+
+test_perf "update-ref --stdin" '
+       git update-ref --stdin <create &&
+       git update-ref --stdin <update &&
+       git update-ref --stdin <delete
+'
+
+test_done
index 1edd5aeb8f01d490b1cceba2c1d67df181868280..6d2467995e7afea65697d7540f2ef05cde54ae4b 100755 (executable)
@@ -464,4 +464,30 @@ test_expect_success MINGW 'redirect std handles' '
        grep "Needed a single revision" output.txt
 '
 
+test_expect_success '--initial-branch' '
+       git init --initial-branch=hello initial-branch-option &&
+       git -C initial-branch-option symbolic-ref HEAD >actual &&
+       echo refs/heads/hello >expect &&
+       test_cmp expect actual &&
+
+       : re-initializing should not change the branch name &&
+       git init --initial-branch=ignore initial-branch-option 2>err &&
+       test_i18ngrep "ignored --initial-branch" err &&
+       git -C initial-branch-option symbolic-ref HEAD >actual &&
+       grep hello actual
+'
+
+test_expect_success 'overridden default initial branch name (config)' '
+       test_config_global init.defaultBranch nmb &&
+       git init initial-branch-config &&
+       git -C initial-branch-config symbolic-ref HEAD >actual &&
+       grep nmb actual
+'
+
+test_expect_success 'invalid default branch name' '
+       test_config_global init.defaultBranch "with space" &&
+       test_must_fail git init initial-branch-invalid 2>err &&
+       test_i18ngrep "invalid branch name" err
+'
+
 test_done
index 91a6fafcb425f367192c7eb4e4cdf0ae4d19ac37..b6df7444c05e06caf3eb6fa491932f1e837112f7 100755 (executable)
@@ -12,8 +12,8 @@ test_submodule_switch_recursing_with_args "read-tree -u -m"
 
 test_submodule_forced_switch_recursing_with_args "read-tree -u --reset"
 
-test_submodule_switch "git read-tree -u -m"
+test_submodule_switch "read-tree -u -m"
 
-test_submodule_forced_switch "git read-tree -u --reset"
+test_submodule_forced_switch "read-tree -u --reset"
 
 test_done
index 184b479a2111a8d16c2aeb8a8bc681299b44725a..6a56d1ca246f3437ab7f8dfd77d9eef9fe4b4144 100755 (executable)
@@ -12,6 +12,7 @@ file_size () {
 }
 
 test_expect_success setup '
+       test_oid_init &&
        # clone does not allow us to pass core.bigfilethreshold to
        # new repos, so set core.bigfilethreshold globally
        git config --global core.bigfilethreshold 200k &&
@@ -64,7 +65,7 @@ test_expect_success 'add a large file or two' '
        test $count = 1 &&
        cnt=$(git show-index <"$idx" | wc -l) &&
        test $cnt = 2 &&
-       for l in .git/objects/??/??????????????????????????????????????
+       for l in .git/objects/$OIDPATH_REGEX
        do
                test_path_is_file "$l" || continue
                bad=t
@@ -177,7 +178,8 @@ test_expect_success 'git-show a large file' '
 
 test_expect_success 'index-pack' '
        git clone file://"$(pwd)"/.git foo &&
-       GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack
+       GIT_DIR=non-existent git index-pack --object-format=$(test_oid algo) \
+               --strict --verify foo/.git/objects/pack/*.pack
 '
 
 test_expect_success 'repack' '
index ce4cff13bbced58add641a463321f36673121fd7..d60c042ce88b5306b8c32f6b3d928338f6720168 100755 (executable)
@@ -8,6 +8,10 @@ test_description='Test repository version check'
 . ./test-lib.sh
 
 test_expect_success 'setup' '
+       test_oid_cache <<-\EOF &&
+       version sha1:0
+       version sha256:1
+       EOF
        cat >test.patch <<-\EOF &&
        diff --git a/test.txt b/test.txt
        new file mode 100644
@@ -23,7 +27,7 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'gitdir selection on normal repos' '
-       echo 0 >expect &&
+       echo $(test_oid version) >expect &&
        git config core.repositoryformatversion >actual &&
        git -C test config core.repositoryformatversion >actual2 &&
        test_cmp expect actual &&
diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh
new file mode 100755 (executable)
index 0000000..da58d86
--- /dev/null
@@ -0,0 +1,109 @@
+#!/bin/sh
+
+test_description='reference transaction hooks'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       mkdir -p .git/hooks &&
+       test_commit PRE &&
+       test_commit POST &&
+       POST_OID=$(git rev-parse POST)
+'
+
+test_expect_success 'hook allows updating ref if successful' '
+       test_when_finished "rm .git/hooks/reference-transaction" &&
+       git reset --hard PRE &&
+       write_script .git/hooks/reference-transaction <<-\EOF &&
+               echo "$*" >>actual
+       EOF
+       cat >expect <<-EOF &&
+               prepared
+               committed
+       EOF
+       git update-ref HEAD POST &&
+       test_cmp expect actual
+'
+
+test_expect_success 'hook aborts updating ref in prepared state' '
+       test_when_finished "rm .git/hooks/reference-transaction" &&
+       git reset --hard PRE &&
+       write_script .git/hooks/reference-transaction <<-\EOF &&
+               if test "$1" = prepared
+               then
+                       exit 1
+               fi
+       EOF
+       test_must_fail git update-ref HEAD POST 2>err &&
+       test_i18ngrep "ref updates aborted by hook" err
+'
+
+test_expect_success 'hook gets all queued updates in prepared state' '
+       test_when_finished "rm .git/hooks/reference-transaction actual" &&
+       git reset --hard PRE &&
+       write_script .git/hooks/reference-transaction <<-\EOF &&
+               if test "$1" = prepared
+               then
+                       while read -r line
+                       do
+                               printf "%s\n" "$line"
+                       done >actual
+               fi
+       EOF
+       cat >expect <<-EOF &&
+               $ZERO_OID $POST_OID HEAD
+               $ZERO_OID $POST_OID refs/heads/master
+       EOF
+       git update-ref HEAD POST <<-EOF &&
+               update HEAD $ZERO_OID $POST_OID
+               update refs/heads/master $ZERO_OID $POST_OID
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'hook gets all queued updates in committed state' '
+       test_when_finished "rm .git/hooks/reference-transaction actual" &&
+       git reset --hard PRE &&
+       write_script .git/hooks/reference-transaction <<-\EOF &&
+               if test "$1" = committed
+               then
+                       while read -r line
+                       do
+                               printf "%s\n" "$line"
+                       done >actual
+               fi
+       EOF
+       cat >expect <<-EOF &&
+               $ZERO_OID $POST_OID HEAD
+               $ZERO_OID $POST_OID refs/heads/master
+       EOF
+       git update-ref HEAD POST &&
+       test_cmp expect actual
+'
+
+test_expect_success 'hook gets all queued updates in aborted state' '
+       test_when_finished "rm .git/hooks/reference-transaction actual" &&
+       git reset --hard PRE &&
+       write_script .git/hooks/reference-transaction <<-\EOF &&
+               if test "$1" = aborted
+               then
+                       while read -r line
+                       do
+                               printf "%s\n" "$line"
+                       done >actual
+               fi
+       EOF
+       cat >expect <<-EOF &&
+               $ZERO_OID $POST_OID HEAD
+               $ZERO_OID $POST_OID refs/heads/master
+       EOF
+       git update-ref --stdin <<-EOF &&
+               start
+               update HEAD POST $ZERO_OID
+               update refs/heads/master POST $ZERO_OID
+               abort
+       EOF
+       test_cmp expect actual
+'
+
+test_done
index dfc0d96d8a8a834743781a08a8ea1c5f9dd63bda..f213aa8053807882e7312a5b9cb8efd252dfae35 100755 (executable)
@@ -137,7 +137,7 @@ test_expect_success 'merge my-side@{u} records the correct name' '
        git branch -t new my-side@{u} &&
        git merge -s ours new@{u} &&
        git show -s --pretty=tformat:%s >actual &&
-       echo "Merge remote-tracking branch ${SQ}origin/side${SQ}" >expect &&
+       echo "Merge remote-tracking branch ${SQ}origin/side${SQ} into master" >expect &&
        test_cmp expect actual
 )
 '
index 8f86b5f4b298f8297d68030f6ff1e51eb0311bf1..b2bdd1fcb425a14a12df9fe896269e5f9c349434 100755 (executable)
@@ -68,8 +68,8 @@ test_submodule_switch_recursing_with_args "checkout"
 
 test_submodule_forced_switch_recursing_with_args "checkout -f"
 
-test_submodule_switch "git checkout"
+test_submodule_switch "checkout"
 
-test_submodule_forced_switch "git checkout -f"
+test_submodule_forced_switch "checkout -f"
 
 test_done
index 8a5d55054f2b7be55ee7eaefd6d9cfac5c344de0..cf0175ad6e414e3a126a205d56a9d910ec173641 100755 (executable)
@@ -240,7 +240,6 @@ test_expect_success 'i-t-a files shown as new for "diff", "diff-files"; not-new
 
        hash_e=$(git hash-object empty) &&
        hash_n=$(git hash-object not-empty) &&
-       hash_t=$(git hash-object -t tree /dev/null) &&
 
        cat >expect.diff_p <<-EOF &&
        diff --git a/empty b/empty
@@ -259,8 +258,8 @@ test_expect_success 'i-t-a files shown as new for "diff", "diff-files"; not-new
         create mode 100644 not-empty
        EOF
        cat >expect.diff_a <<-EOF &&
-       :000000 100644 0000000 $(git rev-parse --short $hash_t) A$(printf "\t")empty
-       :000000 100644 0000000 $(git rev-parse --short $hash_t) A$(printf "\t")not-empty
+       :000000 100644 0000000 0000000 A$(printf "\t")empty
+       :000000 100644 0000000 0000000 A$(printf "\t")not-empty
        EOF
 
        git add -N empty not-empty &&
index 1fd03cae809b767a128b3e772797d9e76c15263e..b6aa04bbec550ef31f85d70104abf974ea64fd0e 100755 (executable)
@@ -402,7 +402,7 @@ EOF
 
 mv .git/config .git/config-saved
 
-test_expect_success 'git branch -m q q2 without config should succeed' '
+test_expect_success SHA1 'git branch -m q q2 without config should succeed' '
        git branch -m q q2 &&
        git branch -m q2 q
 '
index a2bba04ba96cb5e16dfbecf3f0d6180e150a7ec0..0ad3a07bf470939a8fa53f38e83fa609f2d7371f 100755 (executable)
@@ -17,10 +17,11 @@ git_rebase () {
        git status -su >actual &&
        ls -1pR * >>actual &&
        test_cmp expect actual &&
-       git rebase "$1"
+       may_only_be_test_must_fail "$2" &&
+       $2 git rebase "$1"
 }
 
-test_submodule_switch "git_rebase"
+test_submodule_switch_func "git_rebase"
 
 git_rebase_interactive () {
        git status -su >expect &&
@@ -35,10 +36,11 @@ git_rebase_interactive () {
        test_cmp expect actual &&
        set_fake_editor &&
        echo "fake-editor.sh" >.git/info/exclude &&
-       git rebase -i "$1"
+       may_only_be_test_must_fail "$2" &&
+       $2 git rebase -i "$1"
 }
 
-test_submodule_switch "git_rebase_interactive"
+test_submodule_switch_func "git_rebase_interactive"
 
 test_expect_success 'rebase interactive ignores modified submodules' '
        test_when_finished "rm -rf super sub" &&
index bd78287841ee053fd56a44a268f8077a222cc266..6ece1d85736ade855d661a7e34d687e6a85d656b 100755 (executable)
@@ -7,7 +7,7 @@ test_description='cherry-pick can handle submodules'
 
 KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
 KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
-test_submodule_switch "git cherry-pick"
+test_submodule_switch "cherry-pick"
 
 test_expect_success 'unrelated submodule/file conflict is ignored' '
        test_create_repo sub &&
index 5e39fcdb66c0c7c4b112c1bbe941d886db237693..a759f12cbb1d6b7676d639806cdbe94e1cc201ac 100755 (executable)
@@ -15,7 +15,12 @@ git_revert () {
        git status -su >expect &&
        ls -1pR * >>expect &&
        tar cf "$TRASH_DIRECTORY/tmp.tar" * &&
-       git checkout "$1" &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git checkout "$1" &&
+       if test -n "$2"
+       then
+               return
+       fi &&
        git revert HEAD &&
        rm -rf * &&
        tar xf "$TRASH_DIRECTORY/tmp.tar" &&
@@ -26,6 +31,6 @@ git_revert () {
 }
 
 KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
-test_submodule_switch "git_revert"
+test_submodule_switch_func "git_revert"
 
 test_done
index b93d1d74da7b41c51ba483fc015ac56f13799341..a52e53dd2da481e3c24a82d9599a58c0d1c5ab43 100755 (executable)
@@ -8,7 +8,12 @@ test_description='stash can handle submodules'
 git_stash () {
        git status -su >expect &&
        ls -1pR * >>expect &&
-       git read-tree -u -m "$1" &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git read-tree -u -m "$1" &&
+       if test -n "$2"
+       then
+               return
+       fi &&
        git stash &&
        git status -su >actual &&
        ls -1pR * >>actual &&
@@ -19,7 +24,7 @@ git_stash () {
 KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1
 KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1
 KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
-test_submodule_switch "git_stash"
+test_submodule_switch_func "git_stash"
 
 setup_basic () {
        test_when_finished "rm -rf main sub" &&
index 3f60f7d96ce1998cd977751158c09cadfd926d15..43267d6024fb70110634314d664a885ea477053c 100755 (executable)
@@ -117,12 +117,12 @@ test_expect_success setup '
 
 : <<\EOF
 ! [initial] Initial
- * [master] Merge branch 'side'
+ * [master] Merge branch 'side' into master
   ! [rearrange] Rearranged lines in dir/sub
    ! [side] Side
 ----
   +  [rearrange] Rearranged lines in dir/sub
- -   [master] Merge branch 'side'
+ -   [master] Merge branch 'side' into master
  * + [side] Side
  *   [master^] Third
  *   [master~2] Second
index 3f9b872eceb734cb1e7adbd53a4de0580b1cd524..c56783b9854f2e4734403444d09bcb36a24bc374 100644 (file)
@@ -31,7 +31,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
 Author: A U Thor <author@example.com>
index f5e20e1e14aaef179ac9570b0e16bc47077ff79d..1cbdc038f41c84cba220782ab10ae1857b9bc717 100644 (file)
@@ -31,7 +31,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)
 Author: A U Thor <author@example.com>
index a18f1472a9a4b5b098a2c342a9f77fc68a3b6dc0..f5b1b6516b90744b5d3270f19505bcd9bdeb7372 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index ae425c4672200ad73cb2db228bd7385757673ee3..af23803cdcd8f59936270fda5c93373616d45afd 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index d5207cadf4483a7e63b6085a9007623c73b1a694..814098fbf875dfa2e33170e3e594ce485203a9cf 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index 0fc1e8cd71fee38125e77487da29c12c5863a054..b927fe4a98e43ce3fff8fdd8da4623026f49bb02 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
  dir/sub | 2 ++
  file0   | 3 +++
index dffc09dde9e03179f48cea86e04aac34f1d30504..6db3cea32952fb83b6fe68d8f334a3430885be63 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index 55aa98012dece9e96d1092f442b6235d420ca42f..98e9c320c32dea3c152c70fa4ad4a240ad46f746 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index 019d85f7de6c2d360ae2f9addd65bacd9bee318b..b61b1117ae58f7a33d8313a4bb11a4c797dadfe5 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
  dir/sub | 2 ++
  file0   | 3 +++
index b42c334439b71cdb391d832d498b90a22aad2656..345bd9e8a905e1a987853e014bb4124c6342c4dc 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index e8f46159da1e5ca68524f5657010d06667a9c94b..db56b1fe6b27613983b46d39d0b5bd29c59f9bdc 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index 7a0073f5296b19fde379a37b7441de29bcf07a42..bcadb50e26d000bcb02737ee234db03df7d0e9e2 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --git a/dir/sub b/dir/sub
 index cead32e..992913c 100644
index 9ca62a01ed2bea737d66e08126f6c47ef3b768fe..2acf43a9fbe113033cd46d526ff3a819f6b5d102 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --git a/dir/sub b/dir/sub
 index cead32e..992913c 100644
@@ -33,7 +33,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --git a/dir/sub b/dir/sub
 index 7289e35..992913c 100644
index 3fc896d424f9471aa793cd6e9e0dda41264acb9b..c6a5876d8000b7a1f71fcb927ec08964d0470985 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
 Author: A U Thor <author@example.com>
index bf1326dc36629096fc4e4102375c8a9c550391aa..1841cded94fdf7c33994b622d3bde5687bd020dd 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index a8f6ce5abd642e51672eb3e0ae5ea66a08aa74d2..f8ec445eb3ee7cb642e85a73faaf97988ebc484b 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
 Author: A U Thor <author@example.com>
index 3dcbe473a0d2a7ac0b7f4243b610cff756d44759..94548f4598508f45e298e0ce07ef8146c6cfe256 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --git a/dir/sub b/dir/sub
 index cead32e..992913c 100644
index 81aba8da96c05d1b4717bc12b8bfd271d2bdc9bd..1c46ed64fd65631929b064c7b6f16cb452f0c93f 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --combined dir/sub
 index cead32e,7289e35..992913c
index 4ea2ee453d5e18bef87477cb8758e6fcaef0f011..7559fc22f804077bf4b733e2421b2078d02147e4 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --git a/dir/sub b/dir/sub
 index cead32e..992913c 100644
@@ -33,7 +33,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --git a/dir/sub b/dir/sub
 index 7289e35..992913c 100644
index fb08ce0e46d16d223269754295cc4a8dc4364268..57091c5d90d03981b82eff6d8a13ebbc9df14c64 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
index 30aae7817b952d1088c872453a6a38a681fcd946..5f13a71bb53d5ee31c97ce527d3e8744cde57169 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
  dir/sub | 2 ++
  file0   | 3 +++
index d1d32bd34c333411661355685368130faec79764..8acb88267b2f520179042e83ba52ed635b82afcf 100644 (file)
@@ -4,7 +4,7 @@ Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
 
-    Merge branch 'side'
+    Merge branch 'side' into master
 
  dir/sub | 2 ++
  file0   | 3 +++
index a9bd40a6d04398234fafb1dda919872a0a33591d..07d52625375d4bec97db0a14d74a4fd154681b5e 100755 (executable)
@@ -6,15 +6,19 @@ test_description='git apply handling submodules'
 . "$TEST_DIRECTORY"/lib-submodule-update.sh
 
 apply_index () {
-       git diff --ignore-submodules=dirty "..$1" | git apply --index -
+       git diff --ignore-submodules=dirty "..$1" >diff &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git apply --index diff
 }
 
-test_submodule_switch "apply_index"
+test_submodule_switch_func "apply_index"
 
 apply_3way () {
-       git diff --ignore-submodules=dirty "..$1" | git apply --3way -
+       git diff --ignore-submodules=dirty "..$1" >diff &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git apply --3way diff
 }
 
-test_submodule_switch "apply_3way"
+test_submodule_switch_func "apply_3way"
 
 test_done
index a0930599aaa5b18915792c68c3f84b4b184bb27c..fd9af658af20a8fc7de4836c57c0dad455d59e2b 100755 (executable)
@@ -483,7 +483,7 @@ test_expect_success 'set up merge history' '
 '
 
 cat > expect <<\EOF
-*   Merge branch 'side'
+*   Merge branch 'side' into master
 |\
 | * side-2
 | * side-1
@@ -502,7 +502,7 @@ test_expect_success 'log --graph with merge' '
 '
 
 cat > expect <<\EOF
-| | | *   Merge branch 'side'
+| | | *   Merge branch 'side' into master
 | | | |\
 | | | | * side-2
 | | | | * side-1
@@ -521,7 +521,7 @@ test_expect_success 'log --graph --line-prefix="| | | " with merge' '
 '
 
 cat > expect.colors <<\EOF
-*   Merge branch 'side'
+*   Merge branch 'side' into master
 <BLUE>|<RESET><CYAN>\<RESET>
 <BLUE>|<RESET> * side-2
 <BLUE>|<RESET> * side-1
@@ -555,7 +555,7 @@ cat > expect <<\EOF
 |\  Merge: A B
 | | Author: A U Thor <author@example.com>
 | |
-| |     Merge branch 'side'
+| |     Merge branch 'side' into master
 | |
 | * commit tags/side-2
 | | Author: A U Thor <author@example.com>
@@ -632,11 +632,11 @@ test_expect_success 'set up more tangled history' '
 '
 
 cat > expect <<\EOF
-*   Merge tag 'reach'
+*   Merge tag 'reach' into master
 |\
 | \
 |  \
-*-. \   Merge tags 'octopus-a' and 'octopus-b'
+*-. \   Merge tags 'octopus-a' and 'octopus-b' into master
 |\ \ \
 * | | | seventh
 | | * | octopus-b
@@ -646,14 +646,14 @@ cat > expect <<\EOF
 |/ /
 | * reach
 |/
-*   Merge branch 'tangle'
+*   Merge branch 'tangle' into master
 |\
 | *   Merge branch 'side' (early part) into tangle
 | |\
 | * \   Merge branch 'master' (early part) into tangle
 | |\ \
 | * | | tangle-a
-* | | |   Merge branch 'side'
+* | | |   Merge branch 'side' into master
 |\ \ \ \
 | * | | | side-2
 | | |_|/
@@ -735,16 +735,16 @@ test_expect_success 'log.decorate configuration' '
 
 test_expect_success 'decorate-refs with glob' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh
        octopus-b (octopus-b)
        octopus-a (octopus-a)
        reach
        EOF
        cat >expect.no-decorate <<-\EOF &&
-       Merge-tag-reach
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh
        octopus-b
        octopus-a
@@ -765,8 +765,8 @@ test_expect_success 'decorate-refs with glob' '
 
 test_expect_success 'decorate-refs without globs' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh
        octopus-b
        octopus-a
@@ -779,8 +779,8 @@ test_expect_success 'decorate-refs without globs' '
 
 test_expect_success 'multiple decorate-refs' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh
        octopus-b (octopus-b)
        octopus-a (octopus-a)
@@ -794,8 +794,8 @@ test_expect_success 'multiple decorate-refs' '
 
 test_expect_success 'decorate-refs-exclude with glob' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach (HEAD -> master)
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master (HEAD -> master)
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh (tag: seventh)
        octopus-b (tag: octopus-b)
        octopus-a (tag: octopus-a)
@@ -811,8 +811,8 @@ test_expect_success 'decorate-refs-exclude with glob' '
 
 test_expect_success 'decorate-refs-exclude without globs' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach (HEAD -> master)
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master (HEAD -> master)
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh (tag: seventh)
        octopus-b (tag: octopus-b, octopus-b)
        octopus-a (tag: octopus-a, octopus-a)
@@ -828,8 +828,8 @@ test_expect_success 'decorate-refs-exclude without globs' '
 
 test_expect_success 'multiple decorate-refs-exclude' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach (HEAD -> master)
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master (HEAD -> master)
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh (tag: seventh)
        octopus-b (tag: octopus-b)
        octopus-a (tag: octopus-a)
@@ -851,8 +851,8 @@ test_expect_success 'multiple decorate-refs-exclude' '
 
 test_expect_success 'decorate-refs and decorate-refs-exclude' '
        cat >expect.no-decorate <<-\EOF &&
-       Merge-tag-reach (master)
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master (master)
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh
        octopus-b
        octopus-a
@@ -866,8 +866,8 @@ test_expect_success 'decorate-refs and decorate-refs-exclude' '
 
 test_expect_success 'deocrate-refs and log.excludeDecoration' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach (master)
-       Merge-tags-octopus-a-and-octopus-b
+       Merge-tag-reach-into-master (master)
+       Merge-tags-octopus-a-and-octopus-b-into-master
        seventh
        octopus-b (octopus-b)
        octopus-a (octopus-a)
@@ -881,10 +881,10 @@ test_expect_success 'deocrate-refs and log.excludeDecoration' '
 
 test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '
        cat >expect.decorate <<-\EOF &&
-       Merge-tag-reach (HEAD -> master)
+       Merge-tag-reach-into-master (HEAD -> master)
        reach (tag: reach, reach)
        seventh (tag: seventh)
-       Merge-branch-tangle
+       Merge-branch-tangle-into-master
        Merge-branch-side-early-part-into-tangle (tangle)
        tangle-a (tag: tangle-a)
        EOF
@@ -1068,7 +1068,7 @@ cat >expect <<\EOF
 |\  Merge: MERGE_PARENTS
 | | Author: A U Thor <author@example.com>
 | |
-| |     Merge branch 'tangle'
+| |     Merge branch 'tangle' into master
 | |
 | *   commit COMMIT_OBJECT_NAME
 | |\  Merge: MERGE_PARENTS
@@ -1102,7 +1102,7 @@ cat >expect <<\EOF
 |\ \ \ \  Merge: MERGE_PARENTS
 | | | | | Author: A U Thor <author@example.com>
 | | | | |
-| | | | |     Merge branch 'side'
+| | | | |     Merge branch 'side' into master
 | | | | |
 | * | | | commit COMMIT_OBJECT_NAME
 | | |_|/  Author: A U Thor <author@example.com>
@@ -1343,7 +1343,7 @@ cat >expect <<\EOF
 *** |\  Merge: MERGE_PARENTS
 *** | | Author: A U Thor <author@example.com>
 *** | |
-*** | |     Merge branch 'tangle'
+*** | |     Merge branch 'tangle' into master
 *** | |
 *** | *   commit COMMIT_OBJECT_NAME
 *** | |\  Merge: MERGE_PARENTS
@@ -1377,7 +1377,7 @@ cat >expect <<\EOF
 *** |\ \ \ \  Merge: MERGE_PARENTS
 *** | | | | | Author: A U Thor <author@example.com>
 *** | | | | |
-*** | | | | |     Merge branch 'side'
+*** | | | | |     Merge branch 'side' into master
 *** | | | | |
 *** | * | | | commit COMMIT_OBJECT_NAME
 *** | | |_|/  Author: A U Thor <author@example.com>
@@ -1540,8 +1540,8 @@ cat >expect <<-\EOF
 * reach
 |
 | A    reach.t
-* Merge branch 'tangle'
-*   Merge branch 'side'
+* Merge branch 'tangle' into master
+*   Merge branch 'side' into master
 |\
 | * side-2
 |
@@ -1562,8 +1562,8 @@ cat >expect <<-\EOF
 * reach
 |
 | reach.t
-* Merge branch 'tangle'
-*   Merge branch 'side'
+* Merge branch 'tangle' into master
+*   Merge branch 'side' into master
 |\
 | * side-2
 |
index 0ba8194403f6740807cbd63d1bda8a69091e3d6b..a7ba08f728c0b870bf899ee82220a1708699dcb0 100755 (executable)
@@ -6,17 +6,21 @@ test_description='git am handling submodules'
 . "$TEST_DIRECTORY"/lib-submodule-update.sh
 
 am () {
-       git format-patch --stdout --ignore-submodules=dirty "..$1" | git am -
+       git format-patch --stdout --ignore-submodules=dirty "..$1" >patch &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git am patch
 }
 
-test_submodule_switch "am"
+test_submodule_switch_func "am"
 
 am_3way () {
-       git format-patch --stdout --ignore-submodules=dirty "..$1" | git am --3way -
+       git format-patch --stdout --ignore-submodules=dirty "..$1" >patch &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git am --3way patch
 }
 
 KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
-test_submodule_switch "am_3way"
+test_submodule_switch_func "am_3way"
 
 test_expect_success 'setup diff.submodule' '
        test_commit one &&
index 410a09b0dd756c90b8a47dbfc9c0e7ee048e4557..746cdb626e293f840a9e3f910ec5d421a67fb9ca 100755 (executable)
@@ -12,7 +12,8 @@ TRASH=$(pwd)
 
 test_expect_success \
     'setup' \
-    'rm -f .git/index* &&
+    'test_oid_init &&
+     rm -f .git/index* &&
      perl -e "print \"a\" x 4096;" > a &&
      perl -e "print \"b\" x 4096;" > b &&
      perl -e "print \"c\" x 4096;" > c &&
@@ -412,18 +413,18 @@ test_expect_success 'set up pack for non-repo tests' '
 '
 
 test_expect_success 'index-pack --stdin complains of non-repo' '
-       nongit test_must_fail git index-pack --stdin <foo.pack &&
+       nongit test_must_fail git index-pack --object-format=$(test_oid algo) --stdin <foo.pack &&
        test_path_is_missing non-repo/.git
 '
 
 test_expect_success 'index-pack <pack> works in non-repo' '
-       nongit git index-pack ../foo.pack &&
+       nongit git index-pack --object-format=$(test_oid algo) ../foo.pack &&
        test_path_is_file foo.idx
 '
 
 test_expect_success 'index-pack --strict <pack> works in non-repo' '
        rm -f foo.idx &&
-       nongit git index-pack --strict ../foo.pack &&
+       nongit git index-pack --strict --object-format=$(test_oid algo) ../foo.pack &&
        test_path_is_file foo.idx
 '
 
index ad07f2f7fc268d66df10c5484f0a14f7bafec643..8981c9b90ebe1512c22402dd32308f0415708f21 100755 (executable)
@@ -7,65 +7,65 @@ test_description='pack index with 64-bit offsets and object CRC'
 . ./test-lib.sh
 
 test_expect_success 'setup' '
-     test_oid_init &&
-     rawsz=$(test_oid rawsz) &&
-     rm -rf .git &&
-     git init &&
-     git config pack.threads 1 &&
-     i=1 &&
-     while test $i -le 100
-     do
-         iii=$(printf '%03i' $i)
-        test-tool genrandom "bar" 200 > wide_delta_$iii &&
-        test-tool genrandom "baz $iii" 50 >> wide_delta_$iii &&
-        test-tool genrandom "foo"$i 100 > deep_delta_$iii &&
-        test-tool genrandom "foo"$(expr $i + 1) 100 >> deep_delta_$iii &&
-        test-tool genrandom "foo"$(expr $i + 2) 100 >> deep_delta_$iii &&
-         echo $iii >file_$iii &&
-        test-tool genrandom "$iii" 8192 >>file_$iii &&
-         git update-index --add file_$iii deep_delta_$iii wide_delta_$iii &&
-         i=$(expr $i + 1) || return 1
-     done &&
-     { echo 101 && test-tool genrandom 100 8192; } >file_101 &&
-     git update-index --add file_101 &&
-     tree=$(git write-tree) &&
-     commit=$(git commit-tree $tree </dev/null) && {
-        echo $tree &&
-        git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\)       .*/\\1/"
-     } >obj-list &&
-     git update-ref HEAD $commit
+       test_oid_init &&
+       rawsz=$(test_oid rawsz) &&
+       rm -rf .git &&
+       git init &&
+       git config pack.threads 1 &&
+       i=1 &&
+       while test $i -le 100
+       do
+               iii=$(printf '%03i' $i)
+               test-tool genrandom "bar" 200 > wide_delta_$iii &&
+               test-tool genrandom "baz $iii" 50 >> wide_delta_$iii &&
+               test-tool genrandom "foo"$i 100 > deep_delta_$iii &&
+               test-tool genrandom "foo"$(expr $i + 1) 100 >> deep_delta_$iii &&
+               test-tool genrandom "foo"$(expr $i + 2) 100 >> deep_delta_$iii &&
+               echo $iii >file_$iii &&
+               test-tool genrandom "$iii" 8192 >>file_$iii &&
+               git update-index --add file_$iii deep_delta_$iii wide_delta_$iii &&
+               i=$(expr $i + 1) || return 1
+       done &&
+       { echo 101 && test-tool genrandom 100 8192; } >file_101 &&
+       git update-index --add file_101 &&
+       tree=$(git write-tree) &&
+       commit=$(git commit-tree $tree </dev/null) && {
+               echo $tree &&
+               git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\)        .*/\\1/"
+       } >obj-list &&
+       git update-ref HEAD $commit
 '
 
-test_expect_success \
-    'pack-objects with index version 1' \
-    'pack1=$(git pack-objects --index-version=1 test-1 <obj-list) &&
-     git verify-pack -v "test-1-${pack1}.pack"'
+test_expect_success 'pack-objects with index version 1' '
+       pack1=$(git pack-objects --index-version=1 test-1 <obj-list) &&
+       git verify-pack -v "test-1-${pack1}.pack"
+'
 
-test_expect_success \
-    'pack-objects with index version 2' \
-    'pack2=$(git pack-objects --index-version=2 test-2 <obj-list) &&
-     git verify-pack -v "test-2-${pack2}.pack"'
+test_expect_success 'pack-objects with index version 2' '
+       pack2=$(git pack-objects --index-version=2 test-2 <obj-list) &&
+       git verify-pack -v "test-2-${pack2}.pack"
+'
 
-test_expect_success \
-    'both packs should be identical' \
-    'cmp "test-1-${pack1}.pack" "test-2-${pack2}.pack"'
+test_expect_success 'both packs should be identical' '
+       cmp "test-1-${pack1}.pack" "test-2-${pack2}.pack"
+'
 
-test_expect_success \
-    'index v1 and index v2 should be different' \
-    '! cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx"'
+test_expect_success 'index v1 and index v2 should be different' '
+       ! cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx"
+'
 
-test_expect_success \
-    'index-pack with index version 1' \
-    'git index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack"'
+test_expect_success 'index-pack with index version 1' '
+       git index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack"
+'
 
-test_expect_success \
-    'index-pack with index version 2' \
-    'git index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack"'
+test_expect_success 'index-pack with index version 2' '
+       git index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack"
+'
 
-test_expect_success \
-    'index-pack results should match pack-objects ones' \
-    'cmp "test-1-${pack1}.idx" "1.idx" &&
-     cmp "test-2-${pack2}.idx" "2.idx"'
+test_expect_success 'index-pack results should match pack-objects ones' '
+       cmp "test-1-${pack1}.idx" "1.idx" &&
+       cmp "test-2-${pack2}.idx" "2.idx"
+'
 
 test_expect_success 'index-pack --verify on index version 1' '
        git index-pack --verify "test-1-${pack1}.pack"
@@ -75,13 +75,13 @@ test_expect_success 'index-pack --verify on index version 2' '
        git index-pack --verify "test-2-${pack2}.pack"
 '
 
-test_expect_success \
-    'pack-objects --index-version=2, is not accepted' \
-    'test_must_fail git pack-objects --index-version=2, test-3 <obj-list'
+test_expect_success 'pack-objects --index-version=2, is not accepted' '
+       test_must_fail git pack-objects --index-version=2, test-3 <obj-list
+'
 
-test_expect_success \
-    'index v2: force some 64-bit offsets with pack-objects' \
-    'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)'
+test_expect_success 'index v2: force some 64-bit offsets with pack-objects' '
+       pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)
+'
 
 if msg=$(git verify-pack -v "test-3-${pack3}.pack" 2>&1) ||
        ! (echo "$msg" | grep "pack too large .* off_t")
@@ -91,21 +91,21 @@ else
        say "# skipping tests concerning 64-bit offsets"
 fi
 
-test_expect_success OFF64_T \
-    'index v2: verify a pack with some 64-bit offsets' \
-    'git verify-pack -v "test-3-${pack3}.pack"'
+test_expect_success OFF64_T 'index v2: verify a pack with some 64-bit offsets' '
+       git verify-pack -v "test-3-${pack3}.pack"
+'
 
-test_expect_success OFF64_T \
-    '64-bit offsets: should be different from previous index v2 results' \
-    '! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"'
+test_expect_success OFF64_T '64-bit offsets: should be different from previous index v2 results' '
+       ! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"
+'
 
-test_expect_success OFF64_T \
-    'index v2: force some 64-bit offsets with index-pack' \
-    'git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"'
+test_expect_success OFF64_T 'index v2: force some 64-bit offsets with index-pack' '
+       git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"
+'
 
-test_expect_success OFF64_T \
-    '64-bit offsets: index-pack result should match pack-objects one' \
-    'cmp "test-3-${pack3}.idx" "3.idx"'
+test_expect_success OFF64_T '64-bit offsets: index-pack result should match pack-objects one' '
+       cmp "test-3-${pack3}.idx" "3.idx"
+'
 
 test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2 (cheat)' '
        # This cheats by knowing which lower offset should still be encoded
@@ -120,135 +120,143 @@ test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2' '
 # returns the object number for given object in given pack index
 index_obj_nr()
 {
-    idx_file=$1
-    object_sha1=$2
-    nr=0
-    git show-index < $idx_file |
-    while read offs sha1 extra
-    do
-      nr=$(($nr + 1))
-      test "$sha1" = "$object_sha1" || continue
-      echo "$(($nr - 1))"
-      break
-    done
+       idx_file=$1
+       object_sha1=$2
+       nr=0
+       git show-index < $idx_file |
+       while read offs sha1 extra
+       do
+         nr=$(($nr + 1))
+         test "$sha1" = "$object_sha1" || continue
+         echo "$(($nr - 1))"
+         break
+       done
 }
 
 # returns the pack offset for given object as found in given pack index
 index_obj_offset()
 {
-    idx_file=$1
-    object_sha1=$2
-    git show-index < $idx_file | grep $object_sha1 |
-    ( read offs extra && echo "$offs" )
+       idx_file=$1
+       object_sha1=$2
+       git show-index < $idx_file | grep $object_sha1 |
+       ( read offs extra && echo "$offs" )
 }
 
-test_expect_success \
-    '[index v1] 1) stream pack to repository' \
-    'git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" &&
-     git prune-packed &&
-     git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
-     cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
-     cmp "test-1-${pack1}.idx"  ".git/objects/pack/pack-${pack1}.idx"'
+test_expect_success '[index v1] 1) stream pack to repository' '
+       git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" &&
+       git prune-packed &&
+       git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
+       cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
+       cmp "test-1-${pack1}.idx"       ".git/objects/pack/pack-${pack1}.idx"
+'
 
 test_expect_success \
-    '[index v1] 2) create a stealth corruption in a delta base reference' \
-    '# This test assumes file_101 is a delta smaller than 16 bytes.
-     # It should be against file_100 but we substitute its base for file_099
-     sha1_101=$(git hash-object file_101) &&
-     sha1_099=$(git hash-object file_099) &&
-     offs_101=$(index_obj_offset 1.idx $sha1_101) &&
-     nr_099=$(index_obj_nr 1.idx $sha1_099) &&
-     chmod +w ".git/objects/pack/pack-${pack1}.pack" &&
-     recordsz=$((rawsz + 4)) &&
-     dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \
-        if=".git/objects/pack/pack-${pack1}.idx" \
-        skip=$((4 + 256 * 4 + $nr_099 * recordsz)) \
-        bs=1 count=$rawsz conv=notrunc &&
-     git cat-file blob $sha1_101 > file_101_foo1'
+       '[index v1] 2) create a stealth corruption in a delta base reference' '
+       # This test assumes file_101 is a delta smaller than 16 bytes.
+       # It should be against file_100 but we substitute its base for file_099
+       sha1_101=$(git hash-object file_101) &&
+       sha1_099=$(git hash-object file_099) &&
+       offs_101=$(index_obj_offset 1.idx $sha1_101) &&
+       nr_099=$(index_obj_nr 1.idx $sha1_099) &&
+       chmod +w ".git/objects/pack/pack-${pack1}.pack" &&
+       recordsz=$((rawsz + 4)) &&
+       dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \
+              if=".git/objects/pack/pack-${pack1}.idx" \
+              skip=$((4 + 256 * 4 + $nr_099 * recordsz)) \
+              bs=1 count=$rawsz conv=notrunc &&
+       git cat-file blob $sha1_101 > file_101_foo1
+'
 
 test_expect_success \
-    '[index v1] 3) corrupted delta happily returned wrong data' \
-    'test -f file_101_foo1 && ! cmp file_101 file_101_foo1'
+       '[index v1] 3) corrupted delta happily returned wrong data' '
+       test -f file_101_foo1 && ! cmp file_101 file_101_foo1
+'
 
 test_expect_success \
-    '[index v1] 4) confirm that the pack is actually corrupted' \
-    'test_must_fail git fsck --full $commit'
+       '[index v1] 4) confirm that the pack is actually corrupted' '
+       test_must_fail git fsck --full $commit
+'
 
 test_expect_success \
-    '[index v1] 5) pack-objects happily reuses corrupted data' \
-    'pack4=$(git pack-objects test-4 <obj-list) &&
-     test -f "test-4-${pack4}.pack"'
+       '[index v1] 5) pack-objects happily reuses corrupted data' '
+       pack4=$(git pack-objects test-4 <obj-list) &&
+       test -f "test-4-${pack4}.pack"
+'
 
-test_expect_success \
-    '[index v1] 6) newly created pack is BAD !' \
-    'test_must_fail git verify-pack -v "test-4-${pack4}.pack"'
+test_expect_success '[index v1] 6) newly created pack is BAD !' '
+       test_must_fail git verify-pack -v "test-4-${pack4}.pack"
+'
 
-test_expect_success \
-    '[index v2] 1) stream pack to repository' \
-    'rm -f .git/objects/pack/* &&
-     git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
-     git prune-packed &&
-     git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
-     cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
-     cmp "test-2-${pack1}.idx"  ".git/objects/pack/pack-${pack1}.idx"'
+test_expect_success '[index v2] 1) stream pack to repository' '
+       rm -f .git/objects/pack/* &&
+       git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
+       git prune-packed &&
+       git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
+       cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
+       cmp "test-2-${pack1}.idx"       ".git/objects/pack/pack-${pack1}.idx"
+'
 
 test_expect_success \
-    '[index v2] 2) create a stealth corruption in a delta base reference' \
-    '# This test assumes file_101 is a delta smaller than 16 bytes.
-     # It should be against file_100 but we substitute its base for file_099
-     sha1_101=$(git hash-object file_101) &&
-     sha1_099=$(git hash-object file_099) &&
-     offs_101=$(index_obj_offset 1.idx $sha1_101) &&
-     nr_099=$(index_obj_nr 1.idx $sha1_099) &&
-     chmod +w ".git/objects/pack/pack-${pack1}.pack" &&
-     dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \
-        if=".git/objects/pack/pack-${pack1}.idx" \
-        skip=$((8 + 256 * 4 + $nr_099 * rawsz)) \
-        bs=1 count=$rawsz conv=notrunc &&
-     git cat-file blob $sha1_101 > file_101_foo2'
+       '[index v2] 2) create a stealth corruption in a delta base reference' '
+       # This test assumes file_101 is a delta smaller than 16 bytes.
+       # It should be against file_100 but we substitute its base for file_099
+       sha1_101=$(git hash-object file_101) &&
+       sha1_099=$(git hash-object file_099) &&
+       offs_101=$(index_obj_offset 1.idx $sha1_101) &&
+       nr_099=$(index_obj_nr 1.idx $sha1_099) &&
+       chmod +w ".git/objects/pack/pack-${pack1}.pack" &&
+       dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \
+               if=".git/objects/pack/pack-${pack1}.idx" \
+               skip=$((8 + 256 * 4 + $nr_099 * rawsz)) \
+               bs=1 count=$rawsz conv=notrunc &&
+       git cat-file blob $sha1_101 > file_101_foo2
+'
 
 test_expect_success \
-    '[index v2] 3) corrupted delta happily returned wrong data' \
-    'test -f file_101_foo2 && ! cmp file_101 file_101_foo2'
+       '[index v2] 3) corrupted delta happily returned wrong data' '
+       test -f file_101_foo2 && ! cmp file_101 file_101_foo2
+'
 
 test_expect_success \
-    '[index v2] 4) confirm that the pack is actually corrupted' \
-    'test_must_fail git fsck --full $commit'
+       '[index v2] 4) confirm that the pack is actually corrupted' '
+       test_must_fail git fsck --full $commit
+'
 
 test_expect_success \
-    '[index v2] 5) pack-objects refuses to reuse corrupted data' \
-    'test_must_fail git pack-objects test-5 <obj-list &&
-     test_must_fail git pack-objects --no-reuse-object test-6 <obj-list'
+       '[index v2] 5) pack-objects refuses to reuse corrupted data' '
+       test_must_fail git pack-objects test-5 <obj-list &&
+       test_must_fail git pack-objects --no-reuse-object test-6 <obj-list
+'
 
 test_expect_success \
-    '[index v2] 6) verify-pack detects CRC mismatch' \
-    'rm -f .git/objects/pack/* &&
-     git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
-     git verify-pack ".git/objects/pack/pack-${pack1}.pack" &&
-     obj=$(git hash-object file_001) &&
-     nr=$(index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj) &&
-     chmod +w ".git/objects/pack/pack-${pack1}.idx" &&
-     printf xxxx | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \
-        bs=1 count=4 seek=$((8 + 256 * 4 + $(wc -l <obj-list) * rawsz + $nr * 4)) &&
-     ( while read obj
-       do git cat-file -p $obj >/dev/null || exit 1
-       done <obj-list ) &&
-     test_must_fail git verify-pack ".git/objects/pack/pack-${pack1}.pack"
+       '[index v2] 6) verify-pack detects CRC mismatch' '
+       rm -f .git/objects/pack/* &&
+       git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
+       git verify-pack ".git/objects/pack/pack-${pack1}.pack" &&
+       obj=$(git hash-object file_001) &&
+       nr=$(index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj) &&
+       chmod +w ".git/objects/pack/pack-${pack1}.idx" &&
+       printf xxxx | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \
+               bs=1 count=4 seek=$((8 + 256 * 4 + $(wc -l <obj-list) * rawsz + $nr * 4)) &&
+        ( while read obj
+          do git cat-file -p $obj >/dev/null || exit 1
+          done <obj-list ) &&
+       test_must_fail git verify-pack ".git/objects/pack/pack-${pack1}.pack"
 '
 
 test_expect_success 'running index-pack in the object store' '
-    rm -f .git/objects/pack/* &&
-    cp test-1-${pack1}.pack .git/objects/pack/pack-${pack1}.pack &&
-    (
-       cd .git/objects/pack &&
-       git index-pack pack-${pack1}.pack
-    ) &&
-    test -f .git/objects/pack/pack-${pack1}.idx
+       rm -f .git/objects/pack/* &&
+       cp test-1-${pack1}.pack .git/objects/pack/pack-${pack1}.pack &&
+       (
+               cd .git/objects/pack &&
+               git index-pack pack-${pack1}.pack
+       ) &&
+       test -f .git/objects/pack/pack-${pack1}.idx
 '
 
 test_expect_success 'index-pack --strict warns upon missing tagger in tag' '
-    sha=$(git rev-parse HEAD) &&
-    cat >wrong-tag <<EOF &&
+       sha=$(git rev-parse HEAD) &&
+       cat >wrong-tag <<EOF &&
 object $sha
 type commit
 tag guten tag
@@ -256,18 +264,18 @@ tag guten tag
 This is an invalid tag.
 EOF
 
-    tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
-    pack1=$(echo $tag $sha | git pack-objects tag-test) &&
-    echo remove tag object &&
-    thirtyeight=${tag#??} &&
-    rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight &&
-    git index-pack --strict tag-test-${pack1}.pack 2>err &&
-    grep "^warning:.* expected .tagger. line" err
+       tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
+       pack1=$(echo $tag $sha | git pack-objects tag-test) &&
+       echo remove tag object &&
+       thirtyeight=${tag#??} &&
+       rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight &&
+       git index-pack --strict tag-test-${pack1}.pack 2>err &&
+       grep "^warning:.* expected .tagger. line" err
 '
 
 test_expect_success 'index-pack --fsck-objects also warns upon missing tagger in tag' '
-    git index-pack --fsck-objects tag-test-${pack1}.pack 2>err &&
-    grep "^warning:.* expected .tagger. line" err
+       git index-pack --fsck-objects tag-test-${pack1}.pack 2>err &&
+       grep "^warning:.* expected .tagger. line" err
 '
 
 test_done
index 0f5ff2517905246789d780ff53ee00d62a8a67b6..355737431276bd1a8cd23a8439d754fcbd5f3512 100755 (executable)
@@ -871,9 +871,10 @@ test_expect_success 'shallow since with commit graph and already-seen commit' '
 
        GIT_PROTOCOL=version=2 git upload-pack . <<-EOF >/dev/null
        0012command=fetch
+       $(echo "object-format=$(test_oid algo)" | packetize)
        00010013deepen-since 1
-       0032want $(git rev-parse other)
-       0032have $(git rev-parse master)
+       $(echo "want $(git rev-parse other)" | packetize)
+       $(echo "have $(git rev-parse master)" | packetize)
        0000
        EOF
        )
index dda81b7d07a2ee7c5ee24f28f5f8a527a3f187da..8d62edd98b5c87995f5f0697b4b7198c6da58c0d 100755 (executable)
@@ -988,7 +988,7 @@ test_expect_success 'remote set-branches' '
        +refs/heads/maint:refs/remotes/scratch/maint
        +refs/heads/master:refs/remotes/scratch/master
        +refs/heads/next:refs/remotes/scratch/next
-       +refs/heads/pu:refs/remotes/scratch/pu
+       +refs/heads/seen:refs/remotes/scratch/seen
        +refs/heads/t/topic:refs/remotes/scratch/t/topic
        EOF
        sort <<-\EOF >expect.setup-ffonly &&
@@ -998,7 +998,7 @@ test_expect_success 'remote set-branches' '
        sort <<-\EOF >expect.respect-ffonly &&
        refs/heads/master:refs/remotes/scratch/master
        +refs/heads/next:refs/remotes/scratch/next
-       +refs/heads/pu:refs/remotes/scratch/pu
+       +refs/heads/seen:refs/remotes/scratch/seen
        EOF
 
        git clone .git/ setbranches &&
@@ -1016,7 +1016,7 @@ test_expect_success 'remote set-branches' '
                git config --get-all remote.scratch.fetch >config-result &&
                sort <config-result >../actual.replace &&
 
-               git remote set-branches --add scratch pu t/topic &&
+               git remote set-branches --add scratch seen t/topic &&
                git config --get-all remote.scratch.fetch >config-result &&
                sort <config-result >../actual.add-two &&
 
@@ -1028,7 +1028,7 @@ test_expect_success 'remote set-branches' '
                git config --get-all remote.scratch.fetch >config-result &&
                sort <config-result >../actual.setup-ffonly &&
 
-               git remote set-branches --add scratch pu &&
+               git remote set-branches --add scratch seen &&
                git config --get-all remote.scratch.fetch >config-result &&
                sort <config-result >../actual.respect-ffonly
        ) &&
index 9c6218f568ea3bc4c61a1377fc4b2be150b4be1d..36ad20a8491b1a1115e28ea3b20c1070998501a1 100755 (executable)
@@ -747,42 +747,42 @@ test_expect_success 'deletion of a non-existent ref alone does trigger post-rece
 '
 
 test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' '
-       mk_test_with_hooks testrepo heads/master heads/next heads/pu &&
+       mk_test_with_hooks testrepo heads/master heads/next heads/seen &&
        orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
        newmaster=$(git show-ref -s --verify refs/heads/master) &&
        orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
        newnext=$ZERO_OID &&
-       orgpu=$(cd testrepo && git show-ref -s --verify refs/heads/pu) &&
-       newpu=$(git show-ref -s --verify refs/heads/master) &&
+       orgseen=$(cd testrepo && git show-ref -s --verify refs/heads/seen) &&
+       newseen=$(git show-ref -s --verify refs/heads/master) &&
        git push testrepo refs/heads/master:refs/heads/master \
-           refs/heads/master:refs/heads/pu :refs/heads/next \
+           refs/heads/master:refs/heads/seen :refs/heads/next \
            :refs/heads/nonexistent &&
        (
                cd testrepo/.git &&
                cat >pre-receive.expect <<-EOF &&
                $orgmaster $newmaster refs/heads/master
                $orgnext $newnext refs/heads/next
-               $orgpu $newpu refs/heads/pu
+               $orgseen $newseen refs/heads/seen
                $ZERO_OID $ZERO_OID refs/heads/nonexistent
                EOF
 
                cat >update.expect <<-EOF &&
                refs/heads/master $orgmaster $newmaster
                refs/heads/next $orgnext $newnext
-               refs/heads/pu $orgpu $newpu
+               refs/heads/seen $orgseen $newseen
                refs/heads/nonexistent $ZERO_OID $ZERO_OID
                EOF
 
                cat >post-receive.expect <<-EOF &&
                $orgmaster $newmaster refs/heads/master
                $orgnext $newnext refs/heads/next
-               $orgpu $newpu refs/heads/pu
+               $orgseen $newseen refs/heads/seen
                EOF
 
                cat >post-update.expect <<-EOF &&
                refs/heads/master
                refs/heads/next
-               refs/heads/pu
+               refs/heads/seen
                EOF
 
                test_cmp pre-receive.expect pre-receive.actual &&
index 4d1e0c363ea1343738ddeccdfa8ddbd056031f45..f0a287d97dba8e2e72ed50f85d75df91852dab5f 100755 (executable)
@@ -98,6 +98,12 @@ test_expect_success 'push from/to new branch with upstream, matching and simple'
        test_push_failure upstream
 '
 
+test_expect_success '"matching" fails if none match' '
+       git init --bare empty &&
+       test_must_fail git push empty : 2>actual &&
+       test_i18ngrep "Perhaps you should specify a branch" actual
+'
+
 test_expect_success 'push ambiguously named branch with upstream, matching and simple' '
        git checkout -b ambiguous &&
        test_config branch.ambiguous.remote parent1 &&
index d476c335098eef1e61aa8c7b8951fe760e8d13c1..450321fddbbf6aeb90ec8a257fd657d28a32cbf9 100755 (executable)
@@ -126,6 +126,22 @@ test_expect_success 'create and delete remote branch' '
        test_must_fail git show-ref --verify refs/remotes/origin/dev
 '
 
+test_expect_success 'non-force push fails if not up to date' '
+       git init --bare "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo_conflict.git &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo_conflict.git update-server-info &&
+       git clone $HTTPD_URL/dumb/test_repo_conflict.git "$ROOT_PATH"/c1 &&
+       git clone $HTTPD_URL/dumb/test_repo_conflict.git "$ROOT_PATH"/c2 &&
+       test_commit -C "$ROOT_PATH/c1" path1 &&
+       git -C "$ROOT_PATH/c1" push origin HEAD &&
+       git -C "$ROOT_PATH/c2" pull &&
+       test_commit -C "$ROOT_PATH/c1" path2 &&
+       git -C "$ROOT_PATH/c1" push origin HEAD &&
+       test_commit -C "$ROOT_PATH/c2" path3 &&
+       git -C "$ROOT_PATH/c1" log --graph --all &&
+       git -C "$ROOT_PATH/c2" log --graph --all &&
+       test_must_fail git -C "$ROOT_PATH/c2" push origin HEAD
+'
+
 test_expect_success 'MKCOL sends directory names with trailing slashes' '
 
        ! grep "\"MKCOL.*[^/] HTTP/[^ ]*\"" < "$HTTPD_ROOT_PATH"/access.log
index ca2e8af022f0b4749fd4fcd30de93864c780f04a..483578b2d75409798ae2697742fbf728c6383746 100755 (executable)
@@ -50,6 +50,24 @@ test_expect_success 'create password-protected repository' '
               "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
 '
 
+test_expect_success 'create empty remote repository' '
+       git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
+       (cd "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
+        mkdir -p hooks &&
+        write_script "hooks/post-update" <<-\EOF &&
+        exec git update-server-info
+       EOF
+        hooks/post-update
+       )
+'
+
+test_expect_success 'empty dumb HTTP repository has default hash algorithm' '
+       test_when_finished "rm -fr clone-empty" &&
+       git clone $HTTPD_URL/dumb/empty.git clone-empty &&
+       git -C clone-empty rev-parse --show-object-format >empty-format &&
+       test "$(cat empty-format)" = "$(test_oid algo)"
+'
+
 setup_askpass_helper
 
 test_expect_success 'cloning password-protected repository can fail' '
index 3f4ac71f83b571a61c14b5627d843b73cb244f0e..c6ec625497db44eb6a04d8b6a91e3cf99fe86a02 100755 (executable)
@@ -46,6 +46,7 @@ ssize_b100dots() {
 }
 
 test_expect_success 'setup' '
+       test_oid_init &&
        HTTP_CONTENT_ENCODING="identity" &&
        export HTTP_CONTENT_ENCODING &&
        git config http.receivepack true &&
@@ -62,8 +63,8 @@ test_expect_success 'setup' '
        test_copy_bytes 10 <fetch_body >fetch_body.trunc &&
        hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) &&
        {
-               printf "%s %s refs/heads/newbranch\\0report-status\\n" \
-                       "$ZERO_OID" "$hash_next" | packetize &&
+               printf "%s %s refs/heads/newbranch\\0report-status object-format=%s\\n" \
+                       "$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize &&
                printf 0000 &&
                echo "$hash_next" | git pack-objects --stdout
        } >push_body &&
index f916729a12b24b75184144c2eaa9abdbf1c12639..1d75e3b12ba1641d6bad4a8f76e84df9a9bf59f7 100755 (executable)
@@ -13,34 +13,38 @@ reset_branch_to_HEAD () {
 
 git_pull () {
        reset_branch_to_HEAD "$1" &&
-       git pull
+       may_only_be_test_must_fail "$2" &&
+       $2 git pull
 }
 
 # pulls without conflicts
-test_submodule_switch "git_pull"
+test_submodule_switch_func "git_pull"
 
 git_pull_ff () {
        reset_branch_to_HEAD "$1" &&
-       git pull --ff
+       may_only_be_test_must_fail "$2" &&
+       $2 git pull --ff
 }
 
-test_submodule_switch "git_pull_ff"
+test_submodule_switch_func "git_pull_ff"
 
 git_pull_ff_only () {
        reset_branch_to_HEAD "$1" &&
-       git pull --ff-only
+       may_only_be_test_must_fail "$2" &&
+       $2 git pull --ff-only
 }
 
-test_submodule_switch "git_pull_ff_only"
+test_submodule_switch_func "git_pull_ff_only"
 
 git_pull_noff () {
        reset_branch_to_HEAD "$1" &&
-       git pull --no-ff
+       may_only_be_test_must_fail "$2" &&
+       $2 git pull --no-ff
 }
 
 KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
 KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
-test_submodule_switch "git_pull_noff"
+test_submodule_switch_func "git_pull_noff"
 
 test_expect_success 'pull --recurse-submodule setup' '
        test_create_repo child &&
index 9e24ec88e67f0db8be401f2a60f69c408f39fc02..e69427f8817a6e2170ce1175991e8badb0e78ecb 100755 (executable)
@@ -35,4 +35,28 @@ test_expect_success 'redirected clone -v does show progress' '
 
 '
 
+test_expect_success 'chooses correct default initial branch name' '
+       git init --bare empty &&
+       git -c init.defaultBranch=up clone empty whats-up &&
+       test refs/heads/up = $(git -C whats-up symbolic-ref HEAD) &&
+       test refs/heads/up = $(git -C whats-up config branch.up.merge)
+'
+
+test_expect_success 'guesses initial branch name correctly' '
+       git init --initial-branch=guess initial-branch &&
+       test_commit -C initial-branch no-spoilers &&
+       git -C initial-branch branch abc guess &&
+       git clone initial-branch is-it &&
+       test refs/heads/guess = $(git -C is-it symbolic-ref HEAD) &&
+
+       git -c init.defaultBranch=none init --bare no-head &&
+       git -C initial-branch push ../no-head guess abc &&
+       git clone no-head is-it2 &&
+       test_must_fail git -C is-it2 symbolic-ref refs/remotes/origin/HEAD &&
+       git -C no-head update-ref --no-deref HEAD refs/heads/guess &&
+       git -c init.defaultBranch=guess clone no-head is-it3 &&
+       test refs/remotes/origin/guess = \
+               $(git -C is-it3 symbolic-ref refs/remotes/origin/HEAD)
+'
+
 test_done
index ffb9613885904eaf474a726f6124032d13db9753..a1f5fdc9fdcf522706d4ad74230bff3887bbf9f9 100755 (executable)
@@ -5,12 +5,17 @@ test_description='test protocol v2 server commands'
 . ./test-lib.sh
 
 test_expect_success 'test capability advertisement' '
+       test_oid_cache <<-EOF &&
+       wrong_algo sha1:sha256
+       wrong_algo sha256:sha1
+       EOF
        cat >expect <<-EOF &&
        version 2
        agent=git/$(git version | cut -d" " -f3)
        ls-refs
        fetch=shallow
        server-option
+       object-format=$(test_oid algo)
        0000
        EOF
 
@@ -45,6 +50,7 @@ test_expect_success 'request invalid capability' '
 test_expect_success 'request with no command' '
        test-tool pkt-line pack >in <<-EOF &&
        agent=git/test
+       object-format=$(test_oid algo)
        0000
        EOF
        test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
@@ -54,6 +60,7 @@ test_expect_success 'request with no command' '
 test_expect_success 'request invalid command' '
        test-tool pkt-line pack >in <<-EOF &&
        command=foo
+       object-format=$(test_oid algo)
        agent=git/test
        0000
        EOF
@@ -61,6 +68,17 @@ test_expect_success 'request invalid command' '
        test_i18ngrep "invalid command" err
 '
 
+test_expect_success 'wrong object-format' '
+       test-tool pkt-line pack >in <<-EOF &&
+       command=fetch
+       agent=git/test
+       object-format=$(test_oid wrong_algo)
+       0000
+       EOF
+       test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
+       test_i18ngrep "mismatched object format" err
+'
+
 # Test the basics of ls-refs
 #
 test_expect_success 'setup some refs and tags' '
@@ -74,6 +92,7 @@ test_expect_success 'setup some refs and tags' '
 test_expect_success 'basics of ls-refs' '
        test-tool pkt-line pack >in <<-EOF &&
        command=ls-refs
+       object-format=$(test_oid algo)
        0000
        EOF
 
@@ -96,6 +115,7 @@ test_expect_success 'basics of ls-refs' '
 test_expect_success 'basic ref-prefixes' '
        test-tool pkt-line pack >in <<-EOF &&
        command=ls-refs
+       object-format=$(test_oid algo)
        0001
        ref-prefix refs/heads/master
        ref-prefix refs/tags/one
@@ -116,6 +136,7 @@ test_expect_success 'basic ref-prefixes' '
 test_expect_success 'refs/heads prefix' '
        test-tool pkt-line pack >in <<-EOF &&
        command=ls-refs
+       object-format=$(test_oid algo)
        0001
        ref-prefix refs/heads/
        0000
@@ -136,6 +157,7 @@ test_expect_success 'refs/heads prefix' '
 test_expect_success 'peel parameter' '
        test-tool pkt-line pack >in <<-EOF &&
        command=ls-refs
+       object-format=$(test_oid algo)
        0001
        peel
        ref-prefix refs/tags/
@@ -157,6 +179,7 @@ test_expect_success 'peel parameter' '
 test_expect_success 'symrefs parameter' '
        test-tool pkt-line pack >in <<-EOF &&
        command=ls-refs
+       object-format=$(test_oid algo)
        0001
        symrefs
        ref-prefix refs/heads/
@@ -178,6 +201,7 @@ test_expect_success 'symrefs parameter' '
 test_expect_success 'sending server-options' '
        test-tool pkt-line pack >in <<-EOF &&
        command=ls-refs
+       object-format=$(test_oid algo)
        server-option=hello
        server-option=world
        0001
@@ -200,6 +224,7 @@ test_expect_success 'unexpected lines are not allowed in fetch request' '
 
        test-tool pkt-line pack >in <<-EOF &&
        command=fetch
+       object-format=$(test_oid algo)
        0001
        this-is-not-a-command
        0000
index baf1d7b5c8dc52b159f7639e55b998b1febff46d..1b54c35b01792f85e791f6d4614f25d543c47dfd 100755 (executable)
@@ -13,6 +13,7 @@ start_git_daemon --export-all --enable=receive-pack
 daemon_parent=$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent
 
 test_expect_success 'create repo to be served by git-daemon' '
+       test_oid_init &&
        git init "$daemon_parent" &&
        test_commit -C "$daemon_parent" one
 '
@@ -393,6 +394,7 @@ test_expect_success 'even with handcrafted request, filter does not work if not
        # Custom request that tries to filter even though it is not advertised.
        test-tool pkt-line pack >in <<-EOF &&
        command=fetch
+       object-format=$(test_oid algo)
        0001
        want $(git -C server rev-parse master)
        filter blob:none
index 92ad5eeec091122dedf2e707fae398be1a47accb..748282f058cbb996e1ecd694f861851d56365267 100755 (executable)
@@ -27,6 +27,15 @@ check_output () {
        test_cmp sorted_commits actual_commits
 }
 
+write_command () {
+       echo "command=$1"
+
+       if test "$(test_oid algo)" != sha1
+       then
+               echo "object-format=$(test_oid algo)"
+       fi
+}
+
 # c(o/foo) d(o/bar)
 #        \ /
 #         b   e(baz)  f(master)
@@ -65,7 +74,7 @@ test_expect_success 'config controls ref-in-want advertisement' '
 
 test_expect_success 'invalid want-ref line' '
        test-tool pkt-line pack >in <<-EOF &&
-       command=fetch
+       $(write_command fetch)
        0001
        no-progress
        want-ref refs/heads/non-existent
@@ -86,7 +95,7 @@ test_expect_success 'basic want-ref' '
 
        oid=$(git rev-parse a) &&
        test-tool pkt-line pack >in <<-EOF &&
-       command=fetch
+       $(write_command fetch)
        0001
        no-progress
        want-ref refs/heads/master
@@ -110,7 +119,7 @@ test_expect_success 'multiple want-ref lines' '
 
        oid=$(git rev-parse b) &&
        test-tool pkt-line pack >in <<-EOF &&
-       command=fetch
+       $(write_command fetch)
        0001
        no-progress
        want-ref refs/heads/o/foo
@@ -132,7 +141,7 @@ test_expect_success 'mix want and want-ref' '
        git rev-parse e f >expected_commits &&
 
        test-tool pkt-line pack >in <<-EOF &&
-       command=fetch
+       $(write_command fetch)
        0001
        no-progress
        want-ref refs/heads/master
@@ -155,7 +164,7 @@ test_expect_success 'want-ref with ref we already have commit for' '
 
        oid=$(git rev-parse c) &&
        test-tool pkt-line pack >in <<-EOF &&
-       command=fetch
+       $(write_command fetch)
        0001
        no-progress
        want-ref refs/heads/o/foo
index 950cfb21fe6b51c760100b508d14c4344a6309ef..5c941949b980b49607fb9b3876487110cf0acabc 100755 (executable)
@@ -9,6 +9,7 @@ making sure that we do not segfault or otherwise behave badly.'
 test_expect_success 'extra delim packet in v2 ls-refs args' '
        {
                packetize command=ls-refs &&
+               packetize "object-format=$(test_oid algo)" &&
                printf 0001 &&
                # protocol expects 0000 flush here
                printf 0001
@@ -21,6 +22,7 @@ test_expect_success 'extra delim packet in v2 ls-refs args' '
 test_expect_success 'extra delim packet in v2 fetch args' '
        {
                packetize command=fetch &&
+               packetize "object-format=$(test_oid algo)" &&
                printf 0001 &&
                # protocol expects 0000 flush here
                printf 0001
index 6b9f0b5dc79cf0239daf4f6a210baaccf8612d74..1544d6dc6ba19170a1dfdb8ded299530f70be1de 100755 (executable)
@@ -52,9 +52,11 @@ do
                test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
                test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
                echo 'option'
+               echo 'object-format'
                echo
                ;;
        list)
+               echo ":object-format $(git rev-parse --show-object-format=storage)"
                git for-each-ref --format='? %(refname)' 'refs/heads/' 'refs/tags/'
                head=$(git symbolic-ref HEAD)
                echo "@$head HEAD"
@@ -139,6 +141,10 @@ do
                        test $val = "true" && force="true" || force=
                        echo "ok"
                        ;;
+               object-format)
+                       test $val = "true" && object_format="true" || object_format=
+                       echo "ok"
+                       ;;
                *)
                        echo "unsupported"
                        ;;
index 62b8a2e7bbd1cf26710be0a0eb90041d5e3f7d2c..df1eff0fb831e3ede980157c577c575feab04a4d 100755 (executable)
@@ -10,7 +10,12 @@ git_bisect () {
        ls -1pR * >>expect &&
        tar cf "$TRASH_DIRECTORY/tmp.tar" * &&
        GOOD=$(git rev-parse --verify HEAD) &&
-       git checkout "$1" &&
+       may_only_be_test_must_fail "$2" &&
+       $2 git checkout "$1" &&
+       if test -n "$2"
+       then
+               return
+       fi &&
        echo "foo" >bar &&
        git add bar &&
        git commit -m "bisect bad" &&
@@ -27,6 +32,6 @@ git_bisect () {
        git bisect bad $BAD
 }
 
-test_submodule_switch "git_bisect"
+test_submodule_switch_func "git_bisect"
 
 test_done
index e4c2a6eca43564eea71a0a633b5494dd4626544f..2b3fd498d0742874bf9e71ed9b4982f3921b66c8 100755 (executable)
@@ -79,7 +79,7 @@ test_expect_success GPG 'set up a signed tag' '
 '
 
 test_expect_success 'message for merging local branch' '
-       echo "Merge branch ${apos}left${apos}" >expected &&
+       echo "Merge branch ${apos}left${apos} into master" >expected &&
 
        git checkout master &&
        git fetch . left &&
@@ -107,7 +107,7 @@ test_expect_success GPG 'message for merging local tag signed by unknown key' '
 '
 
 test_expect_success 'message for merging external branch' '
-       echo "Merge branch ${apos}left${apos} of $(pwd)" >expected &&
+       echo "Merge branch ${apos}left${apos} of $(pwd) into master" >expected &&
 
        git checkout master &&
        git fetch "$(pwd)" left &&
@@ -118,7 +118,7 @@ test_expect_success 'message for merging external branch' '
 
 test_expect_success '[merge] summary/log configuration' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}
+       Merge branch ${apos}left${apos} into master
 
        # By Another Author (3) and A U Thor (2)
        # Via Another Committer
@@ -160,7 +160,7 @@ test_expect_success 'setup FETCH_HEAD' '
 
 test_expect_success 'merge.log=3 limits shortlog length' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}
+       Merge branch ${apos}left${apos} into master
 
        # By Another Author (3) and A U Thor (2)
        # Via Another Committer
@@ -177,7 +177,7 @@ test_expect_success 'merge.log=3 limits shortlog length' '
 
 test_expect_success 'merge.log=5 shows all 5 commits' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}
+       Merge branch ${apos}left${apos} into master
 
        # By Another Author (3) and A U Thor (2)
        # Via Another Committer
@@ -195,7 +195,7 @@ test_expect_success 'merge.log=5 shows all 5 commits' '
 
 test_expect_success '--log=5 with custom comment character' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}
+       Merge branch ${apos}left${apos} into master
 
        x By Another Author (3) and A U Thor (2)
        x Via Another Committer
@@ -212,14 +212,14 @@ test_expect_success '--log=5 with custom comment character' '
 '
 
 test_expect_success 'merge.log=0 disables shortlog' '
-       echo "Merge branch ${apos}left${apos}" >expected &&
+       echo "Merge branch ${apos}left${apos} into master" >expected &&
        git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual &&
        test_cmp expected actual
 '
 
 test_expect_success '--log=3 limits shortlog length' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}
+       Merge branch ${apos}left${apos} into master
 
        # By Another Author (3) and A U Thor (2)
        # Via Another Committer
@@ -236,7 +236,7 @@ test_expect_success '--log=3 limits shortlog length' '
 
 test_expect_success '--log=5 shows all 5 commits' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}
+       Merge branch ${apos}left${apos} into master
 
        # By Another Author (3) and A U Thor (2)
        # Via Another Committer
@@ -253,13 +253,13 @@ test_expect_success '--log=5 shows all 5 commits' '
 '
 
 test_expect_success '--no-log disables shortlog' '
-       echo "Merge branch ${apos}left${apos}" >expected &&
+       echo "Merge branch ${apos}left${apos} into master" >expected &&
        git fmt-merge-msg --no-log <.git/FETCH_HEAD >actual &&
        test_cmp expected actual
 '
 
 test_expect_success '--log=0 disables shortlog' '
-       echo "Merge branch ${apos}left${apos}" >expected &&
+       echo "Merge branch ${apos}left${apos} into master" >expected &&
        git fmt-merge-msg --no-log <.git/FETCH_HEAD >actual &&
        test_cmp expected actual
 '
@@ -300,7 +300,7 @@ test_expect_success 'fmt-merge-msg -m' '
 
 test_expect_success 'setup: expected shortlog for two branches' '
        cat >expected <<-EOF
-       Merge branches ${apos}left${apos} and ${apos}right${apos}
+       Merge branches ${apos}left${apos} and ${apos}right${apos} into master
 
        # By Another Author (3) and A U Thor (2)
        # Via Another Committer
@@ -397,7 +397,7 @@ test_expect_success 'merge-msg with nothing to merge' '
 
 test_expect_success 'merge-msg tag' '
        cat >expected <<-EOF &&
-       Merge tag ${apos}tag-r3${apos}
+       Merge tag ${apos}tag-r3${apos} into master
 
        * tag ${apos}tag-r3${apos}:
          Right #3
@@ -418,7 +418,7 @@ test_expect_success 'merge-msg tag' '
 
 test_expect_success 'merge-msg two tags' '
        cat >expected <<-EOF &&
-       Merge tags ${apos}tag-r3${apos} and ${apos}tag-l5${apos}
+       Merge tags ${apos}tag-r3${apos} and ${apos}tag-l5${apos} into master
 
        * tag ${apos}tag-r3${apos}:
          Right #3
@@ -448,7 +448,7 @@ test_expect_success 'merge-msg two tags' '
 
 test_expect_success 'merge-msg tag and branch' '
        cat >expected <<-EOF &&
-       Merge branch ${apos}left${apos}, tag ${apos}tag-r3${apos}
+       Merge branch ${apos}left${apos}, tag ${apos}tag-r3${apos} into master
 
        * tag ${apos}tag-r3${apos}:
          Right #3
@@ -479,7 +479,7 @@ test_expect_success 'merge-msg tag and branch' '
 test_expect_success 'merge-msg lots of commits' '
        {
                cat <<-EOF &&
-               Merge branch ${apos}long${apos}
+               Merge branch ${apos}long${apos} into master
 
                * long: (35 commits)
                EOF
@@ -516,7 +516,7 @@ test_expect_success 'merge-msg with "merging" an annotated tag' '
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
        {
                cat <<-\EOF
-               Merge tag '\''annote'\''
+               Merge tag '\''annote'\'' into master
 
                An annotated one
 
@@ -531,7 +531,7 @@ test_expect_success 'merge-msg with "merging" an annotated tag' '
        git merge --no-commit --no-ff $annote &&
        {
                cat <<-EOF
-               Merge tag '\''$annote'\''
+               Merge tag '\''$annote'\'' into master
 
                An annotated one
 
index 67346424a53960c33becefe865ad8881c1f1777e..19830d90365661505a047e2376026a1ada023bb0 100755 (executable)
@@ -12,10 +12,10 @@ test_submodule_switch_recursing_with_args "reset --keep"
 
 test_submodule_forced_switch_recursing_with_args "reset --hard"
 
-test_submodule_switch "git reset --keep"
+test_submodule_switch "reset --keep"
 
-test_submodule_switch "git reset --merge"
+test_submodule_switch "reset --merge"
 
-test_submodule_forced_switch "git reset --hard"
+test_submodule_forced_switch "reset --hard"
 
 test_done
index 4fb447a143e653b780d2e7eef94a7de30d75f7e8..aa19ff3a2e2dca17dcc4d0834008d374885c4272 100755 (executable)
@@ -70,6 +70,22 @@ test_expect_success 'setup a submodule tree' '
        )
 '
 
+test_expect_success 'update --remote falls back to using HEAD' '
+       test_create_repo main-branch-submodule &&
+       test_commit -C main-branch-submodule initial &&
+
+       test_create_repo main-branch &&
+       git -C main-branch submodule add ../main-branch-submodule &&
+       git -C main-branch commit -m add-submodule &&
+
+       git -C main-branch-submodule switch -c hello &&
+       test_commit -C main-branch-submodule world &&
+
+       git clone --recursive main-branch main-branch-clone &&
+       git -C main-branch-clone submodule update --remote main-branch-submodule &&
+       test_path_exists main-branch-clone/main-branch-submodule/world.t
+'
+
 test_expect_success 'submodule update detaching the HEAD ' '
        (cd super/submodule &&
         git reset --hard HEAD~1
index fd25f786a3655e7486222b568e91779b9b5d99bb..3b925c302fc4e2194a2e0ad10c0b48823f2cf021 100755 (executable)
@@ -52,12 +52,13 @@ test_expect_success 'test submodule set-branch --branch' '
 '
 
 test_expect_success 'test submodule set-branch --default' '
+       test_commit -C submodule c &&
        (cd super &&
                git submodule set-branch --default submodule &&
                ! grep branch .gitmodules &&
                git submodule update --remote &&
                cat <<-\EOF >expect &&
-               a
+               c
                EOF
                git -C submodule show -s --pretty=%s >actual &&
                test_cmp expect actual
@@ -65,6 +66,7 @@ test_expect_success 'test submodule set-branch --default' '
 '
 
 test_expect_success 'test submodule set-branch -b' '
+       test_commit -C submodule b &&
        (cd super &&
                git submodule set-branch -b topic submodule &&
                grep "branch = topic" .gitmodules &&
@@ -78,12 +80,13 @@ test_expect_success 'test submodule set-branch -b' '
 '
 
 test_expect_success 'test submodule set-branch -d' '
+       test_commit -C submodule d &&
        (cd super &&
                git submodule set-branch -d submodule &&
                ! grep branch .gitmodules &&
                git submodule update --remote &&
                cat <<-\EOF >expect &&
-               a
+               d
                EOF
                git -C submodule show -s --pretty=%s >actual &&
                test_cmp expect actual
index 5883a6adc31b5f0580b9fea5a7863174e803dc99..1d45f9a4ed001d7135b435e1c1e1b53f27a5d620 100755 (executable)
@@ -14,9 +14,9 @@ Testing basic merge operations/option parsing.
     ! [c4] c4
      ! [c5] c5
       ! [c6] c6
-       * [master] Merge commit 'c1'
+       * [master] Merge commit 'c1' into master
 --------
-       - [master] Merge commit 'c1'
+       - [master] Merge commit 'c1' into master
  +     * [c1] commit 1
       +  [c6] c6
      +   [c5] c5
@@ -44,8 +44,8 @@ test_write_lines '1 X' 2 '3 X' 4 '5 X' 6 7 8 '9 X' >result.1-3-5-9
 test_write_lines 1 2 3 4 5 6 7 8 '9 Z' >result.9z
 
 create_merge_msgs () {
-       echo "Merge tag 'c2'" >msg.1-5 &&
-       echo "Merge tags 'c2' and 'c3'" >msg.1-5-9 &&
+       echo "Merge tag 'c2' into master" >msg.1-5 &&
+       echo "Merge tags 'c2' and 'c3' into master" >msg.1-5-9 &&
        {
                echo "Squashed commit of the following:" &&
                echo &&
@@ -258,7 +258,7 @@ test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
        git commit --no-edit -a &&
 
        cat >expect <<-\EOF &&
-       Merge tag '"'"'c7'"'"'
+       Merge tag '"'"'c7'"'"' into master
 
        # ------------------------ >8 ------------------------
        # Do not modify or remove the line above.
@@ -808,10 +808,10 @@ test_expect_success 'merge with conflicted --autostash changes' '
 '
 
 cat >expected.branch <<\EOF
-Merge branch 'c5-branch' (early part)
+Merge branch 'c5-branch' (early part) into master
 EOF
 cat >expected.tag <<\EOF
-Merge commit 'c5~1'
+Merge commit 'c5~1' into master
 EOF
 
 test_expect_success 'merge early part of c2' '
index 8e7e0a5865d762c1cb859154c2d4735b9bf8722b..2af33f195bc3951f79ad29e3c6c12249c37b9a2d 100755 (executable)
@@ -16,7 +16,7 @@ test_expect_success 'merge local branch' '
        git checkout master &&
        test_commit master-2 &&
        git merge local-branch &&
-       check_oneline "Merge branch Qlocal-branchQ"
+       check_oneline "Merge branch Qlocal-branchQ into master"
 '
 
 test_expect_success 'merge octopus branches' '
@@ -26,7 +26,7 @@ test_expect_success 'merge octopus branches' '
        test_commit octopus-2 &&
        git checkout master &&
        git merge octopus-a octopus-b &&
-       check_oneline "Merge branches Qoctopus-aQ and Qoctopus-bQ"
+       check_oneline "Merge branches Qoctopus-aQ and Qoctopus-bQ into master"
 '
 
 test_expect_success 'merge tag' '
@@ -35,7 +35,7 @@ test_expect_success 'merge tag' '
        git checkout master &&
        test_commit master-3 &&
        git merge tag-1 &&
-       check_oneline "Merge tag Qtag-1Q"
+       check_oneline "Merge tag Qtag-1Q into master"
 '
 
 test_expect_success 'ambiguous tag' '
@@ -44,7 +44,7 @@ test_expect_success 'ambiguous tag' '
        git checkout master &&
        test_commit master-4 &&
        git merge ambiguous &&
-       check_oneline "Merge tag QambiguousQ"
+       check_oneline "Merge tag QambiguousQ into master"
 '
 
 test_expect_success 'remote-tracking branch' '
@@ -54,7 +54,7 @@ test_expect_success 'remote-tracking branch' '
        git checkout master &&
        test_commit master-5 &&
        git merge origin/master &&
-       check_oneline "Merge remote-tracking branch Qorigin/masterQ"
+       check_oneline "Merge remote-tracking branch Qorigin/masterQ into master"
 '
 
 test_done
index d1e9fcc781b94512529a3415bae4c94b030ff674..04bf4be7d79224cebbe66df806acbe069f200e9e 100755 (executable)
@@ -6,14 +6,14 @@ test_description='merge can handle submodules'
 . "$TEST_DIRECTORY"/lib-submodule-update.sh
 
 # merges without conflicts
-test_submodule_switch "git merge"
+test_submodule_switch "merge"
 
-test_submodule_switch "git merge --ff"
+test_submodule_switch "merge --ff"
 
-test_submodule_switch "git merge --ff-only"
+test_submodule_switch "merge --ff-only"
 
 KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
 KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
-test_submodule_switch "git merge --no-ff"
+test_submodule_switch "merge --no-ff"
 
 test_done
index 29b92907e2ad850514fe970ca1adeeda8d0697c8..524f30f7dc7c2388bad3885303541d4a72ed4470 100755 (executable)
@@ -720,6 +720,14 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
        test_cmp expect actual
 '
 
+test_expect_success 'add -N and difftool -d' '
+       test_when_finished git reset --hard &&
+
+       test_write_lines A B C >intent-to-add &&
+       git add -N intent-to-add &&
+       git difftool --dir-diff --extcmd ls
+'
+
 test_expect_success 'outside worktree' '
        echo 1 >1 &&
        echo 2 >2 &&
index 90f61c34009550061f5c713ff83dfe06201331f2..ec261085ec68fdb8c9e9b54a9973be880a5c7db5 100755 (executable)
@@ -42,7 +42,8 @@ clean_fake_sendmail () {
 }
 
 test_expect_success $PREREQ 'Extract patches' '
-       patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1)
+       patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1) &&
+       threaded_patches=$(git format-patch -o threaded -s --in-reply-to="format" HEAD^1)
 '
 
 # Test no confirm early to ensure remaining tests will not hang
@@ -1219,6 +1220,17 @@ test_expect_success $PREREQ 'threading but no chain-reply-to' '
        grep "In-Reply-To: " stdout
 '
 
+test_expect_success $PREREQ 'override in-reply-to if no threading' '
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --no-thread \
+               --in-reply-to="override" \
+               $threaded_patches >stdout &&
+       grep "In-Reply-To: <override>" stdout
+'
+
 test_expect_success $PREREQ 'sendemail.to works' '
        git config --replace-all sendemail.to "Somebody <somebody@ex.com>" &&
        git send-email \
index 9fcfa969a9b4604b1c9bdfff1dd3f58a613b95bb..754c4a3284a2f89484a47fff3cf94166bc6204e6 100755 (executable)
@@ -84,6 +84,12 @@ test_expect_success REMOTE_SVN 'incremental imports must lead to the same head'
        test_cmp master.good .git/refs/remotes/svnsim/master
 '
 
+test_expect_success REMOTE_SVN 'respects configured default initial branch' '
+       git -c init.defaultBranch=trunk remote add -f trunk \
+               "testsvn::file://$TEST_DIRECTORY/t9154/svn.dump" &&
+       git rev-parse --verify refs/remotes/trunk/trunk
+'
+
 test_debug 'git branch -a'
 
 test_done
index 2c309a57d98898e99b76289d2eb298a2bce8cb00..9f2d19ecc4ad058ba00af3373af76d45c0235ed1 100755 (executable)
@@ -208,9 +208,10 @@ name='check imported tree checksums expected tree checksums'
 rm -f expected
 if test_have_prereq UTF8
 then
-       echo tree dc68b14b733e4ec85b04ab6f712340edc5dc936e > expected
+       echo tree dc68b14b733e4ec85b04ab6f712340edc5dc936e > expected.sha1
+       echo tree b95b55b29d771f5eb73aa9b9d52d02fe11a2538c2feb0829f754ce20a91d98eb > expected.sha256
 fi
-cat >> expected <<\EOF
+cat >> expected.sha1 <<\EOF
 tree c3322890dcf74901f32d216f05c5044f670ce632
 tree d3ccd5035feafd17b030c5732e7808cc49122853
 tree d03e1630363d4881e68929d532746b20b0986b83
@@ -220,8 +221,20 @@ tree 149d63cd5878155c846e8c55d7d8487de283f89e
 tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
 tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4
 EOF
+cat >> expected.sha256 <<\EOF
+tree 8d12756699d0b5b110514240a0ff141f6cbf8891fd69ab05e5594196fb437c9f
+tree 8187168d33f7d4ccb8c1cc6e99532810aaccb47658f35d19b3803072d1128d7a
+tree 74e535d85da8ee25eb23d7b506790c5ab3ccdb1ba0826bd57625ed44ef361650
+tree 6fd7dd963e3cdca0cbd6368ed3cfcc8037cc154d2e7719d9d369a0952364fd95
+tree 1fd6cec6aa95102d69266e20419bb62ec2a06372d614b9850ef23ff204103bb4
+tree 6fd7dd963e3cdca0cbd6368ed3cfcc8037cc154d2e7719d9d369a0952364fd95
+tree deb2b7ac79cd8ce6f52af6a5a0a08691e94ba74a2ed55966bb27dbec551730eb
+tree 59e2e936761188476a7752034e8aa0a822b34050c8504b0dfd946407f4bc9215
+EOF
 
-test_expect_success POSIXPERM,SYMLINKS "$name" "test_cmp expected a"
+test_expect_success POSIXPERM,SYMLINKS "$name" '
+       test_cmp expected.$(test_oid algo) a
+'
 
 test_expect_success 'exit if remote refs are ambigious' '
         git config --add svn-remote.svn.fetch \
index c26c4b0927916fca6902eb54600a13aee5e7dea9..8b5681dd68ab05adc504437a54ff2877ed180516 100755 (executable)
@@ -160,11 +160,13 @@ cat >create-ignore.expect <<\EOF
 /no-such-file*
 EOF
 
-cat >create-ignore-index.expect <<\EOF
-100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0      .gitignore
-100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0      deeply/.gitignore
-100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0      deeply/nested/.gitignore
-100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0      deeply/nested/directory/.gitignore
+expectoid=$(git hash-object create-ignore.expect)
+
+cat >create-ignore-index.expect <<EOF
+100644 $expectoid 0    .gitignore
+100644 $expectoid 0    deeply/.gitignore
+100644 $expectoid 0    deeply/nested/.gitignore
+100644 $expectoid 0    deeply/nested/directory/.gitignore
 EOF
 
 test_expect_success 'test create-ignore' "
index 5e0ad1917736591b50e65169216bd5fe80193989..67eed2fefcec974f7f166b3221150392323211c5 100755 (executable)
@@ -161,6 +161,7 @@ test_expect_success "track initial change if it was only made to parent" '
        '
 
 test_expect_success "follow-parent is atomic" '
+       record_size=$(($(test_oid rawsz) + 4)) &&
        (
                cd wc &&
                svn_cmd up &&
@@ -186,7 +187,7 @@ test_expect_success "follow-parent is atomic" '
        mkdir -p "$GIT_DIR"/svn/refs/remotes/flunk@18 &&
        rev_map=$(cd "$GIT_DIR"/svn/refs/remotes/stunk && ls .rev_map*) &&
        dd if="$GIT_DIR"/svn/refs/remotes/stunk/$rev_map \
-          of="$GIT_DIR"/svn/refs/remotes/flunk@18/$rev_map bs=24 count=1 &&
+          of="$GIT_DIR"/svn/refs/remotes/flunk@18/$rev_map bs=$record_size count=1 &&
        rm -rf "$GIT_DIR"/svn/refs/remotes/stunk &&
        git svn init --minimize-url -i flunk "$svnrepo"/flunk &&
        git svn fetch -i flunk &&
index 6990f64364200c75f46d9f6ee3d67ebea3549d5b..d5939d4753ece809a762aa35a6f48663126ae506 100755 (executable)
@@ -48,7 +48,7 @@ test_expect_success 'test refspec globbing' '
                         "tags/*/src/a:refs/remotes/tags/*" &&
        git svn multi-fetch &&
        git log --pretty=oneline refs/remotes/tags/end >actual &&
-       sed -e "s/^.\{41\}//" actual >output.end &&
+       cut -d" " -f2- actual >output.end &&
        test_cmp expect.end output.end &&
        test "$(git rev-parse refs/remotes/tags/end~1)" = \
                "$(git rev-parse refs/remotes/branches/start)" &&
@@ -84,7 +84,7 @@ test_expect_success 'test left-hand-side only globbing' '
        test $(git rev-parse refs/remotes/two/tags/end~3) = \
             $(git rev-parse refs/remotes/two/branches/start) &&
        git log --pretty=oneline refs/remotes/two/tags/end >actual &&
-       sed -e "s/^.\{41\}//" actual >output.two &&
+       cut -d" " -f2- actual >output.two &&
        test_cmp expect.two output.two
        '
 
index c1e7542a371330ecd6b27899cf3f6d4d07d78a29..648dcee1eac137b7e5507ae2717c8e3e79642faa 100755 (executable)
@@ -48,7 +48,7 @@ test_expect_success 'test refspec globbing' '
                         "tags/*/src/a:refs/remotes/tags/*" &&
        git svn multi-fetch &&
        git log --pretty=oneline refs/remotes/tags/end >actual &&
-       sed -e "s/^.\{41\}//" actual >output.end &&
+       cut -d" " -f2- actual >output.end &&
        test_cmp expect.end output.end &&
        test "$(git rev-parse refs/remotes/tags/end~1)" = \
                "$(git rev-parse refs/remotes/branches/v1/start)" &&
@@ -84,7 +84,7 @@ test_expect_success 'test left-hand-side only globbing' '
        test $(git rev-parse refs/remotes/two/tags/end~3) = \
             $(git rev-parse refs/remotes/two/branches/v1/start) &&
        git log --pretty=oneline refs/remotes/two/tags/end >actual &&
-       sed -e "s/^.\{41\}//" actual >output.two &&
+       cut -d" " -f2- actual >output.two &&
        test_cmp expect.two output.two
        '
 cat > expect.four <<EOF
@@ -135,7 +135,7 @@ test_expect_success 'test another branch' '
        test $(git rev-parse refs/remotes/four/tags/next~2) = \
             $(git rev-parse refs/remotes/four/branches/v2/start) &&
        git log --pretty=oneline refs/remotes/four/tags/next >actual &&
-       sed -e "s/^.\{41\}//" actual >output.four &&
+       cut -d" " -f2- actual >output.four &&
        test_cmp expect.four output.four
        '
 
index bdf6e849993bff79a5e04c5b8a1d7df77118091f..854b3419b2c3239090750f96dde3608d25c90136 100755 (executable)
@@ -49,7 +49,7 @@ test_expect_success 'test refspec prefixed globbing' '
                         "tags/t_*/src/a:refs/remotes/tags/t_*" &&
        git svn multi-fetch &&
        git log --pretty=oneline refs/remotes/tags/t_end >actual &&
-       sed -e "s/^.\{41\}//" actual >output.end &&
+       cut -d" " -f2- actual >output.end &&
        test_cmp expect.end output.end &&
        test "$(git rev-parse refs/remotes/tags/t_end~1)" = \
                "$(git rev-parse refs/remotes/branches/b_start)" &&
@@ -87,7 +87,7 @@ test_expect_success 'test left-hand-side only prefixed globbing' '
        test $(git rev-parse refs/remotes/two/tags/t_end~3) = \
             $(git rev-parse refs/remotes/two/branches/b_start) &&
        git log --pretty=oneline refs/remotes/two/tags/t_end >actual &&
-       sed -e "s/^.\{41\}//" actual >output.two &&
+       cut -d" " -f2- actual >output.two &&
        test_cmp expect.two output.two
        '
 
@@ -129,7 +129,7 @@ test_expect_success 'test prefixed globs match just prefix' '
        test $(git rev-parse refs/remotes/three/tags/t_~1) = \
             $(git rev-parse refs/remotes/three/branches/b_) &&
        git log --pretty=oneline refs/remotes/three/tags/t_ >actual &&
-       sed -e "s/^.\{41\}//" actual >output.three &&
+       cut -d" " -f2- actual >output.three &&
        test_cmp expect.three output.three
        '
 
@@ -199,7 +199,7 @@ test_expect_success 'test globbing in the middle of the word' '
        test $(git rev-parse refs/remotes/five/tags/fghij~1) = \
             $(git rev-parse refs/remotes/five/branches/abcde) &&
        git log --pretty=oneline refs/remotes/five/tags/fghij >actual &&
-       sed -e "s/^.\{41\}//" actual >output.five &&
+       cut -d" " -f2- actual >output.five &&
        test_cmp expect.five output.five
        '
 
index 897dc509075a887268f472b8bbdbb5bf67e4d00f..5ac2c3b5eef0657e25418b4a6656b7e63edd8821 100755 (executable)
@@ -6,15 +6,24 @@ test_description='basic tests for fast-export --anonymize'
 test_expect_success 'setup simple repo' '
        test_commit base &&
        test_commit foo &&
+       test_commit retain-me &&
        git checkout -b other HEAD^ &&
        mkdir subdir &&
        test_commit subdir/bar &&
        test_commit subdir/xyzzy &&
+       fake_commit=$(echo $ZERO_OID | sed s/0/a/) &&
+       git update-index --add --cacheinfo 160000,$fake_commit,link1 &&
+       git update-index --add --cacheinfo 160000,$fake_commit,link2 &&
+       git commit -m "add gitlink" &&
        git tag -m "annotated tag" mytag
 '
 
 test_expect_success 'export anonymized stream' '
-       git fast-export --anonymize --all >stream
+       git fast-export --anonymize --all \
+               --anonymize-map=retain-me \
+               --anonymize-map=xyzzy:custom-name \
+               --anonymize-map=other \
+               >stream
 '
 
 # this also covers commit messages
@@ -26,12 +35,23 @@ test_expect_success 'stream omits path names' '
        ! grep xyzzy stream
 '
 
-test_expect_success 'stream allows master as refname' '
-       grep master stream
+test_expect_success 'stream contains user-specified names' '
+       grep retain-me stream &&
+       grep custom-name stream
+'
+
+test_expect_success 'stream omits gitlink oids' '
+       # avoid relying on the whole oid to remain hash-agnostic; this is
+       # plenty to be unique within our test case
+       ! grep a000000000000000000 stream
+'
+
+test_expect_success 'stream retains other as refname' '
+       grep other stream
 '
 
 test_expect_success 'stream omits other refnames' '
-       ! grep other stream &&
+       ! grep master stream &&
        ! grep mytag stream
 '
 
@@ -57,7 +77,8 @@ test_expect_success 'import stream to new repository' '
 test_expect_success 'result has two branches' '
        git for-each-ref --format="%(refname)" refs/heads >branches &&
        test_line_count = 2 branches &&
-       other_branch=$(grep -v refs/heads/master branches)
+       other_branch=refs/heads/other &&
+       main_branch=$(grep -v $other_branch branches)
 '
 
 test_expect_success 'repo has original shape and timestamps' '
@@ -65,34 +86,35 @@ test_expect_success 'repo has original shape and timestamps' '
                git log --format="%m %ct" --left-right --boundary "$@"
        } &&
        (cd .. && shape master...other) >expect &&
-       shape master...$other_branch >actual &&
+       shape $main_branch...$other_branch >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'root tree has original shape' '
        # the output entries are not necessarily in the same
-       # order, but we know at least that we will have one tree
-       # and one blob, so just check the sorted order
-       cat >expect <<-\EOF &&
-       blob
-       tree
-       EOF
+       # order, but we should at least have the same set of
+       # object types.
+       git -C .. ls-tree HEAD >orig-root &&
+       cut -d" " -f2 <orig-root | sort >expect &&
        git ls-tree $other_branch >root &&
        cut -d" " -f2 <root | sort >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'paths in subdir ended up in one tree' '
-       cat >expect <<-\EOF &&
-       blob
-       blob
-       EOF
+       git -C .. ls-tree other:subdir >orig-subdir &&
+       cut -d" " -f2 <orig-subdir | sort >expect &&
        tree=$(grep tree root | cut -f2) &&
        git ls-tree $other_branch:$tree >tree &&
        cut -d" " -f2 <tree >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'identical gitlinks got identical oid' '
+       awk "/commit/ { print \$3 }" <root | sort -u >commits &&
+       test_line_count = 1 commits
+'
+
 test_expect_success 'tag points to branch tip' '
        git rev-parse $other_branch >expect &&
        git for-each-ref --format="%(*objectname)" | grep . >actual &&
index 8f434a0931e5b8146f57aaf8362badade9117820..8425b9a531a6809bdb6dcdd272f589b31f713de6 100755 (executable)
@@ -494,7 +494,7 @@ test_expect_success '__gitcomp - prefix' '
 '
 
 test_expect_success '__gitcomp - suffix' '
-       test_gitcomp "branch.me" "master maint next pu" "branch." \
+       test_gitcomp "branch.me" "master maint next seen" "branch." \
                "ma" "." <<-\EOF
        branch.master.Z
        branch.maint.Z
@@ -545,7 +545,7 @@ read -r -d "" refs <<-\EOF
 maint
 master
 next
-pu
+seen
 EOF
 
 test_expect_success '__gitcomp_nl - trailing space' '
index dbc027ff267e0c3151965960608ef7cbc916950f..618a7c8d5ba57507b4c0ac8915115a381f86fe28 100644 (file)
@@ -1414,6 +1414,7 @@ test_oid_init
 
 ZERO_OID=$(test_oid zero)
 OID_REGEX=$(echo $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
+OIDPATH_REGEX=$(test_oid_to_path $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
 EMPTY_TREE=$(test_oid empty_tree)
 EMPTY_BLOB=$(test_oid empty_blob)
 _z40=$ZERO_OID
diff --git a/tag.c b/tag.c
index 71b544467efacd12f36e8c61efdc387db11d1bff..1ed2684e45bd50d051ade60cc6b66c8c44fbed59 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -103,7 +103,7 @@ struct tag *lookup_tag(struct repository *r, const struct object_id *oid)
        struct object *obj = lookup_object(r, oid);
        if (!obj)
                return create_object(r, oid, alloc_tag_node(r));
-       return object_as_type(r, obj, OBJ_TAG, 0);
+       return object_as_type(obj, OBJ_TAG, 0);
 }
 
 static timestamp_t parse_tag_date(const char *buf, const char *tail)
index 93a6f507936348e3b2eb43f06663725540646441..c6b753bfae4bd4e19fd7e3ea16b9f82a8219f10f 100644 (file)
@@ -32,7 +32,8 @@ struct helper_data {
                signed_tags : 1,
                check_connectivity : 1,
                no_disconnect_req : 1,
-               no_private_update : 1;
+               no_private_update : 1,
+               object_format : 1;
 
        /*
         * As an optimization, the transport code may invoke fetch before
@@ -207,6 +208,8 @@ static struct child_process *get_helper(struct transport *transport)
                        data->import_marks = xstrdup(arg);
                } else if (starts_with(capname, "no-private-update")) {
                        data->no_private_update = 1;
+               } else if (starts_with(capname, "object-format")) {
+                       data->object_format = 1;
                } else if (mandatory) {
                        die(_("unknown mandatory capability %s; this remote "
                              "helper probably needs newer version of Git"),
@@ -1047,7 +1050,7 @@ static int push_refs(struct transport *transport,
        if (!remote_refs) {
                fprintf(stderr,
                        _("No refs in common and none specified; doing nothing.\n"
-                         "Perhaps you should specify a branch such as 'master'.\n"));
+                         "Perhaps you should specify a branch.\n"));
                return 0;
        }
 
@@ -1104,6 +1107,12 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
        data->get_refs_list_called = 1;
        helper = get_helper(transport);
 
+       if (data->object_format) {
+               write_str_in_full(helper->in, "option object-format\n");
+               if (recvline(data, &buf) || strcmp(buf.buf, "ok"))
+                       exit(128);
+       }
+
        if (data->push && for_push)
                write_str_in_full(helper->in, "list for-push\n");
        else
@@ -1116,6 +1125,17 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
 
                if (!*buf.buf)
                        break;
+               else if (buf.buf[0] == ':') {
+                       const char *value;
+                       if (skip_prefix(buf.buf, ":object-format ", &value)) {
+                               int algo = hash_algo_by_name(value);
+                               if (algo == GIT_HASH_UNKNOWN)
+                                       die(_("unsupported object format '%s'"),
+                                           value);
+                               transport->hash_algo = &hash_algos[algo];
+                       }
+                       continue;
+               }
 
                eov = strchr(buf.buf, ' ');
                if (!eov)
@@ -1128,7 +1148,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
                if (buf.buf[0] == '@')
                        (*tail)->symref = xstrdup(buf.buf + 1);
                else if (buf.buf[0] != '?')
-                       get_oid_hex(buf.buf, &(*tail)->old_oid);
+                       get_oid_hex_algop(buf.buf, &(*tail)->old_oid, transport->hash_algo);
                if (eon) {
                        if (has_attribute(eon + 1, "unchanged")) {
                                (*tail)->status |= REF_STATUS_UPTODATE;
index 6ee6771f550522441aa31b0c06ca84e50ef28750..b41386eccb4f6432dcdcd8300ee49f8031bfad56 100644 (file)
@@ -143,6 +143,9 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
        data->fd = read_bundle_header(transport->url, &data->header);
        if (data->fd < 0)
                die(_("could not read bundle '%s'"), transport->url);
+
+       transport->hash_algo = data->header.hash_algo;
+
        for (i = 0; i < data->header.references.nr; i++) {
                struct ref_list_entry *e = data->header.references.list + i;
                struct ref *ref = alloc_ref(e->name);
@@ -157,11 +160,14 @@ static int fetch_refs_from_bundle(struct transport *transport,
                               int nr_heads, struct ref **to_fetch)
 {
        struct bundle_transport_data *data = transport->data;
+       int ret;
 
        if (!data->get_refs_from_bundle_called)
                get_refs_from_bundle(transport, 0, NULL);
-       return unbundle(the_repository, &data->header, data->fd,
-                       transport->progress ? BUNDLE_VERBOSE : 0);
+       ret = unbundle(the_repository, &data->header, data->fd,
+                          transport->progress ? BUNDLE_VERBOSE : 0);
+       transport->hash_algo = data->header.hash_algo;
+       return ret;
 }
 
 static int close_bundle(struct transport *transport)
@@ -312,6 +318,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
                BUG("unknown protocol version");
        }
        data->got_remote_heads = 1;
+       transport->hash_algo = reader.hash_algo;
 
        if (reader.line_peeked)
                BUG("buffer must be empty at the end of handshake()");
@@ -989,9 +996,16 @@ struct transport *transport_get(struct remote *remote, const char *url)
                        ret->smart_options->receivepack = remote->receivepack;
        }
 
+       ret->hash_algo = &hash_algos[GIT_HASH_SHA1];
+
        return ret;
 }
 
+const struct git_hash_algo *transport_get_hash_algo(struct transport *transport)
+{
+       return transport->hash_algo;
+}
+
 int transport_set_option(struct transport *transport,
                         const char *name, const char *value)
 {
index 05efa72db194e7526f8a5887b8ffeb19c86c91d5..b3c30133ea4073603086ac4c2b75bb223b5897b2 100644 (file)
@@ -115,6 +115,8 @@ struct transport {
        struct git_transport_options *smart_options;
 
        enum transport_family family;
+
+       const struct git_hash_algo *hash_algo;
 };
 
 #define TRANSPORT_PUSH_ALL                     (1<<0)
@@ -243,6 +245,12 @@ int transport_push(struct repository *repo,
 const struct ref *transport_get_remote_refs(struct transport *transport,
                                            const struct argv_array *ref_prefixes);
 
+/*
+ * Fetch the hash algorithm used by a remote.
+ *
+ * This can only be called after fetching the remote refs.
+ */
+const struct git_hash_algo *transport_get_hash_algo(struct transport *transport);
 int transport_fetch_refs(struct transport *transport, struct ref *refs);
 void transport_unlock_pack(struct transport *transport);
 int transport_disconnect(struct transport *transport);
diff --git a/tree.c b/tree.c
index 1466bcc6a8cf093970dc3d39e5554a61112548fd..e76517f6b180e4703a032706f6d388d491df22a5 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -200,7 +200,7 @@ struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
        struct object *obj = lookup_object(r, oid);
        if (!obj)
                return create_object(r, oid, alloc_tree_node(r));
-       return object_as_type(r, obj, OBJ_TREE, 0);
+       return object_as_type(obj, OBJ_TREE, 0);
 }
 
 int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
index 39d0cf00be70ec76368dfbce9a2efab5815aea47..951a2b23aaf8f03d08f8976557de8616bbb2b5ca 100644 (file)
@@ -1132,7 +1132,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
                struct strbuf symref_info = STRBUF_INIT;
 
                format_symref_info(&symref_info, &data->symref);
-               packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s agent=%s\n",
+               packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s object-format=%s agent=%s\n",
                             oid_to_hex(oid), refname_nons,
                             0, capabilities,
                             (data->allow_uor & ALLOW_TIP_SHA1) ?
@@ -1142,6 +1142,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
                             data->stateless_rpc ? " no-done" : "",
                             symref_info.buf,
                             data->allow_filter ? " filter" : "",
+                            the_hash_algo->name,
                             git_user_agent_sanitized());
                strbuf_release(&symref_info);
        } else {
index ee82235f260c21748ec987ada46a4422980d9c8b..cba2e545982c0487160244100af44a14d2e9a898 100644 (file)
@@ -50,9 +50,9 @@ static struct worktree *get_main_worktree(void)
        struct strbuf worktree_path = STRBUF_INIT;
 
        strbuf_add_absolute_path(&worktree_path, get_git_common_dir());
-       strbuf_strip_suffix(&worktree_path, "/.");
-       if (!strbuf_strip_suffix(&worktree_path, "/.git"))
-               strbuf_strip_suffix(&worktree_path, "/.");
+       if (!strbuf_strip_suffix(&worktree_path, "/.git/.") && /* in .git */
+           !strbuf_strip_suffix(&worktree_path, "/.git")) /* in worktree */
+               strbuf_strip_suffix(&worktree_path, "/."); /* in bare repo */
 
        worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
@@ -123,14 +123,7 @@ static void mark_current_worktree(struct worktree **worktrees)
        free(git_dir);
 }
 
-static int compare_worktree(const void *a_, const void *b_)
-{
-       const struct worktree *const *a = a_;
-       const struct worktree *const *b = b_;
-       return fspathcmp((*a)->path, (*b)->path);
-}
-
-struct worktree **get_worktrees(unsigned flags)
+struct worktree **get_worktrees(void)
 {
        struct worktree **list = NULL;
        struct strbuf path = STRBUF_INIT;
@@ -161,13 +154,6 @@ struct worktree **get_worktrees(unsigned flags)
        ALLOC_GROW(list, counter + 1, alloc);
        list[counter] = NULL;
 
-       if (flags & GWT_SORT_LINKED)
-               /*
-                * don't sort the first item (main worktree), which will
-                * always be the first
-                */
-               QSORT(list + 1, counter - 1, compare_worktree);
-
        mark_current_worktree(list);
        return list;
 }
@@ -418,7 +404,7 @@ const struct worktree *find_shared_symref(const char *symref,
 
        if (worktrees)
                free_worktrees(worktrees);
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
 
        for (i = 0; worktrees[i]; i++) {
                struct worktree *wt = worktrees[i];
@@ -577,7 +563,7 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
        struct worktree **worktrees, **p;
        int ret = 0;
 
-       worktrees = get_worktrees(0);
+       worktrees = get_worktrees();
        for (p = worktrees; *p; p++) {
                struct worktree *wt = *p;
                struct object_id oid;
index d242a6e71c0333f80b76e44976f0c4356f99bec3..516744c433f1e627abe85a347d72e6516f98c171 100644 (file)
@@ -18,19 +18,14 @@ struct worktree {
        int lock_reason_valid; /* private */
 };
 
-/* Functions for acting on the information about worktrees. */
-
-#define GWT_SORT_LINKED (1 << 0) /* keeps linked worktrees sorted */
-
 /*
  * Get the worktrees.  The primary worktree will always be the first returned,
- * and linked worktrees will be pointed to by 'next' in each subsequent
- * worktree.  No specific ordering is done on the linked worktrees.
+ * and linked worktrees will follow in no particular order.
  *
  * The caller is responsible for freeing the memory from the returned
- * worktree(s).
+ * worktrees by calling free_worktrees().
  */
-struct worktree **get_worktrees(unsigned flags);
+struct worktree **get_worktrees(void);
 
 /*
  * Returns 1 if linked worktrees exist, 0 otherwise.
index 3a1c0e052677dca8d1bc19121d609e0c226e88ee..4ff4a9c3db0e1c797bce777eac5358d74c0bc5c6 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -105,6 +105,14 @@ char *xstrndup(const char *str, size_t len)
        return xmemdupz(str, p ? p - str : len);
 }
 
+int xstrncmpz(const char *s, const char *t, size_t len)
+{
+       int res = strncmp(s, t, len);
+       if (res)
+               return res;
+       return s[len] == '\0' ? 0 : 1;
+}
+
 void *xrealloc(void *ptr, size_t size)
 {
        void *ret;
index 98dfa6f73f9d7cd41867f97fdae41bd4dc5ec2a1..c560cbe860a42daa136e16195535ef10e2ab0a9f 100644 (file)
@@ -1484,6 +1484,18 @@ static void show_bisect_in_progress(struct wt_status *s,
        wt_longstatus_print_trailer(s);
 }
 
+static void show_sparse_checkout_in_use(struct wt_status *s,
+                                       const char *color)
+{
+       if (s->state.sparse_checkout_percentage == SPARSE_CHECKOUT_DISABLED)
+               return;
+
+       status_printf_ln(s, color,
+                        _("You are in a sparse checkout with %d%% of tracked files present."),
+                        s->state.sparse_checkout_percentage);
+       wt_longstatus_print_trailer(s);
+}
+
 /*
  * Extract branch information from rebase/bisect
  */
@@ -1623,6 +1635,31 @@ int wt_status_check_bisect(const struct worktree *wt,
        return 0;
 }
 
+static void wt_status_check_sparse_checkout(struct repository *r,
+                                           struct wt_status_state *state)
+{
+       int skip_worktree = 0;
+       int i;
+
+       if (!core_apply_sparse_checkout || r->index->cache_nr == 0) {
+               /*
+                * Don't compute percentage of checked out files if we
+                * aren't in a sparse checkout or would get division by 0.
+                */
+               state->sparse_checkout_percentage = SPARSE_CHECKOUT_DISABLED;
+               return;
+       }
+
+       for (i = 0; i < r->index->cache_nr; i++) {
+               struct cache_entry *ce = r->index->cache[i];
+               if (ce_skip_worktree(ce))
+                       skip_worktree++;
+       }
+
+       state->sparse_checkout_percentage =
+               100 - (100 * skip_worktree)/r->index->cache_nr;
+}
+
 void wt_status_get_state(struct repository *r,
                         struct wt_status_state *state,
                         int get_detached_from)
@@ -1658,6 +1695,7 @@ void wt_status_get_state(struct repository *r,
        }
        if (get_detached_from)
                wt_status_get_detached_from(r, state);
+       wt_status_check_sparse_checkout(r, state);
 }
 
 static void wt_longstatus_print_state(struct wt_status *s)
@@ -1681,6 +1719,9 @@ static void wt_longstatus_print_state(struct wt_status *s)
                show_revert_in_progress(s, state_color);
        if (state->bisect_in_progress)
                show_bisect_in_progress(s, state_color);
+
+       if (state->sparse_checkout_percentage != SPARSE_CHECKOUT_DISABLED)
+               show_sparse_checkout_in_use(s, state_color);
 }
 
 static void wt_longstatus_print(struct wt_status *s)
index 73ab5d4da1c0b4766cb63501b9db06c0a7fea934..f1fa0ec1a750a92967c35cafe2fdb25a32873d5a 100644 (file)
@@ -79,6 +79,7 @@ enum wt_status_format {
 
 #define HEAD_DETACHED_AT _("HEAD detached at ")
 #define HEAD_DETACHED_FROM _("HEAD detached from ")
+#define SPARSE_CHECKOUT_DISABLED -1
 
 struct wt_status_state {
        int merge_in_progress;
@@ -90,6 +91,7 @@ struct wt_status_state {
        int bisect_in_progress;
        int revert_in_progress;
        int detached_at;
+       int sparse_checkout_percentage; /* SPARSE_CHECKOUT_DISABLED if not sparse */
        char *branch;
        char *onto;
        char *detached_from;