]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'ms/doc-push-fix' into maint-2.42
authorJunio C Hamano <gitster@pobox.com>
Thu, 2 Nov 2023 07:53:28 +0000 (16:53 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Nov 2023 07:53:28 +0000 (16:53 +0900)
Docfix.

* ms/doc-push-fix:
  git-push doc: more visibility for -q option

93 files changed:
.github/workflows/coverity.yml [new file with mode: 0644]
.github/workflows/main.yml
Documentation/CodingGuidelines
Documentation/config/rebase.txt
Documentation/diff-options.txt
Documentation/git-am.txt
Documentation/git-cat-file.txt
Documentation/git-clean.txt
Documentation/git-config.txt
Documentation/git-push.txt
Documentation/git-repack.txt
Documentation/git-show.txt
Documentation/git-worktree.txt
Documentation/scalar.txt
add-interactive.c
builtin/add.c
builtin/am.c
builtin/cat-file.c
builtin/commit.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/diff.c
builtin/gc.c
builtin/grep.c
builtin/log.c
builtin/mv.c
builtin/name-rev.c
builtin/receive-pack.c
builtin/stash.c
builtin/submodule--helper.c
builtin/var.c
builtin/worktree.c
ci/config/README [new file with mode: 0644]
ci/config/allow-ref.sample [deleted file]
ci/lib.sh
commit-graph.c
compat/terminal.c
contrib/completion/git-completion.bash
daemon.c
decorate.c
decorate.h
diff-lib.c
diff-no-index.c
diff.c
diff.h
fetch-pack.c
git-compat-util.h
git-send-email.perl
git-svn.perl
http.c
line-log.c
line-log.h
merge-ort.c
parse-options.h
range-diff.c
ref-filter.c
revision.c
scalar.c
sequencer.c
setup.c
setup.h
t/helper/test-example-decorate.c
t/lib-gpg.sh
t/lib-httpd/apache.conf
t/t0007-git-var.sh
t/t3321-notes-stripspace.sh
t/t3404-rebase-interactive.sh
t/t3418-rebase-continue.sh
t/t3430-rebase-merges.sh
t/t4015-diff-whitespace.sh
t/t4017-diff-retval.sh
t/t4040-whitespace-status.sh
t/t4053-diff-no-index.sh
t/t4217-log-limit.sh
t/t5318-commit-graph.sh
t/t5407-post-rewrite-hook.sh
t/t5510-fetch.sh
t/t5546-receive-limits.sh
t/t5571-pre-push-hook.sh
t/t5583-push-branches.sh
t/t5811-proto-disable-git.sh
t/t6300-for-each-ref.sh
t/t7516-commit-races.sh
t/t7527-builtin-fsmonitor.sh
t/t9001-send-email.sh
t/t9004-example.sh
t/t9211-scalar-clone.sh
t/t9902-completion.sh
t/test-lib.sh
upload-pack.c
wt-status.c

diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
new file mode 100644 (file)
index 0000000..e5532d3
--- /dev/null
@@ -0,0 +1,163 @@
+name: Coverity
+
+# This GitHub workflow automates submitting builds to Coverity Scan. To enable it,
+# set the repository variable `ENABLE_COVERITY_SCAN_FOR_BRANCHES` (for details, see
+# https://docs.github.com/en/actions/learn-github-actions/variables) to a JSON
+# string array containing the names of the branches for which the workflow should be
+# run, e.g. `["main", "next"]`.
+#
+# In addition, two repository secrets must be set (for details how to add secrets, see
+# https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions):
+# `COVERITY_SCAN_EMAIL` and `COVERITY_SCAN_TOKEN`. The former specifies the
+# email to which the Coverity reports should be sent and the latter can be
+# obtained from the Project Settings tab of the Coverity project).
+#
+# The workflow runs on `ubuntu-latest` by default. This can be overridden by setting
+# the repository variable `ENABLE_COVERITY_SCAN_ON_OS` to a JSON string array specifying
+# the operating systems, e.g. `["ubuntu-latest", "windows-latest"]`.
+#
+# By default, the builds are submitted to the Coverity project `git`. To override this,
+# set the repository variable `COVERITY_PROJECT`.
+
+on:
+  push:
+
+defaults:
+  run:
+    shell: bash
+
+jobs:
+  coverity:
+    if: contains(fromJSON(vars.ENABLE_COVERITY_SCAN_FOR_BRANCHES || '[""]'), github.ref_name)
+    strategy:
+      matrix:
+        os: ${{ fromJSON(vars.ENABLE_COVERITY_SCAN_ON_OS || '["ubuntu-latest"]') }}
+    runs-on: ${{ matrix.os }}
+    env:
+      COVERITY_PROJECT: ${{ vars.COVERITY_PROJECT || 'git' }}
+      COVERITY_LANGUAGE: cxx
+      COVERITY_PLATFORM: overridden-below
+    steps:
+      - uses: actions/checkout@v3
+      - name: install minimal Git for Windows SDK
+        if: contains(matrix.os, 'windows')
+        uses: git-for-windows/setup-git-for-windows-sdk@v1
+      - run: ci/install-dependencies.sh
+        if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos')
+        env:
+          runs_on_pool: ${{ matrix.os }}
+
+      # The Coverity site says the tool is usually updated twice yearly, so the
+      # MD5 of download can be used to determine whether there's been an update.
+      - name: get the Coverity Build Tool hash
+        id: lookup
+        run: |
+          case "${{ matrix.os }}" in
+          *windows*)
+            COVERITY_PLATFORM=win64
+            COVERITY_TOOL_FILENAME=cov-analysis.zip
+            MAKEFLAGS=-j$(nproc)
+            ;;
+          *macos*)
+            COVERITY_PLATFORM=macOSX
+            COVERITY_TOOL_FILENAME=cov-analysis.dmg
+            MAKEFLAGS=-j$(sysctl -n hw.physicalcpu)
+            ;;
+          *ubuntu*)
+            COVERITY_PLATFORM=linux64
+            COVERITY_TOOL_FILENAME=cov-analysis.tgz
+            MAKEFLAGS=-j$(nproc)
+            ;;
+          *)
+            echo '::error::unhandled OS ${{ matrix.os }}' >&2
+            exit 1
+            ;;
+          esac
+          echo "COVERITY_PLATFORM=$COVERITY_PLATFORM" >>$GITHUB_ENV
+          echo "COVERITY_TOOL_FILENAME=$COVERITY_TOOL_FILENAME" >>$GITHUB_ENV
+          echo "MAKEFLAGS=$MAKEFLAGS" >>$GITHUB_ENV
+          MD5=$(curl https://scan.coverity.com/download/$COVERITY_LANGUAGE/$COVERITY_PLATFORM \
+                   --fail \
+                   --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+                   --form project="$COVERITY_PROJECT" \
+                   --form md5=1)
+          case $? in
+          0) ;; # okay
+          22) # 40x, i.e. access denied
+            echo "::error::incorrect token or project?" >&2
+            exit 1
+            ;;
+          *) # other error
+            echo "::error::Failed to retrieve MD5" >&2
+            exit 1
+            ;;
+          esac
+          echo "hash=$MD5" >>$GITHUB_OUTPUT
+
+      # Try to cache the tool to avoid downloading 1GB+ on every run.
+      # A cache miss will add ~30s to create, but a cache hit will save minutes.
+      - name: restore the Coverity Build Tool
+        id: cache
+        uses: actions/cache/restore@v3
+        with:
+          path: ${{ runner.temp }}/cov-analysis
+          key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
+      - name: download the Coverity Build Tool (${{ env.COVERITY_LANGUAGE }} / ${{ env.COVERITY_PLATFORM}})
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: |
+          curl https://scan.coverity.com/download/$COVERITY_LANGUAGE/$COVERITY_PLATFORM \
+            --fail --no-progress-meter \
+            --output $RUNNER_TEMP/$COVERITY_TOOL_FILENAME \
+            --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+            --form project="$COVERITY_PROJECT"
+      - name: extract the Coverity Build Tool
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: |
+          case "$COVERITY_TOOL_FILENAME" in
+          *.tgz)
+            mkdir $RUNNER_TEMP/cov-analysis &&
+            tar -xzf $RUNNER_TEMP/$COVERITY_TOOL_FILENAME --strip 1 -C $RUNNER_TEMP/cov-analysis
+            ;;
+          *.dmg)
+            cd $RUNNER_TEMP &&
+            attach="$(hdiutil attach $COVERITY_TOOL_FILENAME)" &&
+            volume="$(echo "$attach" | cut -f 3 | grep /Volumes/)" &&
+            mkdir cov-analysis &&
+            cd cov-analysis &&
+            sh "$volume"/cov-analysis-macosx-*.sh &&
+            ls -l &&
+            hdiutil detach "$volume"
+            ;;
+          *.zip)
+            cd $RUNNER_TEMP &&
+            mkdir cov-analysis-tmp &&
+            unzip -d cov-analysis-tmp $COVERITY_TOOL_FILENAME &&
+            mv cov-analysis-tmp/* cov-analysis
+            ;;
+          *)
+            echo "::error::unhandled archive type: $COVERITY_TOOL_FILENAME" >&2
+            exit 1
+            ;;
+          esac
+      - name: cache the Coverity Build Tool
+        if: steps.cache.outputs.cache-hit != 'true'
+        uses: actions/cache/save@v3
+        with:
+          path: ${{ runner.temp }}/cov-analysis
+          key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
+      - name: build with cov-build
+        run: |
+          export PATH="$RUNNER_TEMP/cov-analysis/bin:$PATH" &&
+          cov-configure --gcc &&
+          cov-build --dir cov-int make
+      - name: package the build
+        run: tar -czvf cov-int.tgz cov-int
+      - name: submit the build to Coverity Scan
+        run: |
+          curl \
+            --fail \
+            --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+            --form email='${{ secrets.COVERITY_SCAN_EMAIL }}' \
+            --form file=@cov-int.tgz \
+            --form version='${{ github.sha }}' \
+            "https://scan.coverity.com/builds?project=$COVERITY_PROJECT"
index 079645b7760887af4cf93b821270f7368c8e5f50..dcf7d78f1d004c54c412973e04a76e92a2287c67 100644 (file)
@@ -5,9 +5,23 @@ on: [push, pull_request]
 env:
   DEVELOPER: 1
 
+# If more than one workflow run is triggered for the very same commit hash
+# (which happens when multiple branches pointing to the same commit), only
+# the first one is allowed to run, the second will be kept in the "queued"
+# state. This allows a successful completion of the first run to be reused
+# in the second run via the `skip-if-redundant` logic in the `config` job.
+#
+# The only caveat is that if a workflow run is triggered for the same commit
+# hash that another run is already being held, that latter run will be
+# canceled. For more details about the `concurrency` attribute, see:
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency
+concurrency:
+  group: ${{ github.sha }}
+
 jobs:
   ci-config:
     name: config
+    if: vars.CI_BRANCHES == '' || contains(vars.CI_BRANCHES, github.ref_name)
     runs-on: ubuntu-latest
     outputs:
       enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }}
@@ -30,10 +44,13 @@ jobs:
         name: check whether CI is enabled for ref
         run: |
           enabled=yes
-          if test -x config-repo/ci/config/allow-ref &&
-             ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+          if test -x config-repo/ci/config/allow-ref
           then
-            enabled=no
+            echo "::warning::ci/config/allow-ref is deprecated; use CI_BRANCHES instead"
+            if ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+            then
+              enabled=no
+            fi
           fi
 
           skip_concurrent=yes
index 65af8d82cedd5fdfd46005d4b4e75114a74810fb..9495df835d5d8170773c0cea071161cc034ca666 100644 (file)
@@ -24,7 +24,7 @@ code.  For Git in general, a few rough rules are:
 
    "Once it _is_ in the tree, it's not really worth the patch noise to
    go and fix it up."
-   Cf. http://lkml.iu.edu/hypermail/linux/kernel/1001.3/01069.html
+   Cf. https://lore.kernel.org/all/20100126160632.3bdbe172.akpm@linux-foundation.org/
 
  - Log messages to explain your changes are as important as the
    changes themselves.  Clearly written code and in-code comments
index afaf6dad99b5542ab06c31e4276a695128ee6b8a..9c248accec2c5d572cf11f26ffcbfe8e7eab1465 100644 (file)
@@ -77,3 +77,9 @@ rebase.rebaseMerges::
        equivalent to `--no-rebase-merges`. Passing `--rebase-merges` on the
        command line, with or without an argument, overrides any
        `rebase.rebaseMerges` configuration.
+
+rebase.maxLabelLength::
+       When generating label names from commit subjects, truncate the names to
+       this length. By default, the names are truncated to a little less than
+       `NAME_MAX` (to allow e.g. `.lock` files to be written for the
+       corresponding loose refs).
index 9f33f887711d3ac1d1f0e8933b22d8004b606dc7..c07488b123c63111a84c027b4d80720383dc82b8 100644 (file)
@@ -22,13 +22,7 @@ ifndef::git-format-patch[]
 -p::
 -u::
 --patch::
-       Generate patch (see section titled
-ifdef::git-log[]
-<<generate_patch_text_with_p, "Generating patch text with -p">>).
-endif::git-log[]
-ifndef::git-log[]
-"Generating patch text with -p").
-endif::git-log[]
+       Generate patch (see <<generate_patch_text_with_p>>).
 ifdef::git-diff[]
        This is the default.
 endif::git-diff[]
index 900be198b14e933d19f87febd9860cb0c67a6bf0..82dadbecc857bb114504f757bc3bc799c8de9d69 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
         [--[no-]3way] [--interactive] [--committer-date-is-author-date]
         [--ignore-date] [--ignore-space-change | --ignore-whitespace]
-        [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
+        [--whitespace=<action>] [-C<n>] [-p<n>] [--directory=<dir>]
         [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
         [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
         [--quoted-cr=<action>]
@@ -118,7 +118,7 @@ include::rerere-options.txt[]
 
 --ignore-space-change::
 --ignore-whitespace::
---whitespace=<option>::
+--whitespace=<action>::
 -C<n>::
 -p<n>::
 --directory=<dir>::
index 0e4936d182632fb3362376787efd7d633bd623d2..bd95a6c10a7d0b1ee16b619c4b546c8d9c0b0e13 100644 (file)
@@ -3,8 +3,7 @@ git-cat-file(1)
 
 NAME
 ----
-git-cat-file - Provide content or type and size information for repository objects
-
+git-cat-file - Provide contents or details of repository objects
 
 SYNOPSIS
 --------
@@ -12,25 +11,24 @@ SYNOPSIS
 'git cat-file' <type> <object>
 'git cat-file' (-e | -p) <object>
 'git cat-file' (-t | -s) [--allow-unknown-type] <object>
+'git cat-file' (--textconv | --filters)
+            [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
 'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
             [--buffer] [--follow-symlinks] [--unordered]
             [--textconv | --filters] [-Z]
-'git cat-file' (--textconv | --filters)
-            [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
 
 DESCRIPTION
 -----------
-In its first form, the command provides the content or the type of an object in
-the repository. The type is required unless `-t` or `-p` is used to find the
-object type, or `-s` is used to find the object size, or `--textconv` or
-`--filters` is used (which imply type "blob").
-
-In the second form, a list of objects (separated by linefeeds) is provided on
-stdin, and the SHA-1, type, and size of each object is printed on stdout. The
-output format can be overridden using the optional `<format>` argument. If
-either `--textconv` or `--filters` was specified, the input is expected to
-list the object names followed by the path name, separated by a single
-whitespace, so that the appropriate drivers can be determined.
+Output the contents or other properties such as size, type or delta
+information of one or more objects.
+
+This command can operate in two modes, depending on whether an option
+from the `--batch` family is specified.
+
+In non-batch mode, the command provides information on an object
+named on the command line.
+
+In batch mode, arguments are read from standard input.
 
 OPTIONS
 -------
@@ -51,8 +49,8 @@ OPTIONS
 
 -e::
        Exit with zero status if `<object>` exists and is a valid
-       object. If `<object>` is of an invalid format exit with non-zero and
-       emits an error on stderr.
+       object. If `<object>` is of an invalid format, exit with non-zero
+       status and emit an error on stderr.
 
 -p::
        Pretty-print the contents of `<object>` based on its type.
index 160d08b86bb8583e9464373aef9cafea638003cb..5e1a3d5148c5ebaeb4e9110fc382dbeed5383b2d 100644 (file)
@@ -127,7 +127,7 @@ ask each::
 
 quit::
 
-  This lets you quit without do cleaning.
+  This lets you quit without doing any cleaning.
 
 help::
 
index 7a2bcb2f6cb6f94b677d47de49ae8c6d0b98f2b8..b1caac887ae2dc5ce683ab4c6d91eed849403afe 100644 (file)
@@ -201,7 +201,7 @@ Valid `<type>`'s include:
   1073741824 upon input.
 - 'bool-or-int': canonicalize according to either 'bool' or 'int', as described
   above.
-- 'path': canonicalize by adding a leading `~` to the value of `$HOME` and
+- 'path': canonicalize by expanding a leading `~` to the value of `$HOME` and
   `~user` to the home directory for the specified user. This specifier has no
   effect when setting the value (but you can use `git config section.variable
   ~/` from the command line to let your shell do the expansion.)
index b5d76604cb8e638a5a77102cc454ed295edddd12..003bc7d9ce0771fa9fc18d086d85de898e0a16c7 100644 (file)
@@ -37,7 +37,7 @@ the default `<refspec>` by consulting `remote.*.push` configuration,
 and if it is not found, honors `push.default` configuration to decide
 what to push (See linkgit:git-config[1] for the meaning of `push.default`).
 
-When neither the command-line nor the configuration specify what to
+When neither the command-line nor the configuration specifies what to
 push, the default behavior is used, which corresponds to the `simple`
 value for `push.default`: the current branch is pushed to the
 corresponding upstream branch, but as a safety measure, the push is
index 4017157949e6d764a619f870c0eed538d3e99f64..b63e8abc7d1bd951fa57f74b1b7d213db2916c55 100644 (file)
@@ -186,7 +186,7 @@ depth is 4095.
        Pass the `--delta-islands` option to `git-pack-objects`, see
        linkgit:git-pack-objects[1].
 
--g=<factor>::
+-g<factor>::
 --geometric=<factor>::
        Arrange resulting pack structure so that each successive pack
        contains at least `<factor>` times the number of objects as the
@@ -203,11 +203,8 @@ uniquely by the set of packs being "rolled-up"; in other words, the
 packs determined to need to be combined in order to restore a geometric
 progression.
 +
-When `--unpacked` is specified, loose objects are implicitly included in
-this "roll-up", without respect to their reachability. This is subject
-to change in the future. This option (implying a drastically different
-repack mode) is not guaranteed to work with all other combinations of
-option to `git repack`.
+Loose objects are implicitly included in this "roll-up", without respect to
+their reachability. This is subject to change in the future.
 +
 When writing a multi-pack bitmap, `git repack` selects the largest resulting
 pack as the preferred pack for object selection by the MIDX (see
index 2b1bc7288d5f6fd27b92ed8119ef5dfbc89b9d1d..03c06345186f24757cac10c8e939fb13722aaa59 100644 (file)
@@ -26,7 +26,7 @@ with --name-only).
 
 For plain blobs, it shows the plain contents.
 
-The command takes options applicable to the 'git diff-tree' command to
+Some options that 'git log' command understands can be used to
 control how the changes the commit introduces are shown.
 
 This manual page describes only the most frequently used options.
index a4fbf5e8386d7d4ae58230b17b534a90461ff421..93d76f5d665a57a8bdca565add921cbd8b76bc37 100644 (file)
@@ -286,7 +286,8 @@ rules and how to access refs of one worktree from another.
 In general, all pseudo refs are per-worktree and all refs starting with
 `refs/` are shared. Pseudo refs are ones like `HEAD` which are directly
 under `$GIT_DIR` instead of inside `$GIT_DIR/refs`. There are exceptions,
-however: refs inside `refs/bisect` and `refs/worktree` are not shared.
+however: refs inside `refs/bisect`, `refs/worktree` and `refs/rewritten` are
+not shared.
 
 Refs that are per-worktree can still be accessed from another worktree via
 two special paths, `main-worktree` and `worktrees`. The former gives
@@ -363,8 +364,8 @@ linked worktree `git rev-parse --git-path HEAD` returns
 `/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
 rev-parse --git-path refs/heads/master` uses
 `$GIT_COMMON_DIR` and returns `/path/main/.git/refs/heads/master`,
-since refs are shared across all worktrees, except `refs/bisect` and
-`refs/worktree`.
+since refs are shared across all worktrees, except `refs/bisect`,
+`refs/worktree` and `refs/rewritten`.
 
 See linkgit:gitrepository-layout[5] for more information. The rule of
 thumb is do not make any assumption about whether a path belongs to
index f33436c7f65ff9fd46f7ee4fa10975c833a61096..361f51a64736fab34faa8efaa90071c957d74c3b 100644 (file)
@@ -8,7 +8,8 @@ scalar - A tool for managing large Git repositories
 SYNOPSIS
 --------
 [verse]
-scalar clone [--single-branch] [--branch <main-branch>] [--full-clone] <url> [<enlistment>]
+scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
+       [--[no-]src] <url> [<enlistment>]
 scalar list
 scalar register [<enlistment>]
 scalar unregister [<enlistment>]
@@ -80,6 +81,11 @@ remote-tracking branch for the branch this option was used for the initial
 cloning. If the HEAD at the remote did not point at any branch when
 `--single-branch` clone was made, no remote-tracking branch is created.
 
+--[no-]src::
+       By default, `scalar clone` places the cloned repository within a
+       `<entlistment>/src` directory. Use `--no-src` to place the cloned
+       repository directly in the `<enlistment>` directory.
+
 --[no-]full-clone::
        A sparse-checkout is initialized by default. This behavior can be
        turned off via `--full-clone`.
index add9a1ad4364f92833256d5f53dbb3bc85b43ede..7fd00c5e2502d6aa2c151196f87fb20ed0c0c578 100644 (file)
@@ -569,7 +569,7 @@ static int get_modified_files(struct repository *r,
                        copy_pathspec(&rev.prune_data, ps);
 
                if (s.mode == FROM_INDEX)
-                       run_diff_index(&rev, 1);
+                       run_diff_index(&rev, DIFF_INDEX_CACHED);
                else {
                        rev.diffopt.flags.ignore_dirty_submodules = 1;
                        run_diff_files(&rev, 0);
index 4b0dd798df5909905f7be69479d4b3b2ce1b19ae..0057392f988fdbaebc55628585b5d519e93307ed 100644 (file)
@@ -182,7 +182,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 
        if (repo_read_index(the_repository) < 0)
-               die(_("Could not read the index"));
+               die(_("could not read the index"));
 
        repo_init_revisions(the_repository, &rev, prefix);
        rev.diffopt.context = 7;
@@ -194,22 +194,21 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
        rev.diffopt.file = xfdopen(out, "w");
        rev.diffopt.close_file = 1;
-       if (run_diff_files(&rev, 0))
-               die(_("Could not write patch"));
+       run_diff_files(&rev, 0);
 
        if (launch_editor(file, NULL, NULL))
                die(_("editing patch failed"));
 
        if (stat(file, &st))
-               die_errno(_("Could not stat '%s'"), file);
+               die_errno(_("could not stat '%s'"), file);
        if (!st.st_size)
-               die(_("Empty patch. Aborted."));
+               die(_("empty patch. aborted"));
 
        child.git_cmd = 1;
        strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
                     NULL);
        if (run_command(&child))
-               die(_("Could not apply '%s'"), file);
+               die(_("could not apply '%s'"), file);
 
        unlink(file);
        free(file);
@@ -567,7 +566,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 finish:
        if (write_locked_index(&the_index, &lock_file,
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
-               die(_("Unable to write new index file"));
+               die(_("unable to write new index file"));
 
        dir_clear(&dir);
        clear_pathspec(&pathspec);
index 8bde034fae68bcdd8fc0f0b9b61837d29608d62b..6655059a57c8fc7563bdd17d266faa510bf1c9c6 100644 (file)
@@ -1430,7 +1430,7 @@ static void write_index_patch(const struct am_state *state)
        rev_info.diffopt.close_file = 1;
        add_pending_object(&rev_info, &tree->object, "");
        diff_setup_done(&rev_info.diffopt);
-       run_diff_index(&rev_info, 1);
+       run_diff_index(&rev_info, DIFF_INDEX_CACHED);
        release_revisions(&rev_info);
 }
 
@@ -1593,7 +1593,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
                rev_info.diffopt.filter |= diff_filter_bit('M');
                add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
                diff_setup_done(&rev_info.diffopt);
-               run_diff_index(&rev_info, 1);
+               run_diff_index(&rev_info, DIFF_INDEX_CACHED);
                release_revisions(&rev_info);
        }
 
@@ -2303,7 +2303,8 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
        if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
                return error(_("options '%s=%s' and '%s=%s' "
                                           "cannot be used together"),
-                                        "--show-current-patch", "--show-current-patch", arg, valid_modes[resume->sub_mode]);
+                            "--show-current-patch", arg,
+                            "--show-current-patch", valid_modes[resume->sub_mode]);
 
        resume->mode = RESUME_SHOW_PATCH;
        resume->sub_mode = new_value;
index 694c8538df2ff8200e214351e5e857530d2a1191..ea8ad601ecc0b7ee2d7eb9c3da2bb70bcfc55cf8 100644 (file)
@@ -922,11 +922,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                N_("git cat-file <type> <object>"),
                N_("git cat-file (-e | -p) <object>"),
                N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
+               N_("git cat-file (--textconv | --filters)\n"
+                  "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
                N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
                   "             [--buffer] [--follow-symlinks] [--unordered]\n"
                   "             [--textconv | --filters] [-Z]"),
-               N_("git cat-file (--textconv | --filters)\n"
-                  "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
                NULL
        };
        const struct option options[] = {
index 7da5f924484d586c765796f8e411a042f2a3817a..781af2e206c1060213f16dd7cacb5ca68884f6b8 100644 (file)
@@ -455,7 +455,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
                refresh_cache_or_die(refresh_flags);
                cache_tree_update(&the_index, WRITE_TREE_SILENT);
                if (write_locked_index(&the_index, &index_lock, 0))
-                       die(_("unable to write new_index file"));
+                       die(_("unable to write new index file"));
                commit_style = COMMIT_NORMAL;
                ret = get_lock_file_path(&index_lock);
                goto out;
@@ -479,7 +479,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
                        cache_tree_update(&the_index, WRITE_TREE_SILENT);
                if (write_locked_index(&the_index, &index_lock,
                                       COMMIT_LOCK | SKIP_IF_UNCHANGED))
-                       die(_("unable to write new_index file"));
+                       die(_("unable to write new index file"));
                commit_style = COMMIT_AS_IS;
                ret = get_index_file();
                goto out;
@@ -527,7 +527,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
        refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
        cache_tree_update(&the_index, WRITE_TREE_SILENT);
        if (write_locked_index(&the_index, &index_lock, 0))
-               die(_("unable to write new_index file"));
+               die(_("unable to write new index file"));
 
        hold_lock_file_for_update(&false_lock,
                                  git_path("next-index-%"PRIuMAX,
@@ -1862,7 +1862,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        if (commit_index_files())
                die(_("repository has been updated, but unable to write\n"
-                     "new_index file. Check that disk is not full and quota is\n"
+                     "new index file. Check that disk is not full and quota is\n"
                      "not exceeded, and then \"git restore --staged :/\" to recover."));
 
        git_test_write_commit_graph_or_die();
index b28a4a1f82d5290f4800b238224946923cf7811b..a9e375882bf2545736b2d38e65bc744c7d7b3497 100644 (file)
@@ -668,7 +668,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        struct lock_file index_lock = LOCK_INIT;
                        struct rev_info revs;
                        struct strvec args = STRVEC_INIT;
-                       int fd, result;
+                       int fd;
 
                        setup_work_tree();
                        prepare_repo_settings(the_repository);
@@ -685,9 +685,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        strvec_pushv(&args, diff_index_args);
                        if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
                                BUG("malformed internal diff-index command line");
-                       result = run_diff_index(&revs, 0);
+                       run_diff_index(&revs, 0);
 
-                       if (!diff_result_code(&revs.diffopt, result))
+                       if (!diff_result_code(&revs.diffopt))
                                suffix = NULL;
                        else
                                suffix = dirty;
index 50330b8dd2fd289a188b6143d528da2658327057..f38912cd407bf4e5098d84a928affd849f4123d8 100644 (file)
@@ -80,14 +80,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
            (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
                diff_merges_set_dense_combined_if_unset(&rev);
 
-       if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
-               perror("repo_read_index_preload");
-               result = -1;
-               goto cleanup;
-       }
-       result = run_diff_files(&rev, options);
-       result = diff_result_code(&rev.diffopt, result);
-cleanup:
+       if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0)
+               die_errno("repo_read_index_preload");
+       run_diff_files(&rev, options);
+       result = diff_result_code(&rev.diffopt);
        release_revisions(&rev);
        return result;
 }
index 9db7139b839e46d10cf553fbb3d4a3a8e567735b..220f341ffa2a138f70d6aa0d343594e6e60d2ebb 100644 (file)
@@ -72,8 +72,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
                perror("repo_read_index");
                return -1;
        }
-       result = run_diff_index(&rev, option);
-       result = diff_result_code(&rev.diffopt, result);
+       run_diff_index(&rev, option);
+       result = diff_result_code(&rev.diffopt);
        release_revisions(&rev);
        return result;
 }
index c9ba35f143814f2b016fccfb57ab99f86bee4c85..86be6342861be40da9edbf2f1a2002fa4abc0cda 100644 (file)
@@ -232,5 +232,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
                diff_free(&opt->diffopt);
        }
 
-       return diff_result_code(&opt->diffopt, 0);
+       return diff_result_code(&opt->diffopt);
 }
index b19530c996c7cd43be9baa3649c93247de888ebd..0b313549c764b7dc0d001b0b793fc160b04059ac 100644 (file)
@@ -77,9 +77,9 @@ static void stuff_change(struct diff_options *opt,
        diff_queue(&diff_queued_diff, one, two);
 }
 
-static int builtin_diff_b_f(struct rev_info *revs,
-                           int argc, const char **argv UNUSED,
-                           struct object_array_entry **blob)
+static void builtin_diff_b_f(struct rev_info *revs,
+                            int argc, const char **argv UNUSED,
+                            struct object_array_entry **blob)
 {
        /* Blob vs file in the working tree*/
        struct stat st;
@@ -109,12 +109,11 @@ static int builtin_diff_b_f(struct rev_info *revs,
                     path);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
-       return 0;
 }
 
-static int builtin_diff_blobs(struct rev_info *revs,
-                             int argc, const char **argv UNUSED,
-                             struct object_array_entry **blob)
+static void builtin_diff_blobs(struct rev_info *revs,
+                              int argc, const char **argv UNUSED,
+                              struct object_array_entry **blob)
 {
        const unsigned mode = canon_mode(S_IFREG | 0644);
 
@@ -134,11 +133,10 @@ static int builtin_diff_blobs(struct rev_info *revs,
                     blob_path(blob[0]), blob_path(blob[1]));
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
-       return 0;
 }
 
-static int builtin_diff_index(struct rev_info *revs,
-                             int argc, const char **argv)
+static void builtin_diff_index(struct rev_info *revs,
+                              int argc, const char **argv)
 {
        unsigned int option = 0;
        while (1 < argc) {
@@ -163,20 +161,18 @@ static int builtin_diff_index(struct rev_info *revs,
                setup_work_tree();
                if (repo_read_index_preload(the_repository,
                                            &revs->diffopt.pathspec, 0) < 0) {
-                       perror("repo_read_index_preload");
-                       return -1;
+                       die_errno("repo_read_index_preload");
                }
        } else if (repo_read_index(the_repository) < 0) {
-               perror("repo_read_cache");
-               return -1;
+               die_errno("repo_read_cache");
        }
-       return run_diff_index(revs, option);
+       run_diff_index(revs, option);
 }
 
-static int builtin_diff_tree(struct rev_info *revs,
-                            int argc, const char **argv,
-                            struct object_array_entry *ent0,
-                            struct object_array_entry *ent1)
+static void builtin_diff_tree(struct rev_info *revs,
+                             int argc, const char **argv,
+                             struct object_array_entry *ent0,
+                             struct object_array_entry *ent1)
 {
        const struct object_id *(oid[2]);
        struct object_id mb_oid;
@@ -209,13 +205,12 @@ static int builtin_diff_tree(struct rev_info *revs,
        }
        diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
        log_tree_diff_flush(revs);
-       return 0;
 }
 
-static int builtin_diff_combined(struct rev_info *revs,
-                                int argc, const char **argv UNUSED,
-                                struct object_array_entry *ent,
-                                int ents, int first_non_parent)
+static void builtin_diff_combined(struct rev_info *revs,
+                                 int argc, const char **argv UNUSED,
+                                 struct object_array_entry *ent,
+                                 int ents, int first_non_parent)
 {
        struct oid_array parents = OID_ARRAY_INIT;
        int i;
@@ -236,7 +231,6 @@ static int builtin_diff_combined(struct rev_info *revs,
        }
        diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
        oid_array_clear(&parents);
-       return 0;
 }
 
 static void refresh_index_quietly(void)
@@ -254,7 +248,7 @@ static void refresh_index_quietly(void)
        repo_update_index_if_able(the_repository, &lock_file);
 }
 
-static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+static void builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
 {
        unsigned int options = 0;
 
@@ -269,8 +263,10 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
                        options |= DIFF_SILENT_ON_REMOVED;
                else if (!strcmp(argv[1], "-h"))
                        usage(builtin_diff_usage);
-               else
-                       return error(_("invalid option: %s"), argv[1]);
+               else {
+                       error(_("invalid option: %s"), argv[1]);
+                       usage(builtin_diff_usage);
+               }
                argv++; argc--;
        }
 
@@ -287,10 +283,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
        setup_work_tree();
        if (repo_read_index_preload(the_repository, &revs->diffopt.pathspec,
                                    0) < 0) {
-               perror("repo_read_index_preload");
-               return -1;
+               die_errno("repo_read_index_preload");
        }
-       return run_diff_files(revs, options);
+       run_diff_files(revs, options);
 }
 
 struct symdiff {
@@ -404,7 +399,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        int blobs = 0, paths = 0;
        struct object_array_entry *blob[2];
        int nongit = 0, no_index = 0;
-       int result = 0;
+       int result;
        struct symdiff sdiff;
 
        /*
@@ -583,17 +578,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        if (!ent.nr) {
                switch (blobs) {
                case 0:
-                       result = builtin_diff_files(&rev, argc, argv);
+                       builtin_diff_files(&rev, argc, argv);
                        break;
                case 1:
                        if (paths != 1)
                                usage(builtin_diff_usage);
-                       result = builtin_diff_b_f(&rev, argc, argv, blob);
+                       builtin_diff_b_f(&rev, argc, argv, blob);
                        break;
                case 2:
                        if (paths)
                                usage(builtin_diff_usage);
-                       result = builtin_diff_blobs(&rev, argc, argv, blob);
+                       builtin_diff_blobs(&rev, argc, argv, blob);
                        break;
                default:
                        usage(builtin_diff_usage);
@@ -602,18 +597,18 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        else if (blobs)
                usage(builtin_diff_usage);
        else if (ent.nr == 1)
-               result = builtin_diff_index(&rev, argc, argv);
+               builtin_diff_index(&rev, argc, argv);
        else if (ent.nr == 2) {
                if (sdiff.warn)
                        warning(_("%s...%s: multiple merge bases, using %s"),
                                sdiff.left, sdiff.right, sdiff.base);
-               result = builtin_diff_tree(&rev, argc, argv,
-                                          &ent.objects[0], &ent.objects[1]);
+               builtin_diff_tree(&rev, argc, argv,
+                                 &ent.objects[0], &ent.objects[1]);
        } else
-               result = builtin_diff_combined(&rev, argc, argv,
-                                              ent.objects, ent.nr,
-                                              first_non_parent);
-       result = diff_result_code(&rev.diffopt, result);
+               builtin_diff_combined(&rev, argc, argv,
+                                     ent.objects, ent.nr,
+                                     first_non_parent);
+       result = diff_result_code(&rev.diffopt);
        if (1 < rev.diffopt.skip_stat_unmatch)
                refresh_index_quietly();
        release_revisions(&rev);
index 5c4315f0d816c8e197bf22105f1d2ae56707ea2b..719cae9a88aa0168ce4023434232c9d186d27271 100644 (file)
@@ -2397,7 +2397,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
               "LockPersonality=yes\n"
               "MemoryDenyWriteExecute=yes\n"
               "NoNewPrivileges=yes\n"
-              "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\n"
+              "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_VSOCK\n"
               "RestrictNamespaces=yes\n"
               "RestrictRealtime=yes\n"
               "RestrictSUIDSGID=yes\n"
index 50e712a18479750d42186214c9be43c7f71eebeb..b71222330add858a8ae6ce0363666e85c04a5cef 100644 (file)
@@ -924,9 +924,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                         N_("process binary files with textconv filters")),
                OPT_SET_INT('r', "recursive", &opt.max_depth,
                            N_("search in subdirectories (default)"), -1),
-               { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
-                       N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
-                       NULL, 1 },
+               OPT_INTEGER_F(0, "max-depth", &opt.max_depth,
+                       N_("descend at most <n> levels"), PARSE_OPT_NONEG),
                OPT_GROUP(""),
                OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
                            N_("use extended POSIX regular expressions"),
@@ -990,7 +989,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_CALLBACK_F(0, "and", &opt, NULL,
                        N_("combine patterns specified with -e"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback),
-               OPT_BOOL(0, "or", &dummy, ""),
+               OPT_BOOL_F(0, "or", &dummy, "", PARSE_OPT_NONEG),
                OPT_CALLBACK_F(0, "not", &opt, NULL, "",
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback),
                OPT_CALLBACK_F('(', NULL, &opt, NULL, "",
index db3a88bfe96058679dff1059a6f4769599ee1801..5d808c92f441523f729e5edcdc3370d09f8bafdc 100644 (file)
@@ -549,7 +549,7 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
            rev->diffopt.flags.check_failed) {
                return 02;
        }
-       return diff_result_code(&rev->diffopt, 0);
+       return diff_result_code(&rev->diffopt);
 }
 
 static int cmd_log_walk(struct rev_info *rev)
index 05e7156034e04d637990cabf105f7fa967b0f2aa..c596515ad0536f4b13ce2fdc2a797f6aaa9df70a 100644 (file)
@@ -305,7 +305,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                }
                if (S_ISDIR(st.st_mode)
                    && lstat(dst, &dest_st) == 0) {
-                       bad = _("cannot move directory over file");
+                       bad = _("destination already exists");
                        goto act_on_entry;
                }
 
index c706fa37201aeabc5bdc3eb752a5be859490a42d..2dd1807c4e09f8dc7ff557c628fdd850dc653361 100644 (file)
@@ -582,12 +582,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
                OPT_BOOL(0, "always",     &always,
                           N_("show abbreviated commit object as fallback")),
-               {
-                       /* A Hidden OPT_BOOL */
-                       OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL,
-                       N_("dereference tags in the input (internal use)"),
-                       PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1,
-               },
+               OPT_HIDDEN_BOOL(0, "peel-tag", &peel_tag,
+                          N_("dereference tags in the input (internal use)")),
                OPT_END(),
        };
 
index fb8e1549d1be1e0b5e90cc2b7426eda7b7ce2f51..8c4f0cb90a936b2b24b8b7b9e8b1b789c33bff51 100644 (file)
@@ -2527,10 +2527,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        if (cert_nonce_seed)
                push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
 
-       if (0 <= transfer_unpack_limit)
-               unpack_limit = transfer_unpack_limit;
-       else if (0 <= receive_unpack_limit)
+       if (0 <= receive_unpack_limit)
                unpack_limit = receive_unpack_limit;
+       else if (0 <= transfer_unpack_limit)
+               unpack_limit = transfer_unpack_limit;
 
        switch (determine_protocol_version_server()) {
        case protocol_v2:
index fe64cde9ce3010e812f789dfbe040c64f16bec45..53e8868ba1cfd7eb9ee27c1505c61b883a9901d9 100644 (file)
@@ -973,7 +973,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
        }
        log_tree_diff_flush(&rev);
 
-       ret = diff_result_code(&rev.diffopt, 0);
+       ret = diff_result_code(&rev.diffopt);
 cleanup:
        strvec_clear(&stash_args);
        free_stash_info(&info);
@@ -1089,7 +1089,6 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
  */
 static int check_changes_tracked_files(const struct pathspec *ps)
 {
-       int result;
        struct rev_info rev;
        struct object_id dummy;
        int ret = 0;
@@ -1111,14 +1110,14 @@ static int check_changes_tracked_files(const struct pathspec *ps)
        add_head_to_pending(&rev);
        diff_setup_done(&rev.diffopt);
 
-       result = run_diff_index(&rev, 1);
-       if (diff_result_code(&rev.diffopt, result)) {
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
+       if (diff_result_code(&rev.diffopt)) {
                ret = 1;
                goto done;
        }
 
-       result = run_diff_files(&rev, 0);
-       if (diff_result_code(&rev.diffopt, result)) {
+       run_diff_files(&rev, 0);
+       if (diff_result_code(&rev.diffopt)) {
                ret = 1;
                goto done;
        }
@@ -1309,10 +1308,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
 
        add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
                           "");
-       if (run_diff_index(&rev, 0)) {
-               ret = -1;
-               goto done;
-       }
+       run_diff_index(&rev, 0);
 
        cp_upd_index.git_cmd = 1;
        strvec_pushl(&cp_upd_index.args, "update-index",
index f6871efd95dbca6da051f2d1b3b81b3c5c52b0b5..6f3bf33e615b3162c9109c1884113497ef130809 100644 (file)
@@ -629,7 +629,6 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
        char *displaypath;
        struct strvec diff_files_args = STRVEC_INIT;
        struct rev_info rev = REV_INFO_INIT;
-       int diff_files_result;
        struct strbuf buf = STRBUF_INIT;
        const char *git_dir;
        struct setup_revision_opt opt = {
@@ -669,9 +668,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
        repo_init_revisions(the_repository, &rev, NULL);
        rev.abbrev = 0;
        setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
-       diff_files_result = run_diff_files(&rev, 0);
+       run_diff_files(&rev, 0);
 
-       if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+       if (!diff_result_code(&rev.diffopt)) {
                print_status(flags, ' ', path, ce_oid,
                             displaypath);
        } else if (!(flags & OPT_CACHED)) {
@@ -1141,7 +1140,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
        }
 
        if (diff_cmd == DIFF_INDEX)
-               run_diff_index(&rev, info->cached);
+               run_diff_index(&rev, info->cached ? DIFF_INDEX_CACHED : 0);
        else
                run_diff_files(&rev, 0);
        prepare_submodule_summary(info, &list);
index 74161bdf1c61b5248150bac284898e3c03c79111..8cf7dd9e2e5cef1d9238c22ed64ea07440d31528 100644 (file)
@@ -66,7 +66,7 @@ static char *git_attr_val_system(int ident_flag UNUSED)
 
 static char *git_attr_val_global(int ident_flag UNUSED)
 {
-       char *file = xstrdup(git_attr_global_file());
+       char *file = xstrdup_or_null(git_attr_global_file());
        if (file) {
                normalize_path_copy(file, file);
                return file;
index 4cd01842de79fb43b842032eeffb1a181f788c6e..10db70b7ec910753278a8506c92ae3573ec5c216 100644 (file)
@@ -696,7 +696,7 @@ static int can_use_remote_refs(const struct add_opts *opts)
                return 1;
        } else if (!opts->force && remote_get(NULL)) {
                die(_("No local or remote refs exist despite at least one remote\n"
-                     "present, stopping; use 'add -f' to overide or fetch a remote first"));
+                     "present, stopping; use 'add -f' to override or fetch a remote first"));
        }
        return 0;
 }
diff --git a/ci/config/README b/ci/config/README
new file mode 100644 (file)
index 0000000..8de3a04
--- /dev/null
@@ -0,0 +1,14 @@
+You can configure some aspects of the GitHub Actions-based CI on a
+per-repository basis by setting "variables" and "secrets" from with the
+GitHub web interface. These can be found at:
+
+  https://github.com/<user>/git/settings/secrets/actions
+
+The following variables can be used:
+
+ - CI_BRANCHES
+
+   By default, CI is run when any branch is pushed. If this variable is
+   non-empty, then only the branches it lists will run CI. Branch names
+   should be separated by spaces, and should use their shortened form
+   (e.g., "main", not "refs/heads/main").
diff --git a/ci/config/allow-ref.sample b/ci/config/allow-ref.sample
deleted file mode 100755 (executable)
index af0e076..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-#
-# Sample script for enabling/disabling GitHub Actions CI runs on
-# particular refs. By default, CI is run for all branches pushed to
-# GitHub. You can override this by dropping the ".sample" from the script,
-# editing it, committing, and pushing the result to the "ci-config" branch of
-# your repository:
-#
-#   git checkout -b ci-config
-#   cp allow-ref.sample allow-ref
-#   $EDITOR allow-ref
-#   git add allow-ref
-#   git commit -am "implement my ci preferences"
-#   git push
-#
-# This script will then be run when any refs are pushed to that repository. It
-# gets the fully qualified refname as the first argument, and should exit with
-# success only for refs for which you want to run CI.
-
-case "$1" in
-# allow one-off tests by pushing to "for-ci" or "for-ci/mybranch"
-refs/heads/for-ci*) true ;;
-# always build your integration branch
-refs/heads/my-integration-branch) true ;;
-# don't build any other branches or tags
-*) false ;;
-esac
index 369d462f1306fbca89442df9be35925ccc272489..6fbb5bade127c33c969f4a3c4d3af40d04fe9d24 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -280,6 +280,8 @@ linux-leaks)
        ;;
 linux-asan-ubsan)
        export SANITIZE=address,undefined
+       export NO_SVN_TESTS=LetsSaveSomeTime
+       MAKEFLAGS="$MAKEFLAGS NO_PYTHON=YepBecauseP4FlakesTooOften"
        ;;
 esac
 
index 0aa1640d15aca59b90617677afd30ef7c8d247c1..9e6eaa8a46b3663979acc32c5b5a2d402d8771ee 100644 (file)
@@ -128,6 +128,16 @@ timestamp_t commit_graph_generation(const struct commit *c)
        return GENERATION_NUMBER_INFINITY;
 }
 
+static timestamp_t commit_graph_generation_from_graph(const struct commit *c)
+{
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       if (!data || data->graph_pos == COMMIT_NOT_FROM_GRAPH)
+               return GENERATION_NUMBER_INFINITY;
+       return data->generation;
+}
+
 static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
 {
        unsigned int i, nth_slab;
@@ -2550,9 +2560,6 @@ static void graph_report(const char *fmt, ...)
        va_end(ap);
 }
 
-#define GENERATION_ZERO_EXISTS 1
-#define GENERATION_NUMBER_EXISTS 2
-
 static int commit_graph_checksum_valid(struct commit_graph *g)
 {
        return hashfile_checksum_valid(g->data, g->data_len);
@@ -2565,7 +2572,8 @@ static int verify_one_commit_graph(struct repository *r,
 {
        uint32_t i, cur_fanout_pos = 0;
        struct object_id prev_oid, cur_oid;
-       int generation_zero = 0;
+       struct commit *seen_gen_zero = NULL;
+       struct commit *seen_gen_non_zero = NULL;
 
        verify_commit_graph_error = verify_commit_graph_lite(g);
        if (verify_commit_graph_error)
@@ -2659,7 +2667,7 @@ static int verify_one_commit_graph(struct repository *r,
                                             oid_to_hex(&graph_parents->item->object.oid),
                                             oid_to_hex(&odb_parents->item->object.oid));
 
-                       generation = commit_graph_generation(graph_parents->item);
+                       generation = commit_graph_generation_from_graph(graph_parents->item);
                        if (generation > max_generation)
                                max_generation = generation;
 
@@ -2671,16 +2679,12 @@ static int verify_one_commit_graph(struct repository *r,
                        graph_report(_("commit-graph parent list for commit %s terminates early"),
                                     oid_to_hex(&cur_oid));
 
-               if (!commit_graph_generation(graph_commit)) {
-                       if (generation_zero == GENERATION_NUMBER_EXISTS)
-                               graph_report(_("commit-graph has generation number zero for commit %s, but non-zero elsewhere"),
-                                            oid_to_hex(&cur_oid));
-                       generation_zero = GENERATION_ZERO_EXISTS;
-               } else if (generation_zero == GENERATION_ZERO_EXISTS)
-                       graph_report(_("commit-graph has non-zero generation number for commit %s, but zero elsewhere"),
-                                    oid_to_hex(&cur_oid));
+               if (commit_graph_generation_from_graph(graph_commit))
+                       seen_gen_non_zero = graph_commit;
+               else
+                       seen_gen_zero = graph_commit;
 
-               if (generation_zero == GENERATION_ZERO_EXISTS)
+               if (seen_gen_zero)
                        continue;
 
                /*
@@ -2706,6 +2710,12 @@ static int verify_one_commit_graph(struct repository *r,
                                     odb_commit->date);
        }
 
+       if (seen_gen_zero && seen_gen_non_zero)
+               graph_report(_("commit-graph has both zero and non-zero "
+                              "generations (e.g., commits '%s' and '%s')"),
+                            oid_to_hex(&seen_gen_zero->object.oid),
+                            oid_to_hex(&seen_gen_non_zero->object.oid));
+
        return verify_commit_graph_error;
 }
 
index 83d95e8656301d29b287801d74bc4dc42af52683..0afda730f278cc776e430ca6b5f44712d5b27f7b 100644 (file)
@@ -479,10 +479,13 @@ struct escape_sequence_entry {
 };
 
 static int sequence_entry_cmp(const void *hashmap_cmp_fn_data UNUSED,
-                             const struct escape_sequence_entry *e1,
-                             const struct escape_sequence_entry *e2,
+                             const struct hashmap_entry *he1,
+                             const struct hashmap_entry *he2,
                              const void *keydata)
 {
+       const struct escape_sequence_entry
+               *e1 = container_of(he1, const struct escape_sequence_entry, entry),
+               *e2 = container_of(he2, const struct escape_sequence_entry, entry);
        return strcmp(e1->sequence, keydata ? keydata : e2->sequence);
 }
 
@@ -496,8 +499,7 @@ static int is_known_escape_sequence(const char *sequence)
                struct strbuf buf = STRBUF_INIT;
                char *p, *eol;
 
-               hashmap_init(&sequences, (hashmap_cmp_fn)sequence_entry_cmp,
-                            NULL, 0);
+               hashmap_init(&sequences, sequence_entry_cmp, NULL, 0);
 
                strvec_pushl(&cp.args, "infocmp", "-L", "-1", NULL);
                if (pipe_command(&cp, NULL, 0, &buf, 0, NULL, 0))
index 133ec92bfae72186721b4a51c50922f6d542be80..55950057c8debd6519282ba98db1c8fa678dc4a3 100644 (file)
@@ -28,6 +28,7 @@
 # completion style.  For example '!f() { : git commit ; ... }; f' will
 # tell the completion to use commit completion.  This also works with aliases
 # of form "!sh -c '...'".  For example, "!sh -c ': git commit ; ... '".
+# Be sure to add a space between the command name and the ';'.
 #
 # If you have a command that is not part of git, but you would still
 # like completion, you can use __git_complete:
@@ -1607,7 +1608,7 @@ _git_checkout ()
 
                if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
                        __git_complete_refs --mode="refs"
-               elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+               elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
                        __git_complete_refs --mode="remote-heads"
                else
                        __git_complete_refs $dwim_opt --mode="refs"
@@ -2514,7 +2515,7 @@ _git_switch ()
 
                if [ -n "$(__git_find_on_cmdline "-c -C -d --detach")" ]; then
                        __git_complete_refs --mode="refs"
-               elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+               elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
                        __git_complete_refs --mode="remote-heads"
                else
                        __git_complete_refs $dwim_opt --mode="heads"
index f5e597114b671fc79cd0acf63c63e5ac427af8bf..17d331b2f38465e295c019e534eff371ef3e6e49 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1243,19 +1243,20 @@ static int serve(struct string_list *listen_addr, int listen_port,
 int cmd_main(int argc, const char **argv)
 {
        int listen_port = 0;
-       struct string_list listen_addr = STRING_LIST_INIT_NODUP;
+       struct string_list listen_addr = STRING_LIST_INIT_DUP;
        int serve_mode = 0, inetd_mode = 0;
        const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
        int detach = 0;
        struct credentials *cred = NULL;
        int i;
+       int ret;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                const char *v;
 
                if (skip_prefix(arg, "--listen=", &v)) {
-                       string_list_append(&listen_addr, xstrdup_tolower(v));
+                       string_list_append_nodup(&listen_addr, xstrdup_tolower(v));
                        continue;
                }
                if (skip_prefix(arg, "--port=", &v)) {
@@ -1437,22 +1438,26 @@ int cmd_main(int argc, const char **argv)
                        die_errno("failed to redirect stderr to /dev/null");
        }
 
-       if (inetd_mode || serve_mode)
-               return execute();
+       if (inetd_mode || serve_mode) {
+               ret = execute();
+       } else {
+               if (detach) {
+                       if (daemonize())
+                               die("--detach not supported on this platform");
+               }
 
-       if (detach) {
-               if (daemonize())
-                       die("--detach not supported on this platform");
-       }
+               if (pid_file)
+                       write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
 
-       if (pid_file)
-               write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
+               /* prepare argv for serving-processes */
+               strvec_push(&cld_argv, argv[0]); /* git-daemon */
+               strvec_push(&cld_argv, "--serve");
+               for (i = 1; i < argc; ++i)
+                       strvec_push(&cld_argv, argv[i]);
 
-       /* prepare argv for serving-processes */
-       strvec_push(&cld_argv, argv[0]); /* git-daemon */
-       strvec_push(&cld_argv, "--serve");
-       for (i = 1; i < argc; ++i)
-               strvec_push(&cld_argv, argv[i]);
+               ret = serve(&listen_addr, listen_port, cred);
+       }
 
-       return serve(&listen_addr, listen_port, cred);
+       string_list_clear(&listen_addr, 0);
+       return ret;
 }
index a5c43c0c1461761bb808b4d6b833222b181843a6..69aeb142b45e9fee08d61dace73f6dc2bce1c2d0 100644 (file)
@@ -81,3 +81,18 @@ void *lookup_decoration(struct decoration *n, const struct object *obj)
                        j = 0;
        }
 }
+
+void clear_decoration(struct decoration *n, void (*free_cb)(void *))
+{
+       if (free_cb) {
+               unsigned int i;
+               for (i = 0; i < n->size; i++) {
+                       void *d = n->entries[i].decoration;
+                       if (d)
+                               free_cb(d);
+               }
+       }
+
+       FREE_AND_NULL(n->entries);
+       n->size = n->nr = 0;
+}
index ee43dee1f008882094ca9c85f6b28b86ec88fdf6..cdeb17c9df2eb680d85e73e8ed2f48b52f44569f 100644 (file)
@@ -58,4 +58,14 @@ void *add_decoration(struct decoration *n, const struct object *obj, void *decor
  */
 void *lookup_decoration(struct decoration *n, const struct object *obj);
 
+/*
+ * Clear all decoration entries, releasing any memory used by the structure.
+ * If free_cb is not NULL, it is called for every decoration value currently
+ * stored.
+ *
+ * After clearing, the decoration struct can be used again. The "name" field is
+ * retained.
+ */
+void clear_decoration(struct decoration *n, void (*free_cb)(void *));
+
 #endif
index 6b0c6a7180cc0432a7e919271dfad74405d30096..5848e4f9ca294052b0e06c7e4d038ebd462ade92 100644 (file)
  * exists for ce that is a submodule -- it is a submodule that is not
  * checked out).  Return negative for an error.
  */
-static int check_removed(const struct index_state *istate, const struct cache_entry *ce, struct stat *st)
+static int check_removed(const struct cache_entry *ce, struct stat *st)
 {
-       assert(is_fsmonitor_refreshed(istate));
-       if (!(ce->ce_flags & CE_FSMONITOR_VALID) && lstat(ce->name, st) < 0) {
+       if (lstat(ce->name, st) < 0) {
                if (!is_missing_file_error(errno))
                        return -1;
                return 1;
        }
+
        if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
                return 1;
        if (S_ISDIR(st->st_mode)) {
@@ -96,7 +96,7 @@ static int match_stat_with_submodule(struct diff_options *diffopt,
        return changed;
 }
 
-int run_diff_files(struct rev_info *revs, unsigned int option)
+void run_diff_files(struct rev_info *revs, unsigned int option)
 {
        int entries, i;
        int diff_unmerged_stage = revs->max_count;
@@ -149,7 +149,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        memset(&(dpath->parent[0]), 0,
                               sizeof(struct combine_diff_parent)*5);
 
-                       changed = check_removed(istate, ce, &st);
+                       changed = check_removed(ce, &st);
                        if (!changed)
                                wt_mode = ce_mode_from_stat(ce, st.st_mode);
                        else {
@@ -229,7 +229,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                } else {
                        struct stat st;
 
-                       changed = check_removed(istate, ce, &st);
+                       changed = check_removed(ce, &st);
                        if (changed) {
                                if (changed < 0) {
                                        perror(ce->name);
@@ -272,7 +272,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        trace_performance_since(start, "diff-files");
-       return 0;
 }
 
 /*
@@ -304,7 +303,7 @@ static int get_stat_data(const struct index_state *istate,
        if (!cached && !ce_uptodate(ce)) {
                int changed;
                struct stat st;
-               changed = check_removed(istate, ce, &st);
+               changed = check_removed(ce, &st);
                if (changed < 0)
                        return -1;
                else if (changed) {
@@ -606,7 +605,7 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
        free_commit_list(merge_bases);
 }
 
-int run_diff_index(struct rev_info *revs, unsigned int option)
+void run_diff_index(struct rev_info *revs, unsigned int option)
 {
        struct object_array_entry *ent;
        int cached = !!(option & DIFF_INDEX_CACHED);
@@ -640,7 +639,6 @@ int run_diff_index(struct rev_info *revs, unsigned int option)
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        trace_performance_leave("diff-index");
-       return 0;
 }
 
 int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
@@ -682,7 +680,7 @@ int index_differs_from(struct repository *r,
                        rev.diffopt.flags.ignore_submodules = flags->ignore_submodules;
        }
        rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
-       run_diff_index(&rev, 1);
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
        has_changes = rev.diffopt.flags.has_changes;
        release_revisions(&rev);
        return (has_changes != 0);
index 4771cf02aa8588b9e7cb162c38e109e42332cf46..e7041b89e38887e04237a00f84366781dbabf739 100644 (file)
@@ -232,6 +232,7 @@ static int queue_diff(struct diff_options *o,
                if (o->flags.reverse_diff) {
                        SWAP(mode1, mode2);
                        SWAP(name1, name2);
+                       SWAP(special1, special2);
                }
 
                d1 = noindex_filespec(name1, mode1, special1);
@@ -364,7 +365,7 @@ int diff_no_index(struct rev_info *revs,
         * The return code for --no-index imitates diff(1):
         * 0 = no changes, 1 = changes, else error
         */
-       ret = diff_result_code(&revs->diffopt, 0);
+       ret = diff_result_code(&revs->diffopt);
 
 out:
        for (i = 0; i < ARRAY_SIZE(to_free); i++)
diff --git a/diff.c b/diff.c
index ee3eb629e3dc5e3010342ed988678d9f0cedd0bd..bccb018da468480615c04d858909891ac59b69e5 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3563,18 +3563,21 @@ static void builtin_diff(const char *name_a,
                strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, meta, two->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
+               o->found_changes = 1;
                must_show_header = 1;
        }
        else if (lbl[1][0] == '/') {
                strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, meta, one->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
+               o->found_changes = 1;
                must_show_header = 1;
        }
        else {
                if (one->mode != two->mode) {
                        strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, meta, one->mode, reset);
                        strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, meta, two->mode, reset);
+                       o->found_changes = 1;
                        must_show_header = 1;
                }
                if (xfrm_msg)
@@ -4832,6 +4835,10 @@ void diff_setup_done(struct diff_options *options)
        else
                options->prefix_length = 0;
 
+       /*
+        * --name-only, --name-status, --checkdiff, and -s
+        * turn other output format off.
+        */
        if (options->output_format & (DIFF_FORMAT_NAME |
                                      DIFF_FORMAT_NAME_STATUS |
                                      DIFF_FORMAT_CHECKDIFF |
@@ -6206,6 +6213,8 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
                fprintf(opt->file, "%s", diff_line_prefix(opt));
                write_name_quoted(name_a, opt->file, opt->line_termination);
        }
+
+       opt->found_changes = 1;
 }
 
 static void show_file_mode_name(struct diff_options *opt, const char *newdelete, struct diff_filespec *fs)
@@ -6684,6 +6693,21 @@ void diff_flush(struct diff_options *options)
                separator++;
        }
 
+       if (output_format & DIFF_FORMAT_PATCH) {
+               if (separator) {
+                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0);
+                       if (options->stat_sep)
+                               /* attach patch instead of inline */
+                               emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP,
+                                                NULL, 0, 0);
+               }
+
+               diff_flush_patch_all_file_pairs(options);
+       }
+
+       if (output_format & DIFF_FORMAT_CALLBACK)
+               options->format_callback(q, options, options->format_callback_data);
+
        if (output_format & DIFF_FORMAT_NO_OUTPUT &&
            options->flags.exit_with_status &&
            options->flags.diff_from_contents) {
@@ -6705,21 +6729,6 @@ void diff_flush(struct diff_options *options)
                }
        }
 
-       if (output_format & DIFF_FORMAT_PATCH) {
-               if (separator) {
-                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0);
-                       if (options->stat_sep)
-                               /* attach patch instead of inline */
-                               emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP,
-                                                NULL, 0, 0);
-               }
-
-               diff_flush_patch_all_file_pairs(options);
-       }
-
-       if (output_format & DIFF_FORMAT_CALLBACK)
-               options->format_callback(q, options, options->format_callback_data);
-
 free_queue:
        diff_free_queue(q);
        DIFF_QUEUE_CLEAR(q);
@@ -6973,16 +6982,14 @@ void diffcore_std(struct diff_options *options)
        options->found_follow = 0;
 }
 
-int diff_result_code(struct diff_options *opt, int status)
+int diff_result_code(struct diff_options *opt)
 {
        int result = 0;
 
        diff_warn_rename_limit("diff.renameLimit",
                               opt->needed_rename_limit,
                               opt->degraded_cc_to_c);
-       if (!opt->flags.exit_with_status &&
-           !(opt->output_format & DIFF_FORMAT_CHECKDIFF))
-               return status;
+
        if (opt->flags.exit_with_status &&
            opt->flags.has_changes)
                result |= 01;
@@ -7029,6 +7036,7 @@ void compute_diffstat(struct diff_options *options,
                if (check_pair_status(p))
                        diff_flush_stat(p, options, diffstat);
        }
+       options->found_changes = !!diffstat->nr;
 }
 
 void diff_addremove(struct diff_options *options,
diff --git a/diff.h b/diff.h
index 260c454155a21af2c133fb78254fdafc20534f7f..caf1528bf077cda0be89882b5ef856fe34dd3999 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -637,17 +637,17 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb);
 #define DIFF_SILENT_ON_REMOVED 01
 /* report racily-clean paths as modified */
 #define DIFF_RACY_IS_MODIFIED 02
-int run_diff_files(struct rev_info *revs, unsigned int option);
+void run_diff_files(struct rev_info *revs, unsigned int option);
 
 #define DIFF_INDEX_CACHED 01
 #define DIFF_INDEX_MERGE_BASE 02
-int run_diff_index(struct rev_info *revs, unsigned int option);
+void run_diff_index(struct rev_info *revs, unsigned int option);
 
 int do_diff_cache(const struct object_id *, struct diff_options *);
 int diff_flush_patch_id(struct diff_options *, struct object_id *, int);
 void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx);
 
-int diff_result_code(struct diff_options *, int);
+int diff_result_code(struct diff_options *);
 
 int diff_no_index(struct rev_info *,
                  int implicit_no_index, int, const char **);
index 65c1ff4bb4fbcdf21b4b13cd427f7a764f60d237..26999e3b6591313a18df430170aaf935d2e24c14 100644 (file)
@@ -1911,10 +1911,10 @@ static void fetch_pack_setup(void)
        if (did_setup)
                return;
        fetch_pack_config();
-       if (0 <= transfer_unpack_limit)
-               unpack_limit = transfer_unpack_limit;
-       else if (0 <= fetch_unpack_limit)
+       if (0 <= fetch_unpack_limit)
                unpack_limit = fetch_unpack_limit;
+       else if (0 <= transfer_unpack_limit)
+               unpack_limit = transfer_unpack_limit;
        did_setup = 1;
 }
 
index d32aa754ae14f518d286a8b2205fd0e1d23b5804..3e7a59b5ff108dddce111cb372b6c846c093b4be 100644 (file)
@@ -422,6 +422,10 @@ char *gitdirname(char *);
 #define PATH_MAX 4096
 #endif
 
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
 typedef uintmax_t timestamp_t;
 #define PRItime PRIuMAX
 #define parse_timestamp strtoumax
index 897cea6564fb504ecfc4efdd59f991cfbab113e9..288ea1ae802dcb88c582085de5a046178b6fbf5e 100755 (executable)
@@ -1166,10 +1166,10 @@ sub extract_valid_address {
 
 sub extract_valid_address_or_die {
        my $address = shift;
-       $address = extract_valid_address($address);
+       my $valid_address = extract_valid_address($address);
        die sprintf(__("error: unable to extract a valid address from: %s\n"), $address)
-               if !$address;
-       return $address;
+               if !$valid_address;
+       return $valid_address;
 }
 
 sub validate_address {
index be987e316f92acda1ff83c880ead3c6848db487c..4e8878f0357ce0d98ae0675b0cabf5c6efb098b2 100755 (executable)
@@ -297,28 +297,12 @@ my %cmd = (
                {} ],
 );
 
-package FakeTerm;
-sub new {
-       my ($class, $reason) = @_;
-       return bless \$reason, shift;
-}
-sub readline {
-       my $self = shift;
-       die "Cannot use readline on FakeTerm: $$self";
-}
-package main;
-
 my $term;
 sub term_init {
-       $term = eval {
-               require Term::ReadLine;
-               $ENV{"GIT_SVN_NOTTY"}
+       require Term::ReadLine;
+       $term = $ENV{"GIT_SVN_NOTTY"}
                        ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
                        : new Term::ReadLine 'git-svn';
-       };
-       if ($@) {
-               $term = new FakeTerm "$@: going non-interactive";
-       }
 }
 
 my $cmd;
diff --git a/http.c b/http.c
index e138b4b96fb9e201623339eada35f9499b5ba371..8f71bf00d8998af44e177a86d73dbc86872c9726 100644 (file)
--- a/http.c
+++ b/http.c
@@ -738,18 +738,43 @@ static int redact_sensitive_header(struct strbuf *header, size_t offset)
        return ret;
 }
 
+static int match_curl_h2_trace(const char *line, const char **out)
+{
+       const char *p;
+
+       /*
+        * curl prior to 8.1.0 gives us:
+        *
+        *     h2h3 [<header-name>: <header-val>]
+        *
+        * Starting in 8.1.0, the first token became just "h2".
+        */
+       if (skip_iprefix(line, "h2h3 [", out) ||
+           skip_iprefix(line, "h2 [", out))
+               return 1;
+
+       /*
+        * curl 8.3.0 uses:
+        *   [HTTP/2] [<stream-id>] [<header-name>: <header-val>]
+        * where <stream-id> is numeric.
+        */
+       if (skip_iprefix(line, "[HTTP/2] [", &p)) {
+               while (isdigit(*p))
+                       p++;
+               if (skip_prefix(p, "] [", out))
+                       return 1;
+       }
+
+       return 0;
+}
+
 /* Redact headers in info */
 static void redact_sensitive_info_header(struct strbuf *header)
 {
        const char *sensitive_header;
 
-       /*
-        * curl's h2h3 prints headers in info, e.g.:
-        *   h2h3 [<header-name>: <header-val>]
-        */
        if (trace_curl_redact &&
-           (skip_iprefix(header->buf, "h2h3 [", &sensitive_header) ||
-            skip_iprefix(header->buf, "h2 [", &sensitive_header))) {
+           match_curl_h2_trace(header->buf, &sensitive_header)) {
                if (redact_sensitive_header(header, sensitive_header - header->buf)) {
                        /* redaction ate our closing bracket */
                        strbuf_addch(header, ']');
index 790ab732127d04df57b330f06b43785532fd68b9..24a1ecb67799c23570ef485bc382b4bbdf2779d2 100644 (file)
@@ -1327,3 +1327,13 @@ int line_log_filter(struct rev_info *rev)
 
        return 0;
 }
+
+static void free_void_line_log_data(void *data)
+{
+       free_line_log_data(data);
+}
+
+void line_log_free(struct rev_info *rev)
+{
+       clear_decoration(&rev->line_log_data, free_void_line_log_data);
+}
index adff361b1bc93905641341df88a7cfcbfb6c118d..4291da8d79235d1f477742a11a5fdb67a4346e2e 100644 (file)
@@ -60,4 +60,6 @@ int line_log_process_ranges_arbitrary_commit(struct rev_info *rev,
 
 int line_log_print(struct rev_info *rev, struct commit *commit);
 
+void line_log_free(struct rev_info *rev);
+
 #endif /* LINE_LOG_H */
index 8631c997002dbbdb1282619c77cc3ac8fd96f880..e5e22e3583fddf2fcebcd01326f8a8a26c4f6864 100644 (file)
@@ -2053,7 +2053,7 @@ static int handle_content_merge(struct merge_options *opt,
         * the three blobs to merge on various sides of history.
         *
         * extra_marker_size is the amount to extend conflict markers in
-        * ll_merge; this is neeed if we have content merges of content
+        * ll_merge; this is needed if we have content merges of content
         * merges, which happens for example with rename/rename(2to1) and
         * rename/add conflicts.
         */
index 57a7fe9d91a1690e59e05838897a8d474aca5de1..4a66ec3bf5f4bfcae08297f4799bdd51222b3b81 100644 (file)
@@ -459,7 +459,6 @@ struct parse_opt_ctx_t {
        unsigned has_subcommands;
        const char *prefix;
        const char **alias_groups; /* must be in groups of 3 elements! */
-       struct option *updated_options;
 };
 
 void parse_options_start(struct parse_opt_ctx_t *ctx,
index 2e86063491e11fcf9162da016be8471f603e07a2..ca5493984a59c8e067b420241091cb919f8e71c9 100644 (file)
@@ -230,16 +230,19 @@ cleanup:
 }
 
 static int patch_util_cmp(const void *cmp_data UNUSED,
-                         const struct patch_util *a,
-                         const struct patch_util *b,
-                         const char *keydata)
+                         const struct hashmap_entry *ha,
+                         const struct hashmap_entry *hb,
+                         const void *keydata)
 {
+       const struct patch_util
+               *a = container_of(ha, const struct patch_util, e),
+               *b = container_of(hb, const struct patch_util, e);
        return strcmp(a->diff, keydata ? keydata : b->diff);
 }
 
 static void find_exact_matches(struct string_list *a, struct string_list *b)
 {
-       struct hashmap map = HASHMAP_INIT((hashmap_cmp_fn)patch_util_cmp, NULL);
+       struct hashmap map = HASHMAP_INIT(patch_util_cmp, NULL);
        int i;
 
        /* First, add the patches of a to a hash map */
index 1bfaf20fbff664b09d1c902be499040c8396e363..9dbc4f71bd272a25423f131bbbbb23152a248be8 100644 (file)
@@ -582,9 +582,10 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
                atom->u.contents.option = C_BARE;
        else if (!strcmp(arg, "body"))
                atom->u.contents.option = C_BODY;
-       else if (!strcmp(arg, "size"))
+       else if (!strcmp(arg, "size")) {
+               atom->type = FIELD_ULONG;
                atom->u.contents.option = C_LENGTH;
-       else if (!strcmp(arg, "signature"))
+       else if (!strcmp(arg, "signature"))
                atom->u.contents.option = C_SIG;
        else if (!strcmp(arg, "subject"))
                atom->u.contents.option = C_SUB;
@@ -690,9 +691,10 @@ static int raw_atom_parser(struct ref_format *format UNUSED,
 {
        if (!arg)
                atom->u.raw_data.option = RAW_BARE;
-       else if (!strcmp(arg, "size"))
+       else if (!strcmp(arg, "size")) {
+               atom->type = FIELD_ULONG;
                atom->u.raw_data.option = RAW_LENGTH;
-       else
+       else
                return err_bad_arg(err, "raw", arg);
        return 0;
 }
@@ -1857,7 +1859,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
                                v->s = xmemdupz(buf, buf_size);
                                v->s_size = buf_size;
                        } else if (atom->u.raw_data.option == RAW_LENGTH) {
-                               v->s = xstrfmt("%"PRIuMAX, (uintmax_t)buf_size);
+                               v->value = buf_size;
+                               v->s = xstrfmt("%"PRIuMAX, v->value);
                        }
                        continue;
                }
@@ -1883,9 +1886,10 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
                        v->s = strbuf_detach(&sb, NULL);
                } else if (atom->u.contents.option == C_BODY_DEP)
                        v->s = xmemdupz(bodypos, bodylen);
-               else if (atom->u.contents.option == C_LENGTH)
-                       v->s = xstrfmt("%"PRIuMAX, (uintmax_t)strlen(subpos));
-               else if (atom->u.contents.option == C_BODY)
+               else if (atom->u.contents.option == C_LENGTH) {
+                       v->value = strlen(subpos);
+                       v->s = xstrfmt("%"PRIuMAX, v->value);
+               } else if (atom->u.contents.option == C_BODY)
                        v->s = xmemdupz(bodypos, nonsiglen);
                else if (atom->u.contents.option == C_SIG)
                        v->s = xmemdupz(sigpos, siglen);
@@ -2265,6 +2269,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
                v->s_size = ATOM_SIZE_UNSPECIFIED;
                v->handler = append_atom;
+               v->value = 0;
                v->atom = atom;
 
                if (*name == '*') {
index 2f4c53ea207b22a68097708b327884ae970c1978..0ae1c76db3e7c991e8333d81db874d072b7c8073 100644 (file)
@@ -3076,6 +3076,11 @@ static void release_revisions_mailmap(struct string_list *mailmap)
 
 static void release_revisions_topo_walk_info(struct topo_walk_info *info);
 
+static void free_void_commit_list(void *list)
+{
+       free_commit_list(list);
+}
+
 void release_revisions(struct rev_info *revs)
 {
        free_commit_list(revs->commits);
@@ -3093,6 +3098,10 @@ void release_revisions(struct rev_info *revs)
        diff_free(&revs->pruning);
        reflog_walk_info_release(revs->reflog_info);
        release_revisions_topo_walk_info(revs->topo_walk_info);
+       clear_decoration(&revs->children, free_void_commit_list);
+       clear_decoration(&revs->merge_simplification, free);
+       clear_decoration(&revs->treesame, free);
+       line_log_free(revs);
 }
 
 static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
index df7358f481cc2d6fd307a27f0bfc5bd070daefd5..fb2940c2a00c94d806319dc8d45e8ffed1231c17 100644 (file)
--- a/scalar.c
+++ b/scalar.c
@@ -409,6 +409,7 @@ static int cmd_clone(int argc, const char **argv)
 {
        const char *branch = NULL;
        int full_clone = 0, single_branch = 0, show_progress = isatty(2);
+       int src = 1;
        struct option clone_options[] = {
                OPT_STRING('b', "branch", &branch, N_("<branch>"),
                           N_("branch to checkout after clone")),
@@ -417,10 +418,13 @@ static int cmd_clone(int argc, const char **argv)
                OPT_BOOL(0, "single-branch", &single_branch,
                         N_("only download metadata for the branch that will "
                            "be checked out")),
+               OPT_BOOL(0, "src", &src,
+                        N_("create repository within 'src' directory")),
                OPT_END(),
        };
        const char * const clone_usage[] = {
-               N_("scalar clone [<options>] [--] <repo> [<dir>]"),
+               N_("scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+                  "\t[--[no-]src] <url> [<enlistment>]"),
                NULL
        };
        const char *url;
@@ -456,7 +460,10 @@ static int cmd_clone(int argc, const char **argv)
        if (is_directory(enlistment))
                die(_("directory '%s' exists already"), enlistment);
 
-       dir = xstrfmt("%s/src", enlistment);
+       if (src)
+               dir = xstrfmt("%s/src", enlistment);
+       else
+               dir = xstrdup(enlistment);
 
        strbuf_reset(&buf);
        if (branch)
@@ -657,6 +664,7 @@ static int cmd_reconfigure(int argc, const char **argv)
        git_config(get_scalar_repos, &scalar_repos);
 
        for (i = 0; i < scalar_repos.nr; i++) {
+               int succeeded = 0;
                const char *dir = scalar_repos.items[i].string;
 
                strbuf_reset(&commondir);
@@ -667,30 +675,56 @@ static int cmd_reconfigure(int argc, const char **argv)
 
                        if (errno != ENOENT) {
                                warning_errno(_("could not switch to '%s'"), dir);
-                               res = -1;
-                               continue;
+                               goto loop_end;
                        }
 
                        strbuf_addstr(&buf, dir);
                        if (remove_deleted_enlistment(&buf))
-                               res = error(_("could not remove stale "
-                                             "scalar.repo '%s'"), dir);
-                       else
-                               warning(_("removing stale scalar.repo '%s'"),
+                               error(_("could not remove stale "
+                                       "scalar.repo '%s'"), dir);
+                       else {
+                               warning(_("removed stale scalar.repo '%s'"),
                                        dir);
+                               succeeded = 1;
+                       }
                        strbuf_release(&buf);
-               } else if (discover_git_directory(&commondir, &gitdir) < 0) {
-                       warning_errno(_("git repository gone in '%s'"), dir);
-                       res = -1;
-               } else {
-                       git_config_clear();
+                       goto loop_end;
+               }
+
+               switch (discover_git_directory_reason(&commondir, &gitdir)) {
+               case GIT_DIR_INVALID_OWNERSHIP:
+                       warning(_("repository at '%s' has different owner"), dir);
+                       goto loop_end;
+
+               case GIT_DIR_INVALID_GITFILE:
+               case GIT_DIR_INVALID_FORMAT:
+                       warning(_("repository at '%s' has a format issue"), dir);
+                       goto loop_end;
+
+               case GIT_DIR_DISCOVERED:
+                       succeeded = 1;
+                       break;
+
+               default:
+                       warning(_("repository not found in '%s'"), dir);
+                       break;
+               }
 
-                       the_repository = &r;
-                       r.commondir = commondir.buf;
-                       r.gitdir = gitdir.buf;
+               git_config_clear();
 
-                       if (set_recommended_config(1) < 0)
-                               res = -1;
+               the_repository = &r;
+               r.commondir = commondir.buf;
+               r.gitdir = gitdir.buf;
+
+               if (set_recommended_config(1) >= 0)
+                       succeeded = 1;
+
+loop_end:
+               if (!succeeded) {
+                       res = -1;
+                       warning(_("to unregister this repository from Scalar, run\n"
+                                 "\tgit config --global --unset --fixed-value scalar.repo \"%s\""),
+                               dir);
                }
        }
 
index 5e0c15a16b73b3bf04fc76afc2bc2bd1c15f677d..42f495c4b42fb152429ca596e0007fd53b774477 100644 (file)
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
+/*
+ * To accommodate common filesystem limitations, where the loose refs' file
+ * names must not exceed `NAME_MAX`, the labels generated by `git rebase
+ * --rebase-merges` need to be truncated if the corresponding commit subjects
+ * are too long.
+ * Add some margin to stay clear from reaching `NAME_MAX`.
+ */
+#define GIT_MAX_LABEL_LENGTH ((NAME_MAX) - (LOCK_SUFFIX_LEN) - 16)
+
 static const char sign_off_header[] = "Signed-off-by: ";
 static const char cherry_picked_prefix[] = "(cherry picked from commit ";
 
@@ -138,6 +147,11 @@ static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
  * the commit object name of the corresponding patch.
  */
 static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
+/*
+ * When we stop for the user to resolve conflicts this file contains
+ * the patch of the commit that is being picked.
+ */
+static GIT_PATH_FUNC(rebase_path_patch, "rebase-merge/patch")
 /*
  * For the post-rewrite hook, we make a list of rewritten commits and
  * their new sha1s.  The rewritten-pending list keeps the sha1s of
@@ -2311,7 +2325,7 @@ static int do_pick_commit(struct repository *r,
                        const char *dest = git_path_squash_msg(r);
                        unlink(dest);
                        if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
-                               res = error(_("could not rename '%s' to '%s'"),
+                               res = error(_("could not copy '%s' to '%s'"),
                                            rebase_path_squash_msg(), dest);
                                goto leave;
                        }
@@ -3392,7 +3406,8 @@ give_advice:
        return -1;
 }
 
-static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts,
+                    int reschedule)
 {
        struct lock_file todo_lock = LOCK_INIT;
        const char *todo_path = get_todo_path(opts);
@@ -3402,7 +3417,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
         * rebase -i writes "git-rebase-todo" without the currently executing
         * command, appending it to "done" instead.
         */
-       if (is_rebase_i(opts))
+       if (is_rebase_i(opts) && !reschedule)
                next++;
 
        fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
@@ -3415,7 +3430,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
        if (commit_lock_file(&todo_lock) < 0)
                return error(_("failed to finalize '%s'"), todo_path);
 
-       if (is_rebase_i(opts) && next > 0) {
+       if (is_rebase_i(opts) && !reschedule && next > 0) {
                const char *done = rebase_path_done();
                int fd = open(done, O_CREAT | O_WRONLY | O_APPEND, 0666);
                int ret = 0;
@@ -3496,18 +3511,19 @@ static int make_patch(struct repository *r,
                      struct commit *commit,
                      struct replay_opts *opts)
 {
-       struct strbuf buf = STRBUF_INIT;
        struct rev_info log_tree_opt;
        const char *subject;
        char hex[GIT_MAX_HEXSZ + 1];
        int res = 0;
 
+       if (!is_rebase_i(opts))
+               BUG("make_patch should only be called when rebasing");
+
        oid_to_hex_r(hex, &commit->object.oid);
        if (write_message(hex, strlen(hex), rebase_path_stopped_sha(), 1) < 0)
                return -1;
        res |= write_rebase_head(&commit->object.oid);
 
-       strbuf_addf(&buf, "%s/patch", get_dir(opts));
        memset(&log_tree_opt, 0, sizeof(log_tree_opt));
        repo_init_revisions(r, &log_tree_opt, NULL);
        log_tree_opt.abbrev = 0;
@@ -3515,28 +3531,26 @@ static int make_patch(struct repository *r,
        log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
        log_tree_opt.disable_stdin = 1;
        log_tree_opt.no_commit_id = 1;
-       log_tree_opt.diffopt.file = fopen(buf.buf, "w");
+       log_tree_opt.diffopt.file = fopen(rebase_path_patch(), "w");
        log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
        if (!log_tree_opt.diffopt.file)
-               res |= error_errno(_("could not open '%s'"), buf.buf);
+               res |= error_errno(_("could not open '%s'"),
+                                  rebase_path_patch());
        else {
                res |= log_tree_commit(&log_tree_opt, commit);
                fclose(log_tree_opt.diffopt.file);
        }
-       strbuf_reset(&buf);
 
-       strbuf_addf(&buf, "%s/message", get_dir(opts));
-       if (!file_exists(buf.buf)) {
+       if (!file_exists(rebase_path_message())) {
                const char *encoding = get_commit_output_encoding();
                const char *commit_buffer = repo_logmsg_reencode(r,
                                                                 commit, NULL,
                                                                 encoding);
                find_commit_subject(commit_buffer, &subject);
-               res |= write_message(subject, strlen(subject), buf.buf, 1);
+               res |= write_message(subject, strlen(subject), rebase_path_message(), 1);
                repo_unuse_commit_buffer(r, commit,
                                         commit_buffer);
        }
-       strbuf_release(&buf);
        release_revisions(&log_tree_opt);
 
        return res;
@@ -4154,6 +4168,7 @@ static int do_merge(struct repository *r,
        if (ret < 0) {
                error(_("could not even attempt to merge '%.*s'"),
                      merge_arg_len, arg);
+               unlink(git_path_merge_msg(r));
                goto leave_merge;
        }
        /*
@@ -4641,6 +4656,68 @@ N_("Could not execute the todo command\n"
 "    git rebase --edit-todo\n"
 "    git rebase --continue\n");
 
+static int pick_one_commit(struct repository *r,
+                          struct todo_list *todo_list,
+                          struct replay_opts *opts,
+                          int *check_todo, int* reschedule)
+{
+       int res;
+       struct todo_item *item = todo_list->items + todo_list->current;
+       const char *arg = todo_item_get_arg(todo_list, item);
+       if (is_rebase_i(opts))
+               opts->reflog_message = reflog_message(
+                       opts, command_to_string(item->command), NULL);
+
+       res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
+                            check_todo);
+       if (is_rebase_i(opts) && res < 0) {
+               /* Reschedule */
+               *reschedule = 1;
+               return -1;
+       }
+       if (item->command == TODO_EDIT) {
+               struct commit *commit = item->commit;
+               if (!res) {
+                       if (!opts->verbose)
+                               term_clear_line();
+                       fprintf(stderr, _("Stopped at %s...  %.*s\n"),
+                               short_commit_name(commit), item->arg_len, arg);
+               }
+               return error_with_patch(r, commit,
+                                       arg, item->arg_len, opts, res, !res);
+       }
+       if (is_rebase_i(opts) && !res)
+               record_in_rewritten(&item->commit->object.oid,
+                                   peek_command(todo_list, 1));
+       if (res && is_fixup(item->command)) {
+               if (res == 1)
+                       intend_to_amend();
+               return error_failed_squash(r, item->commit, opts,
+                                          item->arg_len, arg);
+       } else if (res && is_rebase_i(opts) && item->commit) {
+               int to_amend = 0;
+               struct object_id oid;
+
+               /*
+                * If we are rewording and have either
+                * fast-forwarded already, or are about to
+                * create a new root commit, we want to amend,
+                * otherwise we do not.
+                */
+               if (item->command == TODO_REWORD &&
+                   !repo_get_oid(r, "HEAD", &oid) &&
+                   (oideq(&item->commit->object.oid, &oid) ||
+                    (opts->have_squash_onto &&
+                     oideq(&opts->squash_onto, &oid))))
+                       to_amend = 1;
+
+               return res | error_with_patch(r, item->commit,
+                                             arg, item->arg_len, opts,
+                                             res, to_amend);
+       }
+       return res;
+}
+
 static int pick_commits(struct repository *r,
                        struct todo_list *todo_list,
                        struct replay_opts *opts)
@@ -4656,12 +4733,17 @@ static int pick_commits(struct repository *r,
        if (read_and_refresh_cache(r, opts))
                return -1;
 
+       unlink(rebase_path_message());
+       unlink(rebase_path_stopped_sha());
+       unlink(rebase_path_amend());
+       unlink(rebase_path_patch());
+
        while (todo_list->current < todo_list->nr) {
                struct todo_item *item = todo_list->items + todo_list->current;
                const char *arg = todo_item_get_arg(todo_list, item);
                int check_todo = 0;
 
-               if (save_todo(todo_list, opts))
+               if (save_todo(todo_list, opts, reschedule))
                        return -1;
                if (is_rebase_i(opts)) {
                        if (item->command != TODO_COMMENT) {
@@ -4679,10 +4761,7 @@ static int pick_commits(struct repository *r,
                                                todo_list->total_nr,
                                                opts->verbose ? "\n" : "\r");
                        }
-                       unlink(rebase_path_message());
                        unlink(rebase_path_author_script());
-                       unlink(rebase_path_stopped_sha());
-                       unlink(rebase_path_amend());
                        unlink(git_path_merge_head(r));
                        unlink(git_path_auto_merge(r));
                        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
@@ -4694,66 +4773,10 @@ static int pick_commits(struct repository *r,
                        }
                }
                if (item->command <= TODO_SQUASH) {
-                       if (is_rebase_i(opts))
-                               opts->reflog_message = reflog_message(opts,
-                                     command_to_string(item->command), NULL);
-
-                       res = do_pick_commit(r, item, opts,
-                                            is_final_fixup(todo_list),
-                                            &check_todo);
-                       if (is_rebase_i(opts) && res < 0) {
-                               /* Reschedule */
-                               advise(_(rescheduled_advice),
-                                      get_item_line_length(todo_list,
-                                                           todo_list->current),
-                                      get_item_line(todo_list,
-                                                    todo_list->current));
-                               todo_list->current--;
-                               if (save_todo(todo_list, opts))
-                                       return -1;
-                       }
-                       if (item->command == TODO_EDIT) {
-                               struct commit *commit = item->commit;
-                               if (!res) {
-                                       if (!opts->verbose)
-                                               term_clear_line();
-                                       fprintf(stderr,
-                                               _("Stopped at %s...  %.*s\n"),
-                                               short_commit_name(commit),
-                                               item->arg_len, arg);
-                               }
-                               return error_with_patch(r, commit,
-                                       arg, item->arg_len, opts, res, !res);
-                       }
-                       if (is_rebase_i(opts) && !res)
-                               record_in_rewritten(&item->commit->object.oid,
-                                       peek_command(todo_list, 1));
-                       if (res && is_fixup(item->command)) {
-                               if (res == 1)
-                                       intend_to_amend();
-                               return error_failed_squash(r, item->commit, opts,
-                                       item->arg_len, arg);
-                       } else if (res && is_rebase_i(opts) && item->commit) {
-                               int to_amend = 0;
-                               struct object_id oid;
-
-                               /*
-                                * If we are rewording and have either
-                                * fast-forwarded already, or are about to
-                                * create a new root commit, we want to amend,
-                                * otherwise we do not.
-                                */
-                               if (item->command == TODO_REWORD &&
-                                   !repo_get_oid(r, "HEAD", &oid) &&
-                                   (oideq(&item->commit->object.oid, &oid) ||
-                                    (opts->have_squash_onto &&
-                                     oideq(&opts->squash_onto, &oid))))
-                                       to_amend = 1;
-
-                               return res | error_with_patch(r, item->commit,
-                                               arg, item->arg_len, opts,
-                                               res, to_amend);
-                       }
+                       res = pick_one_commit(r, todo_list, opts, &check_todo,
+                                             &reschedule);
+                       if (!res && item->command == TODO_EDIT)
+                               return 0;
                } else if (item->command == TODO_EXEC) {
                        char *end_of_arg = (char *)(arg + item->arg_len);
                        int saved = *end_of_arg;
@@ -4801,32 +4824,25 @@ static int pick_commits(struct repository *r,
                               get_item_line_length(todo_list,
                                                    todo_list->current),
                               get_item_line(todo_list, todo_list->current));
-                       todo_list->current--;
-                       if (save_todo(todo_list, opts))
+                       if (save_todo(todo_list, opts, reschedule))
                                return -1;
                        if (item->commit)
-                               return error_with_patch(r,
-                                                       item->commit,
-                                                       arg, item->arg_len,
-                                                       opts, res, 0);
+                               write_rebase_head(&item->commit->object.oid);
                } else if (is_rebase_i(opts) && check_todo && !res &&
                           reread_todo_if_changed(r, todo_list, opts)) {
                        return -1;
                }
 
-               todo_list->current++;
                if (res)
                        return res;
+
+               todo_list->current++;
        }
 
        if (is_rebase_i(opts)) {
                struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
                struct stat st;
 
-               /* Stopped in the middle, as planned? */
-               if (todo_list->current < todo_list->nr)
-                       return 0;
-
                if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
                                starts_with(head_ref.buf, "refs/")) {
                        const char *msg;
@@ -4969,6 +4985,11 @@ static int commit_staged_changes(struct repository *r,
 
        is_clean = !has_uncommitted_changes(r, 0);
 
+       if (!is_clean && !file_exists(rebase_path_message())) {
+               const char *gpg_opt = gpg_sign_opt_quoted(opts);
+
+               return error(_(staged_changes_advice), gpg_opt, gpg_opt);
+       }
        if (file_exists(rebase_path_amend())) {
                struct strbuf rev = STRBUF_INIT;
                struct object_id head, to_amend;
@@ -5352,6 +5373,7 @@ struct label_state {
        struct oidmap commit2label;
        struct hashmap labels;
        struct strbuf buf;
+       int max_label_length;
 };
 
 static const char *label_oid(struct object_id *oid, const char *label,
@@ -5408,6 +5430,8 @@ static const char *label_oid(struct object_id *oid, const char *label,
                }
        } else {
                struct strbuf *buf = &state->buf;
+               int label_is_utf8 = 1; /* start with this assumption */
+               size_t max_len = buf->len + state->max_label_length;
 
                /*
                 * Sanitize labels by replacing non-alpha-numeric characters
@@ -5416,14 +5440,34 @@ static const char *label_oid(struct object_id *oid, const char *label,
                 *
                 * Note that we retain non-ASCII UTF-8 characters (identified
                 * via the most significant bit). They should be all acceptable
-                * in file names. We do not validate the UTF-8 here, that's not
-                * the job of this function.
+                * in file names.
+                *
+                * As we will use the labels as names of (loose) refs, it is
+                * vital that the name not be longer than the maximum component
+                * size of the file system (`NAME_MAX`). We are careful to
+                * truncate the label accordingly, allowing for the `.lock`
+                * suffix and for the label to be UTF-8 encoded (i.e. we avoid
+                * truncating in the middle of a character).
                 */
-               for (; *label; label++)
-                       if ((*label & 0x80) || isalnum(*label))
+               for (; *label && buf->len + 1 < max_len; label++)
+                       if (isalnum(*label) ||
+                           (!label_is_utf8 && (*label & 0x80)))
                                strbuf_addch(buf, *label);
+                       else if (*label & 0x80) {
+                               const char *p = label;
+
+                               utf8_width(&p, NULL);
+                               if (p) {
+                                       if (buf->len + (p - label) > max_len)
+                                               break;
+                                       strbuf_add(buf, label, p - label);
+                                       label = p - 1;
+                               } else {
+                                       label_is_utf8 = 0;
+                                       strbuf_addch(buf, *label);
+                               }
                        /* avoid leading dash and double-dashes */
-                       else if (buf->len && buf->buf[buf->len - 1] != '-')
+                       else if (buf->len && buf->buf[buf->len - 1] != '-')
                                strbuf_addch(buf, '-');
                if (!buf->len) {
                        strbuf_addstr(buf, "rev-");
@@ -5485,7 +5529,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
        struct string_entry *entry;
        struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT,
                shown = OIDSET_INIT;
-       struct label_state state = { OIDMAP_INIT, { NULL }, STRBUF_INIT };
+       struct label_state state =
+               { OIDMAP_INIT, { NULL }, STRBUF_INIT, GIT_MAX_LABEL_LENGTH };
 
        int abbr = flags & TODO_LIST_ABBREVIATE_CMDS;
        const char *cmd_pick = abbr ? "p" : "pick",
@@ -5493,6 +5538,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                *cmd_reset = abbr ? "t" : "reset",
                *cmd_merge = abbr ? "m" : "merge";
 
+       git_config_get_int("rebase.maxlabellength", &state.max_label_length);
+
        oidmap_init(&commit2todo, 0);
        oidmap_init(&state.commit2label, 0);
        hashmap_init(&state.labels, labels_cmp, NULL, 0);
@@ -6194,7 +6241,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
        if (checkout_onto(r, opts, onto_name, &oid, orig_head))
                goto cleanup;
 
-       if (require_clean_work_tree(r, "rebase", "", 1, 1))
+       if (require_clean_work_tree(r, "rebase", NULL, 1, 1))
                goto cleanup;
 
        todo_list_write_total_nr(&new_todo);
diff --git a/setup.c b/setup.c
index 18927a847b86bbde543ba5ba539269c9b4e323f1..2e607632dbde807ae76566e282d8f122b1642cda 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1221,19 +1221,6 @@ static const char *allowed_bare_repo_to_string(
        return NULL;
 }
 
-enum discovery_result {
-       GIT_DIR_NONE = 0,
-       GIT_DIR_EXPLICIT,
-       GIT_DIR_DISCOVERED,
-       GIT_DIR_BARE,
-       /* these are errors */
-       GIT_DIR_HIT_CEILING = -1,
-       GIT_DIR_HIT_MOUNT_POINT = -2,
-       GIT_DIR_INVALID_GITFILE = -3,
-       GIT_DIR_INVALID_OWNERSHIP = -4,
-       GIT_DIR_DISALLOWED_BARE = -5,
-};
-
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
@@ -1385,21 +1372,23 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
        }
 }
 
-int discover_git_directory(struct strbuf *commondir,
-                          struct strbuf *gitdir)
+enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
+                                                   struct strbuf *gitdir)
 {
        struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
        size_t gitdir_offset = gitdir->len, cwd_len;
        size_t commondir_offset = commondir->len;
        struct repository_format candidate = REPOSITORY_FORMAT_INIT;
+       enum discovery_result result;
 
        if (strbuf_getcwd(&dir))
-               return -1;
+               return GIT_DIR_CWD_FAILURE;
 
        cwd_len = dir.len;
-       if (setup_git_directory_gently_1(&dir, gitdir, NULL, 0) <= 0) {
+       result = setup_git_directory_gently_1(&dir, gitdir, NULL, 0);
+       if (result <= 0) {
                strbuf_release(&dir);
-               return -1;
+               return result;
        }
 
        /*
@@ -1429,11 +1418,11 @@ int discover_git_directory(struct strbuf *commondir,
                strbuf_setlen(commondir, commondir_offset);
                strbuf_setlen(gitdir, gitdir_offset);
                clear_repository_format(&candidate);
-               return -1;
+               return GIT_DIR_INVALID_FORMAT;
        }
 
        clear_repository_format(&candidate);
-       return 0;
+       return result;
 }
 
 const char *setup_git_directory_gently(int *nongit_ok)
@@ -1515,10 +1504,11 @@ const char *setup_git_directory_gently(int *nongit_ok)
                }
                *nongit_ok = 1;
                break;
-       case GIT_DIR_NONE:
+       case GIT_DIR_CWD_FAILURE:
+       case GIT_DIR_INVALID_FORMAT:
                /*
                 * As a safeguard against setup_git_directory_gently_1 returning
-                * this value, fallthrough to BUG. Otherwise it is possible to
+                * these values, fallthrough to BUG. Otherwise it is possible to
                 * set startup_info->have_repository to 1 when we did nothing to
                 * find a repository.
                 */
diff --git a/setup.h b/setup.h
index 58fd2605dd2697a1c82e1bc81b98a1f783c63d18..b48cf1c43b5a559057a2e92d2fe4250c15255344 100644 (file)
--- a/setup.h
+++ b/setup.h
@@ -42,16 +42,45 @@ const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
 #define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
 
 void setup_work_tree(void);
+
+/*
+ * discover_git_directory_reason() is similar to discover_git_directory(),
+ * except it returns an enum value instead. It is important to note that
+ * a zero-valued return here is actually GIT_DIR_NONE, which is different
+ * from discover_git_directory.
+ */
+enum discovery_result {
+       GIT_DIR_EXPLICIT = 1,
+       GIT_DIR_DISCOVERED = 2,
+       GIT_DIR_BARE = 3,
+       /* these are errors */
+       GIT_DIR_HIT_CEILING = -1,
+       GIT_DIR_HIT_MOUNT_POINT = -2,
+       GIT_DIR_INVALID_GITFILE = -3,
+       GIT_DIR_INVALID_OWNERSHIP = -4,
+       GIT_DIR_DISALLOWED_BARE = -5,
+       GIT_DIR_INVALID_FORMAT = -6,
+       GIT_DIR_CWD_FAILURE = -7,
+};
+enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
+                                                   struct strbuf *gitdir);
+
 /*
  * Find the commondir and gitdir of the repository that contains the current
  * working directory, without changing the working directory or other global
  * state. The result is appended to commondir and gitdir.  If the discovered
  * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
  * both have the same result appended to the buffer.  The return value is
- * either 0 upon success and non-zero if no repository was found.
+ * either 0 upon success and -1 if no repository was found.
  */
-int discover_git_directory(struct strbuf *commondir,
-                          struct strbuf *gitdir);
+static inline int discover_git_directory(struct strbuf *commondir,
+                                        struct strbuf *gitdir)
+{
+       if (discover_git_directory_reason(commondir, gitdir) <= 0)
+               return -1;
+       return 0;
+}
+
 const char *setup_git_directory_gently(int *);
 const char *setup_git_directory(void);
 char *prefix_path(const char *prefix, int len, const char *path);
index 2ed910adaa3da3b5db771679ccb1eefb0a8da2f5..8f59f6be4cff6c53da68ebb4ea7201e71793cbe1 100644 (file)
@@ -72,5 +72,7 @@ int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
        if (objects_noticed != 2)
                BUG("should have 2 objects");
 
+       clear_decoration(&n, NULL);
+
        return 0;
 }
index 4eebd9c2b50f0445b975c46bc660efc9eb90ecd5..83b83c9abb5089186adfd4ac0b647b6f4c673820 100644 (file)
@@ -45,6 +45,7 @@ test_lazy_prereq GPG '
                        "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
                gpg --homedir "${GNUPGHOME}" --import-ownertrust \
                        "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
+               gpg --homedir "${GNUPGHOME}" --update-trustdb &&
                gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null \
                        --sign -u committer@example.com
                ;;
index a22d1386052b40334ddec013ec230af6655fb086..022276a6b9ace5565211327053f9900ff4a1fb06 100644 (file)
@@ -92,6 +92,7 @@ PassEnv GIT_VALGRIND_OPTIONS
 PassEnv GNUPGHOME
 PassEnv ASAN_OPTIONS
 PassEnv LSAN_OPTIONS
+PassEnv UBSAN_OPTIONS
 PassEnv GIT_TRACE
 PassEnv GIT_CONFIG_NOSYSTEM
 PassEnv GIT_TEST_SIDEBAND_ALL
index 8cb597f99c4cead2388681416d3cc0eddd90fa0f..ff4fd9348cca6470f4dbacbc4c9a3d775f15c06d 100755 (executable)
@@ -268,4 +268,13 @@ test_expect_success 'listing and asking for variables are exclusive' '
        test_must_fail git var -l GIT_COMMITTER_IDENT
 '
 
+test_expect_success '`git var -l` works even without HOME' '
+       (
+               XDG_CONFIG_HOME= &&
+               export XDG_CONFIG_HOME &&
+               unset HOME &&
+               git var -l
+       )
+'
+
 test_done
index 028d825e8fb2d1757cd4341d693815bdd1c5642f..36abdca5ee728e4d5d2322641d9d33cdf7e8a7dd 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='Test commit notes with stripspace behavior'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 MULTI_LF="$LF$LF$LF"
index 96a56aafbed67ca7e47ac173c00afdbe17b000ad..8ea2bf13026c1c29d04bfdc715c0901b0c062cf6 100755 (executable)
@@ -604,7 +604,8 @@ test_expect_success 'clean error after failed "exec"' '
        echo "edited again" > file7 &&
        git add file7 &&
        test_must_fail git rebase --continue 2>error &&
-       test_i18ngrep "you have staged changes in your working tree" error
+       test_i18ngrep "you have staged changes in your working tree" error &&
+       test_i18ngrep ! "could not open.*for reading" error
 '
 
 test_expect_success 'rebase a detached HEAD' '
@@ -758,7 +759,7 @@ test_expect_success 'reword' '
        git show HEAD~2 | grep "C changed"
 '
 
-test_expect_success 'no uncommited changes when rewording the todo list is reloaded' '
+test_expect_success 'no uncommitted changes when rewording and the todo list is reloaded' '
        git checkout E &&
        test_when_finished "git checkout @{-1}" &&
        (
@@ -1276,20 +1277,34 @@ test_expect_success 'todo count' '
 '
 
 test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
-       git checkout --force branch2 &&
+       git checkout --force A &&
        git clean -f &&
+       cat >todo <<-EOF &&
+       exec >file2
+       pick $(git rev-parse B) B
+       pick $(git rev-parse C) C
+       pick $(git rev-parse D) D
+       exec cat .git/rebase-merge/done >actual
+       EOF
        (
-               set_fake_editor &&
-               FAKE_LINES="edit 1 2" git rebase -i A
-       ) &&
-       test_cmp_rev HEAD F &&
-       test_path_is_missing file6 &&
-       >file6 &&
-       test_must_fail git rebase --continue &&
-       test_cmp_rev HEAD F &&
-       rm file6 &&
+               set_replace_editor todo &&
+               test_must_fail git rebase -i A
+       ) &&
+       test_cmp_rev HEAD B &&
+       test_cmp_rev REBASE_HEAD C &&
+       head -n3 todo >expect &&
+       test_cmp expect .git/rebase-merge/done &&
+       rm file2 &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
+       git reset --hard HEAD &&
        git rebase --continue &&
-       test_cmp_rev HEAD I
+       test_cmp_rev HEAD D &&
+       tail -n3 todo >>expect &&
+       test_cmp expect actual
 '
 
 test_expect_success 'rebase -i commits that overwrite untracked files (squash)' '
@@ -1305,7 +1320,14 @@ test_expect_success 'rebase -i commits that overwrite untracked files (squash)'
        >file6 &&
        test_must_fail git rebase --continue &&
        test_cmp_rev HEAD F &&
+       test_cmp_rev REBASE_HEAD I &&
        rm file6 &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
+       git reset --hard HEAD &&
        git rebase --continue &&
        test $(git cat-file commit HEAD | sed -ne \$p) = I &&
        git reset --hard original-branch2
@@ -1323,7 +1345,14 @@ test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' '
        >file6 &&
        test_must_fail git rebase --continue &&
        test $(git cat-file commit HEAD | sed -ne \$p) = F &&
+       test_cmp_rev REBASE_HEAD I &&
        rm file6 &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
+       git reset --hard HEAD &&
        git rebase --continue &&
        test $(git cat-file commit HEAD | sed -ne \$p) = I
 '
index fb7b68990cc33a6cbd08ba7031d405713db87446..c4e2fcac67e5886d47a392097dd14e2bd0141a73 100755 (executable)
@@ -268,6 +268,24 @@ test_expect_success 'the todo command "break" works' '
        test_path_is_file execed
 '
 
+test_expect_success 'patch file is removed before break command' '
+       test_when_finished "git rebase --abort" &&
+       cat >todo <<-\EOF &&
+       pick commit-new-file-F2-on-topic-branch
+       break
+       EOF
+
+       (
+               set_replace_editor todo &&
+               test_must_fail git rebase -i --onto commit-new-file-F2 HEAD
+       ) &&
+       test_path_is_file .git/rebase-merge/patch &&
+       echo 22>F2 &&
+       git add F2 &&
+       git rebase --continue &&
+       test_path_is_missing .git/rebase-merge/patch
+'
+
 test_expect_success '--reschedule-failed-exec' '
        test_when_finished "git rebase --abort" &&
        test_must_fail git rebase -x false --reschedule-failed-exec HEAD^ &&
index 96ae0edf1e17275825c2f6fdd57f09431834ed77..59b5d6b6f276c367862df92f847db37906715004 100755 (executable)
@@ -128,14 +128,24 @@ test_expect_success 'generate correct todo list' '
 '
 
 test_expect_success '`reset` refuses to overwrite untracked files' '
-       git checkout -b refuse-to-reset &&
+       git checkout B &&
        test_commit dont-overwrite-untracked &&
-       git checkout @{-1} &&
-       : >dont-overwrite-untracked.t &&
-       echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
+       cat >script-from-scratch <<-EOF &&
+       exec >dont-overwrite-untracked.t
+       pick $(git rev-parse B) B
+       reset refs/tags/dont-overwrite-untracked
+       pick $(git rev-parse C) C
+       exec cat .git/rebase-merge/done >actual
+       EOF
        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
-       test_must_fail git rebase -ir HEAD &&
-       git rebase --abort
+       test_must_fail git rebase -ir A &&
+       test_cmp_rev HEAD B &&
+       head -n3 script-from-scratch >expect &&
+       test_cmp expect .git/rebase-merge/done &&
+       rm dont-overwrite-untracked.t &&
+       git rebase --continue &&
+       tail -n3 script-from-scratch >>expect &&
+       test_cmp expect actual
 '
 
 test_expect_success '`reset` rejects trees' '
@@ -165,12 +175,16 @@ test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' '
        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
        test_tick &&
        test_must_fail git rebase -ir HEAD &&
+       test_cmp_rev REBASE_HEAD H^0 &&
        grep "^merge -C .* G$" .git/rebase-merge/done &&
        grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
-       test_path_is_file .git/rebase-merge/patch &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
 
        : fail because of merge conflict &&
-       rm G.t .git/rebase-merge/patch &&
        git reset --hard conflicting-G &&
        test_must_fail git rebase --continue &&
        ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
@@ -586,4 +600,15 @@ test_expect_success 'progress shows the correct total' '
        test_line_count = 14 progress
 '
 
+test_expect_success 'truncate label names' '
+       commit=$(git commit-tree -p HEAD^ -p HEAD -m "0123456789 æˆ‘ 123" HEAD^{tree}) &&
+       git merge --ff-only $commit &&
+
+       done="$(git rev-parse --git-path rebase-merge/done)" &&
+       git -c rebase.maxLabelLength=14 rebase --rebase-merges -x "cp \"$done\" out" --root &&
+       grep "label 0123456789-我$" out &&
+       git -c rebase.maxLabelLength=13 rebase --rebase-merges -x "cp \"$done\" out" --root &&
+       grep "label 0123456789-$" out
+'
+
 test_done
index b298f220e01fe6de17a5dfe608550a5a57dcf9c6..fcd2473e5290dc5a25d643e6af139378fe7ebdc5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # Copyright (c) 2006 Johannes E. Schindelin
-#
+# Copyright (c) 2023 Google LLC
 
 test_description='Test special whitespace in diff engine.
 
@@ -11,6 +11,43 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \
+              --raw! --name-only! --name-status!
+do
+       opts=${opt_res%!} expect_failure=
+       test "$opts" = "$opt_res" ||
+               expect_failure="test_expect_code 1"
+
+       test_expect_success "status with $opts (different)" '
+               echo foo >x &&
+               git add x &&
+               echo bar >x &&
+               test_expect_code 1 git diff -w $opts --exit-code x
+       '
+
+       test_expect_success POSIXPERM "status with $opts (mode differs)" '
+               test_when_finished "git update-index --chmod=-x x" &&
+               echo foo >x &&
+               git add x &&
+               git update-index --chmod=+x x &&
+               test_expect_code 1 git diff -w $opts --exit-code x
+       '
+
+       test_expect_success "status with $opts (removing an empty file)" '
+               : >x &&
+               git add x &&
+               rm x &&
+               test_expect_code 1 git diff -w $opts --exit-code -- x
+       '
+
+       test_expect_success "status with $opts (different but equivalent)" '
+               echo foo >x &&
+               git add x &&
+               echo " foo" >x &&
+               $expect_failure git diff -w $opts --exit-code x
+       '
+done
+
 test_expect_success "Ray Lehtiniemi's example" '
        cat <<-\EOF >x &&
        do {
index 5bc28ad9f042a0476d94d9e90e5b58073cc17f99..f439f469bd2bfd3942a61e104fd290d8e3461e19 100755 (executable)
@@ -138,4 +138,9 @@ test_expect_success 'check honors conflict marker length' '
        git reset --hard
 '
 
+test_expect_success 'option errors are not confused by --exit-code' '
+       test_must_fail git diff --exit-code --nonsense 2>err &&
+       grep '^usage:' err
+'
+
 test_done
index e70e020ae9349c378b4b922933668932e95acc8d..eec3d73dc2b475be7185d9d1dc8733bf391a868b 100755 (executable)
@@ -28,8 +28,7 @@ test_expect_success 'diff-tree --exit-code' '
 
 test_expect_success 'diff-tree -b --exit-code' '
        git diff -b --exit-code HEAD^ HEAD &&
-       git diff-tree -b -p --exit-code HEAD^ HEAD &&
-       git diff-tree -b --exit-code HEAD^ HEAD
+       git diff-tree -b -p --exit-code HEAD^ HEAD
 '
 
 test_expect_success 'diff-index --cached --exit-code' '
index 6781cc90786e3eb247b83f107a5407d50ba139f3..5f059f65fced87fd0c25400cec0ed1a50b24edb4 100755 (executable)
@@ -224,6 +224,25 @@ test_expect_success "diff --no-index treats '-' as stdin" '
        test_must_be_empty actual
 '
 
+test_expect_success "diff --no-index -R treats '-' as stdin" '
+       cat >expect <<-EOF &&
+       diff --git b/a/1 a/-
+       index $(git hash-object --stdin <a/1)..$ZERO_OID 100644
+       --- b/a/1
+       +++ a/-
+       @@ -1 +1 @@
+       -1
+       +x
+       EOF
+
+       test_write_lines x | test_expect_code 1 \
+               git -c core.abbrev=no diff --no-index -R -- - a/1 >actual &&
+       test_cmp expect actual &&
+
+       test_write_lines 1 | git diff --no-index -R -- a/1 - >actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'diff --no-index refuses to diff stdin and a directory' '
        test_must_fail git diff --no-index -- - a </dev/null 2>err &&
        grep "fatal: cannot compare stdin to a directory" err
index 6e01e2629c1b158464ab29e4086fb4eeea16bbaa..613f0710e90511c6419e843eec3cb4d11aafc437 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git log with filter options limiting the output'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup test' '
index 4df76173a8d774b56f60f12c7ee23372d11b7143..ba65f17dd9cc863a9a92ae90393af3ffdd2309de 100755 (executable)
@@ -450,14 +450,15 @@ GRAPH_BYTE_FANOUT2=$(($GRAPH_FANOUT_OFFSET + 4 * 255))
 GRAPH_OID_LOOKUP_OFFSET=$(($GRAPH_FANOUT_OFFSET + 4 * 256))
 GRAPH_BYTE_OID_LOOKUP_ORDER=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 8))
 GRAPH_BYTE_OID_LOOKUP_MISSING=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 4 + 10))
+GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16))
 GRAPH_COMMIT_DATA_OFFSET=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * $NUM_COMMITS))
 GRAPH_BYTE_COMMIT_TREE=$GRAPH_COMMIT_DATA_OFFSET
 GRAPH_BYTE_COMMIT_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN))
 GRAPH_BYTE_COMMIT_EXTRA_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 4))
 GRAPH_BYTE_COMMIT_WRONG_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 3))
 GRAPH_BYTE_COMMIT_GENERATION=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 11))
+GRAPH_BYTE_COMMIT_GENERATION_LAST=$(($GRAPH_BYTE_COMMIT_GENERATION + $(($NUM_COMMITS - 1)) * $GRAPH_COMMIT_DATA_WIDTH))
 GRAPH_BYTE_COMMIT_DATE=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 12))
-GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16))
 GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \
                             $GRAPH_COMMIT_DATA_WIDTH * $NUM_COMMITS))
 GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4))
@@ -596,11 +597,6 @@ test_expect_success 'detect incorrect generation number' '
                "generation for commit"
 '
 
-test_expect_success 'detect incorrect generation number' '
-       corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\01" \
-               "commit-graph generation for commit"
-'
-
 test_expect_success 'detect incorrect commit date' '
        corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATE "\01" \
                "commit date"
@@ -622,6 +618,16 @@ test_expect_success 'detect incorrect chunk count' '
                $GRAPH_CHUNK_LOOKUP_OFFSET
 '
 
+test_expect_success 'detect mixed generation numbers (non-zero to zero)' '
+       corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION_LAST "\0\0\0\0" \
+               "both zero and non-zero generations"
+'
+
+test_expect_success 'detect mixed generation numbers (zero to non-zero)' '
+       corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\0\0\0\0" \
+               "both zero and non-zero generations"
+'
+
 test_expect_success 'git fsck (checks commit-graph when config set to true)' '
        git -C full fsck &&
        corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
index 5f3ff051ca2fa3bba8beabbcb1491d5e69262f34..ad7f8c6f00202c5ec844108b14a2c1301c185223 100755 (executable)
@@ -17,6 +17,12 @@ test_expect_success 'setup' '
        git checkout A^0 &&
        test_commit E bar E &&
        test_commit F foo F &&
+       git checkout B &&
+       git merge E &&
+       git tag merge-E &&
+       test_commit G G &&
+       test_commit H H &&
+       test_commit I I &&
        git checkout main &&
 
        test_hook --setup post-rewrite <<-EOF
@@ -173,6 +179,48 @@ test_fail_interactive_rebase () {
        )
 }
 
+test_expect_success 'git rebase with failed pick' '
+       clear_hook_input &&
+       cat >todo <<-\EOF &&
+       exec >bar
+       merge -C merge-E E
+       exec >G
+       pick G
+       exec >H 2>I
+       pick H
+       fixup I
+       EOF
+
+       (
+               set_replace_editor todo &&
+               test_must_fail git rebase -i D D 2>err
+       ) &&
+       grep "would be overwritten" err &&
+       rm bar &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "would be overwritten" err &&
+       rm G &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "would be overwritten" err &&
+       rm H &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "would be overwritten" err &&
+       rm I &&
+
+       git rebase --continue &&
+       echo rebase >expected.args &&
+       cat >expected.data <<-EOF &&
+       $(git rev-parse merge-E) $(git rev-parse HEAD~2)
+       $(git rev-parse G) $(git rev-parse HEAD~1)
+       $(git rev-parse H) $(git rev-parse HEAD)
+       $(git rev-parse I) $(git rev-parse HEAD)
+       EOF
+       verify_hook_input
+'
+
 test_expect_success 'git rebase -i (unchanged)' '
        git reset --hard D &&
        clear_hook_input &&
index 4f289063ced85dc2beabde28788c191a20bf9634..19c36b57f4b2d5363599625ea71ee5a9a87509b0 100755 (executable)
@@ -1127,6 +1127,52 @@ do
        '
 done
 
+test_expect_success 'prepare source branch' '
+       echo one >onebranch &&
+       git checkout --orphan onebranch &&
+       git rm --cached -r . &&
+       git add onebranch &&
+       git commit -m onebranch &&
+       git rev-list --objects onebranch -- >actual &&
+       # 3 objects should be created, at least ...
+       test 3 -le $(wc -l <actual)
+'
+
+validate_store_type () {
+       git -C dest count-objects -v >actual &&
+       case "$store_type" in
+       packed)
+               grep "^count: 0$" actual ;;
+       loose)
+               grep "^packs: 0$" actual ;;
+       esac || {
+               echo "store_type is $store_type"
+               cat actual
+               false
+       }
+}
+
+test_unpack_limit () {
+       store_type=$1
+
+       case "$store_type" in
+       packed) fetch_limit=1 transfer_limit=10000 ;;
+       loose) fetch_limit=10000 transfer_limit=1 ;;
+       esac
+
+       test_expect_success "fetch trumps transfer limit" '
+               rm -fr dest &&
+               git --bare init dest &&
+               git -C dest config fetch.unpacklimit $fetch_limit &&
+               git -C dest config transfer.unpacklimit $transfer_limit &&
+               git -C dest fetch .. onebranch &&
+               validate_store_type
+       '
+}
+
+test_unpack_limit packed
+test_unpack_limit loose
+
 setup_negotiation_tip () {
        SERVER="$1"
        URL="$2"
index eed3c9d81abaffa8886b44f26224111b369735ce..9fc9ba552f1db320a595dcf7b5b23c31b5c855b1 100755 (executable)
@@ -9,10 +9,26 @@ TEST_PASSES_SANITIZE_LEAK=true
 # When the limit is 1, `git receive-pack` will call `git index-pack`.
 # When the limit is 10000, `git receive-pack` will call `git unpack-objects`.
 
+validate_store_type () {
+       git -C dest count-objects -v >actual &&
+       case "$store_type" in
+       index)
+               grep "^count: 0$" actual ;;
+       unpack)
+               grep "^packs: 0$" actual ;;
+       esac || {
+               echo "store_type is $store_type"
+               cat actual
+               false;
+       }
+}
+
 test_pack_input_limit () {
-       case "$1" in
-       index) unpack_limit=1 ;;
-       unpack) unpack_limit=10000 ;;
+       store_type=$1
+
+       case "$store_type" in
+       index) unpack_limit=1 other_limit=10000 ;;
+       unpack) unpack_limit=10000 other_limit=1 ;;
        esac
 
        test_expect_success 'prepare destination repository' '
@@ -43,6 +59,19 @@ test_pack_input_limit () {
                git --git-dir=dest config receive.maxInputSize 0 &&
                git push dest HEAD
        '
+
+       test_expect_success 'prepare destination repository (once more)' '
+               rm -fr dest &&
+               git --bare init dest
+       '
+
+       test_expect_success 'receive trumps transfer' '
+               git --git-dir=dest config receive.unpacklimit "$unpack_limit" &&
+               git --git-dir=dest config transfer.unpacklimit "$other_limit" &&
+               git push dest HEAD &&
+               validate_store_type
+       '
+
 }
 
 test_expect_success "create known-size (1024 bytes) commit" '
index a11b20e378223ea30242e70d5befcfeed889a2ed..448134c4bf72bd5f3a4c2287e59f6f2a1f3f074b 100755 (executable)
@@ -4,6 +4,7 @@ test_description='check pre-push hooks'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index e7e1b6dab66fb31d065c4dc7611c824a7bc1bf5b..320f49c753f41376ad757aedf134a76bd6206a68 100755 (executable)
@@ -5,6 +5,7 @@ test_description='check the consisitency of behavior of --all and --branches'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 delete_refs() {
index 8ac6b2a1d0a286cac120c751e5e3038e465dc074..ed773e7432694b7ccc05a4d09084f238c9ff4b42 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test disabling of git-over-tcp in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-proto-disable.sh"
 . "$TEST_DIRECTORY/lib-git-daemon.sh"
index 5b434ab451cf614752210a7e6ed6e420363f1963..7b943fd34cdece8c4fca0b55e4fab8510ac4b7b1 100755 (executable)
@@ -1017,16 +1017,16 @@ test_expect_success 'Verify sorts with raw' '
 test_expect_success 'Verify sorts with raw:size' '
        cat >expected <<-EOF &&
        refs/myblobs/blob8
-       refs/myblobs/first
        refs/myblobs/blob7
-       refs/heads/main
        refs/myblobs/blob4
        refs/myblobs/blob1
        refs/myblobs/blob2
        refs/myblobs/blob3
        refs/myblobs/blob5
        refs/myblobs/blob6
+       refs/myblobs/first
        refs/mytrees/first
+       refs/heads/main
        EOF
        git for-each-ref --format="%(refname)" --sort=raw:size \
                refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
@@ -1138,6 +1138,17 @@ test_expect_success 'for-each-ref --format compare with cat-file --batch' '
        test_cmp expected actual
 '
 
+test_expect_success 'verify sorts with contents:size' '
+       cat >expect <<-\EOF &&
+       refs/heads/main
+       refs/heads/newtag
+       refs/heads/ambiguous
+       EOF
+       git for-each-ref --format="%(refname)" \
+               --sort=contents:size refs/heads/ >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'set up multiple-sort tags' '
        for when in 100000 200000
        do
@@ -1763,10 +1774,7 @@ test_expect_success GPGSSH 'setup for signature atom using ssh' '
 '
 
 test_expect_success GPG2 'bare signature atom' '
-       git verify-commit first-signed 2>out.raw &&
-       grep -Ev "checking the trustdb|PGP trust model" out.raw >out &&
-       head -3 out >expect &&
-       tail -1 out >>expect &&
+       git verify-commit first-signed 2>expect &&
        echo  >>expect &&
        git for-each-ref refs/tags/first-signed \
                --format="%(signature)" >actual &&
index 2d38a16480e82c0441075e0e54ffe8454b413cb2..bb95f09810b704b552352d90b6ec2a046c7d0fc1 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git commit races'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'race to create orphan commit' '
index 0c241d6c148d7b5ebc9a9b3aaf44723fb1028e8b..78503158fd699d2df75e8fbbbaf164a129f2578b 100755 (executable)
@@ -809,6 +809,11 @@ my_match_and_clean () {
                status --porcelain=v2 >actual.without &&
        test_cmp actual.with actual.without &&
 
+       git -C super --no-optional-locks diff-index --name-status HEAD >actual.with &&
+       git -C super --no-optional-locks -c core.fsmonitor=false \
+               diff-index --name-status HEAD >actual.without &&
+       test_cmp actual.with actual.without &&
+
        git -C super/dir_1/dir_2/sub reset --hard &&
        git -C super/dir_1/dir_2/sub clean -d -f
 }
index a60b05ad3f09f03433e2b7fe96e095966ddb104a..263db3ad17ff2591029267d5272cc16850b6c72c 100755 (executable)
@@ -61,8 +61,8 @@ test_no_confirm () {
                --smtp-server="$(pwd)/fake.sendmail" \
                $@ \
                $patches >stdout &&
-               ! grep "Send this email" stdout &&
-               >no_confirm_okay
+       ! grep "Send this email" stdout &&
+       >no_confirm_okay
 }
 
 # Exit immediately to prevent hang if a no-confirm test fails
index 7e8894a4a70648fd12d3ab4425f1beac2c3e4641..590aab0304c679b6559df0e840ddce6dacc684af 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='check that example code compiles and runs'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'decorate' '
index 872ad1c9c2b156bf25797b2651c69e9749cf391e..7869f45ee646dd511b16e404a8b165200f9c8608 100755 (executable)
@@ -180,4 +180,16 @@ test_expect_success 'scalar clone warns when background maintenance fails' '
        grep "could not turn on maintenance" err
 '
 
+test_expect_success '`scalar clone --no-src`' '
+       scalar clone --src "file://$(pwd)/to-clone" with-src &&
+       scalar clone --no-src "file://$(pwd)/to-clone" without-src &&
+
+       test_path_is_dir with-src/src &&
+       test_path_is_missing without-src/src &&
+
+       (cd with-src/src && ls ?*) >with &&
+       (cd without-src && ls ?*) >without &&
+       test_cmp with without
+'
+
 test_done
index 8835e16e8110f458885c977d4002685a2fc16662..47e20fb8b149de244a9336e509b0852b87281000 100755 (executable)
@@ -1622,14 +1622,22 @@ test_expect_success 'git checkout - with -d, complete only references' '
 '
 
 test_expect_success 'git switch - with --track, complete only remote branches' '
-       test_completion "git switch --track " <<-\EOF
+       test_completion "git switch --track " <<-\EOF &&
+       other/branch-in-other Z
+       other/main-in-other Z
+       EOF
+       test_completion "git switch -t " <<-\EOF
        other/branch-in-other Z
        other/main-in-other Z
        EOF
 '
 
 test_expect_success 'git checkout - with --track, complete only remote branches' '
-       test_completion "git checkout --track " <<-\EOF
+       test_completion "git checkout --track " <<-\EOF &&
+       other/branch-in-other Z
+       other/main-in-other Z
+       EOF
+       test_completion "git checkout -t " <<-\EOF
        other/branch-in-other Z
        other/main-in-other Z
        EOF
index 293caf0f20e67a366b347064875c60061ecabf89..1656c9eed006bdce115ed6e7673246847319783a 100644 (file)
@@ -89,6 +89,9 @@ prepend_var LSAN_OPTIONS : $GIT_SAN_OPTIONS
 prepend_var LSAN_OPTIONS : fast_unwind_on_malloc=0
 export LSAN_OPTIONS
 
+prepend_var UBSAN_OPTIONS : $GIT_SAN_OPTIONS
+export UBSAN_OPTIONS
+
 if test ! -f "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
 then
        echo >&2 'error: GIT-BUILD-OPTIONS missing (has Git been built?).'
@@ -334,6 +337,7 @@ nr_san_dir_leaks_ () {
        find "$TEST_RESULTS_SAN_DIR" \
                -type f \
                -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null |
+       xargs grep -lv "Unable to get registers from thread" |
        wc -l
 }
 
index 94751477ab2d1e1ee28c291d3b1aaaa75e5fe3d4..83f3d2651ab3feee758178f86394627ffe4f76b0 100644 (file)
@@ -801,11 +801,12 @@ error:
        for (i = 0; i < data->want_obj.nr; i++) {
                struct object *o = data->want_obj.objects[i].item;
                if (!is_our_ref(o, data->allow_uor)) {
+                       error("git upload-pack: not our ref %s",
+                             oid_to_hex(&o->oid));
                        packet_writer_error(&data->writer,
                                            "upload-pack: not our ref %s",
                                            oid_to_hex(&o->oid));
-                       die("git upload-pack: not our ref %s",
-                           oid_to_hex(&o->oid));
+                       exit(128);
                }
        }
 }
index 5b1378965c9aa37505a23cf9c472f1abe4d8503e..d03dfab9e47d128b15295e499c8113346a593cf7 100644 (file)
@@ -675,7 +675,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
        rev.diffopt.flags.recursive = 1;
 
        copy_pathspec(&rev.prune_data, &s->pathspec);
-       run_diff_index(&rev, 1);
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
        release_revisions(&rev);
 }
 
@@ -1156,7 +1156,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
                rev.diffopt.a_prefix = "c/";
                rev.diffopt.b_prefix = "i/";
        } /* else use prefix as per user config */
-       run_diff_index(&rev, 1);
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
        if (s->verbose > 1 &&
            wt_status_check_worktree_changes(s, &dirty_submodules)) {
                status_printf_ln(s, c,
@@ -2580,8 +2580,8 @@ int has_unstaged_changes(struct repository *r, int ignore_submodules)
        }
        rev_info.diffopt.flags.quick = 1;
        diff_setup_done(&rev_info.diffopt);
-       result = run_diff_files(&rev_info, 0);
-       result = diff_result_code(&rev_info.diffopt, result);
+       run_diff_files(&rev_info, 0);
+       result = diff_result_code(&rev_info.diffopt);
        release_revisions(&rev_info);
        return result;
 }
@@ -2614,8 +2614,8 @@ int has_uncommitted_changes(struct repository *r,
        }
 
        diff_setup_done(&rev_info.diffopt);
-       result = run_diff_index(&rev_info, 1);
-       result = diff_result_code(&rev_info.diffopt, result);
+       run_diff_index(&rev_info, DIFF_INDEX_CACHED);
+       result = diff_result_code(&rev_info.diffopt);
        release_revisions(&rev_info);
        return result;
 }
@@ -2655,8 +2655,12 @@ int require_clean_work_tree(struct repository *r,
        }
 
        if (err) {
-               if (hint)
+               if (hint) {
+                       if (!*hint)
+                               BUG("empty hint passed to require_clean_work_tree();"
+                                   " use NULL instead");
                        error("%s", hint);
+               }
                if (!gently)
                        exit(128);
        }