Merge branch 'jc/git-gui-has-maintainer'
authorJunio C Hamano <gitster@pobox.com>
Sun, 6 Oct 2019 03:25:15 +0000 (12:25 +0900)
committerJunio C Hamano <gitster@pobox.com>
Sun, 6 Oct 2019 03:25:15 +0000 (12:25 +0900)
* jc/git-gui-has-maintainer:
  SubmittingPatches: git-gui has a new maintainer

117 files changed:
.gitignore
Documentation/RelNotes/2.24.0.txt
Documentation/RelNotes/2.7.1.txt
Documentation/RelNotes/2.8.0.txt
Documentation/config/feature.txt
Documentation/config/fetch.txt
Documentation/config/format.txt
Documentation/git-fast-export.txt
Documentation/git-filter-branch.txt
Documentation/git-format-patch.txt
Documentation/git-gc.txt
Documentation/git-rebase.txt
Documentation/git-replace.txt
Documentation/git-svn.txt
Documentation/githooks.txt
Documentation/gitremote-helpers.txt
Documentation/merge-options.txt
Documentation/technical/api-directory-listing.txt
attr.c
banned.h
builtin/am.c
builtin/check-ignore.c
builtin/checkout.c
builtin/clean.c
builtin/describe.c
builtin/fetch.c
builtin/grep.c
builtin/log.c
builtin/ls-files.c
builtin/pack-objects.c
builtin/push.c
builtin/rebase.c
builtin/replace.c
bulk-checkin.c
ci/lib.sh
commit.c
compat/mingw.c
compat/mingw.h
compat/win32/pthread.h
connect.c
contrib/completion/git-completion.bash
contrib/svn-fe/svn-fe.txt
diff-delta.c
dir.c
dir.h
fast-import.c
git-filter-branch.sh
help.c
help.h
http.c
list-objects-filter.c
log-tree.c
notes.c
pack-bitmap-write.c
pack-bitmap.c
pack-objects.c
pack-objects.h
packfile.c
quote.c
quote.h
ref-filter.c
repo-settings.c
repository.h
revision.c
setup.c
t/helper/test-read-cache.c
t/lib-git-svn.sh
t/t0211-trace2-perf.sh
t/t1300-config.sh
t/t1404-update-ref-errors.sh
t/t1414-reflog-walk.sh
t/t1506-rev-parse-diagnosis.sh
t/t1507-rev-parse-upstream.sh
t/t3005-ls-files-relative.sh
t/t3201-branch-contains.sh
t/t3206-range-diff.sh
t/t3301-notes.sh
t/t3305-notes-fanout.sh
t/t3306-notes-prune.sh
t/t3400-rebase.sh
t/t3404-rebase-interactive.sh
t/t3416-rebase-onto-threedots.sh
t/t3420-rebase-autostash.sh
t/t3421-rebase-topology-linear.sh
t/t3430-rebase-merges.sh
t/t3431-rebase-fork-point.sh [new file with mode: 0755]
t/t3432-rebase-fast-forward.sh [new file with mode: 0755]
t/t3506-cherry-pick-ff.sh
t/t3600-rm.sh
t/t3800-mktag.sh
t/t3903-stash.sh
t/t4000-diff-format.sh
t/t4002-diff-basic.sh
t/t4009-diff-rename-4.sh
t/t4013-diff-various.sh
t/t4014-format-patch.sh
t/t5500-fetch-pack.sh
t/t5510-fetch.sh
t/t5515-fetch-merge-logic.sh
t/t5517-push-mirror.sh
t/t5601-clone.sh
t/t6006-rev-list-format.sh
t/t7300-clean.sh
t/t7406-submodule-update.sh
t/t7512-status-help.sh
t/t9902-completion.sh
t/test-lib.sh
tag.c
tag.h
trace2/tr2_dst.c
trace2/tr2_tgt_event.c
trace2/tr2_tgt_normal.c
trace2/tr2_tgt_perf.c
tree.c
unpack-trees.c
unpack-trees.h
wt-status.c

index 521d8f4..fc445ed 100644 (file)
 *.ipdb
 *.dll
 .vs/
-*.manifest
 Debug/
 Release/
 /UpgradeLog*.htm
index ff48d85..7f44e7a 100644 (file)
@@ -6,8 +6,10 @@ Updates since v2.23
 
 Backward compatibility note
 
- * (no entry yet so far)
-
+ * Although it is not officially deprecated, "filter-branch" is
+   showing its age and alternatives are available.  From this release,
+   we started to discourage its uses and hint people about
+   filter-repo.
 
 UI, Workflows & Features
 
@@ -46,6 +48,26 @@ UI, Workflows & Features
  * The list-objects-filter API (used to create a sparse/lazy clone)
    learned to take a combined filter specification.
 
+ * The documentation and tests for "git format-patch" have been
+   cleaned up.
+
+ * On Windows, the root level of UNC share is now allowed to be used
+   just like any other directory.
+
+ * The command line completion support (in contrib/) learned about the
+   "--skip" option of "git revert" and "git cherry-pick".
+
+ * "git rebase --keep-base <upstream>" tries to find the original base
+   of the topic being rebased and rebase on top of that same base,
+   which is useful when running the "git rebase -i" (and its limited
+   variant "git rebase -x").
+
+   The command also has learned to fast-forward in more cases where it
+   can instead of replaying to recreate identical commits.
+
+ * A configuration variable tells "git fetch" to write the commit
+   graph after finishing.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -71,6 +93,21 @@ Performance, Internal Implementation, Development Support etc.
    learned to avoid unnecessary ref advertisement, which has been
    corrected.
 
+ * Preparation for SHA-256 upgrade continues in the test department.
+   (merge 0c37c41d13 bc/hash-independent-tests-part-5 later to maint).
+
+ * The memory ownership model of the "git fast-import" got
+   straightened out.
+
+ * Output from trace2 subsystem is formatted more prettily now.
+
+ * The internal code originally invented for ".gitignore" processing
+   got reshuffled and renamed to make it less tied to "excluding" and
+   stress more that it is about "matching", as it has been reused for
+   things like sparse checkout specification that want to check if a
+   path is "included".
+
+
 
 Fixes since v2.23
 -----------------
@@ -135,9 +172,39 @@ Fixes since v2.23
    xmalloc() wrapper, as the rest of the system, for consistency.
    (merge 93b980e58f cb/curl-use-xmalloc later to maint).
 
+ * Build fix to adjust .gitignore to unignore a path that we started to track.
+   (merge aac6ff7b5b js/visual-studio later to maint).
+
+ * A few implementation fixes in the notes API.
+   (merge 60fe477a0b mh/notes-duplicate-entries later to maint).
+
+ * Fix an earlier regression to "git push --all" which should have
+   been forbidden when the target remote repository is set to be a
+   mirror.
+   (merge 8e4c8af058 tg/push-all-in-mirror-forbidden later to maint).
+
+ * Fix an earlier regression in the test suite, which mistakenly
+   stopped running HTTPD tests.
+   (merge 3960290675 sg/git-test-boolean later to maint).
+
+ * "git rebase --autostash <upstream> <branch>", when <branch> is
+   different from the current branch, incorrectly moved the tip of the
+   current branch, which has been corrected.
+   (merge bf1e28e0ad bw/rebase-autostash-keep-current-branch later to maint).
+
  * Other code cleanup, docfix, build fix, etc.
    (merge d1387d3895 en/fast-import-merge-doc later to maint).
    (merge 1c24a54ea4 bm/repository-layout-typofix later to maint).
    (merge 415b770b88 ds/midx-expire-repack later to maint).
    (merge 19800bdc3f nd/diff-parseopt later to maint).
    (merge 58166c2e9d tg/t0021-racefix later to maint).
+   (merge 7027f508c7 dl/compat-cleanup later to maint).
+   (merge e770fbfeff jc/test-cleanup later to maint).
+   (merge 1fd881d404 rs/trace2-dst-warning later to maint).
+   (merge 7e92756751 mh/http-urlmatch-cleanup later to maint).
+   (merge 9784f97321 mh/release-commit-memory-fix later to maint).
+   (merge 60d198d022 tb/banned-vsprintf-namefix later to maint).
+   (merge 80e3658647 rs/help-unknown-ref-does-not-return later to maint).
+   (merge 0a8bc7068f dt/remote-helper-doc-re-lock-option later to maint).
+   (merge 27fd1e4ea7 en/merge-options-ff-and-friends later to maint).
+   (merge 502c386ff9 sg/clean-nested-repo-with-ignored later to maint).
index 6553d69..6323fea 100644 (file)
@@ -10,7 +10,7 @@ Fixes since v2.7
    setting GIT_WORK_TREE environment themselves.
 
  * The "exclude_list" structure has the usual "alloc, nr" pair of
-   fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot
+   fields to be used by ALLOC_GROW(), but clear_pattern_list() forgot
    to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
    array.
 
index 2507971..5fbe1b8 100644 (file)
@@ -270,7 +270,7 @@ notes for details).
    setting GIT_WORK_TREE environment themselves.
 
  * The "exclude_list" structure has the usual "alloc, nr" pair of
-   fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot
+   fields to be used by ALLOC_GROW(), but clear_pattern_list() forgot
    to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
    array.
 
index 545522f..875f8c8 100644 (file)
@@ -17,6 +17,14 @@ which can improve `git push` performance in repos with many files.
 +
 * `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
 skipping more commits at a time, reducing the number of round trips.
++
+* `fetch.writeCommitGraph=true` writes a commit-graph after every `git fetch`
+command that downloads a pack-file from a remote. Using the `--split` option,
+most executions will create a very small commit-graph file on top of the
+existing commit-graph file(s). Occasionally, these files will merge and the
+write may take longer. Having an updated commit-graph file helps performance
+of many Git commands, including `git merge-base`, `git push -f`, and
+`git log --graph`.
 
 feature.manyFiles::
        Enable config options that optimize for repos with many files in the
index d402110..e8cb205 100644 (file)
@@ -69,3 +69,13 @@ fetch.showForcedUpdates::
        Set to false to enable `--no-show-forced-updates` in
        linkgit:git-fetch[1] and linkgit:git-pull[1] commands.
        Defaults to true.
+
+fetch.writeCommitGraph::
+       Set to true to write a commit-graph after every `git fetch` command
+       that downloads a pack-file from a remote. Using the `--split` option,
+       most executions will create a very small commit-graph file on top of
+       the existing commit-graph file(s). Occasionally, these files will
+       merge and the write may take longer. Having an updated commit-graph
+       file helps performance of many Git commands, including `git merge-base`,
+       `git push -f`, and `git log --graph`. Defaults to false, unless
+       `feature.experimental` is true.
index 414a5a8..cb629fa 100644 (file)
@@ -77,6 +77,7 @@ format.coverLetter::
        A boolean that controls whether to generate a cover-letter when
        format-patch is invoked, but in addition can be set to "auto", to
        generate a cover-letter only when there's more than one patch.
+       Default is false.
 
 format.outputDirectory::
        Set a custom directory to store the resulting files instead of the
index cc940eb..784e934 100644 (file)
@@ -17,9 +17,9 @@ This program dumps the given revisions in a form suitable to be piped
 into 'git fast-import'.
 
 You can use it as a human-readable bundle replacement (see
-linkgit:git-bundle[1]), or as a kind of an interactive
-'git filter-branch'.
-
+linkgit:git-bundle[1]), or as a format that can be edited before being
+fed to 'git fast-import' in order to do history rewrites (an ability
+relied on by tools like 'git filter-repo').
 
 OPTIONS
 -------
index 6b53dd7..5876598 100644 (file)
@@ -16,6 +16,19 @@ SYNOPSIS
        [--original <namespace>] [-d <directory>] [-f | --force]
        [--state-branch <branch>] [--] [<rev-list options>...]
 
+WARNING
+-------
+'git filter-branch' has a plethora of pitfalls that can produce non-obvious
+manglings of the intended history rewrite (and can leave you with little
+time to investigate such problems since it has such abysmal performance).
+These safety and performance issues cannot be backward compatibly fixed and
+as such, its use is not recommended.  Please use an alternative history
+filtering tool such as https://github.com/newren/git-filter-repo/[git
+filter-repo].  If you still need to use 'git filter-branch', please
+carefully read <<SAFETY>> (and <<PERFORMANCE>>) to learn about the land
+mines of filter-branch, and then vigilantly avoid as many of the hazards
+listed there as reasonably possible.
+
 DESCRIPTION
 -----------
 Lets you rewrite Git revision history by rewriting the branches mentioned
@@ -445,36 +458,236 @@ warned.
   (or if your git-gc is not new enough to support arguments to
   `--prune`, use `git repack -ad; git prune` instead).
 
-NOTES
------
-
-git-filter-branch allows you to make complex shell-scripted rewrites
-of your Git history, but you probably don't need this flexibility if
-you're simply _removing unwanted data_ like large files or passwords.
-For those operations you may want to consider
-http://rtyley.github.io/bfg-repo-cleaner/[The BFG Repo-Cleaner],
-a JVM-based alternative to git-filter-branch, typically at least
-10-50x faster for those use-cases, and with quite different
-characteristics:
-
-* Any particular version of a file is cleaned exactly _once_. The BFG,
-  unlike git-filter-branch, does not give you the opportunity to
-  handle a file differently based on where or when it was committed
-  within your history. This constraint gives the core performance
-  benefit of The BFG, and is well-suited to the task of cleansing bad
-  data - you don't care _where_ the bad data is, you just want it
-  _gone_.
-
-* By default The BFG takes full advantage of multi-core machines,
-  cleansing commit file-trees in parallel. git-filter-branch cleans
-  commits sequentially (i.e. in a single-threaded manner), though it
-  _is_ possible to write filters that include their own parallelism,
-  in the scripts executed against each commit.
-
-* The http://rtyley.github.io/bfg-repo-cleaner/#examples[command options]
-  are much more restrictive than git-filter branch, and dedicated just
-  to the tasks of removing unwanted data- e.g:
-  `--strip-blobs-bigger-than 1M`.
+[[PERFORMANCE]]
+PERFORMANCE
+-----------
+
+The performance of git-filter-branch is glacially slow; its design makes it
+impossible for a backward-compatible implementation to ever be fast:
+
+* In editing files, git-filter-branch by design checks out each and
+every commit as it existed in the original repo.  If your repo has 10\^5
+files and 10\^5 commits, but each commit only modifies 5 files, then
+git-filter-branch will make you do 10\^10 modifications, despite only
+having (at most) 5*10^5 unique blobs.
+
+* If you try and cheat and try to make git-filter-branch only work on
+files modified in a commit, then two things happen
+
+  ** you run into problems with deletions whenever the user is simply
+     trying to rename files (because attempting to delete files that
+     don't exist looks like a no-op; it takes some chicanery to remap
+     deletes across file renames when the renames happen via arbitrary
+     user-provided shell)
+
+  ** even if you succeed at the map-deletes-for-renames chicanery, you
+     still technically violate backward compatibility because users are
+     allowed to filter files in ways that depend upon topology of
+     commits instead of filtering solely based on file contents or names
+     (though this has not been observed in the wild).
+
+* Even if you don't need to edit files but only want to e.g. rename or
+remove some and thus can avoid checking out each file (i.e. you can use
+--index-filter), you still are passing shell snippets for your filters.
+This means that for every commit, you have to have a prepared git repo
+where those filters can be run.  That's a significant setup.
+
+* Further, several additional files are created or updated per commit by
+git-filter-branch.  Some of these are for supporting the convenience
+functions provided by git-filter-branch (such as map()), while others
+are for keeping track of internal state (but could have also been
+accessed by user filters; one of git-filter-branch's regression tests
+does so).  This essentially amounts to using the filesystem as an IPC
+mechanism between git-filter-branch and the user-provided filters.
+Disks tend to be a slow IPC mechanism, and writing these files also
+effectively represents a forced synchronization point between separate
+processes that we hit with every commit.
+
+* The user-provided shell commands will likely involve a pipeline of
+commands, resulting in the creation of many processes per commit.
+Creating and running another process takes a widely varying amount of
+time between operating systems, but on any platform it is very slow
+relative to invoking a function.
+
+* git-filter-branch itself is written in shell, which is kind of slow.
+This is the one performance issue that could be backward-compatibly
+fixed, but compared to the above problems that are intrinsic to the
+design of git-filter-branch, the language of the tool itself is a
+relatively minor issue.
+
+  ** Side note: Unfortunately, people tend to fixate on the
+     written-in-shell aspect and periodically ask if git-filter-branch
+     could be rewritten in another language to fix the performance
+     issues.  Not only does that ignore the bigger intrinsic problems
+     with the design, it'd help less than you'd expect: if
+     git-filter-branch itself were not shell, then the convenience
+     functions (map(), skip_commit(), etc) and the `--setup` argument
+     could no longer be executed once at the beginning of the program
+     but would instead need to be prepended to every user filter (and
+     thus re-executed with every commit).
+
+The https://github.com/newren/git-filter-repo/[git filter-repo] tool is
+an alternative to git-filter-branch which does not suffer from these
+performance problems or the safety problems (mentioned below). For those
+with existing tooling which relies upon git-filter-branch, 'git
+repo-filter' also provides
+https://github.com/newren/git-filter-repo/blob/master/contrib/filter-repo-demos/filter-lamely[filter-lamely],
+a drop-in git-filter-branch replacement (with a few caveats).  While
+filter-lamely suffers from all the same safety issues as
+git-filter-branch, it at least ameloriates the performance issues a
+little.
+
+[[SAFETY]]
+SAFETY
+------
+
+git-filter-branch is riddled with gotchas resulting in various ways to
+easily corrupt repos or end up with a mess worse than what you started
+with:
+
+* Someone can have a set of "working and tested filters" which they
+document or provide to a coworker, who then runs them on a different OS
+where the same commands are not working/tested (some examples in the
+git-filter-branch manpage are also affected by this).  BSD vs. GNU
+userland differences can really bite.  If lucky, error messages are
+spewed.  But just as likely, the commands either don't do the filtering
+requested, or silently corrupt by making some unwanted change.  The
+unwanted change may only affect a few commits, so it's not necessarily
+obvious either.  (The fact that problems won't necessarily be obvious
+means they are likely to go unnoticed until the rewritten history is in
+use for quite a while, at which point it's really hard to justify
+another flag-day for another rewrite.)
+
+* Filenames with spaces are often mishandled by shell snippets since
+they cause problems for shell pipelines.  Not everyone is familiar with
+find -print0, xargs -0, git-ls-files -z, etc.  Even people who are
+familiar with these may assume such flags are not relevant because
+someone else renamed any such files in their repo back before the person
+doing the filtering joined the project.  And often, even those familiar
+with handling arguments with spaces may not do so just because they
+aren't in the mindset of thinking about everything that could possibly
+go wrong.
+
+* Non-ascii filenames can be silently removed despite being in a desired
+directory.  Keeping only wanted paths is often done using pipelines like
+`git ls-files | grep -v ^WANTED_DIR/ | xargs git rm`.  ls-files will
+only quote filenames if needed, so folks may not notice that one of the
+files didn't match the regex (at least not until it's much too late).
+Yes, someone who knows about core.quotePath can avoid this (unless they
+have other special characters like \t, \n, or "), and people who use
+ls-files -z with something other than grep can avoid this, but that
+doesn't mean they will.
+
+* Similarly, when moving files around, one can find that filenames with
+non-ascii or special characters end up in a different directory, one
+that includes a double quote character.  (This is technically the same
+issue as above with quoting, but perhaps an interesting different way
+that it can and has manifested as a problem.)
+
+* It's far too easy to accidentally mix up old and new history.  It's
+still possible with any tool, but git-filter-branch almost invites it.
+If lucky, the only downside is users getting frustrated that they don't
+know how to shrink their repo and remove the old stuff.  If unlucky,
+they merge old and new history and end up with multiple "copies" of each
+commit, some of which have unwanted or sensitive files and others which
+don't.  This comes about in multiple different ways:
+
+  ** the default to only doing a partial history rewrite ('--all' is not
+     the default and few examples show it)
+
+  ** the fact that there's no automatic post-run cleanup
+
+  ** the fact that --tag-name-filter (when used to rename tags) doesn't
+     remove the old tags but just adds new ones with the new name
+
+  ** the fact that little educational information is provided to inform
+     users of the ramifications of a rewrite and how to avoid mixing old
+     and new history.  For example, this man page discusses how users
+     need to understand that they need to rebase their changes for all
+     their branches on top of new history (or delete and reclone), but
+     that's only one of multiple concerns to consider.  See the
+     "DISCUSSION" section of the git filter-repo manual page for more
+     details.
+
+* Annotated tags can be accidentally converted to lightweight tags, due
+to either of two issues:
+
+  ** Someone can do a history rewrite, realize they messed up, restore
+     from the backups in refs/original/, and then redo their
+     git-filter-branch command.  (The backup in refs/original/ is not a
+     real backup; it dereferences tags first.)
+
+  ** Running git-filter-branch with either --tags or --all in your
+     <rev-list options>.  In order to retain annotated tags as
+     annotated, you must use --tag-name-filter (and must not have
+     restored from refs/original/ in a previously botched rewrite).
+
+* Any commit messages that specify an encoding will become corrupted
+by the rewrite; git-filter-branch ignores the encoding, takes the original
+bytes, and feeds it to commit-tree without telling it the proper
+encoding.  (This happens whether or not --msg-filter is used.)
+
+* Commit messages (even if they are all UTF-8) by default become
+corrupted due to not being updated -- any references to other commit
+hashes in commit messages will now refer to no-longer-extant commits.
+
+* There are no facilities for helping users find what unwanted crud they
+should delete, which means they are much more likely to have incomplete
+or partial cleanups that sometimes result in confusion and people
+wasting time trying to understand.  (For example, folks tend to just
+look for big files to delete instead of big directories or extensions,
+and once they do so, then sometime later folks using the new repository
+who are going through history will notice a build artifact directory
+that has some files but not others, or a cache of dependencies
+(node_modules or similar) which couldn't have ever been functional since
+it's missing some files.)
+
+* If --prune-empty isn't specified, then the filtering process can
+create hoards of confusing empty commits
+
+* If --prune-empty is specified, then intentionally placed empty
+commits from before the filtering operation are also pruned instead of
+just pruning commits that became empty due to filtering rules.
+
+* If --prune empty is specified, sometimes empty commits are missed
+and left around anyway (a somewhat rare bug, but it happens...)
+
+* A minor issue, but users who have a goal to update all names and
+emails in a repository may be led to --env-filter which will only update
+authors and committers, missing taggers.
+
+* If the user provides a --tag-name-filter that maps multiple tags to
+the same name, no warning or error is provided; git-filter-branch simply
+overwrites each tag in some undocumented pre-defined order resulting in
+only one tag at the end.  (A git-filter-branch regression test requires
+this surprising behavior.)
+
+Also, the poor performance of git-filter-branch often leads to safety
+issues:
+
+* Coming up with the correct shell snippet to do the filtering you want
+is sometimes difficult unless you're just doing a trivial modification
+such as deleting a couple files.  Unfortunately, people often learn if
+the snippet is right or wrong by trying it out, but the rightness or
+wrongness can vary depending on special circumstances (spaces in
+filenames, non-ascii filenames, funny author names or emails, invalid
+timezones, presence of grafts or replace objects, etc.), meaning they
+may have to wait a long time, hit an error, then restart.  The
+performance of git-filter-branch is so bad that this cycle is painful,
+reducing the time available to carefully re-check (to say nothing about
+what it does to the patience of the person doing the rewrite even if
+they do technically have more time available).  This problem is extra
+compounded because errors from broken filters may not be shown for a
+long time and/or get lost in a sea of output.  Even worse, broken
+filters often just result in silent incorrect rewrites.
+
+* To top it all off, even when users finally find working commands, they
+naturally want to share them.  But they may be unaware that their repo
+didn't have some special cases that someone else's does.  So, when
+someone else with a different repository runs the same commands, they
+get hit by the problems above.  Or, the user just runs commands that
+really were vetted for special cases, but they run it on a different OS
+where it doesn't work, as noted above.
 
 GIT
 ---
index b9b97e6..0ac56f4 100644 (file)
@@ -17,9 +17,9 @@ SYNOPSIS
                   [--signature-file=<file>]
                   [-n | --numbered | -N | --no-numbered]
                   [--start-number <n>] [--numbered-files]
-                  [--in-reply-to=Message-Id] [--suffix=.<sfx>]
+                  [--in-reply-to=<message id>] [--suffix=.<sfx>]
                   [--ignore-if-in-upstream]
-                  [--rfc] [--subject-prefix=Subject-Prefix]
+                  [--rfc] [--subject-prefix=<subject prefix>]
                   [(--reroll-count|-v) <n>]
                   [--to=<email>] [--cc=<email>]
                   [--[no-]cover-letter] [--quiet]
@@ -159,9 +159,9 @@ Beware that the default for 'git send-email' is to thread emails
 itself.  If you want `git format-patch` to take care of threading, you
 will want to ensure that threading is disabled for `git send-email`.
 
---in-reply-to=Message-Id::
+--in-reply-to=<message id>::
        Make the first mail (or all the mails with `--no-thread`) appear as a
-       reply to the given Message-Id, which avoids breaking threads to
+       reply to the given <message id>, which avoids breaking threads to
        provide a new patch series.
 
 --ignore-if-in-upstream::
@@ -171,9 +171,9 @@ will want to ensure that threading is disabled for `git send-email`.
        patches being generated, and any patch that matches is
        ignored.
 
---subject-prefix=<Subject-Prefix>::
+--subject-prefix=<subject prefix>::
        Instead of the standard '[PATCH]' prefix in the subject
-       line, instead use '[<Subject-Prefix>]'. This
+       line, instead use '[<subject prefix>]'. This
        allows for useful naming of a patch series, and can be
        combined with the `--numbered` option.
 
@@ -314,7 +314,8 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
 --base=<commit>::
        Record the base tree information to identify the state the
        patch series applies to.  See the BASE TREE INFORMATION section
-       below for details.
+       below for details. If <commit> is "auto", a base commit is
+       automatically chosen.
 
 --root::
        Treat the revision argument as a <revision range>, even if it
@@ -330,8 +331,9 @@ CONFIGURATION
 -------------
 You can specify extra mail header lines to be added to each message,
 defaults for the subject prefix and file suffix, number patches when
-outputting more than one patch, add "To" or "Cc:" headers, configure
-attachments, and sign off patches with configuration variables.
+outputting more than one patch, add "To:" or "Cc:" headers, configure
+attachments, change the patch output directory, and sign off patches
+with configuration variables.
 
 ------------
 [format]
@@ -343,7 +345,8 @@ attachments, and sign off patches with configuration variables.
        cc = <email>
        attach [ = mime-boundary-string ]
        signOff = true
-       coverletter = auto
+       outputDirectory = <directory>
+       coverLetter = auto
 ------------
 
 
index 247f765..0c114ad 100644 (file)
@@ -115,15 +115,14 @@ NOTES
 -----
 
 'git gc' tries very hard not to delete objects that are referenced
-anywhere in your repository. In
-particular, it will keep not only objects referenced by your current set
-of branches and tags, but also objects referenced by the index,
-remote-tracking branches, refs saved by 'git filter-branch' in
-refs/original/, reflogs (which may reference commits in branches
-that were later amended or rewound), and anything else in the refs/* namespace.
-If you are expecting some objects to be deleted and they aren't, check
-all of those locations and decide whether it makes sense in your case to
-remove those references.
+anywhere in your repository. In particular, it will keep not only
+objects referenced by your current set of branches and tags, but also
+objects referenced by the index, remote-tracking branches, notes saved
+by 'git notes' under refs/notes/, reflogs (which may reference commits
+in branches that were later amended or rewound), and anything else in
+the refs/* namespace.  If you are expecting some objects to be deleted
+and they aren't, check all of those locations and decide whether it
+makes sense in your case to remove those references.
 
 On the other hand, when 'git gc' runs concurrently with another process,
 there is a risk of it deleting an object that the other process is using
index 3136c19..639a417 100644 (file)
@@ -8,8 +8,8 @@ git-rebase - Reapply commits on top of another base tip
 SYNOPSIS
 --------
 [verse]
-'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
-       [<upstream> [<branch>]]
+'git rebase' [-i | --interactive] [<options>] [--exec <cmd>]
+       [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
 'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
        --root [<branch>]
 'git rebase' (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
@@ -217,6 +217,24 @@ As a special case, you may use "A\...B" as a shortcut for the
 merge base of A and B if there is exactly one merge base. You can
 leave out at most one of A and B, in which case it defaults to HEAD.
 
+--keep-base::
+       Set the starting point at which to create the new commits to the
+       merge base of <upstream> <branch>. Running
+       'git rebase --keep-base <upstream> <branch>' is equivalent to
+       running 'git rebase --onto <upstream>... <upstream>'.
++
+This option is useful in the case where one is developing a feature on
+top of an upstream branch. While the feature is being worked on, the
+upstream branch may advance and it may not be the best idea to keep
+rebasing on top of the upstream but to keep the base commit as-is.
++
+Although both this option and --fork-point find the merge base between
+<upstream> and <branch>, this option uses the merge base as the _starting
+point_ on which new commits will be created, whereas --fork-point uses
+the merge base to determine the _set of commits_ which will be rebased.
++
+See also INCOMPATIBLE OPTIONS below.
+
 <upstream>::
        Upstream branch to compare against.  May be any valid commit,
        not just an existing branch name. Defaults to the configured
@@ -369,6 +387,10 @@ ends up being empty, the <upstream> will be used as a fallback.
 +
 If either <upstream> or --root is given on the command line, then the
 default is `--no-fork-point`, otherwise the default is `--fork-point`.
++
+If your branch was based on <upstream> but <upstream> was rewound and
+your branch contains commits which were dropped, this option can be used
+with `--keep-base` in order to drop those commits from your branch.
 
 --ignore-whitespace::
 --whitespace=<option>::
@@ -543,6 +565,8 @@ In addition, the following pairs of options are incompatible:
  * --preserve-merges and --interactive
  * --preserve-merges and --signoff
  * --preserve-merges and --rebase-merges
+ * --keep-base and --onto
+ * --keep-base and --root
 
 BEHAVIORAL DIFFERENCES
 -----------------------
@@ -830,7 +854,8 @@ Hard case: The changes are not the same.::
        This happens if the 'subsystem' rebase had conflicts, or used
        `--interactive` to omit, edit, squash, or fixup commits; or
        if the upstream used one of `commit --amend`, `reset`, or
-       `filter-branch`.
+       a full history rewriting command like
+       https://github.com/newren/git-filter-repo[`filter-repo`].
 
 
 The easy case
@@ -868,7 +893,7 @@ NOTE: While an "easy case recovery" sometimes appears to be successful
       --interactive` will be **resurrected**!
 
 The idea is to manually tell 'git rebase' "where the old 'subsystem'
-ended and your 'topic' began", that is, what the old merge-base
+ended and your 'topic' began", that is, what the old merge base
 between them was.  You will have to find a way to name the last commit
 of the old 'subsystem', for example:
 
index 246dc99..f271d75 100644 (file)
@@ -123,10 +123,10 @@ The following format are available:
 CREATING REPLACEMENT OBJECTS
 ----------------------------
 
-linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and
-linkgit:git-rebase[1], among other git commands, can be used to create
-replacement objects from existing objects. The `--edit` option can
-also be used with 'git replace' to create a replacement object by
+linkgit:git-hash-object[1], linkgit:git-rebase[1], and
+https://github.com/newren/git-filter-repo[git-filter-repo], among other git commands, can be used to
+create replacement objects from existing objects. The `--edit` option
+can also be used with 'git replace' to create a replacement object by
 editing an existing object.
 
 If you want to replace many blobs, trees or commits that are part of a
@@ -148,13 +148,13 @@ pending objects.
 SEE ALSO
 --------
 linkgit:git-hash-object[1]
-linkgit:git-filter-branch[1]
 linkgit:git-rebase[1]
 linkgit:git-tag[1]
 linkgit:git-branch[1]
 linkgit:git-commit[1]
 linkgit:git-var[1]
 linkgit:git[1]
+https://github.com/newren/git-filter-repo[git-filter-repo]
 
 GIT
 ---
index 3071162..53774f5 100644 (file)
@@ -769,11 +769,11 @@ option for (hopefully) obvious reasons.
 +
 This option is NOT recommended as it makes it difficult to track down
 old references to SVN revision numbers in existing documentation, bug
-reports and archives.  If you plan to eventually migrate from SVN to Git
-and are certain about dropping SVN history, consider
-linkgit:git-filter-branch[1] instead.  filter-branch also allows
-reformatting of metadata for ease-of-reading and rewriting authorship
-info for non-"svn.authorsFile" users.
+reports, and archives.  If you plan to eventually migrate from SVN to
+Git and are certain about dropping SVN history, consider
+https://github.com/newren/git-filter-repo[git-filter-repo] instead.
+filter-repo also allows reformatting of metadata for ease-of-reading
+and rewriting authorship info for non-"svn.authorsFile" users.
 
 svn.useSvmProps::
 svn-remote.<name>.useSvmProps::
index 57d6e2b..50365f2 100644 (file)
@@ -447,10 +447,12 @@ post-rewrite
 
 This hook is invoked by commands that rewrite commits
 (linkgit:git-commit[1] when called with `--amend` and
-linkgit:git-rebase[1]; currently `git filter-branch` does 'not' call
-it!).  Its first argument denotes the command it was invoked by:
-currently one of `amend` or `rebase`.  Further command-dependent
-arguments may be passed in the future.
+linkgit:git-rebase[1]; however, full-history (re)writing tools like
+linkgit:git-fast-import[1] or
+https://github.com/newren/git-filter-repo[git-filter-repo] typically
+do not call it!).  Its first argument denotes the command it was
+invoked by: currently one of `amend` or `rebase`.  Further
+command-dependent arguments may be passed in the future.
 
 The hook receives a list of the rewritten commits on stdin, in the
 format
index 43f80c8..a5c3c04 100644 (file)
@@ -297,9 +297,13 @@ Supported if the helper has the "option" capability.
        same batch are complete. Only objects which were reported
        in the output of 'list' with a sha1 may be fetched this way.
 +
-Optionally may output a 'lock <file>' line indicating a file under
-GIT_DIR/objects/pack which is keeping a pack until refs can be
-suitably updated.
+Optionally may output a 'lock <file>' line indicating the full path of
+a file under `$GIT_DIR/objects/pack` which is keeping a pack until
+refs can be suitably updated.  The path must end with `.keep`. This is
+a mechanism to name a <pack,idx,keep> tuple by giving only the keep
+component.  The kept pack will not be deleted by a concurrent repack,
+even though its objects may not be referenced until the fetch completes.
+The `.keep` file will be deleted at the conclusion of the fetch.
 +
 If option 'check-connectivity' is requested, the helper must output
 'connectivity-ok' if the clone is self-contained and connected.
index d6a9f4b..59b8ff1 100644 (file)
@@ -40,20 +40,24 @@ set to `no` at the beginning of them.
        case of a merge conflict.
 
 --ff::
-       When the merge resolves as a fast-forward, only update the branch
-       pointer, without creating a merge commit.  This is the default
-       behavior.
-
 --no-ff::
-       Create a merge commit even when the merge resolves as a
-       fast-forward.  This is the default behaviour when merging an
-       annotated (and possibly signed) tag that is not stored in
-       its natural place in 'refs/tags/' hierarchy.
-
 --ff-only::
-       Refuse to merge and exit with a non-zero status unless the
-       current `HEAD` is already up to date or the merge can be
-       resolved as a fast-forward.
+       Specifies how a merge is handled when the merged-in history is
+       already a descendant of the current history.  `--ff` is the
+       default unless merging an annotated (and possibly signed) tag
+       that is not stored in its natural place in the `refs/tags/`
+       hierarchy, in which case `--no-ff` is assumed.
++
+With `--ff`, when possible resolve the merge as a fast-forward (only
+update the branch pointer to match the merged branch; do not create a
+merge commit).  When not possible (when the merged-in history is not a
+descendant of the current history), create a merge commit.
++
+With `--no-ff`, create a merge commit in all cases, even when the merge
+could instead be resolved as a fast-forward.
++
+With `--ff-only`, resolve the merge as a fast-forward when possible.
+When not possible, refuse to merge and exit with a non-zero status.
 
 -S[<keyid>]::
 --gpg-sign[=<keyid>]::
index 5abb8e8..76b6e4f 100644 (file)
@@ -111,11 +111,11 @@ marked. If you to exclude files, make sure you have loaded index first.
 * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
   sizeof(dir))`.
 
-* To add single exclude pattern, call `add_exclude_list()` and then
-  `add_exclude()`.
+* To add single exclude pattern, call `add_pattern_list()` and then
+  `add_pattern()`.
 
 * To add patterns from a file (e.g. `.git/info/exclude`), call
-  `add_excludes_from_file()` , and/or set `dir.exclude_per_dir`.  A
+  `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.  A
   short-hand function `setup_standard_excludes()` can be used to set
   up the standard set of exclude settings.
 
diff --git a/attr.c b/attr.c
index 93dc16b..d02d081 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -259,7 +259,7 @@ struct pattern {
        const char *pattern;
        int patternlen;
        int nowildcardlen;
-       unsigned flags;         /* EXC_FLAG_* */
+       unsigned flags;         /* PATTERN_FLAG_* */
 };
 
 /*
@@ -400,11 +400,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
                char *p = (char *)&(res->state[num_attr]);
                memcpy(p, name, namelen);
                res->u.pat.pattern = p;
-               parse_exclude_pattern(&res->u.pat.pattern,
+               parse_path_pattern(&res->u.pat.pattern,
                                      &res->u.pat.patternlen,
                                      &res->u.pat.flags,
                                      &res->u.pat.nowildcardlen);
-               if (res->u.pat.flags & EXC_FLAG_NEGATIVE) {
+               if (res->u.pat.flags & PATTERN_FLAG_NEGATIVE) {
                        warning(_("Negative patterns are ignored in git attributes\n"
                                  "Use '\\!' for literal leading exclamation."));
                        goto fail_return;
@@ -991,10 +991,10 @@ static int path_matches(const char *pathname, int pathlen,
        int prefix = pat->nowildcardlen;
        int isdir = (pathlen && pathname[pathlen - 1] == '/');
 
-       if ((pat->flags & EXC_FLAG_MUSTBEDIR) && !isdir)
+       if ((pat->flags & PATTERN_FLAG_MUSTBEDIR) && !isdir)
                return 0;
 
-       if (pat->flags & EXC_FLAG_NODIR) {
+       if (pat->flags & PATTERN_FLAG_NODIR) {
                return match_basename(pathname + basename_offset,
                                      pathlen - basename_offset - isdir,
                                      pattern, prefix,
index 447af24..60a18d4 100644 (file)
--- a/banned.h
+++ b/banned.h
@@ -26,7 +26,7 @@
 #define vsprintf(...) BANNED(vsprintf)
 #else
 #define sprintf(buf,fmt,arg) BANNED(sprintf)
-#define vsprintf(buf,fmt,arg) BANNED(sprintf)
+#define vsprintf(buf,fmt,arg) BANNED(vsprintf)
 #endif
 
 #endif /* BANNED_H */
index 1aea657..ee7305e 100644 (file)
@@ -1272,7 +1272,9 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
        buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
 
        ident_line = find_commit_header(buffer, "author", &ident_len);
-
+       if (!ident_line)
+               die(_("missing author line in commit %s"),
+                     oid_to_hex(&commit->object.oid));
        if (split_ident_line(&id, ident_line, ident_len) < 0)
                die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
 
index 5990973..5a4f923 100644 (file)
@@ -32,19 +32,19 @@ static const struct option check_ignore_options[] = {
        OPT_END()
 };
 
-static void output_exclude(const char *path, struct exclude *exclude)
+static void output_pattern(const char *path, struct path_pattern *pattern)
 {
-       char *bang  = (exclude && exclude->flags & EXC_FLAG_NEGATIVE)  ? "!" : "";
-       char *slash = (exclude && exclude->flags & EXC_FLAG_MUSTBEDIR) ? "/" : "";
+       char *bang  = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE)  ? "!" : "";
+       char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
        if (!nul_term_line) {
                if (!verbose) {
                        write_name_quoted(path, stdout, '\n');
                } else {
-                       if (exclude) {
-                               quote_c_style(exclude->el->src, NULL, stdout, 0);
+                       if (pattern) {
+                               quote_c_style(pattern->pl->src, NULL, stdout, 0);
                                printf(":%d:%s%s%s\t",
-                                      exclude->srcpos,
-                                      bang, exclude->pattern, slash);
+                                      pattern->srcpos,
+                                      bang, pattern->pattern, slash);
                        }
                        else {
                                printf("::\t");
@@ -56,11 +56,11 @@ static void output_exclude(const char *path, struct exclude *exclude)
                if (!verbose) {
                        printf("%s%c", path, '\0');
                } else {
-                       if (exclude)
+                       if (pattern)
                                printf("%s%c%d%c%s%s%s%c%s%c",
-                                      exclude->el->src, '\0',
-                                      exclude->srcpos, '\0',
-                                      bang, exclude->pattern, slash, '\0',
+                                      pattern->pl->src, '\0',
+                                      pattern->srcpos, '\0',
+                                      bang, pattern->pattern, slash, '\0',
                                       path, '\0');
                        else
                                printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0');
@@ -74,7 +74,7 @@ static int check_ignore(struct dir_struct *dir,
        const char *full_path;
        char *seen;
        int num_ignored = 0, i;
-       struct exclude *exclude;
+       struct path_pattern *pattern;
        struct pathspec pathspec;
 
        if (!argc) {
@@ -103,15 +103,15 @@ static int check_ignore(struct dir_struct *dir,
        seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
        for (i = 0; i < pathspec.nr; i++) {
                full_path = pathspec.items[i].match;
-               exclude = NULL;
+               pattern = NULL;
                if (!seen[i]) {
                        int dtype = DT_UNKNOWN;
-                       exclude = last_exclude_matching(dir, &the_index,
+                       pattern = last_matching_pattern(dir, &the_index,
                                                        full_path, &dtype);
                }
-               if (!quiet && (exclude || show_non_matching))
-                       output_exclude(pathspec.items[i].original, exclude);
-               if (exclude)
+               if (!quiet && (pattern || show_non_matching))
+                       output_pattern(pathspec.items[i].original, pattern);
+               if (pattern)
                        num_ignored++;
        }
        free(seen);
index 0a3679e..1283727 100644 (file)
@@ -1708,6 +1708,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        opts.checkout_index = -2;    /* default on */
        opts.checkout_worktree = -2; /* default on */
 
+       if (argc == 3 && !strcmp(argv[1], "-b")) {
+               /*
+                * User ran 'git checkout -b <branch>' and expects
+                * the same behavior as 'git switch -c <branch>'.
+                */
+               opts.switch_branch_doing_nothing_is_ok = 0;
+               opts.only_merge_on_switching_branches = 1;
+       }
+
        options = parse_options_dup(checkout_options);
        options = add_common_options(&opts, options);
        options = add_common_switch_branch_options(&opts, options);
index d5579da..851beb7 100644 (file)
@@ -648,7 +648,7 @@ static int filter_by_patterns_cmd(void)
        struct strbuf confirm = STRBUF_INIT;
        struct strbuf **ignore_list;
        struct string_list_item *item;
-       struct exclude_list *el;
+       struct pattern_list *pl;
        int changed = -1, i;
 
        for (;;) {
@@ -671,7 +671,7 @@ static int filter_by_patterns_cmd(void)
                        break;
 
                memset(&dir, 0, sizeof(dir));
-               el = add_exclude_list(&dir, EXC_CMDL, "manual exclude");
+               pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
                ignore_list = strbuf_split_max(&confirm, ' ', 0);
 
                for (i = 0; ignore_list[i]; i++) {
@@ -679,7 +679,7 @@ static int filter_by_patterns_cmd(void)
                        if (!ignore_list[i]->len)
                                continue;
 
-                       add_exclude(ignore_list[i]->buf, "", 0, el, -(i+1));
+                       add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1));
                }
 
                changed = 0;
@@ -901,7 +901,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        struct pathspec pathspec;
        struct strbuf buf = STRBUF_INIT;
        struct string_list exclude_list = STRING_LIST_INIT_NODUP;
-       struct exclude_list *el;
+       struct pattern_list *pl;
        struct string_list_item *item;
        const char *qname;
        struct option options[] = {
@@ -958,9 +958,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        if (!ignored)
                setup_standard_excludes(&dir);
 
-       el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
+       pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
        for (i = 0; i < exclude_list.nr; i++)
-               add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
+               add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
 
        parse_pathspec(&pathspec, 0,
                       PATHSPEC_PREFER_CWD,
index 2001542..e048f85 100644 (file)
@@ -313,7 +313,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
                 */
                append_name(n, dst);
                if (longformat)
-                       append_suffix(0, n->tag ? &n->tag->tagged->oid : oid, dst);
+                       append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
                if (suffix)
                        strbuf_addstr(dst, suffix);
                return;
index 9b27ae9..67c0eb8 100644 (file)
@@ -25,6 +25,7 @@
 #include "commit-reach.h"
 #include "branch.h"
 #include "promisor-remote.h"
+#include "commit-graph.h"
 
 #define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
 
@@ -1759,6 +1760,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 
        string_list_clear(&list, 0);
 
+       prepare_repo_settings(the_repository);
+       if (the_repository->settings.fetch_write_commit_graph) {
+               int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
+               struct split_commit_graph_opts split_opts;
+               memset(&split_opts, 0, sizeof(struct split_commit_graph_opts));
+
+               if (progress)
+                       commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+
+               write_commit_graph_reachable(get_object_directory(),
+                                            commit_graph_flags,
+                                            &split_opts);
+       }
+
        close_object_store(the_repository->objects);
 
        if (enable_auto_gc) {
index 2699001..69ac053 100644 (file)
@@ -1110,8 +1110,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        strbuf_addf(&buf, "+/%s%s",
                                        strcmp("less", pager) ? "" : "*",
                                        opt.pattern_list->pattern);
-                       string_list_append(&path_list, buf.buf);
-                       strbuf_detach(&buf, NULL);
+                       string_list_append(&path_list,
+                                          strbuf_detach(&buf, NULL));
                }
        }
 
index 44b10b3..c4b35fd 100644 (file)
@@ -627,6 +627,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                        break;
                case OBJ_TAG: {
                        struct tag *t = (struct tag *)o;
+                       struct object_id *oid = get_tagged_oid(t);
 
                        if (rev.shown_one)
                                putchar('\n');
@@ -638,10 +639,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                        rev.shown_one = 1;
                        if (ret)
                                break;
-                       o = parse_object(the_repository, &t->tagged->oid);
+                       o = parse_object(the_repository, oid);
                        if (!o)
                                ret = error(_("could not read object %s"),
-                                           oid_to_hex(&t->tagged->oid));
+                                           oid_to_hex(oid));
                        objects[i].item = o;
                        i--;
                        break;
index 670e8fb..f069a02 100644 (file)
@@ -492,7 +492,7 @@ static int option_parse_exclude_from(const struct option *opt,
        BUG_ON_OPT_NEG(unset);
 
        exc_given = 1;
-       add_excludes_from_file(dir, arg);
+       add_patterns_from_file(dir, arg);
 
        return 0;
 }
@@ -516,7 +516,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
        int require_work_tree = 0, show_tag = 0, i;
        const char *max_prefix;
        struct dir_struct dir;
-       struct exclude_list *el;
+       struct pattern_list *pl;
        struct string_list exclude_list = STRING_LIST_INIT_NODUP;
        struct option builtin_ls_files_options[] = {
                /* Think twice before adding "--nul" synonym to this */
@@ -594,9 +594,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 
        argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
                        ls_files_usage, 0);
-       el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
+       pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
        for (i = 0; i < exclude_list.nr; i++) {
-               add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
+               add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
        }
        if (show_tag || show_valid_bit || show_fsmonitor_bit) {
                tag_cached = "H ";
index c8f51bc..5876583 100644 (file)
@@ -610,12 +610,12 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag,
                       void *cb_data)
 {
        struct object_id peeled;
-       struct object_entry *entry = packlist_find(&to_pack, oid, NULL);
+       struct object_entry *entry = packlist_find(&to_pack, oid);
 
        if (entry)
                entry->tagged = 1;
        if (!peel_ref(path, &peeled)) {
-               entry = packlist_find(&to_pack, &peeled, NULL);
+               entry = packlist_find(&to_pack, &peeled);
                if (entry)
                        entry->tagged = 1;
        }
@@ -996,12 +996,11 @@ static int no_try_delta(const char *path)
  * few lines later when we want to add the new entry.
  */
 static int have_duplicate_entry(const struct object_id *oid,
-                               int exclude,
-                               uint32_t *index_pos)
+                               int exclude)
 {
        struct object_entry *entry;
 
-       entry = packlist_find(&to_pack, oid, index_pos);
+       entry = packlist_find(&to_pack, oid);
        if (!entry)
                return 0;
 
@@ -1141,13 +1140,12 @@ static void create_object_entry(const struct object_id *oid,
                                uint32_t hash,
                                int exclude,
                                int no_try_delta,
-                               uint32_t index_pos,
                                struct packed_git *found_pack,
                                off_t found_offset)
 {
        struct object_entry *entry;
 
-       entry = packlist_alloc(&to_pack, oid->hash, index_pos);
+       entry = packlist_alloc(&to_pack, oid);
        entry->hash = hash;
        oe_set_type(entry, type);
        if (exclude)
@@ -1171,11 +1169,10 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
 {
        struct packed_git *found_pack = NULL;
        off_t found_offset = 0;
-       uint32_t index_pos;
 
        display_progress(progress_state, ++nr_seen);
 
-       if (have_duplicate_entry(oid, exclude, &index_pos))
+       if (have_duplicate_entry(oid, exclude))
                return 0;
 
        if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
@@ -1190,7 +1187,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
 
        create_object_entry(oid, type, pack_name_hash(name),
                            exclude, name && no_try_delta(name),
-                           index_pos, found_pack, found_offset);
+                           found_pack, found_offset);
        return 1;
 }
 
@@ -1199,17 +1196,15 @@ static int add_object_entry_from_bitmap(const struct object_id *oid,
                                        int flags, uint32_t name_hash,
                                        struct packed_git *pack, off_t offset)
 {
-       uint32_t index_pos;
-
        display_progress(progress_state, ++nr_seen);
 
-       if (have_duplicate_entry(oid, 0, &index_pos))
+       if (have_duplicate_entry(oid, 0))
                return 0;
 
        if (!want_object_in_pack(oid, 0, &pack, &offset))
                return 0;
 
-       create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
+       create_object_entry(oid, type, name_hash, 0, 0, pack, offset);
        return 1;
 }
 
@@ -1507,7 +1502,7 @@ static int can_reuse_delta(const unsigned char *base_sha1,
         * First see if we're already sending the base (or it's explicitly in
         * our "excluded" list).
         */
-       base = packlist_find(&to_pack, &base_oid, NULL);
+       base = packlist_find(&to_pack, &base_oid);
        if (base) {
                if (!in_same_island(&delta->idx.oid, &base->idx.oid))
                        return 0;
@@ -2568,7 +2563,7 @@ static void add_tag_chain(const struct object_id *oid)
         * it was included via bitmaps, we would not have parsed it
         * previously).
         */
-       if (packlist_find(&to_pack, oid, NULL))
+       if (packlist_find(&to_pack, oid))
                return;
 
        tag = lookup_tag(the_repository, oid);
@@ -2592,7 +2587,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
 
        if (starts_with(path, "refs/tags/") && /* is a tag? */
            !peel_ref(path, &peeled)    && /* peelable? */
-           packlist_find(&to_pack, &peeled, NULL))      /* object packed? */
+           packlist_find(&to_pack, &peeled))      /* object packed? */
                add_tag_chain(oid);
        return 0;
 }
@@ -2788,7 +2783,7 @@ static void show_object(struct object *obj, const char *name, void *data)
                for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
                        depth++;
 
-               ent = packlist_find(&to_pack, &obj->oid, NULL);
+               ent = packlist_find(&to_pack, &obj->oid);
                if (ent && depth > oe_tree_depth(&to_pack, ent))
                        oe_set_tree_depth(&to_pack, ent, depth);
        }
@@ -3019,7 +3014,7 @@ static void loosen_unused_packed_objects(void)
 
                for (i = 0; i < p->num_objects; i++) {
                        nth_packed_object_oid(&oid, p, i);
-                       if (!packlist_find(&to_pack, &oid, NULL) &&
+                       if (!packlist_find(&to_pack, &oid) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
                                if (force_object_loose(&oid, p->mtime))
index 021dd3b..3742daf 100644 (file)
@@ -385,30 +385,14 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
 }
 
 static int do_push(const char *repo, int flags,
-                  const struct string_list *push_options)
+                  const struct string_list *push_options,
+                  struct remote *remote)
 {
        int i, errs;
-       struct remote *remote = pushremote_get(repo);
        const char **url;
        int url_nr;
        struct refspec *push_refspec = &rs;
 
-       if (!remote) {
-               if (repo)
-                       die(_("bad repository '%s'"), repo);
-               die(_("No configured push destination.\n"
-                   "Either specify the URL from the command-line or configure a remote repository using\n"
-                   "\n"
-                   "    git remote add <name> <url>\n"
-                   "\n"
-                   "and then push using the remote name\n"
-                   "\n"
-                   "    git push <name>\n"));
-       }
-
-       if (remote->mirror)
-               flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
-
        if (push_options->nr)
                flags |= TRANSPORT_PUSH_OPTIONS;
 
@@ -548,6 +532,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
        struct string_list *push_options;
        const struct string_list_item *item;
+       struct remote *remote;
 
        struct option options[] = {
                OPT__VERBOSITY(&verbosity),
@@ -602,20 +587,6 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                die(_("--delete is incompatible with --all, --mirror and --tags"));
        if (deleterefs && argc < 2)
                die(_("--delete doesn't make sense without any refs"));
-       if (flags & TRANSPORT_PUSH_ALL) {
-               if (tags)
-                       die(_("--all and --tags are incompatible"));
-               if (argc >= 2)
-                       die(_("--all can't be combined with refspecs"));
-       }
-       if (flags & TRANSPORT_PUSH_MIRROR) {
-               if (tags)
-                       die(_("--mirror and --tags are incompatible"));
-               if (argc >= 2)
-                       die(_("--mirror can't be combined with refspecs"));
-       }
-       if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
-               die(_("--all and --mirror are incompatible"));
 
        if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
                flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
@@ -632,11 +603,43 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                set_refspecs(argv + 1, argc - 1, repo);
        }
 
+       remote = pushremote_get(repo);
+       if (!remote) {
+               if (repo)
+                       die(_("bad repository '%s'"), repo);
+               die(_("No configured push destination.\n"
+                   "Either specify the URL from the command-line or configure a remote repository using\n"
+                   "\n"
+                   "    git remote add <name> <url>\n"
+                   "\n"
+                   "and then push using the remote name\n"
+                   "\n"
+                   "    git push <name>\n"));
+       }
+
+       if (remote->mirror)
+               flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
+
+       if (flags & TRANSPORT_PUSH_ALL) {
+               if (tags)
+                       die(_("--all and --tags are incompatible"));
+               if (argc >= 2)
+                       die(_("--all can't be combined with refspecs"));
+       }
+       if (flags & TRANSPORT_PUSH_MIRROR) {
+               if (tags)
+                       die(_("--mirror and --tags are incompatible"));
+               if (argc >= 2)
+                       die(_("--mirror can't be combined with refspecs"));
+       }
+       if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
+               die(_("--all and --mirror are incompatible"));
+
        for_each_string_list_item(item, push_options)
                if (strchr(item->string, '\n'))
                        die(_("push options must not have new line characters"));
 
-       rc = do_push(repo, flags, push_options);
+       rc = do_push(repo, flags, push_options, remote);
        string_list_clear(&push_options_cmdline, 0);
        string_list_clear(&push_options_config, 0);
        if (rc == -1)
index e8319d5..4a20582 100644 (file)
@@ -29,8 +29,8 @@
 #include "rebase-interactive.h"
 
 static char const * const builtin_rebase_usage[] = {
-       N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
-               "[<upstream>] [<branch>]"),
+       N_("git rebase [-i] [options] [--exec <cmd>] "
+               "[--onto <newbase> | --keep-base] [<upstream> [<branch>]]"),
        N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
                "--root [<branch>]"),
        N_("git rebase --continue | --abort | --skip | --edit-todo"),
@@ -1261,24 +1261,44 @@ static int is_linear_history(struct commit *from, struct commit *to)
        return 1;
 }
 
-static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
-                           struct object_id *merge_base)
+static int can_fast_forward(struct commit *onto, struct commit *upstream,
+                           struct commit *restrict_revision,
+                           struct object_id *head_oid, struct object_id *merge_base)
 {
        struct commit *head = lookup_commit(the_repository, head_oid);
-       struct commit_list *merge_bases;
-       int res;
+       struct commit_list *merge_bases = NULL;
+       int res = 0;
 
        if (!head)
-               return 0;
+               goto done;
 
        merge_bases = get_merge_bases(onto, head);
-       if (merge_bases && !merge_bases->next) {
-               oidcpy(merge_base, &merge_bases->item->object.oid);
-               res = oideq(merge_base, &onto->object.oid);
-       } else {
+       if (!merge_bases || merge_bases->next) {
                oidcpy(merge_base, &null_oid);
-               res = 0;
+               goto done;
        }
+
+       oidcpy(merge_base, &merge_bases->item->object.oid);
+       if (!oideq(merge_base, &onto->object.oid))
+               goto done;
+
+       if (restrict_revision && !oideq(&restrict_revision->object.oid, merge_base))
+               goto done;
+
+       if (!upstream)
+               goto done;
+
+       free_commit_list(merge_bases);
+       merge_bases = get_merge_bases(upstream, head);
+       if (!merge_bases || merge_bases->next)
+               goto done;
+
+       if (!oideq(&onto->object.oid, &merge_bases->item->object.oid))
+               goto done;
+
+       res = 1;
+
+done:
        free_commit_list(merge_bases);
        return res && is_linear_history(onto, head);
 }
@@ -1377,6 +1397,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        struct rebase_options options = REBASE_OPTIONS_INIT;
        const char *branch_name;
        int ret, flags, total_argc, in_progress = 0;
+       int keep_base = 0;
        int ok_to_skip_pre_rebase = 0;
        struct strbuf msg = STRBUF_INIT;
        struct strbuf revisions = STRBUF_INIT;
@@ -1395,6 +1416,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_STRING(0, "onto", &options.onto_name,
                           N_("revision"),
                           N_("rebase onto given branch instead of upstream")),
+               OPT_BOOL(0, "keep-base", &keep_base,
+                        N_("use the merge-base of upstream and branch as the current base")),
                OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
                         N_("allow pre-rebase hook to run")),
                OPT_NEGBIT('q', "quiet", &options.flags,
@@ -1548,6 +1571,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                warning(_("git rebase --preserve-merges is deprecated. "
                          "Use --rebase-merges instead."));
 
+       if (keep_base) {
+               if (options.onto_name)
+                       die(_("cannot combine '--keep-base' with '--onto'"));
+               if (options.root)
+                       die(_("cannot combine '--keep-base' with '--root'"));
+       }
+
        if (action != ACTION_NONE && !in_progress)
                die(_("No rebase in progress?"));
        setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0);
@@ -1876,12 +1906,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        }
 
        /* Make sure the branch to rebase onto is valid. */
-       if (!options.onto_name)
+       if (keep_base) {
+               strbuf_reset(&buf);
+               strbuf_addstr(&buf, options.upstream_name);
+               strbuf_addstr(&buf, "...");
+               options.onto_name = xstrdup(buf.buf);
+       } else if (!options.onto_name)
                options.onto_name = options.upstream_name;
        if (strstr(options.onto_name, "...")) {
-               if (get_oid_mb(options.onto_name, &merge_base) < 0)
-                       die(_("'%s': need exactly one merge base"),
-                           options.onto_name);
+               if (get_oid_mb(options.onto_name, &merge_base) < 0) {
+                       if (keep_base)
+                               die(_("'%s': need exactly one merge base with branch"),
+                                   options.upstream_name);
+                       else
+                               die(_("'%s': need exactly one merge base"),
+                                   options.onto_name);
+               }
                options.onto = lookup_commit_or_die(&merge_base,
                                                    options.onto_name);
        } else {
@@ -1962,9 +2002,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                                state_dir_path("autostash", &options);
                        struct child_process stash = CHILD_PROCESS_INIT;
                        struct object_id oid;
-                       struct commit *head =
-                               lookup_commit_reference(the_repository,
-                                                       &options.orig_head);
 
                        argv_array_pushl(&stash.args,
                                         "stash", "create", "autostash", NULL);
@@ -1985,17 +2022,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                                    options.state_dir);
                        write_file(autostash, "%s", oid_to_hex(&oid));
                        printf(_("Created autostash: %s\n"), buf.buf);
-                       if (reset_head(&head->object.oid, "reset --hard",
+                       if (reset_head(NULL, "reset --hard",
                                       NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
                                die(_("could not reset --hard"));
-                       printf(_("HEAD is now at %s"),
-                              find_unique_abbrev(&head->object.oid,
-                                                 DEFAULT_ABBREV));
-                       strbuf_reset(&buf);
-                       pp_commit_easy(CMIT_FMT_ONELINE, head, &buf);
-                       if (buf.len > 0)
-                               printf(" %s", buf.buf);
-                       putchar('\n');
 
                        if (discard_index(the_repository->index) < 0 ||
                                repo_read_index(the_repository) < 0)
@@ -2016,13 +2045,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
        /*
         * Check if we are already based on onto with linear history,
-        * but this should be done only when upstream and onto are the same
-        * and if this is not an interactive rebase.
+        * in which case we could fast-forward without replacing the commits
+        * with new commits recreated by replaying their changes. This
+        * optimization must not be done if this is an interactive rebase.
         */
-       if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
-           !is_interactive(&options) && !options.restrict_revision &&
-           options.upstream &&
-           !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
+       if (can_fast_forward(options.onto, options.upstream, options.restrict_revision,
+                   &options.orig_head, &merge_base) &&
+           !is_interactive(&options)) {
                int flag;
 
                if (!(options.flags & REBASE_FORCE)) {
index 644b21c..2a4afb3 100644 (file)
@@ -421,7 +421,7 @@ static int check_one_mergetag(struct commit *commit,
                if (get_oid(mergetag_data->argv[i], &oid) < 0)
                        return error(_("not a valid object name: '%s'"),
                                     mergetag_data->argv[i]);
-               if (oideq(&tag->tagged->oid, &oid))
+               if (oideq(get_tagged_oid(tag), &oid))
                        return 0; /* found */
        }
 
index 39ee7d6..583aacb 100644 (file)
@@ -197,7 +197,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
        git_hash_ctx ctx;
        unsigned char obuf[16384];
        unsigned header_len;
-       struct hashfile_checkpoint checkpoint;
+       struct hashfile_checkpoint checkpoint = {0};
        struct pack_idx_entry *idx = NULL;
 
        seekback = lseek(fd, 0, SEEK_CUR);
index 44db2d5..29dc740 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -160,7 +160,7 @@ linux-clang|linux-gcc)
                export CC=gcc-8
        fi
 
-       export GIT_TEST_HTTPD=YesPlease
+       export GIT_TEST_HTTPD=true
 
        # The Linux build installs the defined dependency versions below.
        # The OS X build installs much more recent versions, whichever
index a98de16..3fe5f8f 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -364,8 +364,8 @@ struct object_id *get_commit_tree_oid(const struct commit *commit)
 void release_commit_memory(struct parsed_object_pool *pool, struct commit *c)
 {
        set_commit_tree(c, NULL);
-       c->index = 0;
        free_commit_buffer(pool, c);
+       c->index = 0;
        free_commit_list(c->parents);
 
        c->object.parsed = 0;
index 738f0a8..7a0d619 100644 (file)
@@ -1161,14 +1161,21 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
                         int isexe, int exe_only)
 {
        char path[MAX_PATH];
+       wchar_t wpath[MAX_PATH];
        snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
 
-       if (!isexe && access(path, F_OK) == 0)
+       if (xutftowcs_path(wpath, path) < 0)
+               return NULL;
+
+       if (!isexe && _waccess(wpath, F_OK) == 0)
                return xstrdup(path);
-       path[strlen(path)-4] = '\0';
-       if ((!exe_only || isexe) && access(path, F_OK) == 0)
-               if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
+       wpath[wcslen(wpath)-4] = '\0';
+       if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) {
+               if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) {
+                       path[strlen(path)-4] = '\0';
                        return xstrdup(path);
+               }
+       }
        return NULL;
 }
 
@@ -1265,7 +1272,7 @@ static wchar_t *make_environment_block(char **deltaenv)
                }
 
                ALLOC_ARRAY(result, size);
-               memcpy(result, wenv, size * sizeof(*wenv));
+               COPY_ARRAY(result, wenv, size);
                FreeEnvironmentStringsW(wenv);
                return result;
        }
@@ -1309,7 +1316,7 @@ static wchar_t *make_environment_block(char **deltaenv)
                        continue;
 
                size = wcslen(array[i]) + 1;
-               memcpy(p, array[i], size * sizeof(*p));
+               COPY_ARRAY(p, array[i], size);
                p += size;
        }
        *p = L'\0';
index a03e40e..9ad204c 100644 (file)
@@ -11,7 +11,7 @@ typedef _sigset_t sigset_t;
 #undef _POSIX_THREAD_SAFE_FUNCTIONS
 #endif
 
-extern int mingw_core_config(const char *var, const char *value, void *cb);
+int mingw_core_config(const char *var, const char *value, void *cb);
 #define platform_core_config mingw_core_config
 
 /*
@@ -443,7 +443,7 @@ static inline void convert_slashes(char *path)
                        *path = '/';
 }
 #define PATH_SEP ';'
-extern char *mingw_query_user_email(void);
+char *mingw_query_user_email(void);
 #define query_user_email mingw_query_user_email
 #if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
 #define PRIuMAX "I64u"
@@ -580,4 +580,4 @@ int main(int argc, const char **argv);
 /*
  * Used by Pthread API implementation for Windows
  */
-extern int err_win_to_posix(DWORD winerr);
+int err_win_to_posix(DWORD winerr);
index c6cb8dd..f1cfe73 100644 (file)
@@ -50,7 +50,7 @@ typedef struct {
        DWORD tid;
 } pthread_t;
 
-extern int pthread_create(pthread_t *thread, const void *unused,
+int pthread_create(pthread_t *thread, const void *unused,
                          void *(*start_routine)(void*), void *arg);
 
 /*
@@ -59,10 +59,10 @@ extern int pthread_create(pthread_t *thread, const void *unused,
  */
 #define pthread_join(a, b) win32_pthread_join(&(a), (b))
 
-extern int win32_pthread_join(pthread_t *thread, void **value_ptr);
+int win32_pthread_join(pthread_t *thread, void **value_ptr);
 
 #define pthread_equal(t1, t2) ((t1).tid == (t2).tid)
-extern pthread_t pthread_self(void);
+pthread_t pthread_self(void);
 
 static inline void NORETURN pthread_exit(void *ret)
 {
index 2778481..da7daa2 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -915,6 +915,10 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
 
        if (protocol == PROTO_LOCAL)
                path = end;
+       else if (protocol == PROTO_FILE && *host != '/' &&
+                !has_dos_drive_prefix(host) &&
+                offset_1st_component(host - 2) > 1)
+               path = host - 2; /* include the leading "//" */
        else if (protocol == PROTO_FILE && has_dos_drive_prefix(end))
                path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */
        else
index ce7ff0a..59cd3e8 100644 (file)
@@ -1361,7 +1361,9 @@ _git_checkout ()
        esac
 }
 
-__git_cherry_pick_inprogress_options="--continue --quit --abort"
+__git_sequencer_inprogress_options="--continue --quit --abort --skip"
+
+__git_cherry_pick_inprogress_options=$__git_sequencer_inprogress_options
 
 _git_cherry_pick ()
 {
@@ -2041,7 +2043,7 @@ _git_rebase ()
                        --autosquash --no-autosquash
                        --fork-point --no-fork-point
                        --autostash --no-autostash
-                       --verify --no-verify
+                       --verify --no-verify --keep-base
                        --keep-empty --root --force-rebase --no-ff
                        --rerere-autoupdate
                        --exec
@@ -2624,7 +2626,7 @@ _git_restore ()
        esac
 }
 
-__git_revert_inprogress_options="--continue --quit --abort"
+__git_revert_inprogress_options=$__git_sequencer_inprogress_options
 
 _git_revert ()
 {
index a3425f4..19333fc 100644 (file)
@@ -56,7 +56,7 @@ line.  This line has the form `git-svn-id: URL@REVNO UUID`.
 
 The resulting repository will generally require further processing
 to put each project in its own repository and to separate the history
-of each branch.  The 'git filter-branch --subdirectory-filter' command
+of each branch.  The 'git filter-repo --subdirectory-filter' command
 may be useful for this purpose.
 
 BUGS
@@ -67,5 +67,5 @@ The exit status does not reflect whether an error was detected.
 
 SEE ALSO
 --------
-git-svn(1), svn2git(1), svk(1), git-filter-branch(1), git-fast-import(1),
+git-svn(1), svn2git(1), svk(1), git-filter-repo(1), git-fast-import(1),
 https://svn.apache.org/repos/asf/subversion/trunk/notes/dump-load-format.txt
index e496433..77fea08 100644 (file)
@@ -326,6 +326,8 @@ create_delta(const struct delta_index *index,
        const unsigned char *ref_data, *ref_top, *data, *top;
        unsigned char *out;
 
+       *delta_size = 0;
+
        if (!trg_buf || !trg_size)
                return NULL;
 
diff --git a/dir.c b/dir.c
index d021c90..cab9c2a 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -561,7 +561,7 @@ int no_wildcard(const char *string)
        return string[simple_length(string)] == '\0';
 }
 
-void parse_exclude_pattern(const char **pattern,
+void parse_path_pattern(const char **pattern,
                           int *patternlen,
                           unsigned *flags,
                           int *nowildcardlen)
@@ -571,20 +571,20 @@ void parse_exclude_pattern(const char **pattern,
 
        *flags = 0;
        if (*p == '!') {
-               *flags |= EXC_FLAG_NEGATIVE;
+               *flags |= PATTERN_FLAG_NEGATIVE;
                p++;
        }
        len = strlen(p);
        if (len && p[len - 1] == '/') {
                len--;
-               *flags |= EXC_FLAG_MUSTBEDIR;
+               *flags |= PATTERN_FLAG_MUSTBEDIR;
        }
        for (i = 0; i < len; i++) {
                if (p[i] == '/')
                        break;
        }
        if (i == len)
-               *flags |= EXC_FLAG_NODIR;
+               *flags |= PATTERN_FLAG_NODIR;
        *nowildcardlen = simple_length(p);
        /*
         * we should have excluded the trailing slash from 'p' too,
@@ -594,35 +594,35 @@ void parse_exclude_pattern(const char **pattern,
        if (*nowildcardlen > len)
                *nowildcardlen = len;
        if (*p == '*' && no_wildcard(p + 1))
-               *flags |= EXC_FLAG_ENDSWITH;
+               *flags |= PATTERN_FLAG_ENDSWITH;
        *pattern = p;
        *patternlen = len;
 }
 
-void add_exclude(const char *string, const char *base,
-                int baselen, struct exclude_list *el, int srcpos)
+void add_pattern(const char *string, const char *base,
+                int baselen, struct pattern_list *pl, int srcpos)
 {
-       struct exclude *x;
+       struct path_pattern *pattern;
        int patternlen;
        unsigned flags;
        int nowildcardlen;
 
-       parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);
-       if (flags & EXC_FLAG_MUSTBEDIR) {
-               FLEXPTR_ALLOC_MEM(x, pattern, string, patternlen);
+       parse_path_pattern(&string, &patternlen, &flags, &nowildcardlen);
+       if (flags & PATTERN_FLAG_MUSTBEDIR) {
+               FLEXPTR_ALLOC_MEM(pattern, pattern, string, patternlen);
        } else {
-               x = xmalloc(sizeof(*x));
-               x->pattern = string;
+               pattern = xmalloc(sizeof(*pattern));
+               pattern->pattern = string;
        }
-       x->patternlen = patternlen;
-       x->nowildcardlen = nowildcardlen;
-       x->base = base;
-       x->baselen = baselen;
-       x->flags = flags;
-       x->srcpos = srcpos;
-       ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
-       el->excludes[el->nr++] = x;
-       x->el = el;
+       pattern->patternlen = patternlen;
+       pattern->nowildcardlen = nowildcardlen;
+       pattern->base = base;
+       pattern->baselen = baselen;
+       pattern->flags = flags;
+       pattern->srcpos = srcpos;
+       ALLOC_GROW(pl->patterns, pl->nr + 1, pl->alloc);
+       pl->patterns[pl->nr++] = pattern;
+       pattern->pl = pl;
 }
 
 static int read_skip_worktree_file_from_index(const struct index_state *istate,
@@ -643,19 +643,19 @@ static int read_skip_worktree_file_from_index(const struct index_state *istate,
 }
 
 /*
- * Frees memory within el which was allocated for exclude patterns and
- * the file buffer.  Does not free el itself.
+ * Frees memory within pl which was allocated for exclude patterns and
+ * the file buffer.  Does not free pl itself.
  */
-void clear_exclude_list(struct exclude_list *el)
+void clear_pattern_list(struct pattern_list *pl)
 {
        int i;
 
-       for (i = 0; i < el->nr; i++)
-               free(el->excludes[i]);
-       free(el->excludes);
-       free(el->filebuf);
+       for (i = 0; i < pl->nr; i++)
+               free(pl->patterns[i]);
+       free(pl->patterns);
+       free(pl->filebuf);
 
-       memset(el, 0, sizeof(*el));
+       memset(pl, 0, sizeof(*pl));
 }
 
 static void trim_trailing_spaces(char *buf)
@@ -762,21 +762,21 @@ static void invalidate_directory(struct untracked_cache *uc,
                dir->dirs[i]->recurse = 0;
 }
 
-static int add_excludes_from_buffer(char *buf, size_t size,
+static int add_patterns_from_buffer(char *buf, size_t size,
                                    const char *base, int baselen,
-                                   struct exclude_list *el);
+                                   struct pattern_list *pl);
 
 /*
  * Given a file with name "fname", read it (either from disk, or from
  * an index if 'istate' is non-null), parse it and store the
- * exclude rules in "el".
+ * exclude rules in "pl".
  *
  * If "ss" is not NULL, compute SHA-1 of the exclude file and fill
- * stat data from disk (only valid if add_excludes returns zero). If
+ * stat data from disk (only valid if add_patterns returns zero). If
  * ss_valid is non-zero, "ss" must contain good value as input.
  */
-static int add_excludes(const char *fname, const char *base, int baselen,
-                       struct exclude_list *el, struct index_state *istate,
+static int add_patterns(const char *fname, const char *base, int baselen,
+                       struct pattern_list *pl, struct index_state *istate,
                        struct oid_stat *oid_stat)
 {
        struct stat st;
@@ -837,21 +837,21 @@ static int add_excludes(const char *fname, const char *base, int baselen,
                }
        }
 
-       add_excludes_from_buffer(buf, size, base, baselen, el);
+       add_patterns_from_buffer(buf, size, base, baselen, pl);
        return 0;
 }
 
-static int add_excludes_from_buffer(char *buf, size_t size,
+static int add_patterns_from_buffer(char *buf, size_t size,
                                    const char *base, int baselen,
-                                   struct exclude_list *el)
+                                   struct pattern_list *pl)
 {
        int i, lineno = 1;
        char *entry;
 
-       el->filebuf = buf;
+       pl->filebuf = buf;
 
        if (skip_utf8_bom(&buf, size))
-               size -= buf - el->filebuf;
+               size -= buf - pl->filebuf;
 
        entry = buf;
 
@@ -860,7 +860,7 @@ static int add_excludes_from_buffer(char *buf, size_t size,
                        if (entry != buf + i && entry[0] != '#') {
                                buf[i - (i && buf[i-1] == '\r')] = 0;
                                trim_trailing_spaces(entry);
-                               add_exclude(entry, base, baselen, el, lineno);
+                               add_pattern(entry, base, baselen, pl, lineno);
                        }
                        lineno++;
                        entry = buf + i + 1;
@@ -869,17 +869,17 @@ static int add_excludes_from_buffer(char *buf, size_t size,
        return 0;
 }
 
-int add_excludes_from_file_to_list(const char *fname, const char *base,
-                                  int baselen, struct exclude_list *el,
+int add_patterns_from_file_to_list(const char *fname, const char *base,
+                                  int baselen, struct pattern_list *pl,
                                   struct index_state *istate)
 {
-       return add_excludes(fname, base, baselen, el, istate, NULL);
+       return add_patterns(fname, base, baselen, pl, istate, NULL);
 }
 
-int add_excludes_from_blob_to_list(
+int add_patterns_from_blob_to_list(
        struct object_id *oid,
        const char *base, int baselen,
-       struct exclude_list *el)
+       struct pattern_list *pl)
 {
        char *buf;
        size_t size;
@@ -889,31 +889,31 @@ int add_excludes_from_blob_to_list(
        if (r != 1)
                return r;
 
-       add_excludes_from_buffer(buf, size, base, baselen, el);
+       add_patterns_from_buffer(buf, size, base, baselen, pl);
        return 0;
 }
 
-struct exclude_list *add_exclude_list(struct dir_struct *dir,
+struct pattern_list *add_pattern_list(struct dir_struct *dir,
                                      int group_type, const char *src)
 {
-       struct exclude_list *el;
+       struct pattern_list *pl;
        struct exclude_list_group *group;
 
        group = &dir->exclude_list_group[group_type];
-       ALLOC_GROW(group->el, group->nr + 1, group->alloc);
-       el = &group->el[group->nr++];
-       memset(el, 0, sizeof(*el));
-       el->src = src;
-       return el;
+       ALLOC_GROW(group->pl, group->nr + 1, group->alloc);
+       pl = &group->pl[group->nr++];
+       memset(pl, 0, sizeof(*pl));
+       pl->src = src;
+       return pl;
 }
 
 /*
  * Used to set up core.excludesfile and .git/info/exclude lists.
  */
-static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
+static void add_patterns_from_file_1(struct dir_struct *dir, const char *fname,
                                     struct oid_stat *oid_stat)
 {
-       struct exclude_list *el;
+       struct pattern_list *pl;
        /*
         * catch setup_standard_excludes() that's called before
         * dir->untracked is assigned. That function behaves
@@ -921,15 +921,15 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
         */
        if (!dir->untracked)
                dir->unmanaged_exclude_files++;
-       el = add_exclude_list(dir, EXC_FILE, fname);
-       if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0)
+       pl = add_pattern_list(dir, EXC_FILE, fname);
+       if (add_patterns(fname, "", 0, pl, NULL, oid_stat) < 0)
                die(_("cannot use %s as an exclude file"), fname);
 }
 
-void add_excludes_from_file(struct dir_struct *dir, const char *fname)
+void add_patterns_from_file(struct dir_struct *dir, const char *fname)
 {
        dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */
-       add_excludes_from_file_1(dir, fname, NULL);
+       add_patterns_from_file_1(dir, fname, NULL);
 }
 
 int match_basename(const char *basename, int basenamelen,
@@ -940,7 +940,7 @@ int match_basename(const char *basename, int basenamelen,
                if (patternlen == basenamelen &&
                    !fspathncmp(pattern, basename, basenamelen))
                        return 1;
-       } else if (flags & EXC_FLAG_ENDSWITH) {
+       } else if (flags & PATTERN_FLAG_ENDSWITH) {
                /* "*literal" matching against "fooliteral" */
                if (patternlen - 1 <= basenamelen &&
                    !fspathncmp(pattern + 1,
@@ -1021,85 +1021,97 @@ int match_pathname(const char *pathname, int pathlen,
  * any, determines the fate.  Returns the exclude_list element which
  * matched, or NULL for undecided.
  */
-static struct exclude *last_exclude_matching_from_list(const char *pathname,
+static struct path_pattern *last_matching_pattern_from_list(const char *pathname,
                                                       int pathlen,
                                                       const char *basename,
                                                       int *dtype,
-                                                      struct exclude_list *el,
+                                                      struct pattern_list *pl,
                                                       struct index_state *istate)
 {
-       struct exclude *exc = NULL; /* undecided */
+       struct path_pattern *res = NULL; /* undecided */
        int i;
 
-       if (!el->nr)
+       if (!pl->nr)
                return NULL;    /* undefined */
 
-       for (i = el->nr - 1; 0 <= i; i--) {
-               struct exclude *x = el->excludes[i];
-               const char *exclude = x->pattern;
-               int prefix = x->nowildcardlen;
+       for (i = pl->nr - 1; 0 <= i; i--) {
+               struct path_pattern *pattern = pl->patterns[i];
+               const char *exclude = pattern->pattern;
+               int prefix = pattern->nowildcardlen;
 
-               if (x->flags & EXC_FLAG_MUSTBEDIR) {
+               if (pattern->flags & PATTERN_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
                                *dtype = get_dtype(NULL, istate, pathname, pathlen);
                        if (*dtype != DT_DIR)
                                continue;
                }
 
-               if (x->flags & EXC_FLAG_NODIR) {
+               if (pattern->flags & PATTERN_FLAG_NODIR) {
                        if (match_basename(basename,
                                           pathlen - (basename - pathname),
-                                          exclude, prefix, x->patternlen,
-                                          x->flags)) {
-                               exc = x;
+                                          exclude, prefix, pattern->patternlen,
+                                          pattern->flags)) {
+                               res = pattern;
                                break;
                        }
                        continue;
                }
 
-               assert(x->baselen == 0 || x->base[x->baselen - 1] == '/');
+               assert(pattern->baselen == 0 ||
+                      pattern->base[pattern->baselen - 1] == '/');
                if (match_pathname(pathname, pathlen,
-                                  x->base, x->baselen ? x->baselen - 1 : 0,
-                                  exclude, prefix, x->patternlen, x->flags)) {
-                       exc = x;
+                                  pattern->base,
+                                  pattern->baselen ? pattern->baselen - 1 : 0,
+                                  exclude, prefix, pattern->patternlen,
+                                  pattern->flags)) {
+                       res = pattern;
                        break;
                }
        }
-       return exc;
+       return res;
 }
 
 /*
- * Scan the list and let the last match determine the fate.
- * Return 1 for exclude, 0 for include and -1 for undecided.
+ * Scan the list of patterns to determine if the ordered list
+ * of patterns matches on 'pathname'.
+ *
+ * Return 1 for a match, 0 for not matched and -1 for undecided.
  */
-int is_excluded_from_list(const char *pathname,
-                         int pathlen, const char *basename, int *dtype,
-                         struct exclude_list *el, struct index_state *istate)
-{
-       struct exclude *exclude;
-       exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
-                                                 dtype, el, istate);
-       if (exclude)
-               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
-       return -1; /* undecided */
+enum pattern_match_result path_matches_pattern_list(
+                               const char *pathname, int pathlen,
+                               const char *basename, int *dtype,
+                               struct pattern_list *pl,
+                               struct index_state *istate)
+{
+       struct path_pattern *pattern;
+       pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
+                                                 dtype, pl, istate);
+       if (pattern) {
+               if (pattern->flags & PATTERN_FLAG_NEGATIVE)
+                       return NOT_MATCHED;
+               else
+                       return MATCHED;
+       }
+
+       return UNDECIDED;
 }
 
-static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
-                                                       struct index_state *istate,
-               const char *pathname, int pathlen, const char *basename,
-               int *dtype_p)
+static struct path_pattern *last_matching_pattern_from_lists(
+               struct dir_struct *dir, struct index_state *istate,
+               const char *pathname, int pathlen,
+               const char *basename, int *dtype_p)
 {
        int i, j;
        struct exclude_list_group *group;
-       struct exclude *exclude;
+       struct path_pattern *pattern;
        for (i = EXC_CMDL; i <= EXC_FILE; i++) {
                group = &dir->exclude_list_group[i];
                for (j = group->nr - 1; j >= 0; j--) {
-                       exclude = last_exclude_matching_from_list(
+                       pattern = last_matching_pattern_from_list(
                                pathname, pathlen, basename, dtype_p,
-                               &group->el[j], istate);
-                       if (exclude)
-                               return exclude;
+                               &group->pl[j], istate);
+                       if (pattern)
+                               return pattern;
                }
        }
        return NULL;
@@ -1114,7 +1126,7 @@ static void prep_exclude(struct dir_struct *dir,
                         const char *base, int baselen)
 {
        struct exclude_list_group *group;
-       struct exclude_list *el;
+       struct pattern_list *pl;
        struct exclude_stack *stk = NULL;
        struct untracked_cache_dir *untracked;
        int current;
@@ -1130,17 +1142,17 @@ static void prep_exclude(struct dir_struct *dir,
                if (stk->baselen <= baselen &&
                    !strncmp(dir->basebuf.buf, base, stk->baselen))
                        break;
-               el = &group->el[dir->exclude_stack->exclude_ix];
+               pl = &group->pl[dir->exclude_stack->exclude_ix];
                dir->exclude_stack = stk->prev;
-               dir->exclude = NULL;
-               free((char *)el->src); /* see strbuf_detach() below */
-               clear_exclude_list(el);
+               dir->pattern = NULL;
+               free((char *)pl->src); /* see strbuf_detach() below */
+               clear_pattern_list(pl);
                free(stk);
                group->nr--;
        }
 
        /* Skip traversing into sub directories if the parent is excluded */
-       if (dir->exclude)
+       if (dir->pattern)
                return;
 
        /*
@@ -1181,7 +1193,7 @@ static void prep_exclude(struct dir_struct *dir,
                stk->baselen = cp - base;
                stk->exclude_ix = group->nr;
                stk->ucd = untracked;
-               el = add_exclude_list(dir, EXC_DIRS, NULL);
+               pl = add_pattern_list(dir, EXC_DIRS, NULL);
                strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
                assert(stk->baselen == dir->basebuf.len);
 
@@ -1189,15 +1201,15 @@ static void prep_exclude(struct dir_struct *dir,
                if (stk->baselen) {
                        int dt = DT_DIR;
                        dir->basebuf.buf[stk->baselen - 1] = 0;
-                       dir->exclude = last_exclude_matching_from_lists(dir,
+                       dir->pattern = last_matching_pattern_from_lists(dir,
                                                                        istate,
                                dir->basebuf.buf, stk->baselen - 1,
                                dir->basebuf.buf + current, &dt);
                        dir->basebuf.buf[stk->baselen - 1] = '/';
-                       if (dir->exclude &&
-                           dir->exclude->flags & EXC_FLAG_NEGATIVE)
-                               dir->exclude = NULL;
-                       if (dir->exclude) {
+                       if (dir->pattern &&
+                           dir->pattern->flags & PATTERN_FLAG_NEGATIVE)
+                               dir->pattern = NULL;
+                       if (dir->pattern) {
                                dir->exclude_stack = stk;
                                return;
                        }
@@ -1223,30 +1235,30 @@ static void prep_exclude(struct dir_struct *dir,
                        /*
                         * dir->basebuf gets reused by the traversal, but we
                         * need fname to remain unchanged to ensure the src
-                        * member of each struct exclude correctly
+                        * member of each struct path_pattern correctly
                         * back-references its source file.  Other invocations
-                        * of add_exclude_list provide stable strings, so we
+                        * of add_pattern_list provide stable strings, so we
                         * strbuf_detach() and free() here in the caller.
                         */
                        struct strbuf sb = STRBUF_INIT;
                        strbuf_addbuf(&sb, &dir->basebuf);
                        strbuf_addstr(&sb, dir->exclude_per_dir);
-                       el->src = strbuf_detach(&sb, NULL);
-                       add_excludes(el->src, el->src, stk->baselen, el, istate,
+                       pl->src = strbuf_detach(&sb, NULL);
+                       add_patterns(pl->src, pl->src, stk->baselen, pl, istate,
                                     untracked ? &oid_stat : NULL);
                }
                /*
                 * NEEDSWORK: when untracked cache is enabled, prep_exclude()
                 * will first be called in valid_cached_dir() then maybe many
-                * times more in last_exclude_matching(). When the cache is
-                * used, last_exclude_matching() will not be called and
+                * times more in last_matching_pattern(). When the cache is
+                * used, last_matching_pattern() will not be called and
                 * reading .gitignore content will be a waste.
                 *
                 * So when it's called by valid_cached_dir() and we can get
                 * .gitignore SHA-1 from the index (i.e. .gitignore is not
                 * modified on work tree), we could delay reading the
                 * .gitignore content until we absolutely need it in
-                * last_exclude_matching(). Be careful about ignore rule
+                * last_matching_pattern(). Be careful about ignore rule
                 * order, though, if you do that.
                 */
                if (untracked &&
@@ -1266,7 +1278,7 @@ static void prep_exclude(struct dir_struct *dir,
  * Returns the exclude_list element which matched, or NULL for
  * undecided.
  */
-struct exclude *last_exclude_matching(struct dir_struct *dir,
+struct path_pattern *last_matching_pattern(struct dir_struct *dir,
                                      struct index_state *istate,
                                      const char *pathname,
                                      int *dtype_p)
@@ -1277,10 +1289,10 @@ struct exclude *last_exclude_matching(struct dir_struct *dir,
 
        prep_exclude(dir, istate, pathname, basename-pathname);
 
-       if (dir->exclude)
-               return dir->exclude;
+       if (dir->pattern)
+               return dir->pattern;
 
-       return last_exclude_matching_from_lists(dir, istate, pathname, pathlen,
+       return last_matching_pattern_from_lists(dir, istate, pathname, pathlen,
                        basename, dtype_p);
 }
 
@@ -1292,10 +1304,10 @@ struct exclude *last_exclude_matching(struct dir_struct *dir,
 int is_excluded(struct dir_struct *dir, struct index_state *istate,
                const char *pathname, int *dtype_p)
 {
-       struct exclude *exclude =
-               last_exclude_matching(dir, istate, pathname, dtype_p);
-       if (exclude)
-               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
+       struct path_pattern *pattern =
+               last_matching_pattern(dir, istate, pathname, dtype_p);
+       if (pattern)
+               return pattern->flags & PATTERN_FLAG_NEGATIVE ? 0 : 1;
        return 0;
 }
 
@@ -1808,7 +1820,7 @@ static int valid_cached_dir(struct dir_struct *dir,
 
        /*
         * prep_exclude will be called eventually on this directory,
-        * but it's called much later in last_exclude_matching(). We
+        * but it's called much later in last_matching_pattern(). We
         * need it now to determine the validity of the cache for this
         * path. The next calls will be nearly no-op, the way
         * prep_exclude() is designed.
@@ -2488,14 +2500,14 @@ void setup_standard_excludes(struct dir_struct *dir)
        if (!excludes_file)
                excludes_file = xdg_config_home("ignore");
        if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
-               add_excludes_from_file_1(dir, excludes_file,
+               add_patterns_from_file_1(dir, excludes_file,
                                         dir->untracked ? &dir->ss_excludes_file : NULL);
 
        /* per repository user preference */
        if (startup_info->have_repository) {
                const char *path = git_path_info_exclude();
                if (!access_or_warn(path, R_OK, 0))
-                       add_excludes_from_file_1(dir, path,
+                       add_patterns_from_file_1(dir, path,
                                                 dir->untracked ? &dir->ss_info_exclude : NULL);
        }
 }
@@ -2527,18 +2539,18 @@ void clear_directory(struct dir_struct *dir)
 {
        int i, j;
        struct exclude_list_group *group;
-       struct exclude_list *el;
+       struct pattern_list *pl;
        struct exclude_stack *stk;
 
        for (i = EXC_CMDL; i <= EXC_FILE; i++) {
                group = &dir->exclude_list_group[i];
                for (j = 0; j < group->nr; j++) {
-                       el = &group->el[j];
+                       pl = &group->pl[j];
                        if (i == EXC_DIRS)
-                               free((char *)el->src);
-                       clear_exclude_list(el);
+                               free((char *)pl->src);
+                       clear_pattern_list(pl);
                }
-               free(group->el);
+               free(group->pl);
        }
 
        stk = dir->exclude_stack;
diff --git a/dir.h b/dir.h
index 680079b..608696c 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -11,24 +11,24 @@ struct dir_entry {
        char name[FLEX_ARRAY]; /* more */
 };
 
-#define EXC_FLAG_NODIR 1
-#define EXC_FLAG_ENDSWITH 4
-#define EXC_FLAG_MUSTBEDIR 8
-#define EXC_FLAG_NEGATIVE 16
+#define PATTERN_FLAG_NODIR 1
+#define PATTERN_FLAG_ENDSWITH 4
+#define PATTERN_FLAG_MUSTBEDIR 8
+#define PATTERN_FLAG_NEGATIVE 16
 
-struct exclude {
+struct path_pattern {
        /*
-        * This allows callers of last_exclude_matching() etc.
+        * This allows callers of last_matching_pattern() etc.
         * to determine the origin of the matching pattern.
         */
-       struct exclude_list *el;
+       struct pattern_list *pl;
 
        const char *pattern;
        int patternlen;
        int nowildcardlen;
        const char *base;
        int baselen;
-       unsigned flags;         /* EXC_FLAG_* */
+       unsigned flags;         /* PATTERN_FLAG_* */
 
        /*
         * Counting starts from 1 for line numbers in ignore files,
@@ -44,7 +44,7 @@ struct exclude {
  * can also be used to represent the list of --exclude values passed
  * via CLI args.
  */
-struct exclude_list {
+struct pattern_list {
        int nr;
        int alloc;
 
@@ -54,7 +54,7 @@ struct exclude_list {
        /* origin of list, e.g. path to filename, or descriptive string */
        const char *src;
 
-       struct exclude **excludes;
+       struct path_pattern **patterns;
 };
 
 /*
@@ -72,7 +72,7 @@ struct exclude_stack {
 
 struct exclude_list_group {
        int nr, alloc;
-       struct exclude_list *el;
+       struct pattern_list *pl;
 };
 
 struct oid_stat {
@@ -191,7 +191,7 @@ struct dir_struct {
         * matching exclude struct if the directory is excluded.
         */
        struct exclude_stack *exclude_stack;
-       struct exclude *exclude;
+       struct path_pattern *pattern;
        struct strbuf basebuf;
 
        /* Enable untracked file cache if set */
@@ -230,10 +230,23 @@ int read_directory(struct dir_struct *, struct index_state *istate,
                   const char *path, int len,
                   const struct pathspec *pathspec);
 
-int is_excluded_from_list(const char *pathname, int pathlen,
-                         const char *basename, int *dtype,
-                         struct exclude_list *el,
-                         struct index_state *istate);
+enum pattern_match_result {
+       UNDECIDED = -1,
+       NOT_MATCHED = 0,
+       MATCHED = 1,
+};
+
+/*
+ * Scan the list of patterns to determine if the ordered list
+ * of patterns matches on 'pathname'.
+ *
+ * Return 1 for a match, 0 for not matched and -1 for undecided.
+ */
+enum pattern_match_result path_matches_pattern_list(const char *pathname,
+                               int pathlen,
+                               const char *basename, int *dtype,
+                               struct pattern_list *pl,
+                               struct index_state *istate);
 struct dir_entry *dir_add_ignored(struct dir_struct *dir,
                                  struct index_state *istate,
                                  const char *pathname, int len);
@@ -248,26 +261,26 @@ int match_pathname(const char *, int,
                   const char *, int,
                   const char *, int, int, unsigned);
 
-struct exclude *last_exclude_matching(struct dir_struct *dir,
-                                     struct index_state *istate,
-                                     const char *name, int *dtype);
+struct path_pattern *last_matching_pattern(struct dir_struct *dir,
+                                          struct index_state *istate,
+                                          const char *name, int *dtype);
 
 int is_excluded(struct dir_struct *dir,
                struct index_state *istate,
                const char *name, int *dtype);
 
-struct exclude_list *add_exclude_list(struct dir_struct *dir,
+struct pattern_list *add_pattern_list(struct dir_struct *dir,
                                      int group_type, const char *src);
-int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
-                                  struct exclude_list *el, struct  index_state *istate);
-void add_excludes_from_file(struct dir_struct *, const char *fname);
-int add_excludes_from_blob_to_list(struct object_id *oid,
+int add_patterns_from_file_to_list(const char *fname, const char *base, int baselen,
+                                  struct pattern_list *pl, struct  index_state *istate);
+void add_patterns_from_file(struct dir_struct *, const char *fname);
+int add_patterns_from_blob_to_list(struct object_id *oid,
                                   const char *base, int baselen,
-                                  struct exclude_list *el);
-void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
-void add_exclude(const char *string, const char *base,
-                int baselen, struct exclude_list *el, int srcpos);
-void clear_exclude_list(struct exclude_list *el);
+                                  struct pattern_list *pl);
+void parse_path_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
+void add_pattern(const char *string, const char *base,
+                int baselen, struct pattern_list *pl, int srcpos);
+void clear_pattern_list(struct pattern_list *pl);
 void clear_directory(struct dir_struct *dir);
 
 int repo_file_exists(struct repository *repo, const char *path);
index b44d6a4..1f9160b 100644 (file)
@@ -1763,7 +1763,6 @@ static int read_next_command(void)
                } else {
                        struct recent_command *rc;
 
-                       strbuf_detach(&command_buf, NULL);
                        stdin_eof = strbuf_getline_lf(&command_buf, stdin);
                        if (stdin_eof)
                                return EOF;
@@ -1784,7 +1783,7 @@ static int read_next_command(void)
                                free(rc->buf);
                        }
 
-                       rc->buf = command_buf.buf;
+                       rc->buf = xstrdup(command_buf.buf);
                        rc->prev = cmd_tail;
                        rc->next = cmd_hist.prev;
                        rc->prev->next = rc;
@@ -1833,7 +1832,6 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
                char *term = xstrdup(data);
                size_t term_len = command_buf.len - (data - command_buf.buf);
 
-               strbuf_detach(&command_buf, NULL);
                for (;;) {
                        if (strbuf_getline_lf(&command_buf, stdin) == EOF)
                                die("EOF in data (terminator '%s' not found)", term);
@@ -2588,7 +2586,7 @@ static void parse_new_commit(const char *arg)
        struct branch *b;
        char *author = NULL;
        char *committer = NULL;
-       const char *encoding = NULL;
+       char *encoding = NULL;
        struct hash_list *merge_list = NULL;
        unsigned int merge_count;
        unsigned char prev_fanout, new_fanout;
@@ -2611,8 +2609,10 @@ static void parse_new_commit(const char *arg)
        }
        if (!committer)
                die("Expected committer but didn't get one");
-       if (skip_prefix(command_buf.buf, "encoding ", &encoding))
+       if (skip_prefix(command_buf.buf, "encoding ", &v)) {
+               encoding = xstrdup(v);
                read_next_command();
+       }
        parse_data(&msg, 0, NULL);
        read_next_command();
        parse_from(b);
@@ -2686,6 +2686,7 @@ static void parse_new_commit(const char *arg)
        strbuf_addbuf(&new_data, &msg);
        free(author);
        free(committer);
+       free(encoding);
 
        if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark))
                b->pack_id = pack_id;
index 5c5afa2..fea7964 100755 (executable)
@@ -83,6 +83,20 @@ set_ident () {
        finish_ident COMMITTER
 }
 
+if test -z "$FILTER_BRANCH_SQUELCH_WARNING$GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS"
+then
+       cat <<EOF
+WARNING: git-filter-branch has a glut of gotchas generating mangled history
+        rewrites.  Hit Ctrl-C before proceeding to abort, then use an
+        alternative filtering tool such as 'git filter-repo'
+        (https://github.com/newren/git-filter-repo/) instead.  See the
+        filter-branch manual page for more details; to squelch this warning,
+        set FILTER_BRANCH_SQUELCH_WARNING=1.
+EOF
+       sleep 10
+       printf "Proceeding with filter-branch...\n\n"
+fi
+
 USAGE="[--setup <command>] [--subdirectory-filter <directory>] [--env-filter <command>]
        [--tree-filter <command>] [--index-filter <command>]
        [--parent-filter <command>] [--msg-filter <command>]
diff --git a/help.c b/help.c
index 5261d83..9ff2be6 100644 (file)
--- a/help.c
+++ b/help.c
@@ -774,7 +774,8 @@ static struct string_list guess_refs(const char *ref)
        return similar_refs;
 }
 
-void help_unknown_ref(const char *ref, const char *cmd, const char *error)
+NORETURN void help_unknown_ref(const char *ref, const char *cmd,
+                              const char *error)
 {
        int i;
        struct string_list suggested_refs = guess_refs(ref);
diff --git a/help.h b/help.h
index b8780fb..7a455be 100644 (file)
--- a/help.h
+++ b/help.h
@@ -43,7 +43,7 @@ void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdn
  * call this to die(), when it is suspected that the user mistyped a
  * ref to the command, to give suggested "correct" refs.
  */
-void help_unknown_ref(const char *ref, const char *cmd, const char *error);
+NORETURN void help_unknown_ref(const char *ref, const char *cmd, const char *error);
 
 static inline void list_config_item(struct string_list *list,
                                    const char *prefix,
diff --git a/http.c b/http.c
index 938b9e5..027a86d 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1075,6 +1075,7 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
 
        git_config(urlmatch_config_entry, &config);
        free(normalized_url);
+       string_list_clear(&config.vars, 1);
 
 #if LIBCURL_VERSION_NUM >= 0x073800
        if (http_ssl_backend) {
index d664264..d624f1c 100644 (file)
@@ -328,12 +328,12 @@ static void filter_blobs_limit__init(
  */
 struct frame {
        /*
-        * defval is the usual default include/exclude value that
+        * default_match is the usual default include/exclude value that
         * should be inherited as we recurse into directories based
         * upon pattern matching of the directory itself or of a
         * containing directory.
         */
-       int defval;
+       enum pattern_match_result default_match;
 
        /*
         * 1 if the directory (recursively) contains any provisionally
@@ -347,7 +347,7 @@ struct frame {
 };
 
 struct filter_sparse_data {
-       struct exclude_list el;
+       struct pattern_list pl;
 
        size_t nr, alloc;
        struct frame *array_frame;
@@ -363,8 +363,9 @@ static enum list_objects_filter_result filter_sparse(
        void *filter_data_)
 {
        struct filter_sparse_data *filter_data = filter_data_;
-       int val, dtype;
+       int dtype;
        struct frame *frame;
+       enum pattern_match_result match;
 
        switch (filter_situation) {
        default:
@@ -373,15 +374,15 @@ static enum list_objects_filter_result filter_sparse(
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
                dtype = DT_DIR;
-               val = is_excluded_from_list(pathname, strlen(pathname),
-                                           filename, &dtype, &filter_data->el,
-                                           r->index);
-               if (val < 0)
-                       val = filter_data->array_frame[filter_data->nr - 1].defval;
+               match = path_matches_pattern_list(pathname, strlen(pathname),
+                                                 filename, &dtype, &filter_data->pl,
+                                                 r->index);
+               if (match == UNDECIDED)
+                       match = filter_data->array_frame[filter_data->nr - 1].default_match;
 
                ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1,
                           filter_data->alloc);
-               filter_data->array_frame[filter_data->nr].defval = val;
+               filter_data->array_frame[filter_data->nr].default_match = match;
                filter_data->array_frame[filter_data->nr].child_prov_omit = 0;
                filter_data->nr++;
 
@@ -435,12 +436,12 @@ static enum list_objects_filter_result filter_sparse(
                frame = &filter_data->array_frame[filter_data->nr - 1];
 
                dtype = DT_REG;
-               val = is_excluded_from_list(pathname, strlen(pathname),
-                                           filename, &dtype, &filter_data->el,
+               match = path_matches_pattern_list(pathname, strlen(pathname),
+                                           filename, &dtype, &filter_data->pl,
                                            r->index);
-               if (val < 0)
-                       val = frame->defval;
-               if (val > 0) {
+               if (match == UNDECIDED)
+                       match = frame->default_match;
+               if (match == MATCHED) {
                        if (omits)
                                oidset_remove(omits, &obj->oid);
                        return LOFR_MARK_SEEN | LOFR_DO_SHOW;
@@ -482,12 +483,12 @@ static void filter_sparse_oid__init(
        struct filter *filter)
 {
        struct filter_sparse_data *d = xcalloc(1, sizeof(*d));
-       if (add_excludes_from_blob_to_list(filter_options->sparse_oid_value,
-                                          NULL, 0, &d->el) < 0)
+       if (add_patterns_from_blob_to_list(filter_options->sparse_oid_value,
+                                          NULL, 0, &d->pl) < 0)
                die("could not load filter specification");
 
        ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
-       d->array_frame[d->nr].defval = 0; /* default to include */
+       d->array_frame[d->nr].default_match = 0; /* default to include */
        d->array_frame[d->nr].child_prov_omit = 0;
        d->nr++;
 
index 1e56df6..109c212 100644 (file)
@@ -677,9 +677,7 @@ void show_log(struct rev_info *opt)
                raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
                format_display_notes(&commit->object.oid, &notebuf,
                                     get_log_output_encoding(), raw);
-               ctx.notes_message = notebuf.len
-                       ? strbuf_detach(&notebuf, NULL)
-                       : xcalloc(1, 1);
+               ctx.notes_message = strbuf_detach(&notebuf, NULL);
        }
 
        /*
diff --git a/notes.c b/notes.c
index 75c028b..03e7d0c 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -269,8 +269,10 @@ static int note_tree_insert(struct notes_tree *t, struct int_node *tree,
                case PTR_TYPE_NOTE:
                        if (oideq(&l->key_oid, &entry->key_oid)) {
                                /* skip concatenation if l == entry */
-                               if (oideq(&l->val_oid, &entry->val_oid))
+                               if (oideq(&l->val_oid, &entry->val_oid)) {
+                                       free(entry);
                                        return 0;
+                               }
 
                                ret = combine_notes(&l->val_oid,
                                                    &entry->val_oid);
@@ -458,7 +460,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
                        die("Failed to load %s %s into notes tree "
                            "from %s",
                            type == PTR_TYPE_NOTE ? "note" : "subtree",
-                           oid_to_hex(&l->key_oid), t->ref);
+                           oid_to_hex(&object_oid), t->ref);
 
                continue;
 
index fa78a46..a7a4964 100644 (file)
@@ -144,7 +144,7 @@ static inline void reset_all_seen(void)
 
 static uint32_t find_object_pos(const struct object_id *oid)
 {
-       struct object_entry *entry = packlist_find(writer.to_pack, oid, NULL);
+       struct object_entry *entry = packlist_find(writer.to_pack, oid);
 
        if (!entry) {
                die("Failed to write bitmap index. Packfile doesn't have full closure "
index ed2befa..e07c798 100644 (file)
@@ -709,9 +709,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
                        else
                                object_list_insert(object, &wants);
 
-                       if (!tag->tagged)
-                               die("bad tag");
-                       object = parse_object_or_die(&tag->tagged->oid, NULL);
+                       object = parse_object_or_die(get_tagged_oid(tag), NULL);
                }
 
                if (object->flags & UNINTERESTING)
@@ -1063,7 +1061,7 @@ int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git,
 
                entry = &bitmap_git->pack->revindex[i];
                nth_packed_object_oid(&oid, bitmap_git->pack, entry->nr);
-               oe = packlist_find(mapping, &oid, NULL);
+               oe = packlist_find(mapping, &oid);
 
                if (oe)
                        reposition[i] = oe_in_pack_pos(mapping, oe) + 1;
index 5256029..c6250d7 100644 (file)
@@ -68,8 +68,7 @@ static void rehash_objects(struct packing_data *pdata)
 }
 
 struct object_entry *packlist_find(struct packing_data *pdata,
-                                  const struct object_id *oid,
-                                  uint32_t *index_pos)
+                                  const struct object_id *oid)
 {
        uint32_t i;
        int found;
@@ -79,9 +78,6 @@ struct object_entry *packlist_find(struct packing_data *pdata,
 
        i = locate_object_entry_hash(pdata, oid, &found);
 
-       if (index_pos)
-               *index_pos = i;
-
        if (!found)
                return NULL;
 
@@ -153,8 +149,7 @@ void prepare_packing_data(struct repository *r, struct packing_data *pdata)
 }
 
 struct object_entry *packlist_alloc(struct packing_data *pdata,
-                                   const unsigned char *sha1,
-                                   uint32_t index_pos)
+                                   const struct object_id *oid)
 {
        struct object_entry *new_entry;
 
@@ -177,12 +172,19 @@ struct object_entry *packlist_alloc(struct packing_data *pdata,
        new_entry = pdata->objects + pdata->nr_objects++;
 
        memset(new_entry, 0, sizeof(*new_entry));
-       hashcpy(new_entry->idx.oid.hash, sha1);
+       oidcpy(&new_entry->idx.oid, oid);
 
        if (pdata->index_size * 3 <= pdata->nr_objects * 4)
                rehash_objects(pdata);
-       else
-               pdata->index[index_pos] = pdata->nr_objects;
+       else {
+               int found;
+               uint32_t pos = locate_object_entry_hash(pdata,
+                                                       &new_entry->idx.oid,
+                                                       &found);
+               if (found)
+                       BUG("duplicate object inserted into hash");
+               pdata->index[pos] = pdata->nr_objects;
+       }
 
        if (pdata->in_pack)
                pdata->in_pack[pdata->nr_objects - 1] = NULL;
index 857d438..6fe6ae5 100644 (file)
@@ -183,12 +183,10 @@ static inline void packing_data_unlock(struct packing_data *pdata)
 }
 
 struct object_entry *packlist_alloc(struct packing_data *pdata,
-                                   const unsigned char *sha1,
-                                   uint32_t index_pos);
+                                   const struct object_id *oid);
 
 struct object_entry *packlist_find(struct packing_data *pdata,
-                                  const struct object_id *oid,
-                                  uint32_t *index_pos);
+                                  const struct object_id *oid);
 
 static inline uint32_t pack_name_hash(const char *name)
 {
index 1a7d69f..f3f962a 100644 (file)
@@ -2122,7 +2122,7 @@ static int add_promisor_object(const struct object_id *oid,
                        oidset_insert(set, &parents->item->object.oid);
        } else if (obj->type == OBJ_TAG) {
                struct tag *tag = (struct tag *) obj;
-               oidset_insert(set, &tag->tagged->oid);
+               oidset_insert(set, get_tagged_oid(tag));
        }
        return 0;
 }
diff --git a/quote.c b/quote.c
index 7f2aa6f..c8ba6b3 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -84,12 +84,28 @@ void sq_quote_argv(struct strbuf *dst, const char **argv)
        }
 }
 
+/*
+ * Legacy function to append each argv value, quoted as necessasry,
+ * with whitespace before each value.  This results in a leading
+ * space in the result.
+ */
 void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
+{
+       if (argv[0])
+               strbuf_addch(dst, ' ');
+       sq_append_quote_argv_pretty(dst, argv);
+}
+
+/*
+ * Append each argv value, quoted as necessary, with whitespace between them.
+ */
+void sq_append_quote_argv_pretty(struct strbuf *dst, const char **argv)
 {
        int i;
 
        for (i = 0; argv[i]; i++) {
-               strbuf_addch(dst, ' ');
+               if (i > 0)
+                       strbuf_addch(dst, ' ');
                sq_quote_buf_pretty(dst, argv[i]);
        }
 }
diff --git a/quote.h b/quote.h
index fb08dc0..ca8ee31 100644 (file)
--- a/quote.h
+++ b/quote.h
@@ -40,6 +40,7 @@ void sq_quotef(struct strbuf *, const char *fmt, ...);
  */
 void sq_quote_buf_pretty(struct strbuf *, const char *src);
 void sq_quote_argv_pretty(struct strbuf *, const char **argv);
+void sq_append_quote_argv_pretty(struct strbuf *dst, const char **argv);
 
 /* This unwraps what sq_quote() produces in place, but returns
  * NULL if the input does not look like what sq_quote would have
index 7338cfc..220e9bd 100644 (file)
@@ -1766,7 +1766,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
         * If it is a tag object, see if we use a value that derefs
         * the object, and if we do grab the object it refers to.
         */
-       oi_deref.oid = ((struct tag *)obj)->tagged->oid;
+       oi_deref.oid = *get_tagged_oid((struct tag *)obj);
 
        /*
         * NEEDSWORK: This derefs tag only once, which
@@ -1997,7 +1997,7 @@ static const struct object_id *match_points_at(struct oid_array *points_at,
        if (!obj)
                die(_("malformed object at '%s'"), refname);
        if (obj->type == OBJ_TAG)
-               tagged_oid = &((struct tag *)obj)->tagged->oid;
+               tagged_oid = get_tagged_oid((struct tag *)obj);
        if (tagged_oid && oid_array_lookup(points_at, tagged_oid) >= 0)
                return tagged_oid;
        return NULL;
index 3779b85..05546db 100644 (file)
@@ -49,10 +49,14 @@ void prepare_repo_settings(struct repository *r)
                UPDATE_DEFAULT_BOOL(r->settings.index_version, 4);
                UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_WRITE);
        }
+       if (!repo_config_get_bool(r, "fetch.writecommitgraph", &value))
+               r->settings.fetch_write_commit_graph = value;
        if (!repo_config_get_bool(r, "feature.experimental", &value) && value) {
                UPDATE_DEFAULT_BOOL(r->settings.pack_use_sparse, 1);
                UPDATE_DEFAULT_BOOL(r->settings.fetch_negotiation_algorithm, FETCH_NEGOTIATION_SKIPPING);
+               UPDATE_DEFAULT_BOOL(r->settings.fetch_write_commit_graph, 1);
        }
+       UPDATE_DEFAULT_BOOL(r->settings.fetch_write_commit_graph, 0);
 
        /* Hack for test programs like test-dump-untracked-cache */
        if (ignore_untracked_cache_config)
index 4da275e..fe0b5f5 100644 (file)
@@ -30,6 +30,7 @@ struct repo_settings {
 
        int core_commit_graph;
        int gc_write_commit_graph;
+       int fetch_write_commit_graph;
 
        int index_version;
        enum untracked_cache_setting core_untracked_cache;
index 51690e4..a2406c4 100644 (file)
@@ -404,9 +404,7 @@ static struct commit *handle_commit(struct rev_info *revs,
                struct tag *tag = (struct tag *) object;
                if (revs->tag_objects && !(flags & UNINTERESTING))
                        add_pending_object(revs, object, tag->tag);
-               if (!tag->tagged)
-                       die("bad tag");
-               object = parse_object(revs->repo, &tag->tagged->oid);
+               object = parse_object(revs->repo, get_tagged_oid(tag));
                if (!object) {
                        if (revs->ignore_missing_links || (flags & UNINTERESTING))
                                return NULL;
diff --git a/setup.c b/setup.c
index 25a3038..e2a479a 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -798,7 +798,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
                set_git_dir(gitdir);
        inside_git_dir = 0;
        inside_work_tree = 1;
-       if (offset == cwd->len)
+       if (offset >= cwd->len)
                return NULL;
 
        /* Make "offset" point past the '/' (already the case for root dirs) */
@@ -920,7 +920,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
        struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
        const char *gitdirenv;
-       int ceil_offset = -1, min_offset = has_dos_drive_prefix(dir->buf) ? 3 : 1;
+       int ceil_offset = -1, min_offset = offset_1st_component(dir->buf);
        dev_t current_device = 0;
        int one_filesystem = 1;
 
@@ -948,6 +948,12 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
        if (ceil_offset < 0)
                ceil_offset = min_offset - 2;
 
+       if (min_offset && min_offset == dir->len &&
+           !is_dir_sep(dir->buf[min_offset - 1])) {
+               strbuf_addch(dir, '/');
+               min_offset++;
+       }
+
        /*
         * Test in the following order (relative to the dir):
         * - .git (file containing "gitdir: <path>")
index 7e79b55..244977a 100644 (file)
@@ -4,11 +4,10 @@
 
 int cmd__read_cache(int argc, const char **argv)
 {
-       int i, cnt = 1, namelen;
+       int i, cnt = 1;
        const char *name = NULL;
 
        if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) {
-               namelen = strlen(name);
                argc--;
                argv++;
        }
@@ -24,7 +23,7 @@ int cmd__read_cache(int argc, const char **argv)
 
                        refresh_index(&the_index, REFRESH_QUIET,
                                      NULL, NULL, NULL);
-                       pos = index_name_pos(&the_index, name, namelen);
+                       pos = index_name_pos(&the_index, name, strlen(name));
                        if (pos < 0)
                                die("%s not in index", name);
                        printf("%s is%s up to date\n", name,
index 5d4ae62..bc0b9c7 100644 (file)
@@ -69,7 +69,7 @@ svn_cmd () {
 maybe_start_httpd () {
        loc=${1-svn}
 
-       if git env--helper --type=bool --default=false --exit-code GIT_TEST_HTTPD
+       if git env--helper --type=bool --default=false --exit-code GIT_TEST_SVN_HTTPD
        then
                . "$TEST_DIRECTORY"/lib-httpd.sh
                LIB_HTTPD_SVN="$loc"
index 2c3ad6e..6ee8ee3 100755 (executable)
@@ -130,11 +130,11 @@ test_expect_success 'perf stream, child processes' '
                d0|main|version|||||$V
                d0|main|start||_T_ABS_|||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0
                d0|main|cmd_name|||||trace2 (trace2)
-               d0|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 004child test-tool trace2 001return 0
+               d0|main|child_start||_T_ABS_|||[ch0] class:? argv:[test-tool trace2 004child test-tool trace2 001return 0]
                d1|main|version|||||$V
                d1|main|start||_T_ABS_|||_EXE_ trace2 004child test-tool trace2 001return 0
                d1|main|cmd_name|||||trace2 (trace2/trace2)
-               d1|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 001return 0
+               d1|main|child_start||_T_ABS_|||[ch0] class:? argv:[test-tool trace2 001return 0]
                d2|main|version|||||$V
                d2|main|start||_T_ABS_|||_EXE_ trace2 001return 0
                d2|main|cmd_name|||||trace2 (trace2/trace2/trace2)
index 428177c..983a0a1 100755 (executable)
@@ -1294,26 +1294,25 @@ test_expect_success 'git -c is not confused by empty environment' '
        GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
 '
 
-sq="'"
 test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
        cat >expect <<-\EOF &&
        env.one one
        env.two two
        EOF
-       GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq} ${sq}env.two=two${sq}" \
+       GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \
                git config --get-regexp "env.*" >actual &&
        test_cmp expect actual &&
 
        cat >expect <<-EOF &&
-       env.one one${sq}
+       env.one one${SQ}
        env.two two
        EOF
-       GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq}\\$sq$sq$sq ${sq}env.two=two${sq}" \
+       GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \
                git config --get-regexp "env.*" >actual &&
        test_cmp expect actual &&
 
        test_must_fail env \
-               GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq}\\$sq ${sq}env.two=two${sq}" \
+               GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \
                git config --get-regexp "env.*"
 '
 
index 970c5c3..2d142e5 100755 (executable)
@@ -32,8 +32,6 @@ test_update_rejected () {
        test_cmp unchanged actual
 }
 
-Q="'"
-
 # Test adding and deleting D/F-conflicting references in a single
 # transaction.
 df_test() {
@@ -93,7 +91,7 @@ df_test() {
                delname="$delref"
        fi &&
        cat >expected-err <<-EOF &&
-       fatal: cannot lock ref $Q$addname$Q: $Q$delref$Q exists; cannot create $Q$addref$Q
+       fatal: cannot lock ref $SQ$addname$SQ: $SQ$delref$SQ exists; cannot create $SQ$addref$SQ
        EOF
        $pack &&
        if $add_del
@@ -123,7 +121,7 @@ test_expect_success 'existing loose ref is a simple prefix of new' '
 
        prefix=refs/1l &&
        test_update_rejected "a c e" false "b c/x d" \
-               "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q"
+               "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ"
 
 '
 
@@ -131,7 +129,7 @@ test_expect_success 'existing packed ref is a simple prefix of new' '
 
        prefix=refs/1p &&
        test_update_rejected "a c e" true "b c/x d" \
-               "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q"
+               "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ"
 
 '
 
@@ -139,7 +137,7 @@ test_expect_success 'existing loose ref is a deeper prefix of new' '
 
        prefix=refs/2l &&
        test_update_rejected "a c e" false "b c/x/y d" \
-               "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q"
+               "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ"
 
 '
 
@@ -147,7 +145,7 @@ test_expect_success 'existing packed ref is a deeper prefix of new' '
 
        prefix=refs/2p &&
        test_update_rejected "a c e" true "b c/x/y d" \
-               "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q"
+               "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ"
 
 '
 
@@ -155,7 +153,7 @@ test_expect_success 'new ref is a simple prefix of existing loose' '
 
        prefix=refs/3l &&
        test_update_rejected "a c/x e" false "b c d" \
-               "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q"
+               "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ"
 
 '
 
@@ -163,7 +161,7 @@ test_expect_success 'new ref is a simple prefix of existing packed' '
 
        prefix=refs/3p &&
        test_update_rejected "a c/x e" true "b c d" \
-               "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q"
+               "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ"
 
 '
 
@@ -171,7 +169,7 @@ test_expect_success 'new ref is a deeper prefix of existing loose' '
 
        prefix=refs/4l &&
        test_update_rejected "a c/x/y e" false "b c d" \
-               "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q"
+               "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ"
 
 '
 
@@ -179,7 +177,7 @@ test_expect_success 'new ref is a deeper prefix of existing packed' '
 
        prefix=refs/4p &&
        test_update_rejected "a c/x/y e" true "b c d" \
-               "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q"
+               "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ"
 
 '
 
@@ -187,7 +185,7 @@ test_expect_success 'one new ref is a simple prefix of another' '
 
        prefix=refs/5 &&
        test_update_rejected "a e" false "b c c/x d" \
-               "cannot process $Q$prefix/c$Q and $Q$prefix/c/x$Q at the same time"
+               "cannot process $SQ$prefix/c$SQ and $SQ$prefix/c/x$SQ at the same time"
 
 '
 
@@ -334,7 +332,7 @@ test_expect_success 'D/F conflict prevents indirect delete long packed + indirec
 test_expect_success 'missing old value blocks update' '
        prefix=refs/missing-update &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ
        EOF
        printf "%s\n" "update $prefix/foo $E $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -345,7 +343,7 @@ test_expect_success 'incorrect old value blocks update' '
        prefix=refs/incorrect-update &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: is at $C but expected $D
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D
        EOF
        printf "%s\n" "update $prefix/foo $E $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -356,7 +354,7 @@ test_expect_success 'existing old value blocks create' '
        prefix=refs/existing-create &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: reference already exists
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: reference already exists
        EOF
        printf "%s\n" "create $prefix/foo $E" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -367,7 +365,7 @@ test_expect_success 'incorrect old value blocks delete' '
        prefix=refs/incorrect-delete &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: is at $C but expected $D
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D
        EOF
        printf "%s\n" "delete $prefix/foo $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -378,7 +376,7 @@ test_expect_success 'missing old value blocks indirect update' '
        prefix=refs/missing-indirect-update &&
        git symbolic-ref $prefix/symref $prefix/foo &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ
        EOF
        printf "%s\n" "update $prefix/symref $E $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -390,7 +388,7 @@ test_expect_success 'incorrect old value blocks indirect update' '
        git symbolic-ref $prefix/symref $prefix/foo &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
        EOF
        printf "%s\n" "update $prefix/symref $E $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -402,7 +400,7 @@ test_expect_success 'existing old value blocks indirect create' '
        git symbolic-ref $prefix/symref $prefix/foo &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: reference already exists
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists
        EOF
        printf "%s\n" "create $prefix/symref $E" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -414,7 +412,7 @@ test_expect_success 'incorrect old value blocks indirect delete' '
        git symbolic-ref $prefix/symref $prefix/foo &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
        EOF
        printf "%s\n" "delete $prefix/symref $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -425,7 +423,7 @@ test_expect_success 'missing old value blocks indirect no-deref update' '
        prefix=refs/missing-noderef-update &&
        git symbolic-ref $prefix/symref $prefix/foo &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: reference is missing but expected $D
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: reference is missing but expected $D
        EOF
        printf "%s\n" "option no-deref" "update $prefix/symref $E $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -437,7 +435,7 @@ test_expect_success 'incorrect old value blocks indirect no-deref update' '
        git symbolic-ref $prefix/symref $prefix/foo &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
        EOF
        printf "%s\n" "option no-deref" "update $prefix/symref $E $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -449,7 +447,7 @@ test_expect_success 'existing old value blocks indirect no-deref create' '
        git symbolic-ref $prefix/symref $prefix/foo &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: reference already exists
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists
        EOF
        printf "%s\n" "option no-deref" "create $prefix/symref $E" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -461,7 +459,7 @@ test_expect_success 'incorrect old value blocks indirect no-deref delete' '
        git symbolic-ref $prefix/symref $prefix/foo &&
        git update-ref $prefix/foo $C &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
        EOF
        printf "%s\n" "option no-deref" "delete $prefix/symref $D" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -474,13 +472,13 @@ test_expect_success 'non-empty directory blocks create' '
        : >.git/$prefix/foo/bar/baz.lock &&
        test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: there is a non-empty directory $Q.git/$prefix/foo$Q blocking reference $Q$prefix/foo$Q
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ
        EOF
        printf "%s\n" "update $prefix/foo $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
        test_cmp expected output.err &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ
        EOF
        printf "%s\n" "update $prefix/foo $D $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -493,13 +491,13 @@ test_expect_success 'broken reference blocks create' '
        echo "gobbledigook" >.git/$prefix/foo &&
        test_when_finished "rm -f .git/$prefix/foo" &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
        EOF
        printf "%s\n" "update $prefix/foo $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
        test_cmp expected output.err &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
+       fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
        EOF
        printf "%s\n" "update $prefix/foo $D $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -513,13 +511,13 @@ test_expect_success 'non-empty directory blocks indirect create' '
        : >.git/$prefix/foo/bar/baz.lock &&
        test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: there is a non-empty directory $Q.git/$prefix/foo$Q blocking reference $Q$prefix/foo$Q
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ
        EOF
        printf "%s\n" "update $prefix/symref $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
        test_cmp expected output.err &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ
        EOF
        printf "%s\n" "update $prefix/symref $D $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -532,13 +530,13 @@ test_expect_success 'broken reference blocks indirect create' '
        echo "gobbledigook" >.git/$prefix/foo &&
        test_when_finished "rm -f .git/$prefix/foo" &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
        EOF
        printf "%s\n" "update $prefix/symref $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
        test_cmp expected output.err &&
        cat >expected <<-EOF &&
-       fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
+       fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
        EOF
        printf "%s\n" "update $prefix/symref $D $C" |
        test_must_fail git update-ref --stdin 2>output.err &&
@@ -614,7 +612,7 @@ test_expect_success 'delete fails cleanly if packed-refs file is locked' '
        test_when_finished "rm -f .git/packed-refs.lock" &&
        test_must_fail git update-ref -d $prefix/foo >out 2>err &&
        git for-each-ref $prefix >actual &&
-       test_i18ngrep "Unable to create $Q.*packed-refs.lock$Q: " err &&
+       test_i18ngrep "Unable to create $SQ.*packed-refs.lock$SQ: " err &&
        test_cmp unchanged actual
 '
 
index feb1efd..1181a9f 100755 (executable)
@@ -18,10 +18,9 @@ do_walk () {
        git log -g --format="%gd %gs" "$@"
 }
 
-sq="'"
 test_expect_success 'set up expected reflog' '
        cat >expect.all <<-EOF
-       HEAD@{0} commit (merge): Merge branch ${sq}master${sq} into side
+       HEAD@{0} commit (merge): Merge branch ${SQ}master${SQ} into side
        HEAD@{1} commit: three
        HEAD@{2} checkout: moving from master to side
        HEAD@{3} commit: two
index 4ee009d..21a9c8f 100755 (executable)
@@ -8,10 +8,9 @@ exec </dev/null
 
 test_did_you_mean ()
 {
-       sq="'" &&
        cat >expected <<-EOF &&
-       fatal: Path '$2$3' $4, but not ${5:-$sq$3$sq}.
-       Did you mean '$1:$2$3'${2:+ aka $sq$1:./$3$sq}?
+       fatal: Path '$2$3' $4, but not ${5:-$SQ$3$SQ}.
+       Did you mean '$1:$2$3'${2:+ aka $SQ$1:./$3$SQ}?
        EOF
        test_cmp expected error
 }
index fa3e499..8b4cf8a 100755 (executable)
@@ -28,8 +28,6 @@ test_expect_success 'setup' '
        )
 '
 
-sq="'"
-
 full_name () {
        (cd clone &&
         git rev-parse --symbolic-full-name "$@")
@@ -129,7 +127,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}" >expect &&
        test_cmp expect actual
 )
 '
@@ -156,7 +154,7 @@ test_expect_success 'branch@{u} works when tracking a local branch' '
 
 test_expect_success 'branch@{u} error message when no upstream' '
        cat >expect <<-EOF &&
-       fatal: no upstream configured for branch ${sq}non-tracking${sq}
+       fatal: no upstream configured for branch ${SQ}non-tracking${SQ}
        EOF
        error_message non-tracking@{u} &&
        test_i18ncmp expect error
@@ -164,7 +162,7 @@ test_expect_success 'branch@{u} error message when no upstream' '
 
 test_expect_success '@{u} error message when no upstream' '
        cat >expect <<-EOF &&
-       fatal: no upstream configured for branch ${sq}master${sq}
+       fatal: no upstream configured for branch ${SQ}master${SQ}
        EOF
        test_must_fail git rev-parse --verify @{u} 2>actual &&
        test_i18ncmp expect actual
@@ -172,7 +170,7 @@ test_expect_success '@{u} error message when no upstream' '
 
 test_expect_success 'branch@{u} error message with misspelt branch' '
        cat >expect <<-EOF &&
-       fatal: no such branch: ${sq}no-such-branch${sq}
+       fatal: no such branch: ${SQ}no-such-branch${SQ}
        EOF
        error_message no-such-branch@{u} &&
        test_i18ncmp expect error
@@ -189,7 +187,7 @@ test_expect_success '@{u} error message when not on a branch' '
 
 test_expect_success 'branch@{u} error message if upstream branch not fetched' '
        cat >expect <<-EOF &&
-       fatal: upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch
+       fatal: upstream branch ${SQ}refs/heads/side${SQ} not stored as a remote-tracking branch
        EOF
        error_message bad-upstream@{u} &&
        test_i18ncmp expect error
index 209b4c7..2ec69a8 100755 (executable)
@@ -7,10 +7,6 @@ This test runs git ls-files with various relative path arguments.
 
 . ./test-lib.sh
 
-new_line='
-'
-sq=\'
-
 test_expect_success 'prepare' '
        : >never-mind-me &&
        git add never-mind-me &&
@@ -44,9 +40,9 @@ test_expect_success 'ls-files -c' '
                cd top/sub &&
                for f in ../y*
                do
-                       echo "error: pathspec $sq$f$sq did not match any file(s) known to git"
+                       echo "error: pathspec $SQ$f$SQ did not match any file(s) known to git"
                done >expect.err &&
-               echo "Did you forget to ${sq}git add${sq}?" >>expect.err &&
+               echo "Did you forget to ${SQ}git add${SQ}?" >>expect.err &&
                ls ../x* >expect.out &&
                test_must_fail git ls-files -c --error-unmatch ../[xy]* >actual.out 2>actual.err &&
                test_cmp expect.out actual.out &&
@@ -59,9 +55,9 @@ test_expect_success 'ls-files -o' '
                cd top/sub &&
                for f in ../x*
                do
-                       echo "error: pathspec $sq$f$sq did not match any file(s) known to git"
+                       echo "error: pathspec $SQ$f$SQ did not match any file(s) known to git"
                done >expect.err &&
-               echo "Did you forget to ${sq}git add${sq}?" >>expect.err &&
+               echo "Did you forget to ${SQ}git add${SQ}?" >>expect.err &&
                ls ../y* >expect.out &&
                test_must_fail git ls-files -o --error-unmatch ../[xy]* >actual.out 2>actual.err &&
                test_cmp expect.out actual.out &&
index 0ea4fc4..40251c9 100755 (executable)
@@ -192,10 +192,10 @@ test_expect_success 'branch --merged with --verbose' '
        EOF
        test_cmp expect actual &&
        git branch --verbose --merged topic >actual &&
-       cat >expect <<-\EOF &&
-         master c77a0a9 second on master
-       * topic  2c939f4 [ahead 1] foo
-         zzz    c77a0a9 second on master
+       cat >expect <<-EOF &&
+         master $(git rev-parse --short master) second on master
+       * topic  $(git rev-parse --short topic ) [ahead 1] foo
+         zzz    $(git rev-parse --short zzz   ) second on master
        EOF
        test_i18ncmp expect actual
 '
index ec54865..0120f76 100755 (executable)
@@ -8,17 +8,124 @@ test_description='range-diff tests'
 # harm than good.  We need some real history.
 
 test_expect_success 'setup' '
-       git fast-import < "$TEST_DIRECTORY"/t3206/history.export
+       git fast-import < "$TEST_DIRECTORY"/t3206/history.export &&
+       test_oid_cache <<-EOF
+       # topic
+       t1 sha1:4de457d
+       t2 sha1:fccce22
+       t3 sha1:147e64e
+       t4 sha1:a63e992
+       t1 sha256:b89f8b9
+       t2 sha256:5f12aad
+       t3 sha256:ea8b273
+       t4 sha256:14b7336
+
+       # unmodified
+       u1 sha1:35b9b25
+       u2 sha1:de345ab
+       u3 sha1:9af6654
+       u4 sha1:2901f77
+       u1 sha256:e3731be
+       u2 sha256:14fadf8
+       u3 sha256:736c4bc
+       u4 sha256:673e77d
+
+       # reordered
+       r1 sha1:aca177a
+       r2 sha1:14ad629
+       r3 sha1:ee58208
+       r4 sha1:307b27a
+       r1 sha256:f59d3aa
+       r2 sha256:fb261a8
+       r3 sha256:cb2649b
+       r4 sha256:958577e
+
+       # removed (deleted)
+       d1 sha1:7657159
+       d2 sha1:43d84d3
+       d3 sha1:a740396
+       d1 sha256:e312513
+       d2 sha256:eb19258
+       d3 sha256:1ccb3c1
+
+       # added
+       a1 sha1:2716022
+       a2 sha1:b62accd
+       a3 sha1:df46cfa
+       a4 sha1:3e64548
+       a5 sha1:12b4063
+       a1 sha256:d724f4d
+       a2 sha256:1de7762
+       a3 sha256:e159431
+       a4 sha256:b3e483c
+       a5 sha256:90866a7
+
+       # rebased
+       b1 sha1:cc9c443
+       b2 sha1:c5d9641
+       b3 sha1:28cc2b6
+       b4 sha1:5628ab7
+       b5 sha1:a31b12e
+       b1 sha256:a1a8717
+       b2 sha256:20a5862
+       b3 sha256:587172a
+       b4 sha256:2721c5d
+       b5 sha256:7b57864
+
+       # changed
+       c1 sha1:a4b3333
+       c2 sha1:f51d370
+       c3 sha1:0559556
+       c4 sha1:d966c5c
+       c1 sha256:f8c2b9d
+       c2 sha256:3fb6318
+       c3 sha256:168ab68
+       c4 sha256:3526539
+
+       # changed-message
+       m1 sha1:f686024
+       m2 sha1:4ab067d
+       m3 sha1:b9cb956
+       m4 sha1:8add5f1
+       m1 sha256:31e6281
+       m2 sha256:a06bf1b
+       m3 sha256:82dc654
+       m4 sha256:48470c5
+
+       # renamed
+       n1 sha1:f258d75
+       n2 sha1:017b62d
+       n3 sha1:3ce7af6
+       n4 sha1:1e6226b
+       n1 sha256:ad52114
+       n2 sha256:3b54c8f
+       n3 sha256:3b0a644
+       n4 sha256:e461653
+
+       # added and removed
+       s1 sha1:096b1ba
+       s2 sha1:d92e698
+       s3 sha1:9a1db4d
+       s4 sha1:fea3b5c
+       s1 sha256:a7f9134
+       s2 sha256:b4c2580
+       s3 sha256:1d62aa2
+       s4 sha256:48160e8
+
+       # Empty delimiter (included so lines match neatly)
+       __ sha1:-------
+       __ sha256:-------
+       EOF
 '
 
 test_expect_success 'simple A..B A..C (unmodified)' '
        git range-diff --no-color master..topic master..unmodified \
                >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  35b9b25 s/5/A/
-       2:  fccce22 = 2:  de345ab s/4/A/
-       3:  147e64e = 3:  9af6654 s/11/B/
-       4:  a63e992 = 4:  2901f77 s/12/B/
+       1:  $(test_oid t1) = 1:  $(test_oid u1) s/5/A/
+       2:  $(test_oid t2) = 2:  $(test_oid u2) s/4/A/
+       3:  $(test_oid t3) = 3:  $(test_oid u3) s/11/B/
+       4:  $(test_oid t4) = 4:  $(test_oid u4) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -38,10 +145,10 @@ test_expect_success 'simple A B C (unmodified)' '
 test_expect_success 'trivial reordering' '
        git range-diff --no-color master topic reordered >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  aca177a s/5/A/
-       3:  147e64e = 2:  14ad629 s/11/B/
-       4:  a63e992 = 3:  ee58208 s/12/B/
-       2:  fccce22 = 4:  307b27a s/4/A/
+       1:  $(test_oid t1) = 1:  $(test_oid r1) s/5/A/
+       3:  $(test_oid t3) = 2:  $(test_oid r2) s/11/B/
+       4:  $(test_oid t4) = 3:  $(test_oid r3) s/12/B/
+       2:  $(test_oid t2) = 4:  $(test_oid r4) s/4/A/
        EOF
        test_cmp expected actual
 '
@@ -49,10 +156,10 @@ test_expect_success 'trivial reordering' '
 test_expect_success 'removed a commit' '
        git range-diff --no-color master topic removed >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  7657159 s/5/A/
-       2:  fccce22 < -:  ------- s/4/A/
-       3:  147e64e = 2:  43d84d3 s/11/B/
-       4:  a63e992 = 3:  a740396 s/12/B/
+       1:  $(test_oid t1) = 1:  $(test_oid d1) s/5/A/
+       2:  $(test_oid t2) < -:  $(test_oid __) s/4/A/
+       3:  $(test_oid t3) = 2:  $(test_oid d2) s/11/B/
+       4:  $(test_oid t4) = 3:  $(test_oid d3) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -60,11 +167,11 @@ test_expect_success 'removed a commit' '
 test_expect_success 'added a commit' '
        git range-diff --no-color master topic added >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  2716022 s/5/A/
-       2:  fccce22 = 2:  b62accd s/4/A/
-       -:  ------- > 3:  df46cfa s/6/A/
-       3:  147e64e = 4:  3e64548 s/11/B/
-       4:  a63e992 = 5:  12b4063 s/12/B/
+       1:  $(test_oid t1) = 1:  $(test_oid a1) s/5/A/
+       2:  $(test_oid t2) = 2:  $(test_oid a2) s/4/A/
+       -:  $(test_oid __) > 3:  $(test_oid a3) s/6/A/
+       3:  $(test_oid t3) = 4:  $(test_oid a4) s/11/B/
+       4:  $(test_oid t4) = 5:  $(test_oid a5) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -72,10 +179,10 @@ test_expect_success 'added a commit' '
 test_expect_success 'new base, A B C' '
        git range-diff --no-color master topic rebased >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  cc9c443 s/5/A/
-       2:  fccce22 = 2:  c5d9641 s/4/A/
-       3:  147e64e = 3:  28cc2b6 s/11/B/
-       4:  a63e992 = 4:  5628ab7 s/12/B/
+       1:  $(test_oid t1) = 1:  $(test_oid b1) s/5/A/
+       2:  $(test_oid t2) = 2:  $(test_oid b2) s/4/A/
+       3:  $(test_oid t3) = 3:  $(test_oid b3) s/11/B/
+       4:  $(test_oid t4) = 4:  $(test_oid b4) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -84,11 +191,11 @@ test_expect_success 'new base, B...C' '
        # this syntax includes the commits from master!
        git range-diff --no-color topic...rebased >actual &&
        cat >expected <<-EOF &&
-       -:  ------- > 1:  a31b12e unrelated
-       1:  4de457d = 2:  cc9c443 s/5/A/
-       2:  fccce22 = 3:  c5d9641 s/4/A/
-       3:  147e64e = 4:  28cc2b6 s/11/B/
-       4:  a63e992 = 5:  5628ab7 s/12/B/
+       -:  $(test_oid __) > 1:  $(test_oid b5) unrelated
+       1:  $(test_oid t1) = 2:  $(test_oid b1) s/5/A/
+       2:  $(test_oid t2) = 3:  $(test_oid b2) s/4/A/
+       3:  $(test_oid t3) = 4:  $(test_oid b3) s/11/B/
+       4:  $(test_oid t4) = 5:  $(test_oid b4) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -96,9 +203,9 @@ test_expect_success 'new base, B...C' '
 test_expect_success 'changed commit' '
        git range-diff --no-color topic...changed >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  a4b3333 s/5/A/
-       2:  fccce22 = 2:  f51d370 s/4/A/
-       3:  147e64e ! 3:  0559556 s/11/B/
+       1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
+       2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
+       3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
            @@ file: A
              9
              10
@@ -108,7 +215,7 @@ test_expect_success 'changed commit' '
              12
              13
              14
-       4:  a63e992 ! 4:  d966c5c s/12/B/
+       4:  $(test_oid t4) ! 4:  $(test_oid c4) s/12/B/
            @@ file
             @@ file: A
              9
@@ -125,10 +232,10 @@ test_expect_success 'changed commit' '
 test_expect_success 'changed commit with --no-patch diff option' '
        git range-diff --no-color --no-patch topic...changed >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  a4b3333 s/5/A/
-       2:  fccce22 = 2:  f51d370 s/4/A/
-       3:  147e64e ! 3:  0559556 s/11/B/
-       4:  a63e992 ! 4:  d966c5c s/12/B/
+       1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
+       2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
+       3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
+       4:  $(test_oid t4) ! 4:  $(test_oid c4) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -136,16 +243,16 @@ test_expect_success 'changed commit with --no-patch diff option' '
 test_expect_success 'changed commit with --stat diff option' '
        git range-diff --no-color --stat topic...changed >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  a4b3333 s/5/A/
+       1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
             a => b | 0
             1 file changed, 0 insertions(+), 0 deletions(-)
-       2:  fccce22 = 2:  f51d370 s/4/A/
+       2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
             a => b | 0
             1 file changed, 0 insertions(+), 0 deletions(-)
-       3:  147e64e ! 3:  0559556 s/11/B/
+       3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
             a => b | 0
             1 file changed, 0 insertions(+), 0 deletions(-)
-       4:  a63e992 ! 4:  d966c5c s/12/B/
+       4:  $(test_oid t4) ! 4:  $(test_oid c4) s/12/B/
             a => b | 0
             1 file changed, 0 insertions(+), 0 deletions(-)
        EOF
@@ -155,9 +262,9 @@ test_expect_success 'changed commit with --stat diff option' '
 test_expect_success 'changed commit with sm config' '
        git range-diff --no-color --submodule=log topic...changed >actual &&
        cat >expected <<-EOF &&
-       1:  4de457d = 1:  a4b3333 s/5/A/
-       2:  fccce22 = 2:  f51d370 s/4/A/
-       3:  147e64e ! 3:  0559556 s/11/B/
+       1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
+       2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
+       3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
            @@ file: A
              9
              10
@@ -167,7 +274,7 @@ test_expect_success 'changed commit with sm config' '
              12
              13
              14
-       4:  a63e992 ! 4:  d966c5c s/12/B/
+       4:  $(test_oid t4) ! 4:  $(test_oid c4) s/12/B/
            @@ file
             @@ file: A
              9
@@ -184,8 +291,8 @@ test_expect_success 'changed commit with sm config' '
 test_expect_success 'renamed file' '
        git range-diff --no-color --submodule=log topic...renamed-file >actual &&
        sed s/Z/\ /g >expected <<-EOF &&
-       1:  4de457d = 1:  f258d75 s/5/A/
-       2:  fccce22 ! 2:  017b62d s/4/A/
+       1:  $(test_oid t1) = 1:  $(test_oid n1) s/5/A/
+       2:  $(test_oid t2) ! 2:  $(test_oid n2) s/4/A/
            @@ Metadata
            ZAuthor: Thomas Rast <trast@inf.ethz.ch>
            Z
@@ -198,7 +305,7 @@ test_expect_success 'renamed file' '
            Z@@
            Z 1
            Z 2
-       3:  147e64e ! 3:  3ce7af6 s/11/B/
+       3:  $(test_oid t3) ! 3:  $(test_oid n3) s/11/B/
            @@ Metadata
            Z ## Commit message ##
            Z    s/11/B/
@@ -210,7 +317,7 @@ test_expect_success 'renamed file' '
            Z 8
            Z 9
            Z 10
-       4:  a63e992 ! 4:  1e6226b s/12/B/
+       4:  $(test_oid t4) ! 4:  $(test_oid n4) s/12/B/
            @@ Metadata
            Z ## Commit message ##
            Z    s/12/B/
@@ -229,8 +336,8 @@ test_expect_success 'renamed file' '
 test_expect_success 'file added and later removed' '
        git range-diff --no-color --submodule=log topic...added-removed >actual &&
        sed s/Z/\ /g >expected <<-EOF &&
-       1:  4de457d = 1:  096b1ba s/5/A/
-       2:  fccce22 ! 2:  d92e698 s/4/A/
+       1:  $(test_oid t1) = 1:  $(test_oid s1) s/5/A/
+       2:  $(test_oid t2) ! 2:  $(test_oid s2) s/4/A/
            @@ Metadata
            ZAuthor: Thomas Rast <trast@inf.ethz.ch>
            Z
@@ -246,7 +353,7 @@ test_expect_success 'file added and later removed' '
            Z 7
            +
            + ## new-file (new) ##
-       3:  147e64e ! 3:  9a1db4d s/11/B/
+       3:  $(test_oid t3) ! 3:  $(test_oid s3) s/11/B/
            @@ Metadata
            ZAuthor: Thomas Rast <trast@inf.ethz.ch>
            Z
@@ -262,7 +369,7 @@ test_expect_success 'file added and later removed' '
            Z 14
            +
            + ## new-file (deleted) ##
-       4:  a63e992 = 4:  fea3b5c s/12/B/
+       4:  $(test_oid t4) = 4:  $(test_oid s4) s/12/B/
        EOF
        test_cmp expected actual
 '
@@ -275,8 +382,8 @@ test_expect_success 'no commits on one side' '
 test_expect_success 'changed message' '
        git range-diff --no-color topic...changed-message >actual &&
        sed s/Z/\ /g >expected <<-EOF &&
-       1:  4de457d = 1:  f686024 s/5/A/
-       2:  fccce22 ! 2:  4ab067d s/4/A/
+       1:  $(test_oid t1) = 1:  $(test_oid m1) s/5/A/
+       2:  $(test_oid t2) ! 2:  $(test_oid m2) s/4/A/
            @@ Metadata
            Z ## Commit message ##
            Z    s/4/A/
@@ -286,16 +393,16 @@ test_expect_success 'changed message' '
            Z ## file ##
            Z@@
            Z 1
-       3:  147e64e = 3:  b9cb956 s/11/B/
-       4:  a63e992 = 4:  8add5f1 s/12/B/
+       3:  $(test_oid t3) = 3:  $(test_oid m3) s/11/B/
+       4:  $(test_oid t4) = 4:  $(test_oid m4) s/12/B/
        EOF
        test_cmp expected actual
 '
 
 test_expect_success 'dual-coloring' '
-       sed -e "s|^:||" >expect <<-\EOF &&
-       :<YELLOW>1:  a4b3333 = 1:  f686024 s/5/A/<RESET>
-       :<RED>2:  f51d370 <RESET><YELLOW>!<RESET><GREEN> 2:  4ab067d<RESET><YELLOW> s/4/A/<RESET>
+       sed -e "s|^:||" >expect <<-EOF &&
+       :<YELLOW>1:  $(test_oid c1) = 1:  $(test_oid m1) s/5/A/<RESET>
+       :<RED>2:  $(test_oid c2) <RESET><YELLOW>!<RESET><GREEN> 2:  $(test_oid m2)<RESET><YELLOW> s/4/A/<RESET>
        :    <REVERSE><CYAN>@@<RESET> <RESET>Metadata<RESET>
        :      ## Commit message ##<RESET>
        :         s/4/A/<RESET>
@@ -305,7 +412,7 @@ test_expect_success 'dual-coloring' '
        :      ## file ##<RESET>
        :    <CYAN> @@<RESET>
        :      1<RESET>
-       :<RED>3:  0559556 <RESET><YELLOW>!<RESET><GREEN> 3:  b9cb956<RESET><YELLOW> s/11/B/<RESET>
+       :<RED>3:  $(test_oid c3) <RESET><YELLOW>!<RESET><GREEN> 3:  $(test_oid m3)<RESET><YELLOW> s/11/B/<RESET>
        :    <REVERSE><CYAN>@@<RESET> <RESET>file: A<RESET>
        :      9<RESET>
        :      10<RESET>
@@ -315,7 +422,7 @@ test_expect_success 'dual-coloring' '
        :      12<RESET>
        :      13<RESET>
        :      14<RESET>
-       :<RED>4:  d966c5c <RESET><YELLOW>!<RESET><GREEN> 4:  8add5f1<RESET><YELLOW> s/12/B/<RESET>
+       :<RED>4:  $(test_oid c4) <RESET><YELLOW>!<RESET><GREEN> 4:  $(test_oid m4)<RESET><YELLOW> s/12/B/<RESET>
        :    <REVERSE><CYAN>@@<RESET> <RESET>file<RESET>
        :    <CYAN> @@ file: A<RESET>
        :      9<RESET>
index 704bbc6..d3fa298 100755 (executable)
@@ -66,8 +66,9 @@ test_expect_success 'show notes entry with %N' '
 '
 
 test_expect_success 'create reflog entry' '
+       ref=$(git rev-parse --short refs/notes/commits) &&
        cat <<-EOF >expect &&
-               a1d8fa6 refs/notes/commits@{0}: notes: Notes added by '\''git notes add'\''
+               $ref refs/notes/commits@{0}: notes: Notes added by '\''git notes add'\''
        EOF
        git reflog show refs/notes/commits >actual &&
        test_cmp expect actual
@@ -134,8 +135,9 @@ test_expect_success 'can overwrite existing note with "git notes add -f"' '
 '
 
 test_expect_success 'show notes' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:14:13 2005 -0700
 
@@ -152,8 +154,9 @@ test_expect_success 'show notes' '
 test_expect_success 'show multi-line notes' '
        test_commit 3rd &&
        MSG="b3${LF}c3c3c3c3${LF}d3d3d3" git notes add &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect-multiline <<-EOF &&
-               commit d07d62e5208f22eb5695e7eb47667dc8b9860290
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:15:13 2005 -0700
 
@@ -174,8 +177,9 @@ test_expect_success 'show -F notes' '
        test_commit 4th &&
        echo "xyzzy" >note5 &&
        git notes add -F note5 &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect-F <<-EOF &&
-               commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:16:13 2005 -0700
 
@@ -198,10 +202,13 @@ test_expect_success 'Re-adding -F notes without -f fails' '
 '
 
 test_expect_success 'git log --pretty=raw does not show notes' '
+       commit=$(git rev-parse HEAD) &&
+       tree=$(git rev-parse HEAD^{tree}) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect <<-EOF &&
-               commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
-               tree 05ac65288c4c4b3b709a020ae94b2ece2f2201ae
-               parent d07d62e5208f22eb5695e7eb47667dc8b9860290
+               commit $commit
+               tree $tree
+               parent $parent
                author A U Thor <author@example.com> 1112912173 -0700
                committer C O Mitter <committer@example.com> 1112912173 -0700
 
@@ -291,8 +298,9 @@ test_expect_success 'git log --no-notes resets ref list' '
 test_expect_success 'show -m notes' '
        test_commit 5th &&
        git notes add -m spam -m "foo${LF}bar${LF}baz" &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect-m <<-EOF &&
-               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:17:13 2005 -0700
 
@@ -313,8 +321,9 @@ test_expect_success 'show -m notes' '
 
 test_expect_success 'remove note with add -f -F /dev/null' '
        git notes add -f -F /dev/null &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect-rm-F <<-EOF &&
-               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:17:13 2005 -0700
 
@@ -356,14 +365,16 @@ test_expect_success 'create note with combination of -m and -F' '
 test_expect_success 'remove note with "git notes remove"' '
        git notes remove HEAD^ &&
        git notes remove &&
+       commit=$(git rev-parse HEAD) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect-rm-remove <<-EOF &&
-               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:17:13 2005 -0700
 
                ${indent}5th
 
-               commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+               commit $parent
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:16:13 2005 -0700
 
@@ -459,9 +470,11 @@ test_expect_success 'removing with --stdin --ignore-missing' '
 '
 
 test_expect_success 'list notes with "git notes list"' '
-       cat >expect <<-EOF &&
-               c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691
-               c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290
+       commit_2=$(git rev-parse 2nd) &&
+       commit_3=$(git rev-parse 3rd) &&
+       sort -t" " -k2 >expect <<-EOF &&
+               $(git rev-parse refs/notes/commits:$commit_2) $commit_2
+               $(git rev-parse refs/notes/commits:$commit_3) $commit_3
        EOF
        git notes list >actual &&
        test_cmp expect actual
@@ -474,7 +487,7 @@ test_expect_success 'list notes with "git notes"' '
 
 test_expect_success 'list specific note with "git notes list <object>"' '
        cat >expect <<-EOF &&
-               c18dc024e14f08d18d14eea0d747ff692d66d6a3
+               $(git rev-parse refs/notes/commits:$commit_3)
        EOF
        git notes list HEAD^^ >actual &&
        test_cmp expect actual
@@ -498,10 +511,11 @@ test_expect_success 'append to existing note with "git notes append"' '
 '
 
 test_expect_success '"git notes list" does not expand to "git notes list HEAD"' '
-       cat >expect_list <<-EOF &&
-               c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691
-               4b6ad22357cc8a1296720574b8d2fbc22fab0671 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
-               c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290
+       commit_5=$(git rev-parse 5th) &&
+       sort -t" " -k2 >expect_list <<-EOF &&
+               $(git rev-parse refs/notes/commits:$commit_2) $commit_2
+               $(git rev-parse refs/notes/commits:$commit_3) $commit_3
+               $(git rev-parse refs/notes/commits:$commit_5) $commit_5
        EOF
        git notes list >actual &&
        test_cmp expect_list actual
@@ -531,8 +545,9 @@ test_expect_success 'appending empty string to non-existing note does not create
 test_expect_success 'create other note on a different notes ref (setup)' '
        test_commit 6th &&
        GIT_NOTES_REF="refs/notes/other" git notes add -m "other note" &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect-not-other <<-EOF &&
-               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:18:13 2005 -0700
 
@@ -569,8 +584,10 @@ test_expect_success 'Do not show note when core.notesRef is overridden' '
 '
 
 test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
+       commit=$(git rev-parse HEAD) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect-both <<-EOF &&
-               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:18:13 2005 -0700
 
@@ -582,7 +599,7 @@ test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
                Notes (other):
                ${indent}other note
 
-               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               commit $parent
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:17:13 2005 -0700
 
@@ -616,8 +633,9 @@ test_expect_success 'notes.displayRef can be given more than once' '
 '
 
 test_expect_success 'notes.displayRef respects order' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect-both-reversed <<-EOF &&
-               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:18:13 2005 -0700
 
@@ -642,14 +660,16 @@ test_expect_success 'GIT_NOTES_DISPLAY_REF works' '
 '
 
 test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '
+       commit=$(git rev-parse HEAD) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect-none <<-EOF &&
-               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:18:13 2005 -0700
 
                ${indent}6th
 
-               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               commit $parent
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:17:13 2005 -0700
 
@@ -666,8 +686,9 @@ test_expect_success '--show-notes=* adds to GIT_NOTES_DISPLAY_REF' '
 '
 
 test_expect_success '--no-standard-notes' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect-commits <<-EOF &&
-               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:18:13 2005 -0700
 
@@ -712,8 +733,10 @@ test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
 '
 
 test_expect_success 'create note from other note with "git notes add -C"' '
+       test_commit 7th &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit fb01e0ca8c33b6cc0c6451dde747f97df567cb5c
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:19:13 2005 -0700
 
@@ -722,7 +745,6 @@ test_expect_success 'create note from other note with "git notes add -C"' '
                Notes:
                ${indent}order test
        EOF
-       test_commit 7th &&
        git notes add -C $(git notes list HEAD^) &&
        git log -1 >actual &&
        test_cmp expect actual &&
@@ -744,8 +766,9 @@ test_expect_success 'create note from non-blob with "git notes add -C" fails' '
 '
 
 test_expect_success 'create note from blob with "git notes add -C" reuses blob id' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 9a4c31c7f722b5d517e92c64e932dd751e1413bf
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:20:13 2005 -0700
 
@@ -762,8 +785,10 @@ test_expect_success 'create note from blob with "git notes add -C" reuses blob i
 '
 
 test_expect_success 'create note from other note with "git notes add -c"' '
+       test_commit 9th &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:21:13 2005 -0700
 
@@ -772,7 +797,6 @@ test_expect_success 'create note from other note with "git notes add -c"' '
                Notes:
                ${indent}yet another note
        EOF
-       test_commit 9th &&
        MSG="yet another note" git notes add -c $(git notes list HEAD^^) &&
        git log -1 >actual &&
        test_cmp expect actual
@@ -785,8 +809,9 @@ test_expect_success 'create note from non-existing note with "git notes add -c"
 '
 
 test_expect_success 'append to note from other note with "git notes append -C"' '
+       commit=$(git rev-parse HEAD^) &&
        cat >expect <<-EOF &&
-               commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:21:13 2005 -0700
 
@@ -803,8 +828,9 @@ test_expect_success 'append to note from other note with "git notes append -C"'
 '
 
 test_expect_success 'create note from other note with "git notes append -c"' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:22:13 2005 -0700
 
@@ -819,8 +845,9 @@ test_expect_success 'create note from other note with "git notes append -c"' '
 '
 
 test_expect_success 'append to note from other note with "git notes append -c"' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:22:13 2005 -0700
 
@@ -837,8 +864,10 @@ test_expect_success 'append to note from other note with "git notes append -c"'
 '
 
 test_expect_success 'copy note with "git notes copy"' '
+       test_commit 11th &&
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:23:13 2005 -0700
 
@@ -849,7 +878,6 @@ test_expect_success 'copy note with "git notes copy"' '
                ${indent}
                ${indent}yet another note
        EOF
-       test_commit 11th &&
        git notes copy HEAD^ HEAD &&
        git log -1 >actual &&
        test_cmp expect actual &&
@@ -864,8 +892,9 @@ test_expect_success 'prevent overwrite with "git notes copy"' '
 '
 
 test_expect_success 'allow overwrite with "git notes copy -f"' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:23:13 2005 -0700
 
@@ -889,8 +918,10 @@ test_expect_success 'cannot copy note from object without notes' '
 '
 
 test_expect_success 'git notes copy --stdin' '
+       commit=$(git rev-parse HEAD) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect <<-EOF &&
-               commit e871aa61182b1d95d0a6fb75445d891722863b6b
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:25:13 2005 -0700
 
@@ -901,7 +932,7 @@ test_expect_success 'git notes copy --stdin' '
                ${indent}
                ${indent}yet another note
 
-               commit 65e263ded02ae4e8839bc151095113737579dc12
+               commit $parent
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:24:13 2005 -0700
 
@@ -922,21 +953,23 @@ test_expect_success 'git notes copy --stdin' '
 '
 
 test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
+       test_commit 14th &&
+       test_commit 15th &&
+       commit=$(git rev-parse HEAD) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
                ${indent}15th
 
-               commit 07c85d77059393ed0154b8c96906547a59dfcddd
+               commit $parent
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:26:13 2005 -0700
 
                ${indent}14th
        EOF
-       test_commit 14th &&
-       test_commit 15th &&
        (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
        echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
        git notes copy --for-rewrite=foo &&
@@ -945,8 +978,10 @@ test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
 '
 
 test_expect_success 'git notes copy --for-rewrite (enabled)' '
+       commit=$(git rev-parse HEAD) &&
+       parent=$(git rev-parse HEAD^) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
@@ -957,7 +992,7 @@ test_expect_success 'git notes copy --for-rewrite (enabled)' '
                ${indent}
                ${indent}yet another note
 
-               commit 07c85d77059393ed0154b8c96906547a59dfcddd
+               commit $parent
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:26:13 2005 -0700
 
@@ -986,8 +1021,9 @@ test_expect_success 'git notes copy --for-rewrite (disabled)' '
 '
 
 test_expect_success 'git notes copy --for-rewrite (overwrite)' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
@@ -1015,8 +1051,9 @@ test_expect_success 'git notes copy --for-rewrite (ignore)' '
 '
 
 test_expect_success 'git notes copy --for-rewrite (append)' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
@@ -1037,8 +1074,9 @@ test_expect_success 'git notes copy --for-rewrite (append)' '
 '
 
 test_expect_success 'git notes copy --for-rewrite (append two to one)' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
@@ -1075,8 +1113,9 @@ test_expect_success 'git notes copy --for-rewrite (append empty)' '
 '
 
 test_expect_success 'GIT_NOTES_REWRITE_MODE works' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
@@ -1095,8 +1134,9 @@ test_expect_success 'GIT_NOTES_REWRITE_MODE works' '
 '
 
 test_expect_success 'GIT_NOTES_REWRITE_REF works' '
+       commit=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
-               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               commit $commit
                Author: A U Thor <author@example.com>
                Date:   Thu Apr 7 15:27:13 2005 -0700
 
index 54460be..831f83d 100755 (executable)
@@ -35,15 +35,10 @@ test_expect_success 'many notes created with git-notes triggers fanout' '
        git ls-tree -r --name-only refs/notes/commits |
        while read path
        do
-               case "$path" in
-               ??/??????????????????????????????????????)
-                       : true
-                       ;;
-               *)
+               echo $path | grep "^../[0-9a-f]*$" || {
                        echo "Invalid path \"$path\"" &&
-                       return 1
-                       ;;
-               esac
+                       return 1;
+               }
        done
 '
 
@@ -77,15 +72,10 @@ test_expect_success 'deleting most notes triggers fanout consolidation' '
        git ls-tree -r --name-only refs/notes/commits |
        while read path
        do
-               case "$path" in
-               ????????????????????????????????????????)
-                       : true
-                       ;;
-               *)
+               echo $path | grep -v "^../.*" || {
                        echo "Invalid path \"$path\"" &&
-                       return 1
-                       ;;
-               esac
+                       return 1;
+               }
        done
 '
 
index 6174808..8f4102f 100755 (executable)
@@ -11,23 +11,26 @@ test_expect_success 'setup: create a few commits with notes' '
        test_tick &&
        git commit -m 1st &&
        git notes add -m "Note #1" &&
+       first=$(git rev-parse HEAD) &&
        : > file2 &&
        git add file2 &&
        test_tick &&
        git commit -m 2nd &&
        git notes add -m "Note #2" &&
+       second=$(git rev-parse HEAD) &&
        : > file3 &&
        git add file3 &&
        test_tick &&
        git commit -m 3rd &&
-       COMMIT_FILE=.git/objects/5e/e1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
+       third=$(git rev-parse HEAD) &&
+       COMMIT_FILE=$(echo $third | sed "s!^..!.git/objects/&/!") &&
        test -f $COMMIT_FILE &&
        test-tool chmtime =+0 $COMMIT_FILE &&
        git notes add -m "Note #3"
 '
 
 cat > expect <<END_OF_LOG
-commit 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29
+commit $third
 Author: A U Thor <author@example.com>
 Date:   Thu Apr 7 15:15:13 2005 -0700
 
@@ -36,7 +39,7 @@ Date:   Thu Apr 7 15:15:13 2005 -0700
 Notes:
     Note #3
 
-commit 08341ad9e94faa089d60fd3f523affb25c6da189
+commit $second
 Author: A U Thor <author@example.com>
 Date:   Thu Apr 7 15:14:13 2005 -0700
 
@@ -45,7 +48,7 @@ Date:   Thu Apr 7 15:14:13 2005 -0700
 Notes:
     Note #2
 
-commit ab5f302035f2e7aaf04265f08b42034c23256e1f
+commit $first
 Author: A U Thor <author@example.com>
 Date:   Thu Apr 7 15:13:13 2005 -0700
 
@@ -70,16 +73,16 @@ test_expect_success 'remove some commits' '
 
 test_expect_success 'verify that commits are gone' '
 
-       test_must_fail git cat-file -p 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
-       git cat-file -p 08341ad9e94faa089d60fd3f523affb25c6da189 &&
-       git cat-file -p ab5f302035f2e7aaf04265f08b42034c23256e1f
+       test_must_fail git cat-file -p $third &&
+       git cat-file -p $second &&
+       git cat-file -p $first
 '
 
 test_expect_success 'verify that notes are still present' '
 
-       git notes show 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
-       git notes show 08341ad9e94faa089d60fd3f523affb25c6da189 &&
-       git notes show ab5f302035f2e7aaf04265f08b42034c23256e1f
+       git notes show $third &&
+       git notes show $second &&
+       git notes show $first
 '
 
 test_expect_success 'prune -n does not remove notes' '
@@ -90,13 +93,10 @@ test_expect_success 'prune -n does not remove notes' '
        test_cmp expect actual
 '
 
-cat > expect <<EOF
-5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29
-EOF
 
 test_expect_success 'prune -n lists prunable notes' '
 
-
+       echo $third >expect &&
        git notes prune -n > actual &&
        test_cmp expect actual
 '
@@ -109,9 +109,9 @@ test_expect_success 'prune notes' '
 
 test_expect_success 'verify that notes are gone' '
 
-       test_must_fail git notes show 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
-       git notes show 08341ad9e94faa089d60fd3f523affb25c6da189 &&
-       git notes show ab5f302035f2e7aaf04265f08b42034c23256e1f
+       test_must_fail git notes show $third &&
+       git notes show $second &&
+       git notes show $first
 '
 
 test_expect_success 'remove some commits' '
@@ -121,21 +121,18 @@ test_expect_success 'remove some commits' '
        git gc --prune=now
 '
 
-cat > expect <<EOF
-08341ad9e94faa089d60fd3f523affb25c6da189
-EOF
-
 test_expect_success 'prune -v notes' '
 
+       echo $second >expect &&
        git notes prune -v > actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'verify that notes are gone' '
 
-       test_must_fail git notes show 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
-       test_must_fail git notes show 08341ad9e94faa089d60fd3f523affb25c6da189 &&
-       git notes show ab5f302035f2e7aaf04265f08b42034c23256e1f
+       test_must_fail git notes show $third &&
+       test_must_fail git notes show $second &&
+       git notes show $first
 '
 
 test_done
index 23469cc..ab18ac5 100755 (executable)
@@ -295,7 +295,7 @@ test_expect_success 'rebase --am and --show-current-patch' '
                echo two >>init.t &&
                git commit -a -m two &&
                git tag two &&
-               test_must_fail git rebase --onto init HEAD^ &&
+               test_must_fail git rebase -f --onto init HEAD^ &&
                GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
                grep "show.*$(git rev-parse two)" stderr
        )
index 461dd53..29a3584 100755 (executable)
@@ -29,9 +29,6 @@ Initial setup:
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
-# WARNING: Modifications to the initial repository can change the SHA ID used
-# in the expect2 file for the 'stop on conflicting pick' test.
-
 test_expect_success 'setup' '
        test_commit A file1 &&
        test_commit B file1 &&
@@ -155,8 +152,6 @@ test_expect_success 'rebase -x with empty command fails' '
        test_i18ncmp expected actual
 '
 
-LF='
-'
 test_expect_success 'rebase -x with newline in command fails' '
        test_when_finished "git rebase --abort ||:" &&
        test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
@@ -233,25 +228,28 @@ test_expect_success 'exchange two commits' '
        set_fake_editor &&
        FAKE_LINES="2 1" git rebase -i HEAD~2 &&
        test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
-       test G = $(git cat-file commit HEAD | sed -ne \$p)
+       test G = $(git cat-file commit HEAD | sed -ne \$p) &&
+       blob1=$(git rev-parse --short HEAD^:file1) &&
+       blob2=$(git rev-parse --short HEAD:file1) &&
+       commit=$(git rev-parse --short HEAD)
 '
 
 test_expect_success 'stop on conflicting pick' '
-       cat >expect <<-\EOF &&
+       cat >expect <<-EOF &&
        diff --git a/file1 b/file1
-       index f70f10e..fd79235 100644
+       index $blob1..$blob2 100644
        --- a/file1
        +++ b/file1
        @@ -1 +1 @@
        -A
        +G
        EOF
-       cat >expect2 <<-\EOF &&
+       cat >expect2 <<-EOF &&
        <<<<<<< HEAD
        D
        =======
        G
-       >>>>>>> 5d18e54... G
+       >>>>>>> $commit... G
        EOF
        git tag new-branch1 &&
        set_fake_editor &&
@@ -1003,7 +1001,7 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
        git checkout B &&
        set_fake_editor &&
        test_must_fail env FAKE_LINES="2" git rebase -i --root &&
-       git cat-file commit HEAD | grep "^tree 4b825dc642cb" &&
+       git cat-file commit HEAD | grep "^tree $EMPTY_TREE" &&
        git rebase --abort
 '
 
@@ -1058,7 +1056,7 @@ test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-int
        git reset --hard &&
        git checkout conflict-branch &&
        set_fake_editor &&
-       test_must_fail git rebase --onto HEAD~2 HEAD~ &&
+       test_must_fail git rebase -f --onto HEAD~2 HEAD~ &&
        test_must_fail git rebase --edit-todo &&
        git rebase --abort
 '
@@ -1161,7 +1159,7 @@ test_expect_success 'rebase -i error on commits with \ in message' '
        test_expect_code 1 grep  "      emp" error
 '
 
-test_expect_success 'short SHA-1 setup' '
+test_expect_success SHA1 'short SHA-1 setup' '
        test_when_finished "git checkout master" &&
        git checkout --orphan collide &&
        git rm -rf . &&
@@ -1173,7 +1171,7 @@ test_expect_success 'short SHA-1 setup' '
        )
 '
 
-test_expect_success 'short SHA-1 collide' '
+test_expect_success SHA1 'short SHA-1 collide' '
        test_when_finished "reset_rebase && git checkout master" &&
        git checkout collide &&
        (
@@ -1419,7 +1417,6 @@ test_expect_success 'editor saves as CR/LF' '
        )
 '
 
-SQ="'"
 test_expect_success 'rebase -i --gpg-sign=<key-id>' '
        test_when_finished "test_might_fail git rebase --abort" &&
        set_fake_editor &&
index ddf2f64..9c25484 100755 (executable)
@@ -99,7 +99,64 @@ test_expect_success 'rebase -i --onto master...side' '
        git checkout side &&
        git reset --hard K &&
 
+       set_fake_editor &&
        test_must_fail git rebase -i --onto master...side J
 '
 
+test_expect_success 'rebase --keep-base --onto incompatible' '
+       test_must_fail git rebase --keep-base --onto master...
+'
+
+test_expect_success 'rebase --keep-base --root incompatible' '
+       test_must_fail git rebase --keep-base --root
+'
+
+test_expect_success 'rebase --keep-base master from topic' '
+       git reset --hard &&
+       git checkout topic &&
+       git reset --hard G &&
+
+       git rebase --keep-base master &&
+       git rev-parse C >base.expect &&
+       git merge-base master HEAD >base.actual &&
+       test_cmp base.expect base.actual &&
+
+       git rev-parse HEAD~2 >actual &&
+       git rev-parse C^0 >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rebase --keep-base master from side' '
+       git reset --hard &&
+       git checkout side &&
+       git reset --hard K &&
+
+       test_must_fail git rebase --keep-base master
+'
+
+test_expect_success 'rebase -i --keep-base master from topic' '
+       git reset --hard &&
+       git checkout topic &&
+       git reset --hard G &&
+
+       set_fake_editor &&
+       EXPECT_COUNT=2 git rebase -i --keep-base master &&
+       git rev-parse C >base.expect &&
+       git merge-base master HEAD >base.actual &&
+       test_cmp base.expect base.actual &&
+
+       git rev-parse HEAD~2 >actual &&
+       git rev-parse C^0 >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rebase -i --keep-base master from side' '
+       git reset --hard &&
+       git checkout side &&
+       git reset --hard K &&
+
+       set_fake_editor &&
+       test_must_fail git rebase -i --keep-base master
+'
+
 test_done
index b8f4d03..5f7e73c 100755 (executable)
@@ -37,7 +37,6 @@ test_expect_success setup '
 create_expected_success_am () {
        cat >expected <<-EOF
        $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-       HEAD is now at $(git rev-parse --short feature-branch) third commit
        First, rewinding head to replay your work on top of it...
        Applying: second commit
        Applying: third commit
@@ -48,7 +47,6 @@ create_expected_success_am () {
 create_expected_success_interactive () {
        q_to_cr >expected <<-EOF
        $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-       HEAD is now at $(git rev-parse --short feature-branch) third commit
        Applied autostash.
        Successfully rebased and updated refs/heads/rebased-feature-branch.
        EOF
@@ -57,7 +55,6 @@ create_expected_success_interactive () {
 create_expected_failure_am () {
        cat >expected <<-EOF
        $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-       HEAD is now at $(git rev-parse --short feature-branch) third commit
        First, rewinding head to replay your work on top of it...
        Applying: second commit
        Applying: third commit
@@ -70,7 +67,6 @@ create_expected_failure_am () {
 create_expected_failure_interactive () {
        cat >expected <<-EOF
        $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-       HEAD is now at $(git rev-parse --short feature-branch) third commit
        Applying autostash resulted in conflicts.
        Your changes are safe in the stash.
        You can run "git stash pop" or "git stash drop" at any time.
@@ -306,4 +302,12 @@ test_expect_success 'branch is left alone when possible' '
        test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)"
 '
 
+test_expect_success 'never change active branch' '
+       git checkout -b not-the-feature-branch unrelated-onto-branch &&
+       test_when_finished "git reset --hard && git checkout master" &&
+       echo changed >file0 &&
+       git rebase --autostash not-the-feature-branch feature-branch &&
+       test_cmp_rev not-the-feature-branch unrelated-onto-branch
+'
+
 test_done
index 7274dca..b847064 100755 (executable)
@@ -31,6 +31,16 @@ test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase success -p
 
+test_expect_success 'setup branches and remote tracking' '
+       git tag -l >tags &&
+       for tag in $(cat tags)
+       do
+               git branch branch-$tag $tag || return 1
+       done &&
+       git remote add origin "file://$PWD" &&
+       git fetch origin
+'
+
 test_run_rebase () {
        result=$1
        shift
@@ -57,10 +67,28 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
+test_run_rebase success --fork-point
 test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase failure -p
 
+test_run_rebase () {
+       result=$1
+       shift
+       test_expect_$result "rebase $* -f rewrites even if remote upstream is an ancestor" "
+               reset_rebase &&
+               git rebase $* -f branch-b branch-e &&
+               ! test_cmp_rev branch-e origin/branch-e &&
+               test_cmp_rev branch-b HEAD~2 &&
+               test_linear_range 'd e' branch-b..
+       "
+}
+test_run_rebase success ''
+test_run_rebase success --fork-point
+test_run_rebase success -m
+test_run_rebase success -i
+test_have_prereq !REBASE_P || test_run_rebase success -p
+
 test_run_rebase () {
        result=$1
        shift
@@ -71,6 +99,7 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
+test_run_rebase success --fork-point
 test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase success -p
index fe6489f..9efcf48 100755 (executable)
@@ -37,20 +37,27 @@ test_expect_success 'setup' '
        test_commit A &&
        git checkout -b first &&
        test_commit B &&
+       b=$(git rev-parse --short HEAD) &&
        git checkout master &&
        test_commit C &&
+       c=$(git rev-parse --short HEAD) &&
        test_commit D &&
+       d=$(git rev-parse --short HEAD) &&
        git merge --no-commit B &&
        test_tick &&
        git commit -m E &&
        git tag -m E E &&
+       e=$(git rev-parse --short HEAD) &&
        git checkout -b second C &&
        test_commit F &&
+       f=$(git rev-parse --short HEAD) &&
        test_commit G &&
+       g=$(git rev-parse --short HEAD) &&
        git checkout master &&
        git merge --no-commit G &&
        test_tick &&
        git commit -m H &&
+       h=$(git rev-parse --short HEAD) &&
        git tag -m H H &&
        git checkout A &&
        test_commit conflicting-G G.t
@@ -93,24 +100,24 @@ test_expect_success 'create completely different structure' '
 '
 
 test_expect_success 'generate correct todo list' '
-       cat >expect <<-\EOF &&
+       cat >expect <<-EOF &&
        label onto
 
        reset onto
-       pick d9df450 B
+       pick $b B
        label E
 
        reset onto
-       pick 5dee784 C
+       pick $c C
        label branch-point
-       pick ca2c861 F
-       pick 088b00a G
+       pick $f F
+       pick $g G
        label H
 
        reset branch-point # C
-       pick 12bd07b D
-       merge -C 2051b56 E # E
-       merge -C 233d48a H # H
+       pick $d D
+       merge -C $e E # E
+       merge -C $h H # H
 
        EOF
 
@@ -151,7 +158,6 @@ test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' '
        test_path_is_file .git/rebase-merge/patch
 '
 
-SQ="'"
 test_expect_success 'failed `merge <branch>` does not crash' '
        test_when_finished "test_might_fail git rebase --abort" &&
        git checkout conflicting-G &&
diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh
new file mode 100755 (executable)
index 0000000..78851b9
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Denton Liu
+#
+
+test_description='git rebase --fork-point test'
+
+. ./test-lib.sh
+
+# A---B---D---E    (master)
+#      \
+#       C*---F---G (side)
+#
+# C was formerly part of master but master was rewound to remove C
+#
+test_expect_success setup '
+       test_commit A &&
+       test_commit B &&
+       test_commit C &&
+       git branch -t side &&
+       git reset --hard HEAD^ &&
+       test_commit D &&
+       test_commit E &&
+       git checkout side &&
+       test_commit F &&
+       test_commit G
+'
+
+test_rebase () {
+       expected="$1" &&
+       shift &&
+       test_expect_success "git rebase $*" "
+               git checkout master &&
+               git reset --hard E &&
+               git checkout side &&
+               git reset --hard G &&
+               git rebase $* &&
+               test_write_lines $expected >expect &&
+               git log --pretty=%s >actual &&
+               test_cmp expect actual
+       "
+}
+
+test_rebase 'G F E D B A'
+test_rebase 'G F D B A' --onto D
+test_rebase 'G F B A' --keep-base
+test_rebase 'G F C E D B A' --no-fork-point
+test_rebase 'G F C D B A' --no-fork-point --onto D
+test_rebase 'G F C B A' --no-fork-point --keep-base
+test_rebase 'G F E D B A' --fork-point refs/heads/master
+test_rebase 'G F D B A' --fork-point --onto D refs/heads/master
+test_rebase 'G F B A' --fork-point --keep-base refs/heads/master
+test_rebase 'G F C E D B A' refs/heads/master
+test_rebase 'G F C D B A' --onto D refs/heads/master
+test_rebase 'G F C B A' --keep-base refs/heads/master
+
+test_done
diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh
new file mode 100755 (executable)
index 0000000..034ffc7
--- /dev/null
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Denton Liu
+#
+
+test_description='ensure rebase fast-forwards commits when possible'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       test_commit A &&
+       test_commit B &&
+       test_commit C &&
+       test_commit D &&
+       git checkout -t -b side
+'
+
+test_rebase_same_head () {
+       status_n="$1" &&
+       shift &&
+       what_n="$1" &&
+       shift &&
+       cmp_n="$1" &&
+       shift &&
+       status_f="$1" &&
+       shift &&
+       what_f="$1" &&
+       shift &&
+       cmp_f="$1" &&
+       shift &&
+       test_rebase_same_head_ $status_n $what_n $cmp_n "" "$*" &&
+       test_rebase_same_head_ $status_f $what_f $cmp_f " --no-ff" "$*"
+}
+
+test_rebase_same_head_ () {
+       status="$1" &&
+       shift &&
+       what="$1" &&
+       shift &&
+       cmp="$1" &&
+       shift &&
+       flag="$1"
+       shift &&
+       test_expect_$status "git rebase$flag $* with $changes is $what with $cmp HEAD" "
+               oldhead=\$(git rev-parse HEAD) &&
+               test_when_finished 'git reset --hard \$oldhead' &&
+               git rebase$flag $* >stdout &&
+               if test $what = work
+               then
+                       # Must check this case first, for 'is up to
+                       # date, rebase forced[...]rewinding head' cases
+                       test_i18ngrep 'rewinding head' stdout
+               elif test $what = noop
+               then
+                       test_i18ngrep 'is up to date' stdout &&
+                       test_i18ngrep ! 'rebase forced' stdout
+               elif test $what = noop-force
+               then
+                       test_i18ngrep 'is up to date, rebase forced' stdout
+               fi &&
+               newhead=\$(git rev-parse HEAD) &&
+               if test $cmp = same
+               then
+                       test_cmp_rev \$oldhead \$newhead
+               elif test $cmp = diff
+               then
+                       ! test_cmp_rev \$oldhead \$newhead
+               fi
+       "
+}
+
+changes='no changes'
+test_rebase_same_head success noop same success work same
+test_rebase_same_head success noop same success noop-force same master
+test_rebase_same_head success noop same success noop-force diff --onto B B
+test_rebase_same_head success noop same success noop-force diff --onto B... B
+test_rebase_same_head success noop same success noop-force same --onto master... master
+test_rebase_same_head success noop same success noop-force same --keep-base master
+test_rebase_same_head success noop same success noop-force same --keep-base
+test_rebase_same_head success noop same success noop-force same --no-fork-point
+test_rebase_same_head success noop same success noop-force same --keep-base --no-fork-point
+test_rebase_same_head success noop same success work same --fork-point master
+test_rebase_same_head success noop same success work diff --fork-point --onto B B
+test_rebase_same_head success noop same success work diff --fork-point --onto B... B
+test_rebase_same_head success noop same success work same --fork-point --onto master... master
+test_rebase_same_head success noop same success work same --keep-base --keep-base master
+
+test_expect_success 'add work same to side' '
+       test_commit E
+'
+
+changes='our changes'
+test_rebase_same_head success noop same success work same
+test_rebase_same_head success noop same success noop-force same master
+test_rebase_same_head success noop same success noop-force diff --onto B B
+test_rebase_same_head success noop same success noop-force diff --onto B... B
+test_rebase_same_head success noop same success noop-force same --onto master... master
+test_rebase_same_head success noop same success noop-force same --keep-base master
+test_rebase_same_head success noop same success noop-force same --keep-base
+test_rebase_same_head success noop same success noop-force same --no-fork-point
+test_rebase_same_head success noop same success noop-force same --keep-base --no-fork-point
+test_rebase_same_head success noop same success work same --fork-point master
+test_rebase_same_head success noop same success work diff --fork-point --onto B B
+test_rebase_same_head success noop same success work diff --fork-point --onto B... B
+test_rebase_same_head success noop same success work same --fork-point --onto master... master
+test_rebase_same_head success noop same success work same --fork-point --keep-base master
+
+test_expect_success 'add work same to upstream' '
+       git checkout master &&
+       test_commit F &&
+       git checkout side
+'
+
+changes='our and their changes'
+test_rebase_same_head success noop same success noop-force diff --onto B B
+test_rebase_same_head success noop same success noop-force diff --onto B... B
+test_rebase_same_head success noop same success work diff --onto master... master
+test_rebase_same_head success noop same success work diff --keep-base master
+test_rebase_same_head success noop same success work diff --keep-base
+test_rebase_same_head failure work same success work diff --fork-point --onto B B
+test_rebase_same_head failure work same success work diff --fork-point --onto B... B
+test_rebase_same_head success noop same success work diff --fork-point --onto master... master
+test_rebase_same_head success noop same success work diff --fork-point --keep-base master
+
+test_done
index 127dd00..9d5adbc 100755 (executable)
@@ -16,7 +16,11 @@ test_expect_success setup '
        git add file1 &&
        test_tick &&
        git commit -m "second" &&
-       git tag second
+       git tag second &&
+       test_oid_cache <<-EOF
+       cp_ff sha1:1df192cd8bc58a2b275d842cede4d221ad9000d1
+       cp_ff sha256:e70d6b7fc064bddb516b8d512c9057094b96ce6ff08e12080acc4fe7f1d60a1d
+       EOF
 '
 
 test_expect_success 'cherry-pick using --ff fast forwards' '
@@ -102,7 +106,7 @@ test_expect_success 'cherry pick a root commit with --ff' '
        git add file2 &&
        git commit --amend -m "file2" &&
        git cherry-pick --ff first &&
-       test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
+       test "$(git rev-parse --verify HEAD)" = "$(test_oid cp_ff)"
 '
 
 test_expect_success 'cherry-pick --ff on unborn branch' '
index 66282a7..8c8cca5 100755 (executable)
@@ -240,12 +240,14 @@ test_expect_success 'refresh index before checking if it is up-to-date' '
 '
 
 test_expect_success 'choking "git rm" should not let it die with cruft' '
+       test_oid_init &&
        git reset -q --hard &&
        test_when_finished "rm -f .git/index.lock && git reset -q --hard" &&
        i=0 &&
+       hash=$(test_oid deadbeef) &&
        while test $i -lt 12000
        do
-               echo "100644 1234567890123456789012345678901234567890 0 some-file-$i"
+               echo "100644 $hash 0    some-file-$i"
                i=$(( $i + 1 ))
        done | git update-index --index-info &&
        git rm -n "some-file-*" | : &&
index 8eb4794..64dcc5e 100755 (executable)
@@ -23,6 +23,7 @@ check_verify_failure () {
 # first create a commit, so we have a valid object/type
 # for the tag.
 test_expect_success 'setup' '
+       test_oid_init &&
        echo Hello >A &&
        git update-index --add A &&
        git commit -m "Initial commit" &&
@@ -69,28 +70,28 @@ check_verify_failure '"object" line SHA1 check' '^error: char7: .*SHA1 hash$'
 #  4. type line label check
 
 cat >tag.sig <<EOF
-object 779e9b33986b1c2670fff52c5067603117b3e895
+object $head
 xxxx tag
 tag mytag
 tagger . <> 0 +0000
 
 EOF
 
-check_verify_failure '"type" line label check' '^error: char47: .*"\\ntype "$'
+check_verify_failure '"type" line label check' '^error: char.*: .*"\\ntype "$'
 
 ############################################################
 #  5. type line eol check
 
-echo "object 779e9b33986b1c2670fff52c5067603117b3e895" >tag.sig
+echo "object $head" >tag.sig
 printf "type tagsssssssssssssssssssssssssssssss" >>tag.sig
 
-check_verify_failure '"type" line eol check' '^error: char48: .*"\\n"$'
+check_verify_failure '"type" line eol check' '^error: char.*: .*"\\n"$'
 
 ############################################################
 #  6. tag line label check #1
 
 cat >tag.sig <<EOF
-object 779e9b33986b1c2670fff52c5067603117b3e895
+object $head
 type tag
 xxx mytag
 tagger . <> 0 +0000
@@ -98,37 +99,37 @@ tagger . <> 0 +0000
 EOF
 
 check_verify_failure '"tag" line label check #1' \
-       '^error: char57: no "tag " found$'
+       '^error: char.*: no "tag " found$'
 
 ############################################################
 #  7. tag line label check #2
 
 cat >tag.sig <<EOF
-object 779e9b33986b1c2670fff52c5067603117b3e895
+object $head
 type taggggggggggggggggggggggggggggggg
 tag
 EOF
 
 check_verify_failure '"tag" line label check #2' \
-       '^error: char87: no "tag " found$'
+       '^error: char.*: no "tag " found$'
 
 ############################################################
 #  8. type line type-name length check
 
 cat >tag.sig <<EOF
-object 779e9b33986b1c2670fff52c5067603117b3e895
+object $head
 type taggggggggggggggggggggggggggggggg
 tag mytag
 EOF
 
 check_verify_failure '"type" line type-name length check' \
-       '^error: char53: type too long$'
+       '^error: char.*: type too long$'
 
 ############################################################
 #  9. verify object (SHA1/type) check
 
 cat >tag.sig <<EOF
-object 779e9b33986b1c2670fff52c5067603117b3e895
+object $(test_oid deadbeef)
 type tagggg
 tag mytag
 tagger . <> 0 +0000
@@ -150,7 +151,7 @@ tagger . <> 0 +0000
 EOF
 
 check_verify_failure 'verify tag-name check' \
-       '^error: char67: could not verify tag name$'
+       '^error: char.*: could not verify tag name$'
 
 ############################################################
 # 11. tagger line label check #1
@@ -164,7 +165,7 @@ This is filler
 EOF
 
 check_verify_failure '"tagger" line label check #1' \
-       '^error: char70: could not find "tagger "$'
+       '^error: char.*: could not find "tagger "$'
 
 ############################################################
 # 12. tagger line label check #2
@@ -179,7 +180,7 @@ This is filler
 EOF
 
 check_verify_failure '"tagger" line label check #2' \
-       '^error: char70: could not find "tagger "$'
+       '^error: char.*: could not find "tagger "$'
 
 ############################################################
 # 13. disallow missing tag author name
@@ -194,7 +195,7 @@ This is filler
 EOF
 
 check_verify_failure 'disallow missing tag author name' \
-       '^error: char77: missing tagger name$'
+       '^error: char.*: missing tagger name$'
 
 ############################################################
 # 14. disallow missing tag author name
@@ -209,7 +210,7 @@ tagger T A Gger <
 EOF
 
 check_verify_failure 'disallow malformed tagger' \
-       '^error: char77: malformed tagger field$'
+       '^error: char.*: malformed tagger field$'
 
 ############################################################
 # 15. allow empty tag email
@@ -238,7 +239,7 @@ tagger T A Gger <tag ger@example.com> 0 +0000
 EOF
 
 check_verify_failure 'disallow spaces in tag email' \
-       '^error: char77: malformed tagger field$'
+       '^error: char.*: malformed tagger field$'
 
 ############################################################
 # 17. disallow missing tag timestamp
@@ -252,7 +253,7 @@ tagger T A Gger <tagger@example.com>__
 EOF
 
 check_verify_failure 'disallow missing tag timestamp' \
-       '^error: char107: missing tag timestamp$'
+       '^error: char.*: missing tag timestamp$'
 
 ############################################################
 # 18. detect invalid tag timestamp1
@@ -266,7 +267,7 @@ tagger T A Gger <tagger@example.com> Tue Mar 25 15:47:44 2008
 EOF
 
 check_verify_failure 'detect invalid tag timestamp1' \
-       '^error: char107: missing tag timestamp$'
+       '^error: char.*: missing tag timestamp$'
 
 ############################################################
 # 19. detect invalid tag timestamp2
@@ -280,7 +281,7 @@ tagger T A Gger <tagger@example.com> 2008-03-31T12:20:15-0500
 EOF
 
 check_verify_failure 'detect invalid tag timestamp2' \
-       '^error: char111: malformed tag timestamp$'
+       '^error: char.*: malformed tag timestamp$'
 
 ############################################################
 # 20. detect invalid tag timezone1
@@ -294,7 +295,7 @@ tagger T A Gger <tagger@example.com> 1206478233 GMT
 EOF
 
 check_verify_failure 'detect invalid tag timezone1' \
-       '^error: char118: malformed tag timezone$'
+       '^error: char.*: malformed tag timezone$'
 
 ############################################################
 # 21. detect invalid tag timezone2
@@ -308,7 +309,7 @@ tagger T A Gger <tagger@example.com> 1206478233 +  30
 EOF
 
 check_verify_failure 'detect invalid tag timezone2' \
-       '^error: char118: malformed tag timezone$'
+       '^error: char.*: malformed tag timezone$'
 
 ############################################################
 # 22. detect invalid tag timezone3
@@ -322,7 +323,7 @@ tagger T A Gger <tagger@example.com> 1206478233 -1430
 EOF
 
 check_verify_failure 'detect invalid tag timezone3' \
-       '^error: char118: malformed tag timezone$'
+       '^error: char.*: malformed tag timezone$'
 
 ############################################################
 # 23. detect invalid header entry
@@ -337,7 +338,7 @@ this line should not be here
 EOF
 
 check_verify_failure 'detect invalid header entry' \
-       '^error: char124: trailing garbage in tag header$'
+       '^error: char.*: trailing garbage in tag header$'
 
 ############################################################
 # 24. create valid tag
index b8e3378..820b350 100755 (executable)
@@ -7,6 +7,18 @@ test_description='Test git stash'
 
 . ./test-lib.sh
 
+diff_cmp () {
+       for i in "$1" "$2"
+       do
+               sed -e 's/^index 0000000\.\.[0-9a-f]*/index 0000000..1234567/' \
+               -e 's/^index [0-9a-f]*\.\.[0-9a-f]*/index 1234567..89abcde/' \
+               -e 's/^index [0-9a-f]*,[0-9a-f]*\.\.[0-9a-f]*/index 1234567,7654321..89abcde/' \
+               "$i" >"$i.compare" || return 1
+       done &&
+       test_cmp "$1.compare" "$2.compare" &&
+       rm -f "$1.compare" "$2.compare"
+}
+
 test_expect_success 'stash some dirty working directory' '
        echo 1 >file &&
        git add file &&
@@ -36,7 +48,7 @@ EOF
 test_expect_success 'parents of stash' '
        test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
        git diff stash^2..stash >output &&
-       test_cmp expect output
+       diff_cmp expect output
 '
 
 test_expect_success 'applying bogus stash does nothing' '
@@ -210,13 +222,13 @@ test_expect_success 'stash branch' '
        test refs/heads/stashbranch = $(git symbolic-ref HEAD) &&
        test $(git rev-parse HEAD) = $(git rev-parse master^) &&
        git diff --cached >output &&
-       test_cmp expect output &&
+       diff_cmp expect output &&
        git diff >output &&
-       test_cmp expect1 output &&
+       diff_cmp expect1 output &&
        git add file &&
        git commit -m alternate\ second &&
        git diff master..stashbranch >output &&
-       test_cmp output expect2 &&
+       diff_cmp output expect2 &&
        test 0 = $(git stash list | wc -l)
 '
 
@@ -577,7 +589,7 @@ test_expect_success 'stash show -p - stashes on stack, stash-like argument' '
        +bar
        EOF
        git stash show -p ${STASH_ID} >actual &&
-       test_cmp expected actual
+       diff_cmp expected actual
 '
 
 test_expect_success 'stash show - no stashes on stack, stash-like argument' '
@@ -609,7 +621,7 @@ test_expect_success 'stash show -p - no stashes on stack, stash-like argument' '
        +foo
        EOF
        git stash show -p ${STASH_ID} >actual &&
-       test_cmp expected actual
+       diff_cmp expected actual
 '
 
 test_expect_success 'stash show --patience shows diff' '
@@ -627,7 +639,7 @@ test_expect_success 'stash show --patience shows diff' '
        +foo
        EOF
        git stash show --patience ${STASH_ID} >actual &&
-       test_cmp expected actual
+       diff_cmp expected actual
 '
 
 test_expect_success 'drop: fail early if specified stash is not a stash ref' '
@@ -791,7 +803,7 @@ test_expect_success 'stash where working directory contains "HEAD" file' '
        git diff-index --cached --quiet HEAD &&
        test "$(git rev-parse stash^)" = "$(git rev-parse HEAD)" &&
        git diff stash^..stash >output &&
-       test_cmp expect output
+       diff_cmp expect output
 '
 
 test_expect_success 'store called with invalid commit' '
@@ -847,7 +859,7 @@ test_expect_success 'stash list implies --first-parent -m' '
        +working
        EOF
        git stash list --format=%gd -p >actual &&
-       test_cmp expect actual
+       diff_cmp expect actual
 '
 
 test_expect_success 'stash list --cc shows combined diff' '
@@ -864,7 +876,7 @@ test_expect_success 'stash list --cc shows combined diff' '
        ++working
        EOF
        git stash list --format=%gd -p --cc >actual &&
-       test_cmp expect actual
+       diff_cmp expect actual
 '
 
 test_expect_success 'stash is not confused by partial renames' '
index 8de36b7..e5116a7 100755 (executable)
@@ -78,7 +78,7 @@ test_expect_success 'git diff-files --no-patch --patch shows the patch' '
 
 test_expect_success 'git diff-files --no-patch --patch-with-raw shows the patch and raw data' '
        git diff-files --no-patch --patch-with-raw >actual &&
-       grep -q "^:100644 100755 .* 0000000000000000000000000000000000000000 M  path0\$" actual &&
+       grep -q "^:100644 100755 .* $ZERO_OID M path0\$" actual &&
        tail -n +4 actual >actual-patch &&
        compare_diff_patch expected actual-patch
 '
index 3a6c21e..cbcdd10 100755 (executable)
@@ -7,123 +7,272 @@ test_description='Test diff raw-output.
 
 '
 . ./test-lib.sh
+
 . "$TEST_DIRECTORY"/lib-read-tree-m-3way.sh
 
-cat >.test-plain-OA <<\EOF
-:000000 100644 0000000000000000000000000000000000000000 ccba72ad3888a3520b39efcf780b9ee64167535d A     AA
-:000000 100644 0000000000000000000000000000000000000000 7e426fb079479fd67f6d81f984e4ec649a44bc25 A     AN
-:100644 000000 bcc68ef997017466d5c9094bcf7692295f588c9a 0000000000000000000000000000000000000000 D     DD
-:000000 040000 0000000000000000000000000000000000000000 6d50f65d3bdab91c63444294d38f08aeff328e42 A     DF
-:100644 000000 141c1f1642328e4bc46a7d801a71da392e66791e 0000000000000000000000000000000000000000 D     DM
-:100644 000000 35abde1506ddf806572ff4d407bd06885d0f8ee9 0000000000000000000000000000000000000000 D     DN
-:000000 100644 0000000000000000000000000000000000000000 1d41122ebdd7a640f29d3c9cc4f9d70094374762 A     LL
-:100644 100644 03f24c8c4700babccfd28b654e7e8eac402ad6cd 103d9f89b50b9aad03054b579be5e7aa665f2d57 M     MD
-:100644 100644 b258508afb7ceb449981bd9d63d2d3e971bf8d34 b431b272d829ff3aa4d1a5085f4394ab4d3305b6 M     MM
-:100644 100644 bd084b0c27c7b6cc34f11d6d0509a29be3caf970 a716d58de4a570e0038f5c307bd8db34daea021f M     MN
-:100644 100644 40c959f984c8b89a2b02520d17f00d717f024397 2ac547ae9614a00d1b28275de608131f7a0e259f M     SS
-:100644 100644 4ac13458899ab908ef3b1128fa378daefc88d356 4c86f9a85fbc5e6804ee2e17a797538fbe785bca M     TT
-:040000 040000 7d670fdcdb9929f6c7dac196ff78689cd1c566a1 5e5f22072bb39f6e12cf663a57cb634c76eefb49 M     Z
+test_oid_init
+
+test_oid_cache <<\EOF
+aa_1 sha1:ccba72ad3888a3520b39efcf780b9ee64167535d
+aa_1 sha256:9febfbf18197819b2735c45291f138525d2476d59470f98239647544586ba403
+
+aa_2 sha1:6aa2b5335b16431a0ef71e5c0a28be69183cf6a2
+aa_2 sha256:6eaa3437de83f145a4aaa6ba355303075ade547b128ec6a2cd00a81ff7ce7a56
+
+an_1 sha1:7e426fb079479fd67f6d81f984e4ec649a44bc25
+an_1 sha256:8f92a0bec99e399a38e3bd0e1bf19fbf121e0160efb29b857df79d439f1c4536
+
+dd_1 sha1:bcc68ef997017466d5c9094bcf7692295f588c9a
+dd_1 sha256:07e17428b00639b85485d2b01083d219e2f3e3ba8579e9ca44e9cc8dd554d952
+
+df_1 sha1:6d50f65d3bdab91c63444294d38f08aeff328e42
+df_1 sha256:e367cecc27e9bf5451b1c65828cb21938d36a5f8e39c1b03ad6509cc36bb8e9d
+
+df_2 sha1:71420ab81e254145d26d6fc0cddee64c1acd4787
+df_2 sha256:0f0a86d10347ff6921d03a3c954679f3f1d14fa3d5cd82f57b32c09755f3a47d
+
+dfd1 sha1:68a6d8b91da11045cf4aa3a5ab9f2a781c701249
+dfd1 sha256:f3bd3265b02b6978ce86490d8ad026c573639c974b3de1d9faf30d8d5a77d3d5
+
+dm_1 sha1:141c1f1642328e4bc46a7d801a71da392e66791e
+dm_1 sha256:c89f8656e7b94e21ee5fbaf0e2149bbf783c51edbe2ce110349cac13059ee7ed
+
+dm_2 sha1:3c4d8de5fbad08572bab8e10eef8dbb264cf0231
+dm_2 sha256:83a572e37e0c94086294dae2cecc43d9131afd6f6c906e495c78972230b54988
+
+dn_1 sha1:35abde1506ddf806572ff4d407bd06885d0f8ee9
+dn_1 sha256:775d5852582070e620be63327bfa515fab8f71c7ac3e4f0c3cd6267b4377ba28
+
+ll_2 sha1:1d41122ebdd7a640f29d3c9cc4f9d70094374762
+ll_2 sha256:7917b4948a883cfed0a77d3d5a625dc8577d6ddcc3c6c3bbc56c4d4226a2246d
+
+md_1 sha1:03f24c8c4700babccfd28b654e7e8eac402ad6cd
+md_1 sha256:fc9f30369b978595ad685ba11ca9a17de0af16d79cd4b629975f4f1590033902
+
+md_2 sha1:103d9f89b50b9aad03054b579be5e7aa665f2d57
+md_2 sha256:fc78ec75275628762fe520479a6b2398dec295ce7aabcb1d15e5963c7b4e9317
+
+mm_1 sha1:b258508afb7ceb449981bd9d63d2d3e971bf8d34
+mm_1 sha256:a4b7847d228e900e3000285e240c20fd96f9dd41ce1445305f6eada126d4a04a
+
+mm_2 sha1:b431b272d829ff3aa4d1a5085f4394ab4d3305b6
+mm_2 sha256:3f8b83ea36aacf689bcf1a1290a9a8ed341564d32682ea6f76fea9a979186782
+
+mm_3 sha1:19989d4559aae417fedee240ccf2ba315ea4dc2b
+mm_3 sha256:71b3bfc5747ac033fff9ea0ab39ee453a3af2969890e75d6ef547b87544e2681
+
+mn_1 sha1:bd084b0c27c7b6cc34f11d6d0509a29be3caf970
+mn_1 sha256:47a67450583d7a329eb01a7c4ba644945af72c0ed2c7c95eb5a00d6e46d4d483
+
+mn_2 sha1:a716d58de4a570e0038f5c307bd8db34daea021f
+mn_2 sha256:f95104c1ebe27acb84bac25a7be98c71f6b8d3054b21f357a5be0c524ad97e08
+
+nm_1 sha1:c8f25781e8f1792e3e40b74225e20553041b5226
+nm_1 sha256:09baddc7afaa62e62e152c23c9c3ab94bf15a3894031e227e9be7fe68e1f4e49
+
+nm_2 sha1:cdb9a8c3da571502ac30225e9c17beccb8387983
+nm_2 sha256:58b5227956ac2d2a08d0efa513c0ae37430948b16791ea3869a1308dbf05536d
+
+na_1 sha1:15885881ea69115351c09b38371f0348a3fb8c67
+na_1 sha256:18e4fdd1670cd7968ee23d35bfd29e5418d56fb190c840094c1c57ceee0aad8f
+
+nd_1 sha1:a4e179e4291e5536a5e1c82e091052772d2c5a93
+nd_1 sha256:07dac9b01d00956ea0c65bd993d7de4864aeef2ed3cbb1255d9f1d949fcd6df6
+
+ss_1 sha1:40c959f984c8b89a2b02520d17f00d717f024397
+ss_1 sha256:50fc1b5df74d9910db2f9270993484235f15b69b75b01bcfb53e059289d14af9
+
+ss_2 sha1:2ac547ae9614a00d1b28275de608131f7a0e259f
+ss_2 sha256:a90f02e6044f1497d13db587d22ab12f90150a7d1e084afcf96065fab35ae2bc
+
+tt_1 sha1:4ac13458899ab908ef3b1128fa378daefc88d356
+tt_1 sha256:c53113c7dd5060e86b5b251428bd058f6726f66273c6a24bff1c61a04f498dd3
+
+tt_2 sha1:4c86f9a85fbc5e6804ee2e17a797538fbe785bca
+tt_2 sha256:0775f2a296129a7cf2862b46bc0e88c14d593f2773a3e3fb1c5193db6f5a7e77
+
+tt_3 sha1:c4e4a12231b9fa79a0053cb6077fcb21bb5b135a
+tt_3 sha256:47860f93cdd211f96443e0560f21c57ab6c2f4b0ac27ff03651a352e53fe8484
+
+z__1 sha1:7d670fdcdb9929f6c7dac196ff78689cd1c566a1
+z__1 sha256:44d0f37aff5e51cfcfdd1134c93a6419bcca7b9964f792ffcd5f9b4fcba1ee63
+
+z__2 sha1:5e5f22072bb39f6e12cf663a57cb634c76eefb49
+z__2 sha256:d29de162113190fed104eb5f010820cef4e315f89b9326e8497f7219fb737894
+
+z__3 sha1:1ba523955d5160681af65cb776411f574c1e8155
+z__3 sha256:07422d772b07794ab4369a5648e617719f89c2d2212cbeab05d97214b6471636
+
+zaa1 sha1:8acb8e9750e3f644bf323fcf3d338849db106c77
+zaa1 sha256:e79b029282c8abec2d9f3f7faceaf2a1405e02d1f368e66450ae66cf5b68d1f4
+
+zaa2 sha1:6c0b99286d0bce551ac4a7b3dff8b706edff3715
+zaa2 sha256:c82bd78c3e69ea1796e6b1a7a3ba45bb106c50e819296475b862123d3f5cc5a0
+
+zan1 sha1:087494262084cefee7ed484d20c8dc0580791272
+zan1 sha256:4b159eb3804d05599023dd074f771d06d02870f4ab24a7165add8ac3d703b8d3
+
+zdd1 sha1:879007efae624d2b1307214b24a956f0a8d686a8
+zdd1 sha256:eecfdd4d8092dd0363fb6d4548b54c6afc8982c3ed9b34e393f1d6a921d8eaa3
+
+zdm1 sha1:9b541b2275c06e3a7b13f28badf5294e2ae63df4
+zdm1 sha256:ab136e88e19a843c4bf7713d2090d5a2186ba16a6a80dacc12eeddd256a8e556
+
+zdm2 sha1:d77371d15817fcaa57eeec27f770c505ba974ec1
+zdm2 sha256:1c1a5f57363f46a15d95ce8527b3c2c158d88d16853b4acbf81bd20fd2c89a46
+
+zdn1 sha1:beb5d38c55283d280685ea21a0e50cfcc0ca064a
+zdn1 sha256:0f0eca66183617b0aa5ad74b256540329f841470922ca6760263c996d825eb18
+
+zmd1 sha1:d41fda41b7ec4de46b43cb7ea42a45001ae393d5
+zmd1 sha256:1ed32d481852eddf31a0ce12652a0ad14bf5b7a842667b5dbb0b50f35bf1c80a
+
+zmd2 sha1:a79ac3be9377639e1c7d1edf1ae1b3a5f0ccd8a9
+zmd2 sha256:b238da211b404f8917df2d9c6f7030535e904b2186131007a3c292ec6902f933
+
+zmm1 sha1:4ca22bae2527d3d9e1676498a0fba3b355bd1278
+zmm1 sha256:072b1d85b5f34fabc99dfa46008c5418df68302d3e317430006f49b32d244226
+
+zmm2 sha1:61422ba9c2c873416061a88cd40a59a35b576474
+zmm2 sha256:81dd5d2b3c5cda16fef552256aed4e2ea0802a8450a08f308a92142112ff6dda
+
+zmm3 sha1:697aad7715a1e7306ca76290a3dd4208fbaeddfa
+zmm3 sha256:8b10fab49e9be3414aa5e9a93d0e46f9569053440138a7c19a5eb5536d8e95bf
+
+zmn1 sha1:b16d7b25b869f2beb124efa53467d8a1550ad694
+zmn1 sha256:609e4f75d1295e844c826feeba213acb0b6cfc609adfe8ff705b19e3829ae3e9
+
+zmn2 sha1:a5c544c21cfcb07eb80a4d89a5b7d1570002edfd
+zmn2 sha256:d6d03edf2dc1a3b267a8205de5f41a2ff4b03def8c7ae02052b543fb09d589fc
+
+zna1 sha1:d12979c22fff69c59ca9409e7a8fe3ee25eaee80
+zna1 sha256:b37b80e789e8ea32aa323f004628f02013f632124b0282c7fe00a127d3c64c3c
+
+znd1 sha1:a18393c636b98e9bd7296b8b437ea4992b72440c
+znd1 sha256:af92a22eee8c38410a0c9d2b5135a10aeb052cbc7cf675541ed9a67bfcaf7cf9
+
+znm1 sha1:3fdbe17fd013303a2e981e1ca1c6cd6e72789087
+znm1 sha256:f75aeaa0c11e76918e381c105f0752932c6150e941fec565d24fa31098a13dc1
+
+znm2 sha1:7e09d6a3a14bd630913e8c75693cea32157b606d
+znm2 sha256:938d73cfbaa1c902a84fb5b3afd9736aa0590367fb9bd59c6c4d072ce70fcd6d
+EOF
+
+cat >.test-plain-OA <<EOF
+:000000 100644 $(test_oid zero) $(test_oid aa_1) A     AA
+:000000 100644 $(test_oid zero) $(test_oid an_1) A     AN
+:100644 000000 $(test_oid dd_1) $(test_oid zero) D     DD
+:000000 040000 $(test_oid zero) $(test_oid df_1) A     DF
+:100644 000000 $(test_oid dm_1) $(test_oid zero) D     DM
+:100644 000000 $(test_oid dn_1) $(test_oid zero) D     DN
+:000000 100644 $(test_oid zero) $(test_oid ll_2) A     LL
+:100644 100644 $(test_oid md_1) $(test_oid md_2) M     MD
+:100644 100644 $(test_oid mm_1) $(test_oid mm_2) M     MM
+:100644 100644 $(test_oid mn_1) $(test_oid mn_2) M     MN
+:100644 100644 $(test_oid ss_1) $(test_oid ss_2) M     SS
+:100644 100644 $(test_oid tt_1) $(test_oid tt_2) M     TT
+:040000 040000 $(test_oid z__1) $(test_oid z__2) M     Z
 EOF
 
-cat >.test-recursive-OA <<\EOF
-:000000 100644 0000000000000000000000000000000000000000 ccba72ad3888a3520b39efcf780b9ee64167535d A     AA
-:000000 100644 0000000000000000000000000000000000000000 7e426fb079479fd67f6d81f984e4ec649a44bc25 A     AN
-:100644 000000 bcc68ef997017466d5c9094bcf7692295f588c9a 0000000000000000000000000000000000000000 D     DD
-:000000 100644 0000000000000000000000000000000000000000 68a6d8b91da11045cf4aa3a5ab9f2a781c701249 A     DF/DF
-:100644 000000 141c1f1642328e4bc46a7d801a71da392e66791e 0000000000000000000000000000000000000000 D     DM
-:100644 000000 35abde1506ddf806572ff4d407bd06885d0f8ee9 0000000000000000000000000000000000000000 D     DN
-:000000 100644 0000000000000000000000000000000000000000 1d41122ebdd7a640f29d3c9cc4f9d70094374762 A     LL
-:100644 100644 03f24c8c4700babccfd28b654e7e8eac402ad6cd 103d9f89b50b9aad03054b579be5e7aa665f2d57 M     MD
-:100644 100644 b258508afb7ceb449981bd9d63d2d3e971bf8d34 b431b272d829ff3aa4d1a5085f4394ab4d3305b6 M     MM
-:100644 100644 bd084b0c27c7b6cc34f11d6d0509a29be3caf970 a716d58de4a570e0038f5c307bd8db34daea021f M     MN
-:100644 100644 40c959f984c8b89a2b02520d17f00d717f024397 2ac547ae9614a00d1b28275de608131f7a0e259f M     SS
-:100644 100644 4ac13458899ab908ef3b1128fa378daefc88d356 4c86f9a85fbc5e6804ee2e17a797538fbe785bca M     TT
-:000000 100644 0000000000000000000000000000000000000000 8acb8e9750e3f644bf323fcf3d338849db106c77 A     Z/AA
-:000000 100644 0000000000000000000000000000000000000000 087494262084cefee7ed484d20c8dc0580791272 A     Z/AN
-:100644 000000 879007efae624d2b1307214b24a956f0a8d686a8 0000000000000000000000000000000000000000 D     Z/DD
-:100644 000000 9b541b2275c06e3a7b13f28badf5294e2ae63df4 0000000000000000000000000000000000000000 D     Z/DM
-:100644 000000 beb5d38c55283d280685ea21a0e50cfcc0ca064a 0000000000000000000000000000000000000000 D     Z/DN
-:100644 100644 d41fda41b7ec4de46b43cb7ea42a45001ae393d5 a79ac3be9377639e1c7d1edf1ae1b3a5f0ccd8a9 M     Z/MD
-:100644 100644 4ca22bae2527d3d9e1676498a0fba3b355bd1278 61422ba9c2c873416061a88cd40a59a35b576474 M     Z/MM
-:100644 100644 b16d7b25b869f2beb124efa53467d8a1550ad694 a5c544c21cfcb07eb80a4d89a5b7d1570002edfd M     Z/MN
+cat >.test-recursive-OA <<EOF
+:000000 100644 $(test_oid zero) $(test_oid aa_1) A     AA
+:000000 100644 $(test_oid zero) $(test_oid an_1) A     AN
+:100644 000000 $(test_oid dd_1) $(test_oid zero) D     DD
+:000000 100644 $(test_oid zero) $(test_oid dfd1) A     DF/DF
+:100644 000000 $(test_oid dm_1) $(test_oid zero) D     DM
+:100644 000000 $(test_oid dn_1) $(test_oid zero) D     DN
+:000000 100644 $(test_oid zero) $(test_oid ll_2) A     LL
+:100644 100644 $(test_oid md_1) $(test_oid md_2) M     MD
+:100644 100644 $(test_oid mm_1) $(test_oid mm_2) M     MM
+:100644 100644 $(test_oid mn_1) $(test_oid mn_2) M     MN
+:100644 100644 $(test_oid ss_1) $(test_oid ss_2) M     SS
+:100644 100644 $(test_oid tt_1) $(test_oid tt_2) M     TT
+:000000 100644 $(test_oid zero) $(test_oid zaa1) A     Z/AA
+:000000 100644 $(test_oid zero) $(test_oid zan1) A     Z/AN
+:100644 000000 $(test_oid zdd1) $(test_oid zero) D     Z/DD
+:100644 000000 $(test_oid zdm1) $(test_oid zero) D     Z/DM
+:100644 000000 $(test_oid zdn1) $(test_oid zero) D     Z/DN
+:100644 100644 $(test_oid zmd1) $(test_oid zmd2) M     Z/MD
+:100644 100644 $(test_oid zmm1) $(test_oid zmm2) M     Z/MM
+:100644 100644 $(test_oid zmn1) $(test_oid zmn2) M     Z/MN
 EOF
-cat >.test-plain-OB <<\EOF
-:000000 100644 0000000000000000000000000000000000000000 6aa2b5335b16431a0ef71e5c0a28be69183cf6a2 A     AA
-:100644 000000 bcc68ef997017466d5c9094bcf7692295f588c9a 0000000000000000000000000000000000000000 D     DD
-:000000 100644 0000000000000000000000000000000000000000 71420ab81e254145d26d6fc0cddee64c1acd4787 A     DF
-:100644 100644 141c1f1642328e4bc46a7d801a71da392e66791e 3c4d8de5fbad08572bab8e10eef8dbb264cf0231 M     DM
-:000000 100644 0000000000000000000000000000000000000000 1d41122ebdd7a640f29d3c9cc4f9d70094374762 A     LL
-:100644 000000 03f24c8c4700babccfd28b654e7e8eac402ad6cd 0000000000000000000000000000000000000000 D     MD
-:100644 100644 b258508afb7ceb449981bd9d63d2d3e971bf8d34 19989d4559aae417fedee240ccf2ba315ea4dc2b M     MM
-:000000 100644 0000000000000000000000000000000000000000 15885881ea69115351c09b38371f0348a3fb8c67 A     NA
-:100644 000000 a4e179e4291e5536a5e1c82e091052772d2c5a93 0000000000000000000000000000000000000000 D     ND
-:100644 100644 c8f25781e8f1792e3e40b74225e20553041b5226 cdb9a8c3da571502ac30225e9c17beccb8387983 M     NM
-:100644 100644 40c959f984c8b89a2b02520d17f00d717f024397 2ac547ae9614a00d1b28275de608131f7a0e259f M     SS
-:100644 100644 4ac13458899ab908ef3b1128fa378daefc88d356 c4e4a12231b9fa79a0053cb6077fcb21bb5b135a M     TT
-:040000 040000 7d670fdcdb9929f6c7dac196ff78689cd1c566a1 1ba523955d5160681af65cb776411f574c1e8155 M     Z
+cat >.test-plain-OB <<EOF
+:000000 100644 $(test_oid zero) $(test_oid aa_2) A     AA
+:100644 000000 $(test_oid dd_1) $(test_oid zero) D     DD
+:000000 100644 $(test_oid zero) $(test_oid df_2) A     DF
+:100644 100644 $(test_oid dm_1) $(test_oid dm_2) M     DM
+:000000 100644 $(test_oid zero) $(test_oid ll_2) A     LL
+:100644 000000 $(test_oid md_1) $(test_oid zero) D     MD
+:100644 100644 $(test_oid mm_1) $(test_oid mm_3) M     MM
+:000000 100644 $(test_oid zero) $(test_oid na_1) A     NA
+:100644 000000 $(test_oid nd_1) $(test_oid zero) D     ND
+:100644 100644 $(test_oid nm_1) $(test_oid nm_2) M     NM
+:100644 100644 $(test_oid ss_1) $(test_oid ss_2) M     SS
+:100644 100644 $(test_oid tt_1) $(test_oid tt_3) M     TT
+:040000 040000 $(test_oid z__1) $(test_oid z__3) M     Z
 EOF
-cat >.test-recursive-OB <<\EOF
-:000000 100644 0000000000000000000000000000000000000000 6aa2b5335b16431a0ef71e5c0a28be69183cf6a2 A     AA
-:100644 000000 bcc68ef997017466d5c9094bcf7692295f588c9a 0000000000000000000000000000000000000000 D     DD
-:000000 100644 0000000000000000000000000000000000000000 71420ab81e254145d26d6fc0cddee64c1acd4787 A     DF
-:100644 100644 141c1f1642328e4bc46a7d801a71da392e66791e 3c4d8de5fbad08572bab8e10eef8dbb264cf0231 M     DM
-:000000 100644 0000000000000000000000000000000000000000 1d41122ebdd7a640f29d3c9cc4f9d70094374762 A     LL
-:100644 000000 03f24c8c4700babccfd28b654e7e8eac402ad6cd 0000000000000000000000000000000000000000 D     MD
-:100644 100644 b258508afb7ceb449981bd9d63d2d3e971bf8d34 19989d4559aae417fedee240ccf2ba315ea4dc2b M     MM
-:000000 100644 0000000000000000000000000000000000000000 15885881ea69115351c09b38371f0348a3fb8c67 A     NA
-:100644 000000 a4e179e4291e5536a5e1c82e091052772d2c5a93 0000000000000000000000000000000000000000 D     ND
-:100644 100644 c8f25781e8f1792e3e40b74225e20553041b5226 cdb9a8c3da571502ac30225e9c17beccb8387983 M     NM
-:100644 100644 40c959f984c8b89a2b02520d17f00d717f024397 2ac547ae9614a00d1b28275de608131f7a0e259f M     SS
-:100644 100644 4ac13458899ab908ef3b1128fa378daefc88d356 c4e4a12231b9fa79a0053cb6077fcb21bb5b135a M     TT
-:000000 100644 0000000000000000000000000000000000000000 6c0b99286d0bce551ac4a7b3dff8b706edff3715 A     Z/AA
-:100644 000000 879007efae624d2b1307214b24a956f0a8d686a8 0000000000000000000000000000000000000000 D     Z/DD
-:100644 100644 9b541b2275c06e3a7b13f28badf5294e2ae63df4 d77371d15817fcaa57eeec27f770c505ba974ec1 M     Z/DM
-:100644 000000 d41fda41b7ec4de46b43cb7ea42a45001ae393d5 0000000000000000000000000000000000000000 D     Z/MD
-:100644 100644 4ca22bae2527d3d9e1676498a0fba3b355bd1278 697aad7715a1e7306ca76290a3dd4208fbaeddfa M     Z/MM
-:000000 100644 0000000000000000000000000000000000000000 d12979c22fff69c59ca9409e7a8fe3ee25eaee80 A     Z/NA
-:100644 000000 a18393c636b98e9bd7296b8b437ea4992b72440c 0000000000000000000000000000000000000000 D     Z/ND
-:100644 100644 3fdbe17fd013303a2e981e1ca1c6cd6e72789087 7e09d6a3a14bd630913e8c75693cea32157b606d M     Z/NM
+cat >.test-recursive-OB <<EOF
+:000000 100644 $(test_oid zero) $(test_oid aa_2) A     AA
+:100644 000000 $(test_oid dd_1) $(test_oid zero) D     DD
+:000000 100644 $(test_oid zero) $(test_oid df_2) A     DF
+:100644 100644 $(test_oid dm_1) $(test_oid dm_2) M     DM
+:000000 100644 $(test_oid zero) $(test_oid ll_2) A     LL
+:100644 000000 $(test_oid md_1) $(test_oid zero) D     MD
+:100644 100644 $(test_oid mm_1) $(test_oid mm_3) M     MM
+:000000 100644 $(test_oid zero) $(test_oid na_1) A     NA
+:100644 000000 $(test_oid nd_1) $(test_oid zero) D     ND
+:100644 100644 $(test_oid nm_1) $(test_oid nm_2) M     NM
+:100644 100644 $(test_oid ss_1) $(test_oid ss_2) M     SS
+:100644 100644 $(test_oid tt_1) $(test_oid tt_3) M     TT
+:000000 100644 $(test_oid zero) $(test_oid zaa2) A     Z/AA
+:100644 000000 $(test_oid zdd1) $(test_oid zero) D     Z/DD
+:100644 100644 $(test_oid zdm1) $(test_oid zdm2) M     Z/DM
+:100644 000000 $(test_oid zmd1) $(test_oid zero) D     Z/MD
+:100644 100644 $(test_oid zmm1) $(test_oid zmm3) M     Z/MM
+:000000 100644 $(test_oid zero) $(test_oid zna1) A     Z/NA
+:100644 000000 $(test_oid znd1) $(test_oid zero) D     Z/ND
+:100644 100644 $(test_oid znm1) $(test_oid znm2) M     Z/NM
 EOF
-cat >.test-plain-AB <<\EOF
-:100644 100644 ccba72ad3888a3520b39efcf780b9ee64167535d 6aa2b5335b16431a0ef71e5c0a28be69183cf6a2 M     AA
-:100644 000000 7e426fb079479fd67f6d81f984e4ec649a44bc25 0000000000000000000000000000000000000000 D     AN
-:000000 100644 0000000000000000000000000000000000000000 71420ab81e254145d26d6fc0cddee64c1acd4787 A     DF
-:040000 000000 6d50f65d3bdab91c63444294d38f08aeff328e42 0000000000000000000000000000000000000000 D     DF
-:000000 100644 0000000000000000000000000000000000000000 3c4d8de5fbad08572bab8e10eef8dbb264cf0231 A     DM
-:000000 100644 0000000000000000000000000000000000000000 35abde1506ddf806572ff4d407bd06885d0f8ee9 A     DN
-:100644 000000 103d9f89b50b9aad03054b579be5e7aa665f2d57 0000000000000000000000000000000000000000 D     MD
-:100644 100644 b431b272d829ff3aa4d1a5085f4394ab4d3305b6 19989d4559aae417fedee240ccf2ba315ea4dc2b M     MM
-:100644 100644 a716d58de4a570e0038f5c307bd8db34daea021f bd084b0c27c7b6cc34f11d6d0509a29be3caf970 M     MN
-:000000 100644 0000000000000000000000000000000000000000 15885881ea69115351c09b38371f0348a3fb8c67 A     NA
-:100644 000000 a4e179e4291e5536a5e1c82e091052772d2c5a93 0000000000000000000000000000000000000000 D     ND
-:100644 100644 c8f25781e8f1792e3e40b74225e20553041b5226 cdb9a8c3da571502ac30225e9c17beccb8387983 M     NM
-:100644 100644 4c86f9a85fbc5e6804ee2e17a797538fbe785bca c4e4a12231b9fa79a0053cb6077fcb21bb5b135a M     TT
-:040000 040000 5e5f22072bb39f6e12cf663a57cb634c76eefb49 1ba523955d5160681af65cb776411f574c1e8155 M     Z
+cat >.test-plain-AB <<EOF
+:100644 100644 $(test_oid aa_1) $(test_oid aa_2) M     AA
+:100644 000000 $(test_oid an_1) $(test_oid zero) D     AN
+:000000 100644 $(test_oid zero) $(test_oid df_2) A     DF
+:040000 000000 $(test_oid df_1) $(test_oid zero) D     DF
+:000000 100644 $(test_oid zero) $(test_oid dm_2) A     DM
+:000000 100644 $(test_oid zero) $(test_oid dn_1) A     DN
+:100644 000000 $(test_oid md_2) $(test_oid zero) D     MD
+:100644 100644 $(test_oid mm_2) $(test_oid mm_3) M     MM
+:100644 100644 $(test_oid mn_2) $(test_oid mn_1) M     MN
+:000000 100644 $(test_oid zero) $(test_oid na_1) A     NA
+:100644 000000 $(test_oid nd_1) $(test_oid zero) D     ND
+:100644 100644 $(test_oid nm_1) $(test_oid nm_2) M     NM
+:100644 100644 $(test_oid tt_2) $(test_oid tt_3) M     TT
+:040000 040000 $(test_oid z__2) $(test_oid z__3) M     Z
 EOF
-cat >.test-recursive-AB <<\EOF
-:100644 100644 ccba72ad3888a3520b39efcf780b9ee64167535d 6aa2b5335b16431a0ef71e5c0a28be69183cf6a2 M     AA
-:100644 000000 7e426fb079479fd67f6d81f984e4ec649a44bc25 0000000000000000000000000000000000000000 D     AN
-:000000 100644 0000000000000000000000000000000000000000 71420ab81e254145d26d6fc0cddee64c1acd4787 A     DF
-:100644 000000 68a6d8b91da11045cf4aa3a5ab9f2a781c701249 0000000000000000000000000000000000000000 D     DF/DF
-:000000 100644 0000000000000000000000000000000000000000 3c4d8de5fbad08572bab8e10eef8dbb264cf0231 A     DM
-:000000 100644 0000000000000000000000000000000000000000 35abde1506ddf806572ff4d407bd06885d0f8ee9 A     DN
-:100644 000000 103d9f89b50b9aad03054b579be5e7aa665f2d57 0000000000000000000000000000000000000000 D     MD
-:100644 100644 b431b272d829ff3aa4d1a5085f4394ab4d3305b6 19989d4559aae417fedee240ccf2ba315ea4dc2b M     MM
-:100644 100644 a716d58de4a570e0038f5c307bd8db34daea021f bd084b0c27c7b6cc34f11d6d0509a29be3caf970 M     MN
-:000000 100644 0000000000000000000000000000000000000000 15885881ea69115351c09b38371f0348a3fb8c67 A     NA
-:100644 000000 a4e179e4291e5536a5e1c82e091052772d2c5a93 0000000000000000000000000000000000000000 D     ND
-:100644 100644 c8f25781e8f1792e3e40b74225e20553041b5226 cdb9a8c3da571502ac30225e9c17beccb8387983 M     NM
-:100644 100644 4c86f9a85fbc5e6804ee2e17a797538fbe785bca c4e4a12231b9fa79a0053cb6077fcb21bb5b135a M     TT
-:100644 100644 8acb8e9750e3f644bf323fcf3d338849db106c77 6c0b99286d0bce551ac4a7b3dff8b706edff3715 M     Z/AA
-:100644 000000 087494262084cefee7ed484d20c8dc0580791272 0000000000000000000000000000000000000000 D     Z/AN
-:000000 100644 0000000000000000000000000000000000000000 d77371d15817fcaa57eeec27f770c505ba974ec1 A     Z/DM
-:000000 100644 0000000000000000000000000000000000000000 beb5d38c55283d280685ea21a0e50cfcc0ca064a A     Z/DN
-:100644 000000 a79ac3be9377639e1c7d1edf1ae1b3a5f0ccd8a9 0000000000000000000000000000000000000000 D     Z/MD
-:100644 100644 61422ba9c2c873416061a88cd40a59a35b576474 697aad7715a1e7306ca76290a3dd4208fbaeddfa M     Z/MM
-:100644 100644 a5c544c21cfcb07eb80a4d89a5b7d1570002edfd b16d7b25b869f2beb124efa53467d8a1550ad694 M     Z/MN
-:000000 100644 0000000000000000000000000000000000000000 d12979c22fff69c59ca9409e7a8fe3ee25eaee80 A     Z/NA
-:100644 000000 a18393c636b98e9bd7296b8b437ea4992b72440c 0000000000000000000000000000000000000000 D     Z/ND
-:100644 100644 3fdbe17fd013303a2e981e1ca1c6cd6e72789087 7e09d6a3a14bd630913e8c75693cea32157b606d M     Z/NM
+cat >.test-recursive-AB <<EOF
+:100644 100644 $(test_oid aa_1) $(test_oid aa_2) M     AA
+:100644 000000 $(test_oid an_1) $(test_oid zero) D     AN
+:000000 100644 $(test_oid zero) $(test_oid df_2) A     DF
+:100644 000000 $(test_oid dfd1) $(test_oid zero) D     DF/DF
+:000000 100644 $(test_oid zero) $(test_oid dm_2) A     DM
+:000000 100644 $(test_oid zero) $(test_oid dn_1) A     DN
+:100644 000000 $(test_oid md_2) $(test_oid zero) D     MD
+:100644 100644 $(test_oid mm_2) $(test_oid mm_3) M     MM
+:100644 100644 $(test_oid mn_2) $(test_oid mn_1) M     MN
+:000000 100644 $(test_oid zero) $(test_oid na_1) A     NA
+:100644 000000 $(test_oid nd_1) $(test_oid zero) D     ND
+:100644 100644 $(test_oid nm_1) $(test_oid nm_2) M     NM
+:100644 100644 $(test_oid tt_2) $(test_oid tt_3) M     TT
+:100644 100644 $(test_oid zaa1) $(test_oid zaa2) M     Z/AA
+:100644 000000 $(test_oid zan1) $(test_oid zero) D     Z/AN
+:000000 100644 $(test_oid zero) $(test_oid zdm2) A     Z/DM
+:000000 100644 $(test_oid zero) $(test_oid zdn1) A     Z/DN
+:100644 000000 $(test_oid zmd2) $(test_oid zero) D     Z/MD
+:100644 100644 $(test_oid zmm2) $(test_oid zmm3) M     Z/MM
+:100644 100644 $(test_oid zmn2) $(test_oid zmn1) M     Z/MN
+:000000 100644 $(test_oid zero) $(test_oid zna1) A     Z/NA
+:100644 000000 $(test_oid znd1) $(test_oid zero) D     Z/ND
+:100644 100644 $(test_oid znm1) $(test_oid znm2) M     Z/NM
 EOF
 
 cmp_diff_files_output () {
index 3641fd8..b63bdf0 100755 (executable)
@@ -14,6 +14,7 @@ test_expect_success \
     'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
+    orig=$(git hash-object COPYING) &&
     tree=$(git write-tree) &&
     echo $tree'
 
@@ -22,6 +23,8 @@ test_expect_success \
     'sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
     sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
     rm -f COPYING &&
+    c1=$(git hash-object COPYING.1) &&
+    c2=$(git hash-object COPYING.2) &&
     git update-index --add --remove COPYING COPYING.?'
 
 # tree has COPYING and rezrov.  work tree has COPYING.1 and COPYING.2,
@@ -31,11 +34,11 @@ test_expect_success \
 
 git diff-index -z -C $tree >current
 
-cat >expected <<\EOF
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
+cat >expected <<EOF
+:100644 100644 $orig $c1 C1234
 COPYING
 COPYING.1
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 06c67961bbaed34a127f76d261f4c0bf73eda471 R1234
+:100644 100644 $orig $c2 R1234
 COPYING
 COPYING.2
 EOF
@@ -57,10 +60,10 @@ test_expect_success \
 # about rezrov.
 
 git diff-index -z -C $tree >current
-cat >expected <<\EOF
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 06c67961bbaed34a127f76d261f4c0bf73eda471 M
+cat >expected <<EOF
+:100644 100644 $orig $c2 M
 COPYING
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
+:100644 100644 $orig $c1 C1234
 COPYING
 COPYING.1
 EOF
@@ -82,8 +85,8 @@ test_expect_success \
      git update-index --add --remove COPYING COPYING.1'
 
 git diff-index -z -C --find-copies-harder $tree >current
-cat >expected <<\EOF
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
+cat >expected <<EOF
+:100644 100644 $orig $c1 C1234
 COPYING
 COPYING.1
 EOF
index a9054d2..5ac94b3 100755 (executable)
@@ -7,9 +7,6 @@ test_description='Various diff formatting options'
 
 . ./test-lib.sh
 
-LF='
-'
-
 test_expect_success setup '
 
        GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" &&
index ca7debf..83f5261 100755 (executable)
@@ -9,7 +9,6 @@ test_description='various format-patch tests'
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
 test_expect_success setup '
-
        for i in 1 2 3 4 5 6 7 8 9 10; do echo "$i"; done >file &&
        cat file >elif &&
        git add file elif &&
@@ -34,7 +33,8 @@ test_expect_success setup '
        git commit -m "Side changes #3 with \\n backslash-n in it." &&
 
        git checkout master &&
-       git diff-tree -p C2 | git apply --index &&
+       git diff-tree -p C2 >patch &&
+       git apply --index <patch &&
        test_tick &&
        git commit -m "Master accepts moral equivalent of #2" &&
 
@@ -59,33 +59,28 @@ test_expect_success setup '
        git checkout master
 '
 
-test_expect_success "format-patch --ignore-if-in-upstream" '
-
+test_expect_success 'format-patch --ignore-if-in-upstream' '
        git format-patch --stdout master..side >patch0 &&
-       cnt=$(grep "^From " patch0 | wc -l) &&
-       test $cnt = 3
-
+       grep "^From " patch0 >from0 &&
+       test_line_count = 3 from0
 '
 
-test_expect_success "format-patch --ignore-if-in-upstream" '
-
+test_expect_success 'format-patch --ignore-if-in-upstream' '
        git format-patch --stdout \
                --ignore-if-in-upstream master..side >patch1 &&
-       cnt=$(grep "^From " patch1 | wc -l) &&
-       test $cnt = 2
-
+       grep "^From " patch1 >from1 &&
+       test_line_count = 2 from1
 '
 
-test_expect_success "format-patch --ignore-if-in-upstream handles tags" '
+test_expect_success 'format-patch --ignore-if-in-upstream handles tags' '
        git tag -a v1 -m tag side &&
        git tag -a v2 -m tag master &&
        git format-patch --stdout --ignore-if-in-upstream v2..v1 >patch1 &&
-       cnt=$(grep "^From " patch1 | wc -l) &&
-       test $cnt = 2
+       grep "