diff options
153 files changed, 2137 insertions, 1341 deletions
@@ -35,11 +35,13 @@ Chris Wright <chrisw@sous-sol.org> <chrisw@osdl.org> Cord Seele <cowose@gmail.com> <cowose@googlemail.com> Christian Couder <chriscool@tuxfamily.org> <christian.couder@gmail.com> Christian Stimming <stimming@tuhh.de> <chs@ckiste.goetheallee> +Christopher DÃaz Riveros <chrisadr@gentoo.org> Christopher Diaz Riveros Csaba Henk <csaba@gluster.com> <csaba@lowlife.hu> Dan Johnson <computerdruid@gmail.com> Dana L. How <danahow@gmail.com> <how@deathvalley.cswitch.com> Dana L. How <danahow@gmail.com> Dana How Daniel Barkalow <barkalow@iabervon.org> +Daniel Knittl-Frank <knittl89@googlemail.com> knittl Daniel Trstenjak <daniel.trstenjak@gmail.com> <daniel.trstenjak@online.de> Daniel Trstenjak <daniel.trstenjak@gmail.com> <trsten@science-computing.de> David Brown <git@davidb.org> <davidb@quicinc.com> @@ -57,6 +59,7 @@ Eric S. Raymond <esr@thyrsus.com> Eric Wong <e@80x24.org> <normalperson@yhbt.net> Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com> Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com> <eyvind-git@orakel.ntnu.no> +Fangyi Zhou <fangyi.zhou@yuriko.moe> Zhou Fangyi Florian Achleitner <florian.achleitner.2.6.31@gmail.com> <florian.achleitner2.6.31@gmail.com> Franck Bui-Huu <vagabon.xyz@gmail.com> <fbuihuu@gmail.com> Frank Lichtenheld <frank@lichtenheld.de> <djpig@debian.org> @@ -86,6 +89,8 @@ Jason McMullan <mcmullan@netapp.com> Jason Riedy <ejr@eecs.berkeley.edu> <ejr@EECS.Berkeley.EDU> Jason Riedy <ejr@eecs.berkeley.edu> <ejr@cs.berkeley.edu> Jay Soffian <jaysoffian@gmail.com> <jaysoffian+git@gmail.com> +Jean-Noël Avila <jn.avila@free.fr> Jean-Noel Avila +Jean-Noël Avila <jn.avila@free.fr> Jean-Noël AVILA Jeff King <peff@peff.net> <peff@github.com> Jeff Muizelaar <jmuizelaar@mozilla.com> <jeff@infidigm.net> Jens Axboe <axboe@kernel.dk> <axboe@suse.de> @@ -149,6 +154,7 @@ Matt Draisey <matt@draisey.ca> <mattdraisey@sympatico.ca> Matt Kraai <kraai@ftbfs.org> <matt.kraai@amo.abbott.com> Matt McCutchen <matt@mattmccutchen.net> <hashproduct@gmail.com> Matthias Kestenholz <matthias@spinlock.ch> <mk@spinlock.ch> +Matthias Rüster <matthias.ruester@gmail.com> Matthias Ruester Matthias Urlichs <matthias@urlichs.de> <smurf@kiste.(none)> Matthias Urlichs <matthias@urlichs.de> <smurf@smurf.noris.de> Michael Coleman <tutufan@gmail.com> @@ -213,6 +219,8 @@ Sean Estabrooks <seanlkml@sympatico.ca> Sebastian Schuberth <sschuberth@gmail.com> <sschuberth@visageimaging.com> Seth Falcon <seth@userprimary.net> <sfalcon@fhcrc.org> Shawn O. Pearce <spearce@spearce.org> +Wei Shuyu <wsy@dogben.com> Shuyu Wei +Sidhant Sharma <tigerkid001@gmail.com> Sidhant Sharma [:tk] Simon Hausmann <hausmann@kde.org> <simon@lst.de> Simon Hausmann <hausmann@kde.org> <shausman@trolltech.com> Stefan Beller <stefanbeller@gmail.com> <stefanbeller@googlemail.com> @@ -253,7 +261,8 @@ Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <ukleinek@informatik.uni-frei Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <uzeisberger@io.fsforth.de> Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <zeisberg@informatik.uni-freiburg.de> Ville Skyttä <ville.skytta@iki.fi> <scop@xemacs.org> -Vitaly "_Vi" Shukela <public_vi@tut.by> +Vitaly "_Vi" Shukela <vi0oss@gmail.com> <public_vi@tut.by> +Vitaly "_Vi" Shukela <vi0oss@gmail.com> Vitaly _Vi Shukela W. Trevor King <wking@tremily.us> <wking@drexel.edu> William Pursell <bill.pursell@gmail.com> YONETANI Tomokazu <y0n3t4n1@gmail.com> <qhwt+git@les.ath.cx> diff --git a/Documentation/RelNotes/2.19.0.txt b/Documentation/RelNotes/2.19.0.txt index 2b45b6ff5c..f2e261abf3 100644 --- a/Documentation/RelNotes/2.19.0.txt +++ b/Documentation/RelNotes/2.19.0.txt @@ -15,6 +15,15 @@ UI, Workflows & Features otherwise working-tree-only application of a patch will add new paths to the index marked with the "intent-to-add" bit. + * "git grep" learned the "--column" option that gives not just the + line number but the column number of the hit. + + * The "-l" option in "git branch -l" is an unfortunate short-hand for + "--create-reflog", but many users, both old and new, somehow expect + it to be something else, perhaps "--list". This step warns when "-l" + is used as a short-hand for "--create-reflog" and warns about the + future repurposing of the it when it is used. + Performance, Internal Implementation, Development Support etc. @@ -51,6 +60,18 @@ Performance, Internal Implementation, Development Support etc. * Build and test procedure for netrc credential helper (in contrib/) has been updated. + * The conversion to pass "the_repository" and then "a_repository" + throughout the object access API continues. + + * Remove unused function definitions and declarations from ewah + bitmap subsystem. + + * Code preparation to make "git p4" closer to be usable with Python 3. + + * Tighten the API to make it harder to misuse in-tree .gitmodules + file, even though it shares the same syntax with configuration + files, to read random configuration items from it. + Fixes since v2.18 ----------------- @@ -96,6 +117,43 @@ Fixes since v2.18 to the submodule was changed in the range of commits in the superproject, sometimes showing "(null)". This has been corrected. - * Code cleanup. + * "git submodule" did not correctly adjust core.worktree setting that + indicates whether/where a submodule repository has its associated + working tree across various state transitions, which has been + corrected. + (merge 984cd77ddb sb/submodule-core-worktree later to maint). + + * Bugfix for "rebase -i" corner case regression. + (merge a9279c6785 pw/rebase-i-keep-reword-after-conflict later to maint). + + * Recently added "--base" option to "git format-patch" command did + not correctly generate prereq patch ids. + (merge 15b76c1fb3 xy/format-patch-prereq-patch-id-fix later to maint). + + * POSIX portability fix in Makefile to fix a glitch introduced a few + releases ago. + (merge 6600054e9b dj/runtime-prefix later to maint). + + * "git filter-branch" when used with the "--state-branch" option + still attempted to rewrite the commits whose filtered result is + known from the previous attempt (which is recorded on the state + branch); the command has been corrected not to waste cycles doing + so. + (merge 709cfe848a mb/filter-branch-optim later to maint). + + * Clarify that setting core.ignoreCase to deviate from reality would + not turn a case-incapable filesystem into a case-capable one. + (merge 48294b512a ms/core-icase-doc later to maint). + + * Code cleanup, docfix, build fix, etc. (merge aee9be2ebe sg/update-ref-stdin-cleanup later to maint). (merge 037714252f jc/clean-after-sanity-tests later to maint). + (merge 5b26c3c941 en/merge-recursive-cleanup later to maint). + (merge 0dcbc0392e bw/config-refer-to-gitsubmodules-doc later to maint). + (merge bb4d000e87 bw/protocol-v2 later to maint). + (merge 928f0ab4ba vs/typofixes later to maint). + (merge d7f590be84 en/rebase-i-microfixes later to maint). + (merge 81d395cc85 js/rebase-recreate-merge later to maint). + (merge 51d1863168 tz/exclude-doc-smallfixes later to maint). + (merge a9aa3c0927 ds/commit-graph later to maint). + (merge 5cf8e06474 js/enhanced-version-info later to maint). diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 2488544407..b44fd51f27 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -298,7 +298,7 @@ smaller project it is a good discipline to follow it. The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have -the right to pass it on as a open-source patch. The rules are +the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below D-C-O: [[dco]] @@ -403,7 +403,7 @@ don't demand). +git log -p {litdd} _$area_you_are_modifying_+ would help you find out who they are. . You get comments and suggestions for improvements. You may - even get them in a "on top of your change" patch form. + even get them in an "on top of your change" patch form. . Polish, refine, and re-send to the list and the people who spend their time to improve your patch. Go back to step (2). diff --git a/Documentation/config.txt b/Documentation/config.txt index 1cc18a828c..a32172a43c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -354,7 +354,7 @@ advice.*:: Advice on what to do when you've accidentally added one git repo inside of another. ignoredHook:: - Advice shown if an hook is ignored because the hook is not + Advice shown if a hook is ignored because the hook is not set as executable. waitingForEditor:: Print a message to the terminal whenever Git is waiting for @@ -390,16 +390,19 @@ core.hideDotFiles:: default mode is 'dotGitOnly'. core.ignoreCase:: - If true, this option enables various workarounds to enable + Internal variable which enables various workarounds to enable Git to work better on filesystems that are not case sensitive, - like FAT. For example, if a directory listing finds - "makefile" when Git expects "Makefile", Git will assume + like APFS, HFS+, FAT, NTFS, etc. For example, if a directory listing + finds "makefile" when Git expects "Makefile", Git will assume it is really the same file, and continue to remember it as "Makefile". + The default is false, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.ignoreCase true if appropriate when the repository is created. ++ +Git relies on the proper configuration of this variable for your operating +and file system. Modifying this value may result in unexpected behavior. core.precomposeUnicode:: This option is only used by Mac OS implementation of Git. @@ -1182,8 +1185,10 @@ color.grep.<slot>:: filename prefix (when not using `-h`) `function`;; function name lines (when using `-p`) -`linenumber`;; +`lineNumber`;; line number prefix (when using `-n`) +`column`;; + column number prefix (when using `--column`) `match`;; matching text (same as setting `matchContext` and `matchSelected`) `matchContext`;; @@ -1798,6 +1803,9 @@ gitweb.snapshot:: grep.lineNumber:: If set to true, enable `-n` option by default. +grep.column:: + If set to true, enable the `--column` option by default. + grep.patternType:: Set the default matching behavior. Using a value of 'basic', 'extended', 'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`, @@ -3328,12 +3336,13 @@ submodule.<name>.ignore:: submodule.<name>.active:: Boolean value indicating if the submodule is of interest to git commands. This config option takes precedence over the - submodule.active config option. + submodule.active config option. See linkgit:gitsubmodules[7] for + details. submodule.active:: A repeated field which contains a pathspec used to match against a submodule's path to determine if the submodule is of interest to git - commands. + commands. See linkgit:gitsubmodules[7] for details. submodule.recurse:: Specifies if commands recurse into submodules by default. This diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt index 78479b003e..0f9ef2f25e 100644 --- a/Documentation/git-bisect-lk2009.txt +++ b/Documentation/git-bisect-lk2009.txt @@ -1103,7 +1103,7 @@ _____________ Combining test suites, git bisect and other systems together ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -We have seen that test suites an git bisect are very powerful when +We have seen that test suites and git bisect are very powerful when used together. It can be even more powerful if you can combine them with other systems. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 02eccbb931..1072ca0eb6 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -91,7 +91,6 @@ OPTIONS -D:: Shortcut for `--delete --force`. --l:: --create-reflog:: Create the branch's reflog. This activates recording of all changes made to the branch ref, enabling use of date @@ -101,6 +100,8 @@ OPTIONS The negated form `--no-create-reflog` only overrides an earlier `--create-reflog`, but currently does not negate the setting of `core.logAllRefUpdates`. ++ +The `-l` option is a deprecated synonym for `--create-reflog`. -f:: --force:: diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 312409a607..0de3493b80 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -13,7 +13,7 @@ SYNOPSIS [-v | --invert-match] [-h|-H] [--full-name] [-E | --extended-regexp] [-G | --basic-regexp] [-P | --perl-regexp] - [-F | --fixed-strings] [-n | --line-number] + [-F | --fixed-strings] [-n | --line-number] [--column] [-l | --files-with-matches] [-L | --files-without-match] [(-O | --open-files-in-pager) [<pager>]] [-z | --null] @@ -44,6 +44,9 @@ CONFIGURATION grep.lineNumber:: If set to true, enable `-n` option by default. +grep.column:: + If set to true, enable the `--column` option by default. + grep.patternType:: Set the default matching behavior. Using a value of 'basic', 'extended', 'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`, @@ -169,6 +172,10 @@ providing this option will cause it to die. --line-number:: Prefix the line number to matching lines. +--column:: + Prefix the 1-indexed byte-offset of the first match from the start of the + matching line. + -l:: --files-with-matches:: --name-only:: diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt index 032613c420..7b157441eb 100644 --- a/Documentation/git-imap-send.txt +++ b/Documentation/git-imap-send.txt @@ -68,8 +68,8 @@ imap.tunnel:: to the server. Required when imap.host is not set. imap.host:: - A URL identifying the server. Use a `imap://` prefix for non-secure - connections and a `imaps://` prefix for secure connections. + A URL identifying the server. Use an `imap://` prefix for non-secure + connections and an `imaps://` prefix for secure connections. Ignored when imap.tunnel is set, but required otherwise. imap.user:: diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index e8dec1b3c8..df2b64dbb6 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -199,7 +199,7 @@ OPTIONS .git/NOTES_MERGE_REF symref is updated to the resulting commit. --abort:: - Abort/reset a in-progress 'git notes merge', i.e. a notes merge + Abort/reset an in-progress 'git notes merge', i.e. a notes merge with conflicts. This simply removes all files related to the notes merge. diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 0e20a66e73..a7850415b1 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD. --keep-empty:: Keep the commits that do not change anything from its parents in the result. ++ +See also INCOMPATIBLE OPTIONS below. --allow-empty-message:: By default, rebasing commits with an empty message will fail. This option overrides that behavior, allowing commits with empty messages to be rebased. ++ +See also INCOMPATIBLE OPTIONS below. --skip:: Restart the rebasing process by skipping the current patch. @@ -271,6 +275,8 @@ branch on top of the <upstream> branch. Because of this, when a merge conflict happens, the side reported as 'ours' is the so-far rebased series, starting with <upstream>, and 'theirs' is the working branch. In other words, the sides are swapped. ++ +See also INCOMPATIBLE OPTIONS below. -s <strategy>:: --strategy=<strategy>:: @@ -280,8 +286,10 @@ other words, the sides are swapped. + Because 'git rebase' replays each commit from the working branch on top of the <upstream> branch using the given strategy, using -the 'ours' strategy simply discards all patches from the <branch>, +the 'ours' strategy simply empties all patches from the <branch>, which makes little sense. ++ +See also INCOMPATIBLE OPTIONS below. -X <strategy-option>:: --strategy-option=<strategy-option>:: @@ -289,6 +297,8 @@ which makes little sense. This implies `--merge` and, if no strategy has been specified, `-s recursive`. Note the reversal of 'ours' and 'theirs' as noted above for the `-m` option. ++ +See also INCOMPATIBLE OPTIONS below. -S[<keyid>]:: --gpg-sign[=<keyid>]:: @@ -324,17 +334,21 @@ which makes little sense. and after each change. When fewer lines of surrounding context exist they all must match. By default no context is ever ignored. ++ +See also INCOMPATIBLE OPTIONS below. --f:: +--no-ff:: --force-rebase:: - Force a rebase even if the current branch is up to date and - the command without `--force` would return without doing anything. +-f:: + Individually replay all rebased commits instead of fast-forwarding + over the unchanged ones. This ensures that the entire history of + the rebased branch is composed of new commits. + -You may find this (or --no-ff with an interactive rebase) helpful after -reverting a topic branch merge, as this option recreates the topic branch with -fresh commits so it can be remerged successfully without needing to "revert -the reversion" (see the -link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details). +You may find this helpful after reverting a topic branch merge, as this option +recreates the topic branch with fresh commits so it can be remerged +successfully without needing to "revert the reversion" (see the +link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for +details). --fork-point:: --no-fork-point:: @@ -355,19 +369,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`. --whitespace=<option>:: These flag are passed to the 'git apply' program (see linkgit:git-apply[1]) that applies the patch. - Incompatible with the --interactive option. ++ +See also INCOMPATIBLE OPTIONS below. --committer-date-is-author-date:: --ignore-date:: These flags are passed to 'git am' to easily change the dates of the rebased commits (see linkgit:git-am[1]). - Incompatible with the --interactive option. ++ +See also INCOMPATIBLE OPTIONS below. --signoff:: Add a Signed-off-by: trailer to all the rebased commits. Note that if `--interactive` is given then only commits marked to be - picked, edited or reworded will have the trailer added. Incompatible - with the `--preserve-merges` option. + picked, edited or reworded will have the trailer added. ++ +See also INCOMPATIBLE OPTIONS below. -i:: --interactive:: @@ -378,6 +395,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`. The commit list format can be changed by setting the configuration option rebase.instructionFormat. A customized instruction format will automatically have the long commit hash prepended to the format. ++ +See also INCOMPATIBLE OPTIONS below. -r:: --rebase-merges[=(rebase-cousins|no-rebase-cousins)]:: @@ -404,7 +423,7 @@ It is currently only possible to recreate the merge commits using the `recursive` merge strategy; Different merge strategies can be used only via explicit `exec git merge -s <strategy> [...]` commands. + -See also REBASING MERGES below. +See also REBASING MERGES and INCOMPATIBLE OPTIONS below. -p:: --preserve-merges:: @@ -415,6 +434,8 @@ See also REBASING MERGES below. This uses the `--interactive` machinery internally, but combining it with the `--interactive` option explicitly is generally not a good idea unless you know what you are doing (see BUGS below). ++ +See also INCOMPATIBLE OPTIONS below. -x <cmd>:: --exec <cmd>:: @@ -437,6 +458,8 @@ squash/fixup series. + This uses the `--interactive` machinery internally, but it can be run without an explicit `--interactive`. ++ +See also INCOMPATIBLE OPTIONS below. --root:: Rebase all commits reachable from <branch>, instead of @@ -447,6 +470,8 @@ without an explicit `--interactive`. When used together with both --onto and --preserve-merges, 'all' root commits will be rewritten to have <newbase> as parent instead. ++ +See also INCOMPATIBLE OPTIONS below. --autosquash:: --no-autosquash:: @@ -461,11 +486,11 @@ without an explicit `--interactive`. too. The recommended way to create fixup/squash commits is by using the `--fixup`/`--squash` options of linkgit:git-commit[1]. + -This option is only valid when the `--interactive` option is used. -+ If the `--autosquash` option is enabled by default using the configuration variable `rebase.autoSquash`, this option can be used to override and disable this setting. ++ +See also INCOMPATIBLE OPTIONS below. --autostash:: --no-autostash:: @@ -475,17 +500,73 @@ used to override and disable this setting. with care: the final stash application after a successful rebase might result in non-trivial conflicts. ---no-ff:: - With --interactive, cherry-pick all rebased commits instead of - fast-forwarding over the unchanged ones. This ensures that the - entire history of the rebased branch is composed of new commits. -+ -Without --interactive, this is a synonym for --force-rebase. -+ -You may find this helpful after reverting a topic branch merge, as this option -recreates the topic branch with fresh commits so it can be remerged -successfully without needing to "revert the reversion" (see the -link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details). +INCOMPATIBLE OPTIONS +-------------------- + +git-rebase has many flags that are incompatible with each other, +predominantly due to the fact that it has three different underlying +implementations: + + * one based on linkgit:git-am[1] (the default) + * one based on git-merge-recursive (merge backend) + * one based on linkgit:git-cherry-pick[1] (interactive backend) + +Flags only understood by the am backend: + + * --committer-date-is-author-date + * --ignore-date + * --whitespace + * --ignore-whitespace + * -C + +Flags understood by both merge and interactive backends: + + * --merge + * --strategy + * --strategy-option + * --allow-empty-message + +Flags only understood by the interactive backend: + + * --[no-]autosquash + * --rebase-merges + * --preserve-merges + * --interactive + * --exec + * --keep-empty + * --autosquash + * --edit-todo + * --root when used in combination with --onto + +Other incompatible flag pairs: + + * --preserve-merges and --interactive + * --preserve-merges and --signoff + * --preserve-merges and --rebase-merges + * --rebase-merges and --strategy + * --rebase-merges and --strategy-option + +BEHAVIORAL DIFFERENCES +----------------------- + + * empty commits: + + am-based rebase will drop any "empty" commits, whether the + commit started empty (had no changes relative to its parent to + start with) or ended empty (all changes were already applied + upstream in other commits). + + merge-based rebase does the same. + + interactive-based rebase will by default drop commits that + started empty and halt if it hits a commit that ended up empty. + The `--keep-empty` option exists for interactive rebases to allow + it to keep commits that started empty. + + * directory rename detection: + + merge-based and interactive-based rebases work fine with + directory rename detection. am-based rebases sometimes do not. include::merge-strategies.txt[] @@ -804,7 +885,7 @@ The ripple effect of a "hard case" recovery is especially bad: case" recovery too! REBASING MERGES ------------------ +--------------- The interactive rebase command was originally designed to handle individual patch series. As such, it makes sense to exclude merge diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index c4467ffb98..d9f422d560 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -106,7 +106,7 @@ It is optional: it defaults to 'traditional'. The possible options are: + - 'traditional' - Shows ignored files and directories, unless - --untracked-files=all is specifed, in which case + --untracked-files=all is specified, in which case individual files in ignored directories are displayed. - 'no' - Show no ignored files. diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 7ea24fc942..b99029520d 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -452,7 +452,7 @@ Any other arguments are passed directly to 'git log' 'commit-diff':: Commits the diff of two tree-ish arguments from the - command-line. This command does not rely on being inside an `git svn + command-line. This command does not rely on being inside a `git svn init`-ed repository. This command takes three arguments, (a) the original tree to diff against, (b) the new tree result, (c) the URL of the target Subversion repository. The final argument diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt index 10c8ff93c0..9f2528fc8c 100644 --- a/Documentation/giteveryday.txt +++ b/Documentation/giteveryday.txt @@ -244,7 +244,7 @@ commands in addition to the ones needed by participants. This section can also be used by those who respond to `git request-pull` or pull-request on GitHub (www.github.com) to -integrate the work of others into their history. An sub-area +integrate the work of others into their history. A sub-area lieutenant for a repository will act both as a participant and as an integrator. diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index ff5d7f9ed6..d107daaffd 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -7,7 +7,7 @@ gitignore - Specifies intentionally untracked files to ignore SYNOPSIS -------- -$HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore +$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore DESCRIPTION ----------- diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt index 3b9faabdbb..504c5f1a88 100644 --- a/Documentation/gitsubmodules.txt +++ b/Documentation/gitsubmodules.txt @@ -194,7 +194,7 @@ In the above config only the submodule 'bar' and 'baz' are active, Note that (c) is a historical artefact and will be ignored if the (a) and (b) specify that the submodule is not active. In other words, -if we have an `submodule.<name>.active` set to `false` or if the +if we have a `submodule.<name>.active` set to `false` or if the submodule's path is excluded in the pathspec in `submodule.active`, the url doesn't matter whether it is present or not. This is illustrated in the example that follows. diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 6c2d23dc48..0d2aa48c63 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -334,7 +334,7 @@ The optional colon that terminates the "magic signature" can be omitted if the pattern begins with a character that does not belong to "magic signature" symbol set and is not a colon. + -In the long form, the leading colon `:` is followed by a open +In the long form, the leading colon `:` is followed by an open parenthesis `(`, a comma-separated list of zero or more "magic words", and a close parentheses `)`, and the remainder is the pattern to match against the path. diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt index 4f44ca24f6..5abb8e8b1f 100644 --- a/Documentation/technical/api-directory-listing.txt +++ b/Documentation/technical/api-directory-listing.txt @@ -54,7 +54,7 @@ The notable options are: this case, the contents are returned as individual entries. + If this is set, files and directories that explicitly match an ignore -pattern are reported. Implicity ignored directories (directories that +pattern are reported. Implicitly ignored directories (directories that do not match an ignore pattern, but whose contents are all ignored) are not reported, instead all of the contents are reported. diff --git a/Documentation/technical/api-gitattributes.txt b/Documentation/technical/api-gitattributes.txt index e7cbb7c13a..45f0df600f 100644 --- a/Documentation/technical/api-gitattributes.txt +++ b/Documentation/technical/api-gitattributes.txt @@ -146,7 +146,7 @@ To get the values of all attributes associated with a file: * Iterate over the `attr_check.items[]` array to examine the attribute names and values. The name of the attribute - described by a `attr_check.items[]` object can be retrieved via + described by an `attr_check.items[]` object can be retrieved via `git_attr_name(check->items[i].attr)`. (Please note that no items will be returned for unset attributes, so `ATTR_UNSET()` will return false for all returned `attr_check.items[]` objects.) diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt index ad6af8105c..cc0474ba3e 100644 --- a/Documentation/technical/commit-graph-format.txt +++ b/Documentation/technical/commit-graph-format.txt @@ -18,9 +18,9 @@ metadata, including: the graph file. These positional references are stored as unsigned 32-bit integers -corresponding to the array position withing the list of commit OIDs. We -use the most-significant bit for special purposes, so we can store at most -(1 << 31) - 1 (around 2 billion) commits. +corresponding to the array position within the list of commit OIDs. Due +to some special constants we use to track parents, we can store at most +(1 << 30) + (1 << 29) + (1 << 28) - 1 (around 1.8 billion) commits. == Commit graph files have the following format: @@ -70,10 +70,10 @@ CHUNK DATA: OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes) The OIDs for all commits in the graph, sorted in ascending order. - Commit Data (ID: {'C', 'G', 'E', 'T' }) (N * (H + 16) bytes) + Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes) * The first H bytes are for the OID of the root tree. * The next 8 bytes are for the positions of the first two parents - of the ith commit. Stores value 0xffffffff if no parent in that + of the ith commit. Stores value 0x7000000 if no parent in that position. If there are more than two parents, the second value has its most-significant bit on and the other bits store an array position into the Large Edge List chunk. diff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt new file mode 100644 index 0000000000..1c0086e287 --- /dev/null +++ b/Documentation/technical/directory-rename-detection.txt @@ -0,0 +1,115 @@ +Directory rename detection +========================== + +Rename detection logic in diffcore-rename that checks for renames of +individual files is aggregated and analyzed in merge-recursive for cases +where combinations of renames indicate that a full directory has been +renamed. + +Scope of abilities +------------------ + +It is perhaps easiest to start with an example: + + * When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is + likely that x/d added in the meantime would also want to move to z/d by + taking the hint that the entire directory 'x' moved to 'z'. + +More interesting possibilities exist, though, such as: + + * one side of history renames x -> z, and the other renames some file to + x/e, causing the need for the merge to do a transitive rename. + + * one side of history renames x -> z, but also renames all files within + x. For example, x/a -> z/alpha, x/b -> z/bravo, etc. + + * both 'x' and 'y' being merged into a single directory 'z', with a + directory rename being detected for both x->z and y->z. + + * not all files in a directory being renamed to the same location; + i.e. perhaps most the files in 'x' are now found under 'z', but a few + are found under 'w'. + + * a directory being renamed, which also contained a subdirectory that was + renamed to some entirely different location. (And perhaps the inner + directory itself contained inner directories that were renamed to yet + other locations). + + * combinations of the above; see t/t6043-merge-rename-directories.sh for + various interesting cases. + +Limitations -- applicability of directory renames +------------------------------------------------- + +In order to prevent edge and corner cases resulting in either conflicts +that cannot be represented in the index or which might be too complex for +users to try to understand and resolve, a couple basic rules limit when +directory rename detection applies: + + 1) If a given directory still exists on both sides of a merge, we do + not consider it to have been renamed. + + 2) If a subset of to-be-renamed files have a file or directory in the + way (or would be in the way of each other), "turn off" the directory + rename for those specific sub-paths and report the conflict to the + user. + + 3) If the other side of history did a directory rename to a path that + your side of history renamed away, then ignore that particular + rename from the other side of history for any implicit directory + renames (but warn the user). + +Limitations -- detailed rules and testcases +------------------------------------------- + +t/t6043-merge-rename-directories.sh contains extensive tests and commentary +which generate and explore the rules listed above. It also lists a few +additional rules: + + a) If renames split a directory into two or more others, the directory + with the most renames, "wins". + + b) Avoid directory-rename-detection for a path, if that path is the + source of a rename on either side of a merge. + + c) Only apply implicit directory renames to directories if the other side + of history is the one doing the renaming. + +Limitations -- support in different commands +-------------------------------------------- + +Directory rename detection is supported by 'merge' and 'cherry-pick'. +Other git commands which users might be surprised to see limited or no +directory rename detection support in: + + * diff + + Folks have requested in the past that `git diff` detect directory + renames and somehow simplify its output. It is not clear whether this + would be desirable or how the output should be simplified, so this was + simply not implemented. Further, to implement this, directory rename + detection logic would need to move from merge-recursive to + diffcore-rename. + + * am + + git-am tries to avoid a full three way merge, instead calling + git-apply. That prevents us from detecting renames at all, which may + defeat the directory rename detection. There is a fallback, though; if + the initial git-apply fails and the user has specified the -3 option, + git-am will fall back to a three way merge. However, git-am lacks the + necessary information to do a "real" three way merge. Instead, it has + to use build_fake_ancestor() to get a merge base that is missing files + whose rename may have been important to detect for directory rename + detection to function. + + * rebase + + Since am-based rebases work by first generating a bunch of patches + (which no longer record what the original commits were and thus don't + have the necessary info from which we can find a real merge-base), and + then calling git-am, this implies that am-based rebases will not always + successfully detect directory renames either (see the 'am' section + above). merged-based rebases (rebase -m) and cherry-pick-based rebases + (rebase -i) are not affected by this shortcoming, and fully support + directory rename detection. diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt index 49bda76d23..f58f24b1ef 100644 --- a/Documentation/technical/protocol-v2.txt +++ b/Documentation/technical/protocol-v2.txt @@ -64,9 +64,8 @@ When using the http:// or https:// transport a client makes a "smart" info/refs request as described in `http-protocol.txt` and requests that v2 be used by supplying "version=2" in the `Git-Protocol` header. - C: Git-Protocol: version=2 - C: C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0 + C: Git-Protocol: version=2 A v2 server would reply: @@ -2021,8 +2021,9 @@ version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT version.sp version.s version.o: EXTRA_CPPFLAGS = \ '-DGIT_VERSION="$(GIT_VERSION)"' \ '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)' \ - '-DGIT_BUILT_FROM_COMMIT="$(shell GIT_CEILING_DIRECTORIES=\"$(CURDIR)/..\" \ - git rev-parse -q --verify HEAD || :)"' + '-DGIT_BUILT_FROM_COMMIT="$(shell \ + GIT_CEILING_DIRECTORIES="$(CURDIR)/.." \ + git rev-parse -q --verify HEAD 2>/dev/null)"' $(BUILT_INS): git$X $(QUIET_BUILT_IN)$(RM) $@ && \ @@ -2110,7 +2111,7 @@ $(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE $(QUIET_GEN)$(RM) $@ $@+ && \ sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ - -e ' rGIT-PERL-HEADER' \ + -e ' r GIT-PERL-HEADER' \ -e ' G' \ -e '}' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ @@ -9,6 +9,7 @@ #include "cache.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "delta.h" #include "diff.h" diff --git a/archive-tar.c b/archive-tar.c index b6f58ddf38..7df8565246 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -5,6 +5,7 @@ #include "config.h" #include "tar.h" #include "archive.h" +#include "object-store.h" #include "streaming.h" #include "run-command.h" diff --git a/archive-zip.c b/archive-zip.c index 74f3fe9103..abc556e5a7 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -6,6 +6,7 @@ #include "archive.h" #include "streaming.h" #include "utf8.h" +#include "object-store.h" #include "userdiff.h" #include "xdiff-interface.h" @@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "tree-walk.h" #include "attr.h" @@ -1,5 +1,6 @@ #include "cache.h" #include "refs.h" +#include "object-store.h" #include "cache-tree.h" #include "mergesort.h" #include "diff.h" @@ -129,17 +130,19 @@ static void append_merge_parents(struct commit_list **tail) int merge_head; struct strbuf line = STRBUF_INIT; - merge_head = open(git_path_merge_head(), O_RDONLY); + merge_head = open(git_path_merge_head(the_repository), O_RDONLY); if (merge_head < 0) { if (errno == ENOENT) return; - die("cannot open '%s' for reading", git_path_merge_head()); + die("cannot open '%s' for reading", + git_path_merge_head(the_repository)); } while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { struct object_id oid; if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid)) - die("unknown line in '%s': %s", git_path_merge_head(), line.buf); + die("unknown line in '%s': %s", + git_path_merge_head(the_repository), line.buf); tail = append_parent(tail, &oid); } close(merge_head); @@ -340,13 +340,13 @@ void create_branch(const char *name, const char *start_name, void remove_branch_state(void) { - unlink(git_path_cherry_pick_head()); - unlink(git_path_revert_head()); - unlink(git_path_merge_head()); - unlink(git_path_merge_rr()); - unlink(git_path_merge_msg()); - unlink(git_path_merge_mode()); - unlink(git_path_squash_msg()); + unlink(git_path_cherry_pick_head(the_repository)); + unlink(git_path_revert_head(the_repository)); + unlink(git_path_merge_head(the_repository)); + unlink(git_path_merge_rr(the_repository)); + unlink(git_path_merge_msg(the_repository)); + unlink(git_path_merge_mode(the_repository)); + unlink(git_path_squash_msg(the_repository)); } void die_if_checked_out(const char *branch, int ignore_current_worktree) diff --git a/builtin/blame.c b/builtin/blame.c index 5a0388aaef..921d127f29 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -9,6 +9,7 @@ #include "config.h" #include "color.h" #include "builtin.h" +#include "repository.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -23,6 +24,7 @@ #include "line-log.h" #include "dir.h" #include "progress.h" +#include "object-store.h" #include "blame.h" #include "string-list.h" @@ -576,7 +578,7 @@ static int read_ancestry(const char *graft_file) /* The format is just "Commit Parent1 Parent2 ...\n" */ struct commit_graft *graft = read_graft_line(&buf); if (graft) - register_commit_graft(graft, 0); + register_commit_graft(the_repository, graft, 0); } fclose(fp); strbuf_release(&buf); diff --git a/builtin/branch.c b/builtin/branch.c index 1876ca9e79..0192d4a879 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -37,6 +37,7 @@ static const char * const builtin_branch_usage[] = { static const char *head; static struct object_id head_oid; +static int used_deprecated_reflog_option; static int branch_use_color = -1; static char branch_colors[][COLOR_MAXLEN] = { @@ -568,6 +569,14 @@ static int edit_branch_description(const char *branch_name) return 0; } +static int deprecated_reflog_option_cb(const struct option *opt, + const char *arg, int unset) +{ + used_deprecated_reflog_option = 1; + *(int *)opt->value = !unset; + return 0; +} + int cmd_branch(int argc, const char **argv, const char *prefix) { int delete = 0, rename = 0, copy = 0, force = 0, list = 0; @@ -610,7 +619,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BIT('c', "copy", ©, N_("copy a branch and its reflog"), 1), OPT_BIT('C', NULL, ©, N_("copy a branch, even if target exists"), 2), OPT_BOOL(0, "list", &list, N_("list branch names")), - OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")), + OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")), + { + OPTION_CALLBACK, 'l', NULL, &reflog, NULL, + N_("deprecated synonym for --create-reflog"), + PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, + deprecated_reflog_option_cb + }, OPT_BOOL(0, "edit-description", &edit_description, N_("edit the description for the branch")), OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE), @@ -683,6 +698,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (list) setup_auto_pager("branch", 1); + if (used_deprecated_reflog_option && !list) { + warning("the '-l' alias for '--create-reflog' is deprecated;"); + warning("it will be removed in a future version of Git"); + } + if (delete) { if (!argc) die(_("branch name required")); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 665b581949..4a44b2404f 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -13,6 +13,7 @@ #include "tree-walk.h" #include "sha1-array.h" #include "packfile.h" +#include "object-store.h" struct batch_options { int enabled; diff --git a/builtin/checkout.c b/builtin/checkout.c index 4c41d8b4c8..28627650cd 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -4,6 +4,7 @@ #include "lockfile.h" #include "parse-options.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "tree-walk.h" diff --git a/builtin/clone.c b/builtin/clone.c index 74a804f2e8..1d939af9d8 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -15,6 +15,7 @@ #include "fetch-pack.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index ecf42191da..9fbd3529fb 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "config.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "builtin.h" diff --git a/builtin/commit.c b/builtin/commit.c index 9bcbb0c25c..158e3f843a 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -168,9 +168,9 @@ static int opt_parse_rename_score(const struct option *opt, const char *arg, int static void determine_whence(struct wt_status *s) { - if (file_exists(git_path_merge_head())) + if (file_exists(git_path_merge_head(the_repository))) whence = FROM_MERGE; - else if (file_exists(git_path_cherry_pick_head())) { + else if (file_exists(git_path_cherry_pick_head(the_repository))) { whence = FROM_CHERRY_PICK; if (file_exists(git_path_seq_dir())) sequencer_in_use = 1; @@ -718,21 +718,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (have_option_m) strbuf_addbuf(&sb, &message); hook_arg1 = "message"; - } else if (!stat(git_path_merge_msg(), &statbuf)) { + } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) { /* * prepend SQUASH_MSG here if it exists and a * "merge --squash" was originally performed */ - if (!stat(git_path_squash_msg(), &statbuf)) { - if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0) + if (!stat(git_path_squash_msg(the_repository), &statbuf)) { + if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else hook_arg1 = "merge"; - if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0) + if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0) die_errno(_("could not read MERGE_MSG")); - } else if (!stat(git_path_squash_msg(), &statbuf)) { - if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0) + } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) { + if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else if (template_file) { @@ -813,8 +813,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, " %s\n" "and try again.\n"), whence == FROM_MERGE ? - git_path_merge_head() : - git_path_cherry_pick_head()); + git_path_merge_head(the_repository) : + git_path_cherry_pick_head(the_repository)); } fprintf(s->fp, "\n"); @@ -1564,7 +1564,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!reflog_msg) reflog_msg = "commit (merge)"; pptr = commit_list_append(current_head, pptr); - fp = xfopen(git_path_merge_head(), "r"); + fp = xfopen(git_path_merge_head(the_repository), "r"); while (strbuf_getline_lf(&m, fp) != EOF) { struct commit *parent; @@ -1575,8 +1575,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } fclose(fp); strbuf_release(&m); - if (!stat(git_path_merge_mode(), &statbuf)) { - if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0) + if (!stat(git_path_merge_mode(the_repository), &statbuf)) { + if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0) die_errno(_("could not read MERGE_MODE")); if (!strcmp(sb.buf, "no-ff")) allow_fast_forward = 0; @@ -1639,12 +1639,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("%s", err.buf); } - unlink(git_path_cherry_pick_head()); - unlink(git_path_revert_head()); - unlink(git_path_merge_head()); - unlink(git_path_merge_msg()); - unlink(git_path_merge_mode()); - unlink(git_path_squash_msg()); + unlink(git_path_cherry_pick_head(the_repository)); + unlink(git_path_revert_head(the_repository)); + unlink(git_path_merge_head(the_repository)); + unlink(git_path_merge_msg(the_repository)); + unlink(git_path_merge_mode(the_repository)); + unlink(git_path_squash_msg(the_repository)); if (commit_index_files()) die (_("Repository has been updated, but unable to write\n" diff --git a/builtin/describe.c b/builtin/describe.c index bec2513b66..1e87f68d5e 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -13,6 +13,7 @@ #include "hashmap.h" #include "argv-array.h" #include "run-command.h" +#include "object-store.h" #include "revision.h" #include "list-objects.h" #include "commit-slab.h" diff --git a/builtin/difftool.c b/builtin/difftool.c index bc97d4aef2..51f6c9cdb4 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -20,6 +20,7 @@ #include "argv-array.h" #include "strbuf.h" #include "lockfile.h" +#include "object-store.h" #include "dir.h" static char *diff_gui_tool; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 73d12c1020..9ee6a4d2e8 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -8,6 +8,7 @@ #include "config.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "commit.h" #include "object.h" #include "tag.h" diff --git a/builtin/fetch.c b/builtin/fetch.c index ea5b9669ad..d9bb72bf49 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -6,6 +6,7 @@ #include "repository.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "commit.h" #include "builtin.h" #include "string-list.h" @@ -93,19 +94,6 @@ static int git_fetch_config(const char *k, const char *v, void *cb) return git_default_config(k, v, cb); } -static int gitmodules_fetch_config(const char *var, const char *value, void *cb) -{ - if (!strcmp(var, "submodule.fetchjobs")) { - max_children = parse_submodule_fetchjobs(var, value); - return 0; - } else if (!strcmp(var, "fetch.recursesubmodules")) { - recurse_submodules = parse_fetch_recurse_submodules_arg(var, value); - return 0; - } - - return 0; -} - static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) { /* @@ -777,7 +765,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, const char *what, *kind; struct ref *rm; char *url; - const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(); + const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository); int want_status; int summary_width = transport_summary_width(ref_map); @@ -1029,7 +1017,7 @@ static void check_not_current_branch(struct ref *ref_map) static int truncate_fetch_head(void) { - const char *filename = git_path_fetch_head(); + const char *filename = git_path_fetch_head(the_repository); FILE *fp = fopen_for_writing(filename); if (!fp) @@ -1433,7 +1421,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) for (i = 1; i < argc; i++) strbuf_addf(&default_rla, " %s", argv[i]); - config_from_gitmodules(gitmodules_fetch_config, NULL); + fetch_config_from_gitmodules(&max_children, &recurse_submodules); git_config(git_fetch_config, NULL); argc = parse_options(argc, argv, prefix, @@ -1449,7 +1437,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (unshallow) { if (depth) die(_("--depth and --unshallow cannot be used together")); - else if (!is_repository_shallow()) + else if (!is_repository_shallow(the_repository)) die(_("--unshallow on a complete repository does not make sense")); else depth = xstrfmt("%d", INFINITE_DEPTH); diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index bd680be687..1b526adb3a 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -2,6 +2,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "commit.h" #include "diff.h" #include "revision.h" diff --git a/builtin/grep.c b/builtin/grep.c index ee753a403e..61bcaf6e58 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -828,6 +828,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")), + OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")), OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, diff --git a/builtin/hash-object.c b/builtin/hash-object.c index a9a3a198c3..9ada4f4dfd 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -6,6 +6,7 @@ */ #include "builtin.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "quote.h" #include "parse-options.h" diff --git a/builtin/log.c b/builtin/log.c index 0583f7f383..805f89d7e1 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -7,6 +7,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "object-store.h" #include "color.h" #include "commit.h" #include "diff.h" @@ -1755,6 +1756,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (base_commit || base_auto) { struct commit *base = get_base_commit(base_commit, list, nr); reset_revision_walk(); + clear_object_flags(UNINTERESTING); prepare_bases(&bases, base, list, nr); } diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 409da4e835..fe3b952cb3 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "config.h" +#include "object-store.h" #include "blob.h" #include "tree.h" #include "commit.h" diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index bf01e05808..8a8d579752 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "tree-walk.h" #include "xdiff-interface.h" +#include "object-store.h" #include "blob.h" #include "exec-cmd.h" #include "merge-blobs.h" diff --git a/builtin/merge.c b/builtin/merge.c index 4a4c09496c..d1b547d973 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -247,9 +247,9 @@ static struct option builtin_merge_options[] = { /* Cleans up metadata that is uninteresting after a succeeded merge. */ static void drop_save(void) { - unlink(git_path_merge_head()); - unlink(git_path_merge_msg()); - unlink(git_path_merge_mode()); + unlink(git_path_merge_head(the_repository)); + unlink(git_path_merge_msg(the_repository)); + unlink(git_path_merge_mode(the_repository)); } static int save_state(struct object_id *stash) @@ -382,7 +382,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead oid_to_hex(&commit->object.oid)); pretty_print_commit(&ctx, commit, &out); } - write_file_buf(git_path_squash_msg(), out.buf, out.len); + write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len); strbuf_release(&out); } @@ -741,7 +741,7 @@ static void add_strategies(const char *string, unsigned attr) static void read_merge_msg(struct strbuf *msg) { - const char *filename = git_path_merge_msg(); + const char *filename = git_path_merge_msg(the_repository); strbuf_reset(msg); if (strbuf_read_file(msg, filename, 0) < 0) die_errno(_("Could not read from '%s'"), filename); @@ -778,18 +778,18 @@ static void prepare_to_commit(struct commit_list *remoteheads) if (signoff) append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0); write_merge_heads(remoteheads); - write_file_buf(git_path_merge_msg(), msg.buf, msg.len); + write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len); if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg", - git_path_merge_msg(), "merge", NULL)) + git_path_merge_msg(the_repository), "merge", NULL)) abort_commit(remoteheads, NULL); if (0 < option_edit) { - if (launch_editor(git_path_merge_msg(), NULL, NULL)) + if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL)) abort_commit(remoteheads, NULL); } if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(), "commit-msg", - git_path_merge_msg(), NULL)) + git_path_merge_msg(the_repository), NULL)) abort_commit(remoteheads, NULL); read_merge_msg(&msg); @@ -859,7 +859,7 @@ static int suggest_conflicts(void) FILE *fp; struct strbuf msgbuf = STRBUF_INIT; - filename = git_path_merge_msg(); + filename = git_path_merge_msg(the_repository); fp = xfopen(filename, "a"); append_conflicts_hint(&msgbuf); @@ -942,12 +942,12 @@ static void write_merge_heads(struct commit_list *remoteheads) } strbuf_addf(&buf, "%s\n", oid_to_hex(oid)); } - write_file_buf(git_path_merge_head(), buf.buf, buf.len); + write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len); strbuf_reset(&buf); if (fast_forward == FF_NO) strbuf_addstr(&buf, "no-ff"); - write_file_buf(git_path_merge_mode(), buf.buf, buf.len); + write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len); strbuf_release(&buf); } @@ -955,7 +955,8 @@ static void write_merge_state(struct commit_list *remoteheads) { write_merge_heads(remoteheads); strbuf_addch(&merge_msg, '\n'); - write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len); + write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf, + merge_msg.len); } static int default_edit_option(void) @@ -1038,7 +1039,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge if (!merge_names) merge_names = &fetch_head_file; - filename = git_path_fetch_head(); + filename = git_path_fetch_head(the_repository); fd = open(filename, O_RDONLY); if (fd < 0) die_errno(_("could not open '%s' for reading"), filename); @@ -1213,7 +1214,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) usage_msg_opt(_("--abort expects no arguments"), builtin_merge_usage, builtin_merge_options); - if (!file_exists(git_path_merge_head())) + if (!file_exists(git_path_merge_head(the_repository))) die(_("There is no merge to abort (MERGE_HEAD missing).")); /* Invoke 'git reset --merge' */ @@ -1229,7 +1230,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) usage_msg_opt(_("--continue expects no arguments"), builtin_merge_usage, builtin_merge_options); - if (!file_exists(git_path_merge_head())) + if (!file_exists(git_path_merge_head(the_repository))) die(_("There is no merge in progress (MERGE_HEAD missing).")); /* Invoke 'git commit' */ @@ -1240,7 +1241,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (read_cache_unmerged()) die_resolve_conflict("merge"); - if (file_exists(git_path_merge_head())) { + if (file_exists(git_path_merge_head(the_repository))) { /* * There is no unmerged entry, don't advise 'git * add/rm <file>', just 'git commit'. @@ -1251,7 +1252,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) else die(_("You have not concluded your merge (MERGE_HEAD exists).")); } - if (file_exists(git_path_cherry_pick_head())) { + if (file_exists(git_path_cherry_pick_head(the_repository))) { if (advice_resolve_conflict) die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you merge.")); diff --git a/builtin/mktag.c b/builtin/mktag.c index 82a6e86077..6fb7dc8578 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "tag.h" #include "replace-object.h" +#include "object-store.h" /* * A signature file has a very simple fixed format: four lines diff --git a/builtin/mktree.c b/builtin/mktree.c index bb76b469fd..2dc4ad6ba8 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -7,6 +7,7 @@ #include "quote.h" #include "tree.h" #include "parse-options.h" +#include "object-store.h" static struct treeent { unsigned mode; diff --git a/builtin/notes.c b/builtin/notes.c index 6981e2d906..a0a1840040 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -11,6 +11,7 @@ #include "config.h" #include "builtin.h" #include "notes.h" +#include "object-store.h" #include "blob.h" #include "pretty.h" #include "refs.h" diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 71056d8294..ebc8cefb53 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2929,11 +2929,13 @@ static int pack_options_allow_reuse(void) static int get_object_list_from_bitmap(struct rev_info *revs) { - if (prepare_bitmap_walk(revs) < 0) + struct bitmap_index *bitmap_git; + if (!(bitmap_git = prepare_bitmap_walk(revs))) return -1; if (pack_options_allow_reuse() && !reuse_partial_packfile_from_bitmap( + bitmap_git, &reuse_packfile, &reuse_packfile_objects, &reuse_packfile_offset)) { @@ -2942,7 +2944,8 @@ static int get_object_list_from_bitmap(struct rev_info *revs) display_progress(progress_state, nr_result); } - traverse_bitmap_commit_list(&add_object_entry_from_bitmap); + traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap); + free_bitmap_index(bitmap_git); return 0; } @@ -2969,7 +2972,7 @@ static void get_object_list(int ac, const char **av) setup_revisions(ac, av, &revs, NULL); /* make sure shallows are read */ - is_repository_shallow(); + is_repository_shallow(the_repository); while (fgets(line, sizeof(line), stdin) != NULL) { int len = strlen(line); @@ -2987,7 +2990,7 @@ static void get_object_list(int ac, const char **av) struct object_id oid; if (get_oid_hex(line + 10, &oid)) die("not an SHA-1 '%s'", line + 10); - register_shallow(&oid); + register_shallow(the_repository, &oid); use_bitmap_index = 0; continue; } @@ -3299,7 +3302,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) use_bitmap_index = use_bitmap_index_default; /* "hard" reasons not to use bitmaps; these just won't work at all */ - if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow()) + if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow(the_repository)) use_bitmap_index = 0; if (pack_to_stdout || !rev_list_all) diff --git a/builtin/prune.c b/builtin/prune.c index 518ffbea13..70ec35aa05 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -6,6 +6,7 @@ #include "reachable.h" #include "parse-options.h" #include "progress.h" +#include "object-store.h" static const char * const prune_usage[] = { N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"), @@ -159,7 +160,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) remove_temporary_files(s); free(s); - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) prune_shallow(show_only); return 0; diff --git a/builtin/pull.c b/builtin/pull.c index fe002a72f8..7197b22b16 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -356,7 +356,7 @@ static int git_pull_config(const char *var, const char *value, void *cb) */ static void get_merge_heads(struct oid_array *merge_heads) { - const char *filename = git_path_fetch_head(); + const char *filename = git_path_fetch_head(the_repository); FILE *fp; struct strbuf sb = STRBUF_INIT; struct object_id oid; @@ -864,7 +864,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (read_cache_unmerged()) die_resolve_conflict("pull"); - if (file_exists(git_path_merge_head())) + if (file_exists(git_path_merge_head(the_repository))) die_conclude_merge(); if (get_oid("HEAD", &orig_head)) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 68d36e0a56..44c7c9ee82 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -25,6 +25,7 @@ #include "tmp-objdir.h" #include "oidset.h" #include "packfile.h" +#include "object-store.h" #include "protocol.h" static const char * const receive_pack_usage[] = { @@ -905,7 +906,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) - register_shallow(&extra.oid[i]); + register_shallow(the_repository, &extra.oid[i]); si->shallow_ref[cmd->index] = 0; oid_array_clear(&extra); diff --git a/builtin/reflog.c b/builtin/reflog.c index a48984d37e..0091192995 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "config.h" #include "lockfile.h" +#include "object-store.h" #include "commit.h" #include "refs.h" #include "dir.h" diff --git a/builtin/remote.c b/builtin/remote.c index 1a82d850a2..c74ee88690 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -8,6 +8,7 @@ #include "run-command.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "argv-array.h" static const char * const builtin_remote_usage[] = { diff --git a/builtin/replace.c b/builtin/replace.c index 6da2411e14..deabda2101 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -487,7 +487,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle) static int convert_graft_file(int force) { - const char *graft_file = get_graft_file(); + const char *graft_file = get_graft_file(the_repository); FILE *fp = fopen_or_warn(graft_file, "r"); struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT; struct argv_array args = ARGV_ARRAY_INIT; diff --git a/builtin/reset.c b/builtin/reset.c index a862c70fab..ffe41c924b 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -39,7 +39,7 @@ static const char *reset_type_names[] = { static inline int is_merge(void) { - return !access(git_path_merge_head(), F_OK); + return !access(git_path_merge_head(the_repository), F_OK); } static int reset_index(const struct object_id *oid, int reset_type, int quiet) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index fadd3ec14c..6fcb0ff6d5 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -6,6 +6,7 @@ #include "list-objects.h" #include "list-objects-filter.h" #include "list-objects-filter-options.h" +#include "object-store.h" #include "pack.h" #include "pack-bitmap.h" #include "builtin.h" @@ -16,6 +17,7 @@ #include "reflog-walk.h" #include "oidset.h" #include "packfile.h" +#include "object-store.h" static const char rev_list_usage[] = "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n" @@ -514,17 +516,21 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (revs.count && !revs.left_right && !revs.cherry_mark) { uint32_t commit_count; int max_count = revs.max_count; - if (!prepare_bitmap_walk(&revs)) { - count_bitmap_commit_list(&commit_count, NULL, NULL, NULL); + struct bitmap_index *bitmap_git; + if ((bitmap_git = prepare_bitmap_walk(&revs))) { + count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL); if (max_count >= 0 && max_count < commit_count) commit_count = max_count; printf("%d\n", commit_count); + free_bitmap_index(bitmap_git); return 0; } } else if (revs.max_count < 0 && revs.tag_objects && revs.tree_objects && revs.blob_objects) { - if (!prepare_bitmap_walk(&revs)) { - traverse_bitmap_commit_list(&show_object_fast); + struct bitmap_index *bitmap_git; + if ((bitmap_git = prepare_bitmap_walk(&revs))) { + traverse_bitmap_commit_list(bitmap_git, &show_object_fast); + free_bitmap_index(bitmap_git); return 0; } } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 4f49e96bfd..2a6cb298bd 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -883,7 +883,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--is-shallow-repository")) { - printf("%s\n", is_repository_shallow() ? "true" + printf("%s\n", + is_repository_shallow(the_repository) ? "true" : "false"); continue; } diff --git a/builtin/show-ref.c b/builtin/show-ref.c index f2eb1a7724..2f13f1316f 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "cache.h" #include "refs.h" +#include "object-store.h" #include "object.h" #include "tag.h" #include "string-list.h" diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 20ae9191ca..a3c4564c6c 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1124,6 +1124,8 @@ static void deinit_submodule(const char *path, const char *prefix, if (!(flags & OPT_QUIET)) printf(format, displaypath); + submodule_unset_core_worktree(sub); + strbuf_release(&sb_rm); } @@ -1706,8 +1708,8 @@ static int update_clone_task_finished(int result, return 0; } -static int gitmodules_update_clone_config(const char *var, const char *value, - void *cb) +static int git_update_clone_config(const char *var, const char *value, + void *cb) { int *max_jobs = cb; if (!strcmp(var, "submodule.fetchjobs")) @@ -1757,8 +1759,8 @@ static int update_clone(int argc, const char **argv, const char *prefix) }; suc.prefix = prefix; - config_from_gitmodules(gitmodules_update_clone_config, &max_jobs); - git_config(gitmodules_update_clone_config, &max_jobs); + update_clone_config_from_gitmodules(&max_jobs); + git_config(git_update_clone_config, &max_jobs); argc = parse_options(argc, argv, prefix, module_update_clone_options, git_submodule_helper_usage, 0); @@ -2004,6 +2006,29 @@ static int check_name(int argc, const char **argv, const char *prefix) return 0; } +static int connect_gitdir_workingtree(int argc, const char **argv, const char *prefix) +{ + struct strbuf sb = STRBUF_INIT; + const char *name, *path; + char *sm_gitdir; + + if (argc != 3) + BUG("submodule--helper connect-gitdir-workingtree <name> <path>"); + + name = argv[1]; + path = argv[2]; + + strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name); + sm_gitdir = absolute_pathdup(sb.buf); + + connect_work_tree_and_git_dir(path, sm_gitdir, 0); + + strbuf_release(&sb); + free(sm_gitdir); + + return 0; +} + #define SUPPORT_SUPER_PREFIX (1<<0) struct cmd_struct { @@ -2017,6 +2042,7 @@ static struct cmd_struct commands[] = { {"name", module_name, 0}, {"clone", module_clone, 0}, {"update-clone", update_clone, 0}, + {"connect-gitdir-workingtree", connect_gitdir_workingtree, 0}, {"relative-path", resolve_relative_path, 0}, {"resolve-relative-url", resolve_relative_url, 0}, {"resolve-relative-url-test", resolve_relative_url_test, 0}, diff --git a/builtin/tag.c b/builtin/tag.c index 5d0dd11240..9919b03b2d 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -10,6 +10,7 @@ #include "config.h" #include "builtin.h" #include "refs.h" +#include "object-store.h" #include "tag.h" #include "run-command.h" #include "parse-options.h" diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 300eb59657..58652229f2 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "config.h" +#include "object-store.h" static char *create_temp_file(struct object_id *oid) { diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 6e81ca8ca2..cf585fcc5e 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "cache.h" #include "config.h" +#include "object-store.h" #include "object.h" #include "delta.h" #include "pack.h" diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index dcdaada111..f6922da16d 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -8,6 +8,7 @@ #include "cache.h" #include "config.h" #include "builtin.h" +#include "object-store.h" #include "commit.h" #include "run-command.h" #include <signal.h> diff --git a/bulk-checkin.c b/bulk-checkin.c index b7e131c47a..9f3b644811 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -8,6 +8,7 @@ #include "pack.h" #include "strbuf.h" #include "packfile.h" +#include "object-store.h" static struct bulk_checkin_state { unsigned plugged:1; @@ -1,6 +1,7 @@ #include "cache.h" #include "lockfile.h" #include "bundle.h" +#include "object-store.h" #include "object.h" #include "commit.h" #include "diff.h" diff --git a/cache-tree.c b/cache-tree.c index 25663825b5..6b46711996 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -3,6 +3,7 @@ #include "tree.h" #include "tree-walk.h" #include "cache-tree.h" +#include "object-store.h" #ifndef DEBUG #define DEBUG 0 @@ -484,7 +484,7 @@ extern const char *get_git_dir(void); extern const char *get_git_common_dir(void); extern char *get_object_directory(void); extern char *get_index_file(void); -extern char *get_graft_file(void); +extern char *get_graft_file(struct repository *r); extern void set_git_dir(const char *path); extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir); extern int get_common_dir(struct strbuf *sb, const char *gitdir); @@ -1192,32 +1192,6 @@ extern char *xdg_config_home(const char *filename); */ extern char *xdg_cache_home(const char *filename); -extern void *read_object_file_extended(const struct object_id *oid, - enum object_type *type, - unsigned long *size, int lookup_replace); -static inline void *read_object_file(const struct object_id *oid, enum object_type *type, unsigned long *size) -{ - return read_object_file_extended(oid, type, size, 1); -} - -/* Read and unpack an object file into memory, write memory to an object file */ -int oid_object_info(struct repository *r, const struct object_id *, unsigned long *); - -extern int hash_object_file(const void *buf, unsigned long len, - const char *type, struct object_id *oid); - -extern int write_object_file(const void *buf, unsigned long len, - const char *type, struct object_id *oid); - -extern int hash_object_file_literally(const void *buf, unsigned long len, - const char *type, struct object_id *oid, - unsigned flags); - -extern int pretend_object_file(void *, unsigned long, enum object_type, - struct object_id *oid); - -extern int force_object_loose(const struct object_id *oid, time_t mtime); - extern int git_open_cloexec(const char *name, int flags); #define git_open(name) git_open_cloexec(name, O_RDONLY) extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz); @@ -1227,43 +1201,6 @@ extern int check_object_signature(const struct object_id *oid, void *buf, unsign extern int finalize_object_file(const char *tmpfile, const char *filename); -/* - * Open the loose object at path, check its hash, and return the contents, - * type, and size. If the object is a blob, then "contents" may return NULL, - * to allow streaming of large blobs. - * - * Returns 0 on success, negative on error (details may be written to stderr). - */ -int read_loose_object(const char *path, - const struct object_id *expected_oid, - enum object_type *type, - unsigned long *size, - void **contents); - -/* - * Convenience for sha1_object_info_extended() with a NULL struct - * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass - * nonzero flags to also set other flags. - */ -extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags); -static inline int has_sha1_file(const unsigned char *sha1) -{ - return has_sha1_file_with_flags(sha1, 0); -} - -/* Same as the above, except for struct object_id. */ -extern int has_object_file(const struct object_id *oid); -extern int has_object_file_with_flags(const struct object_id *oid, int flags); - -/* - * Return true iff an alternate object database has a loose object - * with the specified name. This function does not respect replace - * references. - */ -extern int has_loose_object_nonlocal(const struct object_id *oid); - -extern void assert_oid_type(const struct object_id *oid, enum object_type expect); - /* Helper to check and "touch" a file */ extern int check_and_freshen_file(const char *fn, int freshen); @@ -1631,60 +1568,6 @@ int for_each_loose_file_in_objdir_buf(struct strbuf *path, #define FOR_EACH_OBJECT_LOCAL_ONLY 0x1 extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags); -struct object_info { - /* Request */ - enum object_type *typep; - unsigned long *sizep; - off_t *disk_sizep; - unsigned char *delta_base_sha1; - struct strbuf *type_name; - void **contentp; - - /* Response */ - enum { - OI_CACHED, - OI_LOOSE, - OI_PACKED, - OI_DBCACHED - } whence; - union { - /* - * struct { - * ... Nothing to expose in this case - * } cached; - * struct { - * ... Nothing to expose in this case - * } loose; - */ - struct { - struct packed_git *pack; - off_t offset; - unsigned int is_delta; - } packed; - } u; -}; - -/* - * Initializer for a "struct object_info" that wants no items. You may - * also memset() the memory to all-zeroes. - */ -#define OBJECT_INFO_INIT {NULL} - -/* Invoke lookup_replace_object() on the given hash */ -#define OBJECT_INFO_LOOKUP_REPLACE 1 -/* Allow reading from a loose object file of unknown/bogus type */ -#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2 -/* Do not check cached storage */ -#define OBJECT_INFO_SKIP_CACHED 4 -/* Do not retry packed storage after checking packed and loose storage */ -#define OBJECT_INFO_QUICK 8 -/* Do not check loose object */ -#define OBJECT_INFO_IGNORE_LOOSE 16 - -int oid_object_info_extended(struct repository *r, - const struct object_id *, - struct object_info *, unsigned flags); - /* * Set this to 0 to prevent sha1_object_info_extended() from fetching missing * blobs. This has a difference only if extensions.partialClone is set. diff --git a/combine-diff.c b/combine-diff.c index 2ef495963f..de7695e728 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "object-store.h" #include "commit.h" #include "blob.h" #include "diff.h" @@ -2,6 +2,8 @@ #include "tag.h" #include "commit.h" #include "commit-graph.h" +#include "repository.h" +#include "object-store.h" #include "pkt-line.h" #include "utf8.h" #include "diff.h" @@ -98,41 +100,44 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail) return parse_timestamp(dateptr, NULL, 10); } -static struct commit_graft **commit_graft; -static int commit_graft_alloc, commit_graft_nr; - static const unsigned char *commit_graft_sha1_access(size_t index, void *table) { struct commit_graft **commit_graft_table = table; return commit_graft_table[index]->oid.hash; } -static int commit_graft_pos(const unsigned char *sha1) +static int commit_graft_pos(struct repository *r, const unsigned char *sha1) { - return sha1_pos(sha1, commit_graft, commit_graft_nr, + return sha1_pos(sha1, r->parsed_objects->grafts, + r->parsed_objects->grafts_nr, commit_graft_sha1_access); } -int register_commit_graft(struct commit_graft *graft, int ignore_dups) +int register_commit_graft(struct repository *r, struct commit_graft *graft, + int ignore_dups) { - int pos = commit_graft_pos(graft->oid.hash); + int pos = commit_graft_pos(r, graft->oid.hash); if (0 <= pos) { if (ignore_dups) free(graft); else { - free(commit_graft[pos]); - commit_graft[pos] = graft; + free(r->parsed_objects->grafts[pos]); + r->parsed_objects->grafts[pos] = graft; } return 1; } pos = -pos - 1; - ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc); - commit_graft_nr++; - if (pos < commit_graft_nr) - MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos, - commit_graft_nr - pos - 1); - commit_graft[pos] = graft; + ALLOC_GROW(r->parsed_objects->grafts, + r->parsed_objects->grafts_nr + 1, + r->parsed_objects->grafts_alloc); + r->parsed_objects->grafts_nr++; + if (pos < r->parsed_objects->grafts_nr) + memmove(r->parsed_objects->grafts + pos + 1, + r->parsed_objects->grafts + pos, + (r->parsed_objects->grafts_nr - pos - 1) * + sizeof(*r->parsed_objects->grafts)); + r->parsed_objects->grafts[pos] = graft; return 0; } @@ -174,7 +179,7 @@ bad_graft_data: return NULL; } -static int read_graft_file(const char *graft_file) +static int read_graft_file(struct repository *r, const char *graft_file) { FILE *fp = fopen_or_warn(graft_file, "r"); struct strbuf buf = STRBUF_INIT; @@ -194,7 +199,7 @@ static int read_graft_file(const char *graft_file) struct commit_graft *graft = read_graft_line(&buf); if (!graft) continue; - if (register_commit_graft(graft, 1)) + if (register_commit_graft(r, graft, 1)) error("duplicate graft data: %s", buf.buf); } fclose(fp); @@ -202,50 +207,50 @@ static int read_graft_file(const char *graft_file) return 0; } -static void prepare_commit_graft(void) +static void prepare_commit_graft(struct repository *r) { - static int commit_graft_prepared; char *graft_file; - if (commit_graft_prepared) + if (r->parsed_objects->commit_graft_prepared) return; if (!startup_info->have_repository) return; - graft_file = get_graft_file(); - read_graft_file(graft_file); + graft_file = get_graft_file(r); + read_graft_file(r, graft_file); /* make sure shallows are read */ - is_repository_shallow(); - commit_graft_prepared = 1; + is_repository_shallow(r); + r->parsed_objects->commit_graft_prepared = 1; } -struct commit_graft *lookup_commit_graft(const struct object_id *oid) +struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid) { int pos; - prepare_commit_graft(); - pos = commit_graft_pos(oid->hash); + prepare_commit_graft(r); + pos = commit_graft_pos(r, oid->hash); if (pos < 0) return NULL; - return commit_graft[pos]; + return r->parsed_objects->grafts[pos]; } int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data) { int i, ret; - for (i = ret = 0; i < commit_graft_nr && !ret; i++) - ret = fn(commit_graft[i], cb_data); + for (i = ret = 0; i < the_repository->parsed_objects->grafts_nr && !ret; i++) + ret = fn(the_repository->parsed_objects->grafts[i], cb_data); return ret; } int unregister_shallow(const struct object_id *oid) { - int pos = commit_graft_pos(oid->hash); + int pos = commit_graft_pos(the_repository, oid->hash); if (pos < 0) return -1; - if (pos + 1 < commit_graft_nr) - MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1, - commit_graft_nr - pos - 1); - commit_graft_nr--; + if (pos + 1 < the_repository->parsed_objects->grafts_nr) + MOVE_ARRAY(the_repository->parsed_objects->grafts + pos, + the_repository->parsed_objects->grafts + pos + 1, + the_repository->parsed_objects->grafts_nr - pos - 1); + the_repository->parsed_objects->grafts_nr--; return 0; } @@ -381,7 +386,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */ pptr = &item->parents; - graft = lookup_commit_graft(&item->object.oid); + graft = lookup_commit_graft(the_repository, &item->object.oid); while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) { struct commit *new_parent; @@ -194,8 +194,8 @@ struct commit_graft { typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *); struct commit_graft *read_graft_line(struct strbuf *line); -int register_commit_graft(struct commit_graft *, int); -struct commit_graft *lookup_commit_graft(const struct object_id *oid); +int register_commit_graft(struct repository *r, struct commit_graft *, int); +struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid); extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2); extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos); @@ -209,15 +209,15 @@ extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct oid_array; struct ref; -extern int register_shallow(const struct object_id *oid); +extern int register_shallow(struct repository *r, const struct object_id *oid); extern int unregister_shallow(const struct object_id *oid); extern int for_each_commit_graft(each_commit_graft_fn, void *); -extern int is_repository_shallow(void); +extern int is_repository_shallow(struct repository *r); extern struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag); extern struct commit_list *get_shallow_commits_by_rev_list( int ac, const char **av, int shallow_flag, int not_shallow_flag); -extern void set_alternate_shallow_file(const char *path, int override); +extern void set_alternate_shallow_file(struct repository *r, const char *path, int override); extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol, const struct oid_array *extra); extern void setup_alternate_shallow(struct lock_file *shallow_lock, @@ -14,6 +14,7 @@ #include "quote.h" #include "hashmap.h" #include "string-list.h" +#include "object-store.h" #include "utf8.h" #include "dir.h" #include "color.h" @@ -2172,23 +2173,6 @@ int git_config_get_pathname(const char *key, const char **dest) return repo_config_get_pathname(the_repository, key, dest); } -/* - * Note: This function exists solely to maintain backward compatibility with - * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should - * NOT be used anywhere else. - * - * Runs the provided config function on the '.gitmodules' file found in the - * working directory. - */ -void config_from_gitmodules(config_fn_t fn, void *data) -{ - if (the_repository->worktree) { - char *file = repo_worktree_path(the_repository, GITMODULES_FILE); - git_config_from_file(fn, file, data); - free(file); - } -} - int git_config_get_expiry(const char *key, const char **output) { int ret = git_config_get_string_const(key, output); @@ -215,16 +215,6 @@ extern int repo_config_get_maybe_bool(struct repository *repo, extern int repo_config_get_pathname(struct repository *repo, const char *key, const char **dest); -/* - * Note: This function exists solely to maintain backward compatibility with - * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should - * NOT be used anywhere else. - * - * Runs the provided config function on the '.gitmodules' file found in the - * working directory. - */ -extern void config_from_gitmodules(config_fn_t fn, void *data); - extern int git_config_get_value(const char *key, const char **value); extern const struct string_list *git_config_get_value_multi(const char *key); extern void git_config_clear(void); diff --git a/contrib/git-jump/README b/contrib/git-jump/README index 4484bda410..2f618a7f97 100644 --- a/contrib/git-jump/README +++ b/contrib/git-jump/README @@ -25,6 +25,13 @@ git-jump will feed this to the editor: foo.c:2: printf("hello word!\n"); ----------------------------------- +Or, when running 'git jump grep', column numbers will also be emitted, +e.g. `git jump grep "hello"` would return: + +----------------------------------- +foo.c:2:9: printf("hello word!\n"); +----------------------------------- + Obviously this trivial case isn't that interesting; you could just open `foo.c` yourself. But when you have many changes scattered across a project, you can use the editor's support to "jump" from point to point. @@ -35,7 +42,8 @@ Git-jump can generate four types of interesting lists: 2. The beginning of any merge conflict markers. - 3. Any grep matches. + 3. Any grep matches, including the column of the first match on a + line. 4. Any whitespace errors detected by `git diff --check`. @@ -82,7 +90,7 @@ which does something similar to `git jump grep`. However, it is limited to positioning the cursor to the correct line in only the first file, leaving you to locate subsequent hits in that file or other files using the editor or pager. By contrast, git-jump provides the editor with a -complete list of files and line numbers for each match. +complete list of files, lines, and a column number for each match. Limitations diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump index 80ab0590bc..931b0fe3a9 100755 --- a/contrib/git-jump/git-jump +++ b/contrib/git-jump/git-jump @@ -52,7 +52,7 @@ mode_merge() { # editor shows them to us in the status bar. mode_grep() { cmd=$(git config jump.grepCmd) - test -n "$cmd" || cmd="git grep -n" + test -n "$cmd" || cmd="git grep -n --column" $cmd "$@" | perl -pe ' s/[ \t]+/ /g; @@ -1,6 +1,7 @@ #define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "config.h" +#include "object-store.h" #include "attr.h" #include "run-command.h" #include "quote.h" @@ -13,6 +13,7 @@ #include "attr.h" #include "run-command.h" #include "utf8.h" +#include "object-store.h" #include "userdiff.h" #include "submodule-config.h" #include "submodule.h" diff --git a/diffcore-rename.c b/diffcore-rename.c index 0b7e4989a8..d775183c2f 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -4,6 +4,7 @@ #include "cache.h" #include "diff.h" #include "diffcore.h" +#include "object-store.h" #include "hashmap.h" #include "progress.h" @@ -11,6 +11,7 @@ #include "cache.h" #include "config.h" #include "dir.h" +#include "object-store.h" #include "attr.h" #include "refs.h" #include "wildmatch.h" @@ -2497,7 +2498,7 @@ void setup_standard_excludes(struct dir_struct *dir) { dir->exclude_per_dir = ".gitignore"; - /* core.excludefile defaulting to $XDG_HOME/git/ignore */ + /* core.excludesfile defaulting to $XDG_CONFIG_HOME/git/ignore */ if (!excludes_file) excludes_file = xdg_config_home("ignore"); if (excludes_file && !access_or_warn(excludes_file, R_OK, 0)) @@ -1,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "object-store.h" #include "dir.h" #include "streaming.h" #include "submodule.h" diff --git a/environment.c b/environment.c index 2a6de2330b..013e845235 100644 --- a/environment.c +++ b/environment.c @@ -192,7 +192,7 @@ void setup_git_env(const char *git_dir) git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT)); shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT); if (shallow_file) - set_alternate_shallow_file(shallow_file, 0); + set_alternate_shallow_file(the_repository, shallow_file, 0); } int is_bare_repository(void) @@ -319,11 +319,11 @@ char *get_index_file(void) return the_repository->index_file; } -char *get_graft_file(void) +char *get_graft_file(struct repository *r) { - if (!the_repository->graft_file) + if (!r->graft_file) BUG("git environment hasn't been setup"); - return the_repository->graft_file; + return r->graft_file; } static void set_git_dir_1(const char *path) diff --git a/ewah/bitmap.c b/ewah/bitmap.c index 756bdd050e..52f1178db4 100644 --- a/ewah/bitmap.c +++ b/ewah/bitmap.c @@ -45,14 +45,6 @@ void bitmap_set(struct bitmap *self, size_t pos) self->words[block] |= EWAH_MASK(pos); } -void bitmap_clear(struct bitmap *self, size_t pos) -{ - size_t block = EWAH_BLOCK(pos); - - if (block < self->word_alloc) - self->words[block] &= ~EWAH_MASK(pos); -} - int bitmap_get(struct bitmap *self, size_t pos) { size_t block = EWAH_BLOCK(pos); @@ -137,30 +129,6 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other) self->words[i++] |= word; } -void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data) -{ - size_t pos = 0, i; - - for (i = 0; i < self->word_alloc; ++i) { - eword_t word = self->words[i]; - uint32_t offset; - - if (word == (eword_t)~0) { - for (offset = 0; offset < BITS_IN_EWORD; ++offset) - callback(pos++, data); - } else { - for (offset = 0; offset < BITS_IN_EWORD; ++offset) { - if ((word >> offset) == 0) - break; - - offset += ewah_bit_ctz64(word >> offset); - callback(pos + offset, data); - } - pos += BITS_IN_EWORD; - } - } -} - size_t bitmap_popcount(struct bitmap *self) { size_t i, count = 0; diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c index b9fdda1d3d..d59b1afe3d 100644 --- a/ewah/ewah_bitmap.c +++ b/ewah/ewah_bitmap.c @@ -276,6 +276,18 @@ void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), vo } } +/** + * Clear all the bits in the bitmap. Does not free or resize + * memory. + */ +static void ewah_clear(struct ewah_bitmap *self) +{ + self->buffer_size = 1; + self->buffer[0] = 0; + self->bit_size = 0; + self->rlw = self->buffer; +} + struct ewah_bitmap *ewah_new(void) { struct ewah_bitmap *self; @@ -288,14 +300,6 @@ struct ewah_bitmap *ewah_new(void) return self; } -void ewah_clear(struct ewah_bitmap *self) -{ - self->buffer_size = 1; - self->buffer[0] = 0; - self->bit_size = 0; - self->rlw = self->buffer; -} - void ewah_free(struct ewah_bitmap *self) { if (!self) @@ -376,25 +380,6 @@ void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent) read_new_rlw(it); } -void ewah_not(struct ewah_bitmap *self) -{ - size_t pointer = 0; - - while (pointer < self->buffer_size) { - eword_t *word = &self->buffer[pointer]; - size_t literals, k; - - rlw_xor_run_bit(word); - ++pointer; - - literals = rlw_get_literal_words(word); - for (k = 0; k < literals; ++k) { - self->buffer[pointer] = ~self->buffer[pointer]; - ++pointer; - } - } -} - void ewah_xor( struct ewah_bitmap *ewah_i, struct ewah_bitmap *ewah_j, @@ -459,216 +444,6 @@ void ewah_xor( out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size); } -void ewah_and( - struct ewah_bitmap *ewah_i, - struct ewah_bitmap *ewah_j, - struct ewah_bitmap *out) -{ - struct rlw_iterator rlw_i; - struct rlw_iterator rlw_j; - size_t literals; - - rlwit_init(&rlw_i, ewah_i); - rlwit_init(&rlw_j, ewah_j); - - while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) { - while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) { - struct rlw_iterator *prey, *predator; - - if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) { - prey = &rlw_i; - predator = &rlw_j; - } else { - prey = &rlw_j; - predator = &rlw_i; - } - - if (predator->rlw.running_bit == 0) { - ewah_add_empty_words(out, 0, - predator->rlw.running_len); - rlwit_discard_first_words(prey, - predator->rlw.running_len); - rlwit_discard_first_words(predator, - predator->rlw.running_len); - } else { - size_t index = rlwit_discharge(prey, out, - predator->rlw.running_len, 0); - ewah_add_empty_words(out, 0, - predator->rlw.running_len - index); - rlwit_discard_first_words(predator, - predator->rlw.running_len); - } - } - - literals = min_size( - rlw_i.rlw.literal_words, - rlw_j.rlw.literal_words); - - if (literals) { - size_t k; - - for (k = 0; k < literals; ++k) { - ewah_add(out, - rlw_i.buffer[rlw_i.literal_word_start + k] & - rlw_j.buffer[rlw_j.literal_word_start + k] - ); - } - - rlwit_discard_first_words(&rlw_i, literals); - rlwit_discard_first_words(&rlw_j, literals); - } - } - - if (rlwit_word_size(&rlw_i) > 0) - rlwit_discharge_empty(&rlw_i, out); - else - rlwit_discharge_empty(&rlw_j, out); - - out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size); -} - -void ewah_and_not( - struct ewah_bitmap *ewah_i, - struct ewah_bitmap *ewah_j, - struct ewah_bitmap *out) -{ - struct rlw_iterator rlw_i; - struct rlw_iterator rlw_j; - size_t literals; - - rlwit_init(&rlw_i, ewah_i); - rlwit_init(&rlw_j, ewah_j); - - while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) { - while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) { - struct rlw_iterator *prey, *predator; - - if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) { - prey = &rlw_i; - predator = &rlw_j; - } else { - prey = &rlw_j; - predator = &rlw_i; - } - - if ((predator->rlw.running_bit && prey == &rlw_i) || - (!predator->rlw.running_bit && prey != &rlw_i)) { - ewah_add_empty_words(out, 0, - predator->rlw.running_len); - rlwit_discard_first_words(prey, - predator->rlw.running_len); - rlwit_discard_first_words(predator, - predator->rlw.running_len); - } else { - size_t index; - int negate_words; - - negate_words = (&rlw_i != prey); - index = rlwit_discharge(prey, out, - predator->rlw.running_len, negate_words); - ewah_add_empty_words(out, negate_words, - predator->rlw.running_len - index); - rlwit_discard_first_words(predator, - predator->rlw.running_len); - } - } - - literals = min_size( - rlw_i.rlw.literal_words, - rlw_j.rlw.literal_words); - - if (literals) { - size_t k; - - for (k = 0; k < literals; ++k) { - ewah_add(out, - rlw_i.buffer[rlw_i.literal_word_start + k] & - ~(rlw_j.buffer[rlw_j.literal_word_start + k]) - ); - } - - rlwit_discard_first_words(&rlw_i, literals); - rlwit_discard_first_words(&rlw_j, literals); - } - } - - if (rlwit_word_size(&rlw_i) > 0) - rlwit_discharge(&rlw_i, out, ~0, 0); - else - rlwit_discharge_empty(&rlw_j, out); - - out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size); -} - -void ewah_or( - struct ewah_bitmap *ewah_i, - struct ewah_bitmap *ewah_j, - struct ewah_bitmap *out) -{ - struct rlw_iterator rlw_i; - struct rlw_iterator rlw_j; - size_t literals; - - rlwit_init(&rlw_i, ewah_i); - rlwit_init(&rlw_j, ewah_j); - - while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) { - while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) { - struct rlw_iterator *prey, *predator; - - if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) { - prey = &rlw_i; - predator = &rlw_j; - } else { - prey = &rlw_j; - predator = &rlw_i; - } - - if (predator->rlw.running_bit) { - ewah_add_empty_words(out, 0, - predator->rlw.running_len); - rlwit_discard_first_words(prey, - predator->rlw.running_len); - rlwit_discard_first_words(predator, - predator->rlw.running_len); - } else { - size_t index = rlwit_discharge(prey, out, - predator->rlw.running_len, 0); - ewah_add_empty_words(out, 0, - predator->rlw.running_len - index); - rlwit_discard_first_words(predator, - predator->rlw.running_len); - } - } - - literals = min_size( - rlw_i.rlw.literal_words, - rlw_j.rlw.literal_words); - - if (literals) { - size_t k; - - for (k = 0; k < literals; ++k) { - ewah_add(out, - rlw_i.buffer[rlw_i.literal_word_start + k] | - rlw_j.buffer[rlw_j.literal_word_start + k] - ); - } - - rlwit_discard_first_words(&rlw_i, literals); - rlwit_discard_first_words(&rlw_j, literals); - } - } - - if (rlwit_word_size(&rlw_i) > 0) - rlwit_discharge(&rlw_i, out, ~0, 0); - else - rlwit_discharge(&rlw_j, out, ~0, 0); - - out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size); -} - - #define BITMAP_POOL_MAX 16 static struct ewah_bitmap *bitmap_pool[BITMAP_POOL_MAX]; static size_t bitmap_pool_size; diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c index 33c08c40f8..9035ee65ea 100644 --- a/ewah/ewah_io.c +++ b/ewah/ewah_io.c @@ -20,32 +20,6 @@ #include "ewok.h" #include "strbuf.h" -int ewah_serialize_native(struct ewah_bitmap *self, int fd) -{ - uint32_t write32; - size_t to_write = self->buffer_size * 8; - - /* 32 bit -- bit size for the map */ - write32 = (uint32_t)self->bit_size; - if (write(fd, &write32, 4) != 4) - return -1; - - /** 32 bit -- number of compressed 64-bit words */ - write32 = (uint32_t)self->buffer_size; - if (write(fd, &write32, 4) != 4) - return -1; - - if (write(fd, self->buffer, to_write) != to_write) - return -1; - - /** 32 bit -- position for the RLW */ - write32 = self->rlw - self->buffer; - if (write(fd, &write32, 4) != 4) - return -1; - - return (3 * 4) + to_write; -} - int ewah_serialize_to(struct ewah_bitmap *self, int (*write_fun)(void *, const void *, size_t), void *data) @@ -100,16 +74,6 @@ int ewah_serialize_to(struct ewah_bitmap *self, return (3 * 4) + (self->buffer_size * 8); } -static int write_helper(void *fd, const void *buf, size_t len) -{ - return write((intptr_t)fd, buf, len); -} - -int ewah_serialize(struct ewah_bitmap *self, int fd) -{ - return ewah_serialize_to(self, write_helper, (void *)(intptr_t)fd); -} - static int write_strbuf(void *user_data, const void *data, size_t len) { struct strbuf *sb = user_data; @@ -168,58 +132,3 @@ ssize_t ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len) return ptr - (const uint8_t *)map; } - -int ewah_deserialize(struct ewah_bitmap *self, int fd) -{ - size_t i; - eword_t dump[2048]; - const size_t words_per_dump = sizeof(dump) / sizeof(eword_t); - uint32_t bitsize, word_count, rlw_pos; - - eword_t *buffer = NULL; - size_t words_left; - - ewah_clear(self); - - /* 32 bit -- bit size for the map */ - if (read(fd, &bitsize, 4) != 4) - return -1; - - self->bit_size = (size_t)ntohl(bitsize); - - /** 32 bit -- number of compressed 64-bit words */ - if (read(fd, &word_count, 4) != 4) - return -1; - - self->buffer_size = self->alloc_size = (size_t)ntohl(word_count); - REALLOC_ARRAY(self->buffer, self->alloc_size); - - /** 64 bit x N -- compressed words */ - buffer = self->buffer; - words_left = self->buffer_size; - - while (words_left >= words_per_dump) { - if (read(fd, dump, sizeof(dump)) != sizeof(dump)) - return -1; - - for (i = 0; i < words_per_dump; ++i, ++buffer) - *buffer = ntohll(dump[i]); - - words_left -= words_per_dump; - } - - if (words_left) { - if (read(fd, dump, words_left * 8) != words_left * 8) - return -1; - - for (i = 0; i < words_left; ++i, ++buffer) - *buffer = ntohll(dump[i]); - } - - /** 32 bit -- position for the RLW */ - if (read(fd, &rlw_pos, 4) != 4) - return -1; - - self->rlw = self->buffer + ntohl(rlw_pos); - return 0; -} diff --git a/ewah/ewah_rlw.c b/ewah/ewah_rlw.c index b9643b7d0f..5093d43e2f 100644 --- a/ewah/ewah_rlw.c +++ b/ewah/ewah_rlw.c @@ -104,11 +104,3 @@ size_t rlwit_discharge( return index; } - -void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out) -{ - while (rlwit_word_size(it) > 0) { - ewah_add_empty_words(out, 0, rlwit_word_size(it)); - rlwit_discard_first_words(it, rlwit_word_size(it)); - } -} diff --git a/ewah/ewok.h b/ewah/ewok.h index 357fd93c84..84b2a29faa 100644 --- a/ewah/ewok.h +++ b/ewah/ewok.h @@ -73,12 +73,6 @@ void ewah_pool_free(struct ewah_bitmap *self); struct ewah_bitmap *ewah_new(void); /** - * Clear all the bits in the bitmap. Does not free or resize - * memory. - */ -void ewah_clear(struct ewah_bitmap *self); - -/** * Free all the memory of the bitmap */ void ewah_free(struct ewah_bitmap *self); @@ -86,23 +80,13 @@ void ewah_free(struct ewah_bitmap *self); int ewah_serialize_to(struct ewah_bitmap *self, int (*write_fun)(void *out, const void *buf, size_t len), void *out); -int ewah_serialize(struct ewah_bitmap *self, int fd); -int ewah_serialize_native(struct ewah_bitmap *self, int fd); int ewah_serialize_strbuf(struct ewah_bitmap *self, struct strbuf *); -int ewah_deserialize(struct ewah_bitmap *self, int fd); ssize_t ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len); uint32_t ewah_checksum(struct ewah_bitmap *self); /** - * Logical not (bitwise negation) in-place on the bitmap - * - * This operation is linear time based on the size of the bitmap. - */ -void ewah_not(struct ewah_bitmap *self); - -/** * Call the given callback with the position of every single bit * that has been set on the bitmap. * @@ -164,26 +148,11 @@ void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent); */ int ewah_iterator_next(eword_t *next, struct ewah_iterator *it); -void ewah_or( - struct ewah_bitmap *ewah_i, - struct ewah_bitmap *ewah_j, - struct ewah_bitmap *out); - -void ewah_and_not( - struct ewah_bitmap *ewah_i, - struct ewah_bitmap *ewah_j, - struct ewah_bitmap *out); - void ewah_xor( struct ewah_bitmap *ewah_i, struct ewah_bitmap *ewah_j, struct ewah_bitmap *out); -void ewah_and( - struct ewah_bitmap *ewah_i, - struct ewah_bitmap *ewah_j, - struct ewah_bitmap *out); - /** * Direct word access */ @@ -204,7 +173,6 @@ struct bitmap { struct bitmap *bitmap_new(void); void bitmap_set(struct bitmap *self, size_t pos); -void bitmap_clear(struct bitmap *self, size_t pos); int bitmap_get(struct bitmap *self, size_t pos); void bitmap_reset(struct bitmap *self); void bitmap_free(struct bitmap *self); @@ -218,7 +186,6 @@ void bitmap_and_not(struct bitmap *self, struct bitmap *other); void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other); void bitmap_or(struct bitmap *self, const struct bitmap *other); -void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data); size_t bitmap_popcount(struct bitmap *self); #endif diff --git a/ewah/ewok_rlw.h b/ewah/ewok_rlw.h index bb3c6ff7e0..7cdfdd0c02 100644 --- a/ewah/ewok_rlw.h +++ b/ewah/ewok_rlw.h @@ -98,7 +98,6 @@ void rlwit_init(struct rlw_iterator *it, struct ewah_bitmap *bitmap); void rlwit_discard_first_words(struct rlw_iterator *it, size_t x); size_t rlwit_discharge( struct rlw_iterator *it, struct ewah_bitmap *out, size_t max, int negate); -void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out); static inline size_t rlwit_word_size(struct rlw_iterator *it) { diff --git a/fetch-pack.c b/fetch-pack.c index cc7a42fee9..dbd879ac7f 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -19,6 +19,7 @@ #include "sha1-array.h" #include "oidset.h" #include "packfile.h" +#include "object-store.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -396,7 +397,7 @@ static int find_common(struct fetch_pack_args *args, return 1; } - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) write_shallow_commits(&req_buf, 1, NULL); if (args->depth > 0) packet_buf_write(&req_buf, "deepen %d", args->depth); @@ -427,7 +428,7 @@ static int find_common(struct fetch_pack_args *args, if (skip_prefix(line, "shallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), line); - register_shallow(&oid); + register_shallow(the_repository, &oid); continue; } if (skip_prefix(line, "unshallow ", &arg)) { @@ -985,7 +986,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); - if ((args->depth > 0 || is_repository_shallow()) && !server_supports("shallow")) + if ((args->depth > 0 || is_repository_shallow(the_repository)) && !server_supports("shallow")) die(_("Server does not support shallow clients")); if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; @@ -1083,7 +1084,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, static void add_shallow_requests(struct strbuf *req_buf, const struct fetch_pack_args *args) { - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) write_shallow_commits(req_buf, 1, NULL); if (args->depth > 0) packet_buf_write(req_buf, "deepen %d", args->depth); @@ -1195,7 +1196,7 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args, /* Add shallow-info and deepen request */ if (server_supports_feature("fetch", "shallow", 0)) add_shallow_requests(&req_buf, args); - else if (is_repository_shallow() || args->deepen) + else if (is_repository_shallow(the_repository) || args->deepen) die(_("Server does not support shallow requests")); /* Add filter */ @@ -1308,7 +1309,7 @@ static void receive_shallow_info(struct fetch_pack_args *args, if (skip_prefix(reader->line, "shallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), reader->line); - register_shallow(&oid); + register_shallow(the_repository, &oid); continue; } if (skip_prefix(reader->line, "unshallow ", &arg)) { @@ -1479,7 +1480,7 @@ static void update_shallow(struct fetch_pack_args *args, if (args->deepen && alternate_shallow_file) { if (*alternate_shallow_file == '\0') { /* --unshallow */ - unlink_or_warn(git_path_shallow()); + unlink_or_warn(git_path_shallow(the_repository)); rollback_lock_file(&shallow_lock); } else commit_lock_file(&shallow_lock); @@ -1,4 +1,5 @@ #include "cache.h" +#include "object-store.h" #include "object.h" #include "blob.h" #include "tree.h" @@ -315,6 +316,13 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id) strbuf_addstr(sb, ": "); } +static int object_on_skiplist(struct fsck_options *opts, struct object *obj) +{ + if (opts && opts->skiplist && obj) + return oid_array_lookup(opts->skiplist, &obj->oid) >= 0; + return 0; +} + __attribute__((format (printf, 4, 5))) static int report(struct fsck_options *options, struct object *object, enum fsck_msg_id id, const char *fmt, ...) @@ -326,8 +334,7 @@ static int report(struct fsck_options *options, struct object *object, if (msg_type == FSCK_IGNORE) return 0; - if (options->skiplist && object && - oid_array_lookup(options->skiplist, &object->oid) >= 0) + if (object_on_skiplist(options, object)) return 0; if (msg_type == FSCK_FATAL) @@ -795,7 +802,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, buffer = p + 1; parent_line_count++; } - graft = lookup_commit_graft(&commit->object.oid); + graft = lookup_commit_graft(the_repository, &commit->object.oid); parent_count = commit_list_count(commit->parents); if (graft) { if (graft->nr_parent == -1 && !parent_count) @@ -997,6 +1004,9 @@ static int fsck_blob(struct blob *blob, const char *buf, return 0; oidset_insert(&gitmodules_done, &blob->object.oid); + if (object_on_skiplist(options, &blob->object)) + return 0; + if (!buf) { /* * A missing buffer here is a sign that the caller found the diff --git a/git-filter-branch.sh b/git-filter-branch.sh index ccceaf19a7..5c5afa2b98 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -372,6 +372,7 @@ while read commit parents; do git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1)) report_progress + test -f "$workdir"/../map/$commit && continue case "$filter_subdir" in "") @@ -27,6 +27,22 @@ import zlib import ctypes import errno +# support basestring in python3 +try: + unicode = unicode +except NameError: + # 'unicode' is undefined, must be Python 3 + str = str + unicode = str + bytes = bytes + basestring = (str,bytes) +else: + # 'unicode' exists, must be Python 2 + str = str + unicode = unicode + bytes = str + basestring = basestring + try: from subprocess import CalledProcessError except ImportError: @@ -767,7 +783,7 @@ def gitDeleteRef(ref): _gitConfig = {} def gitConfig(key, typeSpecifier=None): - if not _gitConfig.has_key(key): + if key not in _gitConfig: cmd = [ "git", "config" ] if typeSpecifier: cmd += [ typeSpecifier ] @@ -781,12 +797,12 @@ def gitConfigBool(key): variable is set to true, and False if set to false or not present in the config.""" - if not _gitConfig.has_key(key): + if key not in _gitConfig: _gitConfig[key] = gitConfig(key, '--bool') == "true" return _gitConfig[key] def gitConfigInt(key): - if not _gitConfig.has_key(key): + if key not in _gitConfig: cmd = [ "git", "config", "--int", key ] s = read_pipe(cmd, ignore_error=True) v = s.strip() @@ -797,7 +813,7 @@ def gitConfigInt(key): return _gitConfig[key] def gitConfigList(key): - if not _gitConfig.has_key(key): + if key not in _gitConfig: s = read_pipe(["git", "config", "--get-all", key], ignore_error=True) _gitConfig[key] = s.strip().splitlines() if _gitConfig[key] == ['']: @@ -855,7 +871,7 @@ def findUpstreamBranchPoint(head = "HEAD"): tip = branches[branch] log = extractLogMessageFromGitCommit(tip) settings = extractSettingsGitLog(log) - if settings.has_key("depot-paths"): + if "depot-paths" in settings: paths = ",".join(settings["depot-paths"]) branchByDepotPath[paths] = "remotes/p4/" + branch @@ -865,9 +881,9 @@ def findUpstreamBranchPoint(head = "HEAD"): commit = head + "~%s" % parent log = extractLogMessageFromGitCommit(commit) settings = extractSettingsGitLog(log) - if settings.has_key("depot-paths"): + if "depot-paths" in settings: paths = ",".join(settings["depot-paths"]) - if branchByDepotPath.has_key(paths): + if paths in branchByDepotPath: return [branchByDepotPath[paths], settings] parent = parent + 1 @@ -876,7 +892,7 @@ def findUpstreamBranchPoint(head = "HEAD"): def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent=True): if not silent: - print ("Creating/updating branch(es) in %s based on origin branch(es)" + print("Creating/updating branch(es) in %s based on origin branch(es)" % localRefPrefix) originPrefix = "origin/p4/" @@ -891,29 +907,29 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent originHead = line original = extractSettingsGitLog(extractLogMessageFromGitCommit(originHead)) - if (not original.has_key('depot-paths') - or not original.has_key('change')): + if ('depot-paths' not in original + or 'change' not in original): continue update = False if not gitBranchExists(remoteHead): if verbose: - print "creating %s" % remoteHead + print("creating %s" % remoteHead) update = True else: settings = extractSettingsGitLog(extractLogMessageFromGitCommit(remoteHead)) - if settings.has_key('change') > 0: + if 'change' in settings: if settings['depot-paths'] == original['depot-paths']: originP4Change = int(original['change']) p4Change = int(settings['change']) if originP4Change > p4Change: - print ("%s (%s) is newer than %s (%s). " + print("%s (%s) is newer than %s (%s). " "Updating p4 branch from origin." % (originHead, originP4Change, remoteHead, p4Change)) update = True else: - print ("Ignoring: %s was imported from %s while " + print("Ignoring: %s was imported from %s while " "%s was imported from %s" % (originHead, ','.join(original['depot-paths']), remoteHead, ','.join(settings['depot-paths']))) @@ -1002,7 +1018,7 @@ def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize): # Insert changes in chronological order for entry in reversed(result): - if not entry.has_key('change'): + if 'change' not in entry: continue changes.add(int(entry['change'])) @@ -1312,7 +1328,7 @@ class P4UserMap: results = p4CmdList("user -o") for r in results: - if r.has_key('User'): + if 'User' in r: self.myP4UserId = r['User'] return r['User'] die("Could not find your p4 user id") @@ -1336,7 +1352,7 @@ class P4UserMap: self.emails = {} for output in p4CmdList("users"): - if not output.has_key("User"): + if "User" not in output: continue self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">" self.emails[output["Email"]] = output["User"] @@ -1381,9 +1397,9 @@ class P4Debug(Command): def run(self, args): j = 0 for output in p4CmdList(args): - print 'Element: %d' % j + print('Element: %d' % j) j += 1 - print output + print(output) return True class P4RollBack(Command): @@ -1424,14 +1440,14 @@ class P4RollBack(Command): if len(p4Cmd("changes -m 1 " + ' '.join (['%s...@%s' % (p, maxChange) for p in depotPaths]))) == 0: - print "Branch %s did not exist at change %s, deleting." % (ref, maxChange) + print("Branch %s did not exist at change %s, deleting." % (ref, maxChange)) system("git update-ref -d %s `git rev-parse %s`" % (ref, ref)) continue while change and int(change) > maxChange: changed = True if self.verbose: - print "%s is at %s ; rewinding towards %s" % (ref, change, maxChange) + print("%s is at %s ; rewinding towards %s" % (ref, change, maxChange)) system("git update-ref %s \"%s^\"" % (ref, ref)) log = extractLogMessageFromGitCommit(ref) settings = extractSettingsGitLog(log) @@ -1441,7 +1457,7 @@ class P4RollBack(Command): change = settings['change'] if changed: - print "%s rewound to %s" % (ref, change) + print("%s rewound to %s" % (ref, change)) return True @@ -1577,10 +1593,10 @@ class P4Submit(Command, P4UserMap): except: # cleanup our temporary file os.unlink(outFileName) - print "Failed to strip RCS keywords in %s" % file + print("Failed to strip RCS keywords in %s" % file) raise - print "Patched up RCS keywords in %s" % file + print("Patched up RCS keywords in %s" % file) def p4UserForCommit(self,id): # Return the tuple (perforce user,git email) for a given git commit id @@ -1588,7 +1604,7 @@ class P4Submit(Command, P4UserMap): gitEmail = read_pipe(["git", "log", "--max-count=1", "--format=%ae", id]) gitEmail = gitEmail.strip() - if not self.emails.has_key(gitEmail): + if gitEmail not in self.emails: return (None,gitEmail) else: return (self.emails[gitEmail],gitEmail) @@ -1600,7 +1616,7 @@ class P4Submit(Command, P4UserMap): if not user: msg = "Cannot find p4 user for email %s in commit %s." % (email, id) if gitConfigBool("git-p4.allowMissingP4Users"): - print "%s" % msg + print("%s" % msg) else: die("Error: %s\nSet git-p4.allowMissingP4Users to true to allow this." % msg) @@ -1612,14 +1628,14 @@ class P4Submit(Command, P4UserMap): results = p4CmdList("client -o") # find the current client client = None for r in results: - if r.has_key('Client'): + if 'Client' in r: client = r['Client'] break if not client: die("could not get client spec") results = p4CmdList(["changes", "-c", client, "-m", "1"]) for r in results: - if r.has_key('change'): + if 'change' in r: return r['change'] die("Could not get changelist number for last submit - cannot patch up user details") @@ -1637,10 +1653,10 @@ class P4Submit(Command, P4UserMap): result = p4CmdList("change -f -i", stdin=input) for r in result: - if r.has_key('code'): + if 'code' in r: if r['code'] == 'error': die("Could not modify user field of changelist %s to %s:%s" % (changelist, newUser, r['data'])) - if r.has_key('data'): + if 'data' in r: print("Updated user field for changelist %s to %s" % (changelist, newUser)) return die("Could not modify user field of changelist %s to %s" % (changelist, newUser)) @@ -1650,7 +1666,7 @@ class P4Submit(Command, P4UserMap): # which are required to modify changelists. results = p4CmdList(["protects", self.depotPath]) for r in results: - if r.has_key('perm'): + if 'perm' in r: if r['perm'] == 'admin': return 1 if r['perm'] == 'super': @@ -1690,7 +1706,7 @@ class P4Submit(Command, P4UserMap): if changelist: args.append(str(changelist)) for entry in p4CmdList(args): - if not entry.has_key('code'): + if 'code' not in entry: continue if entry['code'] == 'stat': change_entry = entry @@ -1699,7 +1715,7 @@ class P4Submit(Command, P4UserMap): die('Failed to decode output of p4 change -o') for key, value in change_entry.iteritems(): if key.startswith('File'): - if settings.has_key('depot-paths'): + if 'depot-paths' in settings: if not [p for p in settings['depot-paths'] if p4PathStartsWith(value, p)]: continue @@ -1710,7 +1726,7 @@ class P4Submit(Command, P4UserMap): continue # Output in the order expected by prepareLogMessage for key in ['Change', 'Client', 'User', 'Status', 'Description', 'Jobs']: - if not change_entry.has_key(key): + if key not in change_entry: continue template += '\n' template += key + ':' @@ -1738,7 +1754,7 @@ class P4Submit(Command, P4UserMap): mtime = os.stat(template_file).st_mtime # invoke the editor - if os.environ.has_key("P4EDITOR") and (os.environ.get("P4EDITOR") != ""): + if "P4EDITOR" in os.environ and (os.environ.get("P4EDITOR") != ""): editor = os.environ.get("P4EDITOR") else: editor = read_pipe("git var GIT_EDITOR").strip() @@ -1762,7 +1778,7 @@ class P4Submit(Command, P4UserMap): def get_diff_description(self, editedFiles, filesToAdd, symlinks): # diff - if os.environ.has_key("P4DIFF"): + if "P4DIFF" in os.environ: del(os.environ["P4DIFF"]) diff = "" for editedFile in editedFiles: @@ -1792,8 +1808,8 @@ class P4Submit(Command, P4UserMap): def applyCommit(self, id): """Apply one commit, return True if it succeeded.""" - print "Applying", read_pipe(["git", "show", "-s", - "--format=format:%h %s", id]) + print("Applying", read_pipe(["git", "show", "-s", + "--format=format:%h %s", id])) (p4User, gitEmail) = self.p4UserForCommit(id) @@ -1825,7 +1841,7 @@ class P4Submit(Command, P4UserMap): filesToDelete.remove(path) dst_mode = int(diff['dst_mode'], 8) - if dst_mode == 0120000: + if dst_mode == 0o120000: symlinks.add(path) elif modifier == "D": @@ -1883,7 +1899,7 @@ class P4Submit(Command, P4UserMap): if os.system(tryPatchCmd) != 0: fixed_rcs_keywords = False patch_succeeded = False - print "Unfortunately applying the change failed!" + print("Unfortunately applying the change failed!") # Patch failed, maybe it's just RCS keyword woes. Look through # the patch to see if that's possible. @@ -1901,13 +1917,13 @@ class P4Submit(Command, P4UserMap): for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]): if regexp.search(line): if verbose: - print "got keyword match on %s in %s in %s" % (pattern, line, file) + print("got keyword match on %s in %s in %s" % (pattern, line, file)) kwfiles[file] = pattern break for file in kwfiles: if verbose: - print "zapping %s with %s" % (line,pattern) + print("zapping %s with %s" % (line,pattern)) # File is being deleted, so not open in p4. Must # disable the read-only bit on windows. if self.isWindows and file not in editedFiles: @@ -1916,7 +1932,7 @@ class P4Submit(Command, P4UserMap): fixed_rcs_keywords = True if fixed_rcs_keywords: - print "Retrying the patch with RCS keywords cleaned up" + print("Retrying the patch with RCS keywords cleaned up") if os.system(tryPatchCmd) == 0: patch_succeeded = True @@ -1984,34 +2000,34 @@ class P4Submit(Command, P4UserMap): # Leave the p4 tree prepared, and the submit template around # and let the user decide what to do next # - print - print "P4 workspace prepared for submission." - print "To submit or revert, go to client workspace" - print " " + self.clientPath - print - print "To submit, use \"p4 submit\" to write a new description," - print "or \"p4 submit -i <%s\" to use the one prepared by" \ - " \"git p4\"." % fileName - print "You can delete the file \"%s\" when finished." % fileName + print() + print("P4 workspace prepared for submission.") + print("To submit or revert, go to client workspace") + print(" " + self.clientPath) + print() + print("To submit, use \"p4 submit\" to write a new description,") + print("or \"p4 submit -i <%s\" to use the one prepared by" \ + " \"git p4\"." % fileName) + print("You can delete the file \"%s\" when finished." % fileName) if self.preserveUser and p4User and not self.p4UserIsMe(p4User): - print "To preserve change ownership by user %s, you must\n" \ + print("To preserve change ownership by user %s, you must\n" \ "do \"p4 change -f <change>\" after submitting and\n" \ - "edit the User field." + "edit the User field.") if pureRenameCopy: - print "After submitting, renamed files must be re-synced." - print "Invoke \"p4 sync -f\" on each of these files:" + print("After submitting, renamed files must be re-synced.") + print("Invoke \"p4 sync -f\" on each of these files:") for f in pureRenameCopy: - print " " + f + print(" " + f) - print - print "To revert the changes, use \"p4 revert ...\", and delete" - print "the submit template file \"%s\"" % fileName + print() + print("To revert the changes, use \"p4 revert ...\", and delete") + print("the submit template file \"%s\"" % fileName) if filesToAdd: - print "Since the commit adds new files, they must be deleted:" + print("Since the commit adds new files, they must be deleted:") for f in filesToAdd: - print " " + f - print + print(" " + f) + print() return True # @@ -2078,17 +2094,17 @@ class P4Submit(Command, P4UserMap): if not m.match(name): if verbose: - print "tag %s does not match regexp %s" % (name, validLabelRegexp) + print("tag %s does not match regexp %s" % (name, validLabelRegexp)) continue # Get the p4 commit this corresponds to logMessage = extractLogMessageFromGitCommit(name) values = extractSettingsGitLog(logMessage) - if not values.has_key('change'): + if 'change' not in values: # a tag pointing to something not sent to p4; ignore if verbose: - print "git tag %s does not give a p4 commit" % name + print("git tag %s does not give a p4 commit" % name) continue else: changelist = values['change'] @@ -2123,10 +2139,10 @@ class P4Submit(Command, P4UserMap): labelTemplate += "\t%s\n" % depot_side if self.dry_run: - print "Would create p4 label %s for tag" % name + print("Would create p4 label %s for tag" % name) elif self.prepare_p4_only: - print "Not creating p4 label %s for tag due to option" \ - " --prepare-p4-only" % name + print("Not creating p4 label %s for tag due to option" \ + " --prepare-p4-only" % name) else: p4_write_pipe(["label", "-i"], labelTemplate) @@ -2135,7 +2151,7 @@ class P4Submit(Command, P4UserMap): ["%s@%s" % (depot_side, changelist) for depot_side in clientSpec.mappings]) if verbose: - print "created p4 label for tag %s" % name + print("created p4 label for tag %s" % name) def run(self, args): if len(args) == 0: @@ -2179,10 +2195,10 @@ class P4Submit(Command, P4UserMap): self.conflict_behavior = val if self.verbose: - print "Origin branch is " + self.origin + print("Origin branch is " + self.origin) if len(self.depotPath) == 0: - print "Internal error: cannot locate perforce depot path from existing branches" + print("Internal error: cannot locate perforce depot path from existing branches") sys.exit(128) self.useClientSpec = False @@ -2203,7 +2219,7 @@ class P4Submit(Command, P4UserMap): if self.clientPath == "": die("Error: Cannot locate perforce checkout of %s in client view" % self.depotPath) - print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath) + print("Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)) self.oldWorkingDirectory = os.getcwd() # ensure the clientPath exists @@ -2214,9 +2230,9 @@ class P4Submit(Command, P4UserMap): chdir(self.clientPath, is_client_path=True) if self.dry_run: - print "Would synchronize p4 checkout in %s" % self.clientPath + print("Would synchronize p4 checkout in %s" % self.clientPath) else: - print "Synchronizing p4 checkout..." + print("Synchronizing p4 checkout...") if new_client_dir: # old one was destroyed, and maybe nobody told p4 p4_sync("...", "-f") @@ -2292,13 +2308,13 @@ class P4Submit(Command, P4UserMap): # continue to try the rest of the patches, or quit. # if self.dry_run: - print "Would apply" + print("Would apply") applied = [] last = len(commits) - 1 for i, commit in enumerate(commits): if self.dry_run: - print " ", read_pipe(["git", "show", "-s", - "--format=format:%h %s", commit]) + print(" ", read_pipe(["git", "show", "-s", + "--format=format:%h %s", commit])) ok = True else: ok = self.applyCommit(commit) @@ -2306,15 +2322,15 @@ class P4Submit(Command, P4UserMap): applied.append(commit) else: if self.prepare_p4_only and i < last: - print "Processing only the first commit due to option" \ - " --prepare-p4-only" + print("Processing only the first commit due to option" \ + " --prepare-p4-only") break if i < last: quit = False while True: # prompt for what to do, or use the option/variable if self.conflict_behavior == "ask": - print "What do you want to do?" + print("What do you want to do?") response = raw_input("[s]kip this commit but apply" " the rest, or [q]uit? ") if not response: @@ -2328,10 +2344,10 @@ class P4Submit(Command, P4UserMap): self.conflict_behavior) if response[0] == "s": - print "Skipping this commit, but applying the rest" + print("Skipping this commit, but applying the rest") break if response[0] == "q": - print "Quitting" + print("Quitting") quit = True break if quit: @@ -2344,7 +2360,7 @@ class P4Submit(Command, P4UserMap): elif self.prepare_p4_only: pass elif len(commits) == len(applied): - print ("All commits {0}!".format(shelved_applied)) + print("All commits {0}!".format(shelved_applied)) sync = P4Sync() if self.branch: @@ -2360,17 +2376,17 @@ class P4Submit(Command, P4UserMap): else: if len(applied) == 0: - print ("No commits {0}.".format(shelved_applied)) + print("No commits {0}.".format(shelved_applied)) else: - print ("{0} only the commits marked with '*':".format(shelved_applied.capitalize())) + print("{0} only the commits marked with '*':".format(shelved_applied.capitalize())) for c in commits: if c in applied: star = "*" else: star = " " - print star, read_pipe(["git", "show", "-s", - "--format=format:%h %s", c]) - print "You will have to do 'git p4 sync' and rebase." + print(star, read_pipe(["git", "show", "-s", + "--format=format:%h %s", c])) + print("You will have to do 'git p4 sync' and rebase.") if gitConfigBool("git-p4.exportLabels"): self.exportLabels = True @@ -2580,7 +2596,7 @@ class P4Sync(Command, P4UserMap): self.gitStream.write("progress checkpoint\n\n") out = self.gitOutput.readline() if self.verbose: - print "checkpoint finished: " + out + print("checkpoint finished: " + out) def cmp_shelved(self, path, filerev, revision): """ Determine if a path at revision #filerev is the same as the file @@ -2600,7 +2616,7 @@ class P4Sync(Command, P4UserMap): for path in self.cloneExclude] files = [] fnum = 0 - while commit.has_key("depotFile%s" % fnum): + while "depotFile%s" % fnum in commit: path = commit["depotFile%s" % fnum] if [p for p in self.cloneExclude @@ -2638,7 +2654,7 @@ class P4Sync(Command, P4UserMap): def extractJobsFromCommit(self, commit): jobs = [] jnum = 0 - while commit.has_key("job%s" % jnum): + while "job%s" % jnum in commit: job = commit["job%s" % jnum] jobs.append(job) jnum = jnum + 1 @@ -2686,7 +2702,7 @@ class P4Sync(Command, P4UserMap): branches = {} fnum = 0 - while commit.has_key("depotFile%s" % fnum): + while "depotFile%s" % fnum in commit: path = commit["depotFile%s" % fnum] found = [p for p in self.depotPaths if p4PathStartsWith(path, p)] @@ -2735,7 +2751,7 @@ class P4Sync(Command, P4UserMap): encoding = gitConfig('git-p4.pathEncoding') path = path.decode(encoding, 'replace').encode('utf8', 'replace') if self.verbose: - print 'Path with non-ASCII characters detected. Used %s to encode: %s ' % (encoding, path) + print('Path with non-ASCII characters detected. Used %s to encode: %s ' % (encoding, path)) return path # output one file from the P4 stream @@ -2764,7 +2780,7 @@ class P4Sync(Command, P4UserMap): # to nothing. This causes p4 errors when checking out such # a change, and errors here too. Work around it by ignoring # the bad symlink; hopefully a future change fixes it. - print "\nIgnoring empty symlink in %s" % file['depotFile'] + print("\nIgnoring empty symlink in %s" % file['depotFile']) return elif data[-1] == '\n': contents = [data[:-1]] @@ -2804,7 +2820,7 @@ class P4Sync(Command, P4UserMap): # Ideally, someday, this script can learn how to generate # appledouble files directly and import those to git, but # non-mac machines can never find a use for apple filetype. - print "\nIgnoring apple filetype file %s" % file['depotFile'] + print("\nIgnoring apple filetype file %s" % file['depotFile']) return # Note that we do not try to de-mangle keywords on utf16 files, @@ -2866,7 +2882,7 @@ class P4Sync(Command, P4UserMap): else: die("Error from p4 print: %s" % err) - if marshalled.has_key('depotFile') and self.stream_have_file_info: + if 'depotFile' in marshalled and self.stream_have_file_info: # start of a new file - output the old one first self.streamOneP4File(self.stream_file, self.stream_contents) self.stream_file = {} @@ -2938,7 +2954,7 @@ class P4Sync(Command, P4UserMap): cb=streamP4FilesCbSelf) # do the last chunk - if self.stream_file.has_key('depotFile'): + if 'depotFile' in self.stream_file: self.streamOneP4File(self.stream_file, self.stream_contents) def make_email(self, userid): @@ -2953,11 +2969,11 @@ class P4Sync(Command, P4UserMap): """ if verbose: - print "writing tag %s for commit %s" % (labelName, commit) + print("writing tag %s for commit %s" % (labelName, commit)) gitStream.write("tag %s\n" % labelName) gitStream.write("from %s\n" % commit) - if labelDetails.has_key('Owner'): + if 'Owner' in labelDetails: owner = labelDetails["Owner"] else: owner = None @@ -2972,8 +2988,8 @@ class P4Sync(Command, P4UserMap): gitStream.write("tagger %s\n" % tagger) - print "labelDetails=",labelDetails - if labelDetails.has_key('Description'): + print("labelDetails=",labelDetails) + if 'Description' in labelDetails: description = labelDetails['Description'] else: description = 'Label from git p4' @@ -3044,7 +3060,7 @@ class P4Sync(Command, P4UserMap): if len(parent) > 0: if self.verbose: - print "parent %s" % parent + print("parent %s" % parent) self.gitStream.write("from %s\n" % parent) self.streamP4Files(files) @@ -3052,12 +3068,12 @@ class P4Sync(Command, P4UserMap): change = int(details["change"]) - if self.labels.has_key(change): + if change in self.labels: label = self.labels[change] labelDetails = label[0] labelRevisions = label[1] if self.verbose: - print "Change %s is labelled %s" % (change, labelDetails) + print("Change %s is labelled %s" % (change, labelDetails)) files = p4CmdList(["files"] + ["%s...@%s" % (p, change) for p in self.branchPrefixes]) @@ -3075,12 +3091,12 @@ class P4Sync(Command, P4UserMap): else: if not self.silent: - print ("Tag %s does not match with change %s: files do not match." + print("Tag %s does not match with change %s: files do not match." % (labelDetails["label"], change)) else: if not self.silent: - print ("Tag %s does not match with change %s: file count is different." + print("Tag %s does not match with change %s: file count is different." % (labelDetails["label"], change)) # Build a dictionary of changelists and labels, for "detect-labels" option. @@ -3089,14 +3105,14 @@ class P4Sync(Command, P4UserMap): l = p4CmdList(["labels"] + ["%s..." % p for p in self.depotPaths]) if len(l) > 0 and not self.silent: - print "Finding files belonging to labels in %s" % `self.depotPaths` + print("Finding files belonging to labels in %s" % self.depotPaths) for output in l: label = output["label"] revisions = {} newestChange = 0 if self.verbose: - print "Querying files for label %s" % label + print("Querying files for label %s" % label) for file in p4CmdList(["files"] + ["%s...@%s" % (p, label) for p in self.depotPaths]): @@ -3108,7 +3124,7 @@ class P4Sync(Command, P4UserMap): self.labels[newestChange] = [output, revisions] if self.verbose: - print "Label changes: %s" % self.labels.keys() + print("Label changes: %s" % self.labels.keys()) # Import p4 labels as git tags. A direct mapping does not # exist, so assume that if all the files are at the same revision @@ -3116,7 +3132,7 @@ class P4Sync(Command, P4UserMap): # just ignore. def importP4Labels(self, stream, p4Labels): if verbose: - print "import p4 labels: " + ' '.join(p4Labels) + print("import p4 labels: " + ' '.join(p4Labels)) ignoredP4Labels = gitConfigList("git-p4.ignoredP4Labels") validLabelRegexp = gitConfig("git-p4.labelImportRegexp") @@ -3129,7 +3145,7 @@ class P4Sync(Command, P4UserMap): if not m.match(name): if verbose: - print "label %s does not match regexp %s" % (name,validLabelRegexp) + print("label %s does not match regexp %s" % (name,validLabelRegexp)) continue if name in ignoredP4Labels: @@ -3141,7 +3157,7 @@ class P4Sync(Command, P4UserMap): change = p4Cmd(["changes", "-m", "1"] + ["%s...@%s" % (p, name) for p in self.depotPaths]) - if change.has_key('change'): + if 'change' in change: # find the corresponding git commit; take the oldest commit changelist = int(change['change']) if changelist in self.committedChanges: @@ -3151,7 +3167,7 @@ class P4Sync(Command, P4UserMap): gitCommit = read_pipe(["git", "rev-list", "--max-count=1", "--reverse", ":/\[git-p4:.*change = %d\]" % changelist], ignore_error=True) if len(gitCommit) == 0: - print "importing label %s: could not find git commit for changelist %d" % (name, changelist) + print("importing label %s: could not find git commit for changelist %d" % (name, changelist)) else: commitFound = True gitCommit = gitCommit.strip() @@ -3161,16 +3177,16 @@ class P4Sync(Command, P4UserMap): try: tmwhen = time.strptime(labelDetails['Update'], "%Y/%m/%d %H:%M:%S") except ValueError: - print "Could not convert label time %s" % labelDetails['Update'] + print("Could not convert label time %s" % labelDetails['Update']) tmwhen = 1 when = int(time.mktime(tmwhen)) self.streamTag(stream, name, labelDetails, gitCommit, when) if verbose: - print "p4 label %s mapped to git commit %s" % (name, gitCommit) + print("p4 label %s mapped to git commit %s" % (name, gitCommit)) else: if verbose: - print "Label %s has no changelists - possibly deleted?" % name + print("Label %s has no changelists - possibly deleted?" % name) if not commitFound: # We can't import this label; don't try again as it will get very @@ -3200,7 +3216,7 @@ class P4Sync(Command, P4UserMap): for info in p4CmdList(command): details = p4Cmd(["branch", "-o", info["branch"]]) viewIdx = 0 - while details.has_key("View%s" % viewIdx): + while "View%s" % viewIdx in details: paths = details["View%s" % viewIdx].split(" ") viewIdx = viewIdx + 1 # require standard //depot/foo/... //depot/bar/... mapping @@ -3215,8 +3231,8 @@ class P4Sync(Command, P4UserMap): if destination in self.knownBranches: if not self.silent: - print "p4 branch %s defines a mapping from %s to %s" % (info["branch"], source, destination) - print "but there exists another mapping from %s to %s already!" % (self.knownBranches[destination], destination) + print("p4 branch %s defines a mapping from %s to %s" % (info["branch"], source, destination)) + print("but there exists another mapping from %s to %s already!" % (self.knownBranches[destination], destination)) continue self.knownBranches[destination] = source @@ -3266,7 +3282,7 @@ class P4Sync(Command, P4UserMap): d["options"] = ' '.join(sorted(option_keys.keys())) def readOptions(self, d): - self.keepRepoPath = (d.has_key('options') + self.keepRepoPath = ('options' in d and ('keepRepoPath' in d['options'])) def gitRefForBranch(self, branch): @@ -3280,28 +3296,28 @@ class P4Sync(Command, P4UserMap): def gitCommitByP4Change(self, ref, change): if self.verbose: - print "looking in ref " + ref + " for change %s using bisect..." % change + print("looking in ref " + ref + " for change %s using bisect..." % change) earliestCommit = "" latestCommit = parseRevision(ref) while True: if self.verbose: - print "trying: earliest %s latest %s" % (earliestCommit, latestCommit) + print("trying: earliest %s latest %s" % (earliestCommit, latestCommit)) next = read_pipe("git rev-list --bisect %s %s" % (latestCommit, earliestCommit)).strip() if len(next) == 0: if self.verbose: - print "argh" + print("argh") return "" log = extractLogMessageFromGitCommit(next) settings = extractSettingsGitLog(log) currentChange = int(settings['change']) if self.verbose: - print "current change %s" % currentChange + print("current change %s" % currentChange) if currentChange == change: if self.verbose: - print "found %s" % next + print("found %s" % next) return next if currentChange < change: @@ -3347,7 +3363,7 @@ class P4Sync(Command, P4UserMap): if len(read_pipe(["git", "diff-tree", blob, target])) == 0: parentFound = True if self.verbose: - print "Found parent of %s in commit %s" % (branch, blob) + print("Found parent of %s in commit %s" % (branch, blob)) break if parentFound: return blob @@ -3378,7 +3394,7 @@ class P4Sync(Command, P4UserMap): filesForCommit = branches[branch] if self.verbose: - print "branch is %s" % branch + print("branch is %s" % branch) self.updatedBranches.add(branch) @@ -3399,13 +3415,13 @@ class P4Sync(Command, P4UserMap): print("\n Resuming with change %s" % change); if self.verbose: - print "parent determined through known branches: %s" % parent + print("parent determined through known branches: %s" % parent) branch = self.gitRefForBranch(branch) parent = self.gitRefForBranch(parent) if self.verbose: - print "looking for initial parent for %s; current parent is %s" % (branch, parent) + print("looking for initial parent for %s; current parent is %s" % (branch, parent)) if len(parent) == 0 and branch in self.initialParents: parent = self.initialParents[branch] @@ -3415,7 +3431,7 @@ class P4Sync(Command, P4UserMap): if len(parent) > 0: tempBranch = "%s/%d" % (self.tempBranchLocation, change) if self.verbose: - print "Creating temporary branch: " + tempBranch + print("Creating temporary branch: " + tempBranch) self.commit(description, filesForCommit, tempBranch) self.tempBranches.append(tempBranch) self.checkpoint() @@ -3424,7 +3440,7 @@ class P4Sync(Command, P4UserMap): self.commit(description, filesForCommit, branch, blob) else: if self.verbose: - print "Parent of %s not found. Committing into head of %s" % (branch, parent) + print("Parent of %s not found. Committing into head of %s" % (branch, parent)) self.commit(description, filesForCommit, branch, parent) else: files = self.extractFilesFromCommit(description, shelved, change, origin_revision) @@ -3433,7 +3449,7 @@ class P4Sync(Command, P4UserMap): # only needed once, to connect to the previous commit self.initialParent = "" except IOError: - print self.gitError.read() + print(self.gitError.read()) sys.exit(1) def sync_origin_only(self): @@ -3441,11 +3457,11 @@ class P4Sync(Command, P4UserMap): self.hasOrigin = originP4BranchesExist() if self.hasOrigin: if not self.silent: - print 'Syncing with origin first, using "git fetch origin"' + print('Syncing with origin first, using "git fetch origin"') system("git fetch origin") def importHeadRevision(self, revision): - print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch) + print("Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)) details = {} details["user"] = "git perforce import user" @@ -3497,8 +3513,8 @@ class P4Sync(Command, P4UserMap): try: self.commit(details, self.extractFilesFromCommit(details), self.branch) except IOError: - print "IO error with git fast-import. Is your git version recent enough?" - print self.gitError.read() + print("IO error with git fast-import. Is your git version recent enough?") + print(self.gitError.read()) def openStreams(self): self.importProcess = subprocess.Popen(["git", "fast-import"], @@ -3560,14 +3576,14 @@ class P4Sync(Command, P4UserMap): if len(self.p4BranchesInGit) > 1: if not self.silent: - print "Importing from/into multiple branches" + print("Importing from/into multiple branches") self.detectBranches = True for branch in branches.keys(): self.initialParents[self.refPrefix + branch] = \ branches[branch] if self.verbose: - print "branches: %s" % self.p4BranchesInGit + print("branches: %s" % self.p4BranchesInGit) p4Change = 0 for branch in self.p4BranchesInGit: @@ -3576,8 +3592,8 @@ class P4Sync(Command, P4UserMap): settings = extractSettingsGitLog(logMsg) self.readOptions(settings) - if (settings.has_key('depot-paths') - and settings.has_key ('change')): + if ('depot-paths' in settings + and 'change' in settings): change = int(settings['change']) + 1 p4Change = max(p4Change, change) @@ -3590,7 +3606,7 @@ class P4Sync(Command, P4UserMap): prev_list = prev.split("/") cur_list = cur.split("/") for i in range(0, min(len(cur_list), len(prev_list))): - if cur_list[i] <> prev_list[i]: + if cur_list[i] != prev_list[i]: i = i - 1 break @@ -3602,7 +3618,7 @@ class P4Sync(Command, P4UserMap): self.depotPaths = sorted(self.previousDepotPaths) self.changeRange = "@%s,#head" % p4Change if not self.silent and not self.detectBranches: - print "Performing incremental import into %s git branch" % self.branch + print("Performing incremental import into %s git branch" % self.branch) # accept multiple ref name abbreviations: # refs/foo/bar/branch -> use it exactly @@ -3619,10 +3635,10 @@ class P4Sync(Command, P4UserMap): if len(args) == 0 and self.depotPaths: if not self.silent: - print "Depot paths: %s" % ' '.join(self.depotPaths) + print("Depot paths: %s" % ' '.join(self.depotPaths)) else: if self.depotPaths and self.depotPaths != args: - print ("previous import used depot path %s and now %s was specified. " + print("previous import used depot path %s and now %s was specified. " "This doesn't work!" % (' '.join (self.depotPaths), ' '.join (args))) sys.exit(1) @@ -3689,8 +3705,8 @@ class P4Sync(Command, P4UserMap): else: self.getBranchMapping() if self.verbose: - print "p4-git branches: %s" % self.p4BranchesInGit - print "initial parents: %s" % self.initialParents + print("p4-git branches: %s" % self.p4BranchesInGit) + print("initial parents: %s" % self.initialParents) for b in self.p4BranchesInGit: if b != "master": @@ -3734,8 +3750,8 @@ class P4Sync(Command, P4UserMap): self.branch) if self.verbose: - print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), - self.changeRange) + print("Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), + self.changeRange)) changes = p4ChangesForPaths(self.depotPaths, self.changeRange, self.changes_block_size) if len(self.maxChanges) > 0: @@ -3743,10 +3759,10 @@ class P4Sync(Command, P4UserMap): if len(changes) == 0: if not self.silent: - print "No changes to import!" + print("No changes to import!") else: if not self.silent and not self.detectBranches: - print "Import destination: %s" % self.branch + print("Import destination: %s" % self.branch) self.updatedBranches = set() @@ -3761,7 +3777,7 @@ class P4Sync(Command, P4UserMap): self.importChanges(changes) if not self.silent: - print "" + print("") if len(self.updatedBranches) > 0: sys.stdout.write("Updated branches: ") for b in self.updatedBranches: @@ -3825,7 +3841,7 @@ class P4Rebase(Command): # the branchpoint may be p4/foo~3, so strip off the parent upstream = re.sub("~[0-9]+$", "", upstream) - print "Rebasing the current branch onto %s" % upstream + print("Rebasing the current branch onto %s" % upstream) oldHead = read_pipe("git rev-parse HEAD").strip() system("git rebase %s" % upstream) system("git diff-tree --stat --summary -M %s HEAD --" % oldHead) @@ -3879,7 +3895,7 @@ class P4Clone(P4Sync): if not self.cloneDestination: self.cloneDestination = self.defaultDestination(args) - print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination) + print("Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)) if not os.path.exists(self.cloneDestination): os.makedirs(self.cloneDestination) @@ -3901,8 +3917,8 @@ class P4Clone(P4Sync): if not self.cloneBare: system([ "git", "checkout", "-f" ]) else: - print 'Not checking out any branch, use ' \ - '"git checkout -q -b master <branch>"' + print('Not checking out any branch, use ' \ + '"git checkout -q -b master <branch>"') # auto-set this variable if invoked with --use-client-spec if self.useClientSpec_from_options: @@ -3950,7 +3966,7 @@ class P4Unshelve(Command): for parent in (range(65535)): log = extractLogMessageFromGitCommit("{0}^{1}".format(starting_point, parent)) settings = extractSettingsGitLog(log) - if settings.has_key('change'): + if 'change' in settings: return settings sys.exit("could not find git-p4 commits in {0}".format(self.origin)) @@ -4018,7 +4034,7 @@ class P4Branches(Command): log = extractLogMessageFromGitCommit("refs/remotes/%s" % branch) settings = extractSettingsGitLog(log) - print "%s <= %s (%s)" % (branch, ",".join(settings["depot-paths"]), settings["change"]) + print("%s <= %s (%s)" % (branch, ",".join(settings["depot-paths"]), settings["change"])) return True class HelpFormatter(optparse.IndentedHelpFormatter): @@ -4032,12 +4048,12 @@ class HelpFormatter(optparse.IndentedHelpFormatter): return "" def printUsage(commands): - print "usage: %s <command> [options]" % sys.argv[0] - print "" - print "valid commands: %s" % ", ".join(commands) - print "" - print "Try %s <command> --help for command specific help." % sys.argv[0] - print "" + print("usage: %s <command> [options]" % sys.argv[0]) + print("") + print("valid commands: %s" % ", ".join(commands)) + print("") + print("Try %s <command> --help for command specific help." % sys.argv[0]) + print("") commands = { "debug" : P4Debug, @@ -4062,8 +4078,8 @@ def main(): klass = commands[cmdName] cmd = klass() except KeyError: - print "unknown command %s" % cmdName - print "" + print("unknown command %s" % cmdName) + print("") printUsage(commands.keys()) sys.exit(2) diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index cf4c042214..aa2f2f0872 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -71,7 +71,7 @@ call_merge () { test -z "$strategy" && strategy=recursive # If cmt doesn't have a parent, don't include it as a base base=$(git rev-parse --verify --quiet $cmt^) - eval 'git-merge-$strategy' $strategy_opts $base ' -- "$hd" "$cmt"' + eval 'git merge-$strategy' $strategy_opts $base ' -- "$hd" "$cmt"' rv=$? case "$rv" in 0) @@ -88,7 +88,7 @@ call_merge () { ;; *) die "Unknown exit code ($rv) from command:" \ - "git-merge-$strategy $cmt^ -- HEAD $cmt" + "git merge-$strategy $cmt^ -- HEAD $cmt" ;; esac } diff --git a/git-rebase.sh b/git-rebase.sh index 19bdebb480..7973447645 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -20,23 +20,23 @@ onto=! rebase onto given branch instead of upstream r,rebase-merges? try to rebase merges instead of skipping them p,preserve-merges! try to recreate merges instead of ignoring them s,strategy=! use the given merge strategy +X,strategy-option=! pass the argument through to the merge strategy no-ff! cherry-pick all commits, even if unchanged +f,force-rebase! cherry-pick all commits, even if unchanged m,merge! use merging strategies to rebase i,interactive! let the user edit the list of commits to rebase x,exec=! add exec lines after each commit of the editable list k,keep-empty preserve empty commits during rebase allow-empty-message allow rebasing commits with empty messages -f,force-rebase! force rebase even if branch is up to date -X,strategy-option=! pass the argument through to the merge strategy stat! display a diffstat of what changed upstream n,no-stat! do not show diffstat of what changed upstream verify allow pre-rebase hook to run rerere-autoupdate allow rerere to update index with resolved conflicts root! rebase all reachable commits up to the root(s) autosquash move commits that begin with squash!/fixup! under -i +signoff add a Signed-off-by: line to each commit committer-date-is-author-date! passed to 'git am' ignore-date! passed to 'git am' -signoff passed to 'git am' whitespace=! passed to 'git apply' ignore-whitespace! passed to 'git apply' C=! passed to 'git apply' @@ -95,7 +95,7 @@ rebase_cousins= preserve_merges= autosquash= keep_empty= -allow_empty_message= +allow_empty_message=--allow-empty-message signoff= test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t case "$(git config --bool commit.gpgsign)" in @@ -328,7 +328,7 @@ do do_merge=t ;; --strategy-option=*) - strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}")" + strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)" do_merge=t test -z "$strategy" && strategy=recursive ;; @@ -521,6 +521,24 @@ then git_format_patch_opt="$git_format_patch_opt --progress" fi +if test -n "$git_am_opt"; then + incompatible_opts=$(echo " $git_am_opt " | \ + sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/') + if test -n "$interactive_rebase" + then + if test -n "$incompatible_opts" + then + die "$(gettext "error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)")" + fi + fi + if test -n "$do_merge"; then + if test -n "$incompatible_opts" + then + die "$(gettext "error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)")" + fi + fi +fi + if test -n "$signoff" then test -n "$preserve_merges" && @@ -529,6 +547,23 @@ then force_rebase=t fi +if test -n "$preserve_merges" +then + # Note: incompatibility with --signoff handled in signoff block above + # Note: incompatibility with --interactive is just a strong warning; + # git-rebase.txt caveats with "unless you know what you are doing" + test -n "$rebase_merges" && + die "$(gettext "error: cannot combine '--preserve_merges' with '--rebase-merges'")" +fi + +if test -n "$rebase_merges" +then + test -n "$strategy_opts" && + die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy-option'")" + test -n "$strategy" && + die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy'")" +fi + if test -z "$rebase_root" then case "$#" in diff --git a/git-submodule.sh b/git-submodule.sh index 5f9d9f6ea3..8b5ad59bde 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -577,6 +577,11 @@ cmd_update() die "$(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")" fi + if ! $(git config -f "$(git rev-parse --git-common-dir)/modules/$name/config" core.worktree) 2>/dev/null + then + git submodule--helper connect-gitdir-workingtree "$name" "$sm_path" + fi + if test "$subsha1" != "$sha1" || test -n "$force" then subforce=$force @@ -267,7 +267,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) } else if (!strcmp(cmd, "--shallow-file")) { (*argv)++; (*argc)--; - set_alternate_shallow_file((*argv)[0], 1); + set_alternate_shallow_file(the_repository, (*argv)[0], 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "-C")) { @@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "grep.h" +#include "object-store.h" #include "userdiff.h" #include "xdiff-interface.h" #include "diff.h" @@ -19,6 +20,7 @@ static const char *color_grep_slots[] = { [GREP_COLOR_FILENAME] = "filename", [GREP_COLOR_FUNCTION] = "function", [GREP_COLOR_LINENO] = "lineNumber", + [GREP_COLOR_COLUMNNO] = "column", [GREP_COLOR_MATCH_CONTEXT] = "matchContext", [GREP_COLOR_MATCH_SELECTED] = "matchSelected", [GREP_COLOR_SELECTED] = "selected", @@ -58,6 +60,7 @@ void init_grep_defaults(void) color_set(opt->colors[GREP_COLOR_FILENAME], ""); color_set(opt->colors[GREP_COLOR_FUNCTION], ""); color_set(opt->colors[GREP_COLOR_LINENO], ""); + color_set(opt->colors[GREP_COLOR_COLUMNNO], ""); color_set(opt->colors[GREP_COLOR_MATCH_CONTEXT], GIT_COLOR_BOLD_RED); color_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED); color_set(opt->colors[GREP_COLOR_SELECTED], ""); @@ -109,6 +112,10 @@ int grep_config(const char *var, const char *value, void *cb) opt->linenum = git_config_bool(var, value); return 0; } + if (!strcmp(var, "grep.column")) { + opt->columnnum = git_config_bool(var, value); + return 0; + } if (!strcmp(var, "grep.fullname")) { opt->relative = !git_config_bool(var, value); @@ -156,6 +163,7 @@ void grep_init(struct grep_opt *opt, const char *prefix) opt->extended_regexp_option = def->extended_regexp_option; opt->pattern_type_option = def->pattern_type_option; opt->linenum = def->linenum; + opt->columnnum = def->columnnum; opt->max_depth = def->max_depth; opt->pathname = def->pathname; opt->relative = def->relative; @@ -1243,11 +1251,11 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, return hit; } -static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, - enum grep_context ctx, int collect_hits) +static int match_expr_eval(struct grep_opt *opt, struct grep_expr *x, char *bol, + char *eol, enum grep_context ctx, ssize_t *col, + ssize_t *icol, int collect_hits) { int h = 0; - regmatch_t match; if (!x) die("Not a valid grep expression"); @@ -1256,25 +1264,52 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, h = 1; break; case GREP_NODE_ATOM: - h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); + { + regmatch_t tmp; + h = match_one_pattern(x->u.atom, bol, eol, ctx, + &tmp, 0); + if (h && (*col < 0 || tmp.rm_so < *col)) + *col = tmp.rm_so; + } break; case GREP_NODE_NOT: - h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0); + /* + * Upon visiting a GREP_NODE_NOT, col and icol become swapped. + */ + h = !match_expr_eval(opt, x->u.unary, bol, eol, ctx, icol, col, + 0); break; case GREP_NODE_AND: - if (!match_expr_eval(x->u.binary.left, bol, eol, ctx, 0)) - return 0; - h = match_expr_eval(x->u.binary.right, bol, eol, ctx, 0); + h = match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col, + icol, 0); + if (h || opt->columnnum) { + /* + * Don't short-circuit AND when given --column, since a + * NOT earlier in the tree may turn this into an OR. In + * this case, see the below comment. + */ + h &= match_expr_eval(opt, x->u.binary.right, bol, eol, + ctx, col, icol, 0); + } break; case GREP_NODE_OR: - if (!collect_hits) - return (match_expr_eval(x->u.binary.left, - bol, eol, ctx, 0) || - match_expr_eval(x->u.binary.right, - bol, eol, ctx, 0)); - h = match_expr_eval(x->u.binary.left, bol, eol, ctx, 0); - x->u.binary.left->hit |= h; - h |= match_expr_eval(x->u.binary.right, bol, eol, ctx, 1); + if (!(collect_hits || opt->columnnum)) { + /* + * Don't short-circuit OR when given --column (or + * collecting hits) to ensure we don't skip a later + * child that would produce an earlier match. + */ + return (match_expr_eval(opt, x->u.binary.left, bol, eol, + ctx, col, icol, 0) || + match_expr_eval(opt, x->u.binary.right, bol, + eol, ctx, col, icol, 0)); + } + h = match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col, + icol, 0); + if (collect_hits) + x->u.binary.left->hit |= h; + h |= match_expr_eval(opt, x->u.binary.right, bol, eol, ctx, col, + icol, collect_hits); break; default: die("Unexpected node type (internal error) %d", x->node); @@ -1285,27 +1320,43 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, } static int match_expr(struct grep_opt *opt, char *bol, char *eol, - enum grep_context ctx, int collect_hits) + enum grep_context ctx, ssize_t *col, + ssize_t *icol, int collect_hits) { struct grep_expr *x = opt->pattern_expression; - return match_expr_eval(x, bol, eol, ctx, collect_hits); + return match_expr_eval(opt, x, bol, eol, ctx, col, icol, collect_hits); } static int match_line(struct grep_opt *opt, char *bol, char *eol, + ssize_t *col, ssize_t *icol, enum grep_context ctx, int collect_hits) { struct grep_pat *p; - regmatch_t match; + int hit = 0; if (opt->extended) - return match_expr(opt, bol, eol, ctx, collect_hits); + return match_expr(opt, bol, eol, ctx, col, icol, + collect_hits); /* we do not call with collect_hits without being extended */ for (p = opt->pattern_list; p; p = p->next) { - if (match_one_pattern(p, bol, eol, ctx, &match, 0)) - return 1; + regmatch_t tmp; + if (match_one_pattern(p, bol, eol, ctx, &tmp, 0)) { + hit |= 1; + if (!opt->columnnum) { + /* + * Without --column, any single match on a line + * is enough to know that it needs to be + * printed. With --column, scan _all_ patterns + * to find the earliest. + */ + break; + } + if (*col < 0 || tmp.rm_so < *col) + *col = tmp.rm_so; + } } - return 0; + return hit; } static int match_next_pattern(struct grep_pat *p, char *bol, char *eol, @@ -1354,7 +1405,7 @@ static int next_match(struct grep_opt *opt, char *bol, char *eol, } static void show_line(struct grep_opt *opt, char *bol, char *eol, - const char *name, unsigned lno, char sign) + const char *name, unsigned lno, ssize_t cno, char sign) { int rest = eol - bol; const char *match_color, *line_color = NULL; @@ -1389,6 +1440,17 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_LINENO]); output_sep(opt, sign); } + /* + * Treat 'cno' as the 1-indexed offset from the start of a non-context + * line to its first match. Otherwise, 'cno' is 0 indicating that we are + * being called with a context line. + */ + if (opt->columnnum && cno) { + char buf[32]; + xsnprintf(buf, sizeof(buf), "%"PRIuMAX, (uintmax_t)cno); + output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_COLUMNNO]); + output_sep(opt, sign); + } if (opt->color) { regmatch_t match; enum grep_context ctx = GREP_CONTEXT_BODY; @@ -1494,7 +1556,7 @@ static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs, break; if (match_funcname(opt, gs, bol, eol)) { - show_line(opt, bol, eol, gs->name, lno, '='); + show_line(opt, bol, eol, gs->name, lno, 0, '='); break; } } @@ -1559,7 +1621,7 @@ static void show_pre_context(struct grep_opt *opt, struct grep_source *gs, while (*eol != '\n') eol++; - show_line(opt, bol, eol, gs->name, cur, sign); + show_line(opt, bol, eol, gs->name, cur, 0, sign); bol = eol + 1; cur++; } @@ -1758,6 +1820,8 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle while (left) { char *eol, ch; int hit; + ssize_t cno; + ssize_t col = -1, icol = -1; /* * look_ahead() skips quickly to the line that possibly @@ -1781,7 +1845,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol)) ctx = GREP_CONTEXT_BODY; - hit = match_line(opt, bol, eol, ctx, collect_hits); + hit = match_line(opt, bol, eol, &col, &icol, ctx, collect_hits); *eol = ch; if (collect_hits) @@ -1822,7 +1886,18 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle show_pre_context(opt, gs, bol, eol, lno); else if (opt->funcname) show_funcname_line(opt, gs, bol, lno); - show_line(opt, bol, eol, gs->name, lno, ':'); + cno = opt->invert ? icol : col; + if (cno < 0) { + /* + * A negative cno indicates that there was no + * match on the line. We are thus inverted and + * being asked to show all lines that _don't_ + * match a given expression. Therefore, set cno + * to 0 to suggest the whole line matches. + */ + cno = 0; + } + show_line(opt, bol, eol, gs->name, lno, cno + 1, ':'); last_hit = lno; if (opt->funcbody) show_function = 1; @@ -1851,7 +1926,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle /* If the last hit is within the post context, * we need to show this line. */ - show_line(opt, bol, eol, gs->name, lno, '-'); + show_line(opt, bol, eol, gs->name, lno, col + 1, '-'); } next_line: @@ -67,6 +67,7 @@ enum grep_color { GREP_COLOR_FILENAME, GREP_COLOR_FUNCTION, GREP_COLOR_LINENO, + GREP_COLOR_COLUMNNO, GREP_COLOR_MATCH_CONTEXT, GREP_COLOR_MATCH_SELECTED, GREP_COLOR_SELECTED, @@ -139,6 +140,7 @@ struct grep_opt { int prefix_length; regex_t regexp; int linenum; + int columnnum; int invert; int ignore_case; int status_only; diff --git a/list-objects-filter.c b/list-objects-filter.c index 5b14d2711a..a0ba78b20c 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -11,6 +11,7 @@ #include "list-objects-filter.h" #include "list-objects-filter-options.h" #include "oidset.h" +#include "object-store.h" /* Remember to update object flag allocation in object.h */ /* diff --git a/list-objects.c b/list-objects.c index 3eec510357..3e5e1992eb 100644 --- a/list-objects.c +++ b/list-objects.c @@ -10,6 +10,7 @@ #include "list-objects-filter.h" #include "list-objects-filter-options.h" #include "packfile.h" +#include "object-store.h" static void process_blob(struct rev_info *revs, struct blob *blob, diff --git a/log-tree.c b/log-tree.c index d3a43e29cd..4a3907fea0 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "diff.h" +#include "object-store.h" #include "commit.h" #include "tag.h" #include "graph.h" @@ -1,6 +1,7 @@ #include "cache.h" #include "string-list.h" #include "mailmap.h" +#include "object-store.h" #define DEBUG_MAILMAP 0 #if DEBUG_MAILMAP diff --git a/match-trees.c b/match-trees.c index 72cc2baa3f..4cdeff53e1 100644 --- a/match-trees.c +++ b/match-trees.c @@ -1,6 +1,7 @@ #include "cache.h" #include "tree.h" #include "tree-walk.h" +#include "object-store.h" static int score_missing(unsigned mode, const char *path) { diff --git a/merge-blobs.c b/merge-blobs.c index fa49c17287..fabb8c19ce 100644 --- a/merge-blobs.c +++ b/merge-blobs.c @@ -4,6 +4,7 @@ #include "ll-merge.h" #include "blob.h" #include "merge-blobs.h" +#include "object-store.h" static int fill_mmfile_blob(mmfile_t *f, struct blob *obj) { diff --git a/merge-recursive.c b/merge-recursive.c index bed4a5be02..113c1d6962 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -8,6 +8,7 @@ #include "advice.h" #include "lockfile.h" #include "cache-tree.h" +#include "object-store.h" #include "commit.h" #include "blob.h" #include "builtin.h" @@ -182,7 +183,7 @@ static int oid_eq(const struct object_id *a, const struct object_id *b) enum rename_type { RENAME_NORMAL = 0, - RENAME_DIR, + RENAME_VIA_DIR, RENAME_DELETE, RENAME_ONE_FILE_TO_ONE, RENAME_ONE_FILE_TO_TWO, @@ -312,8 +313,8 @@ static void output_commit_title(struct merge_options *o, struct commit *commit) } static int add_cacheinfo(struct merge_options *o, - unsigned int mode, const struct object_id *oid, - const char *path, int stage, int refresh, int options) + unsigned int mode, const struct object_id *oid, + const char *path, int stage, int refresh, int options) { struct cache_entry *ce; int ret; @@ -420,8 +421,8 @@ struct tree *write_tree_from_memory(struct merge_options *o) } static int save_files_dirs(const struct object_id *oid, - struct strbuf *base, const char *path, - unsigned int mode, int stage, void *context) + struct strbuf *base, const char *path, + unsigned int mode, int stage, void *context) { struct path_hashmap_entry *entry; int baselen = base->len; @@ -542,7 +543,7 @@ static void record_df_conflict_files(struct merge_options *o, struct string_list *entries) { /* If there is a D/F conflict and the file for such a conflict - * currently exist in the working tree, we want to allow it to be + * currently exists in the working tree, we want to allow it to be * removed to make room for the corresponding directory if needed. * The files underneath the directories of such D/F conflicts will * be processed before the corresponding file involved in the D/F @@ -916,7 +917,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) */ if (would_lose_untracked(path)) return err(o, _("refusing to lose untracked file at '%s'"), - path); + path); /* Successful unlink is good.. */ if (!unlink(path)) @@ -995,16 +996,16 @@ static int update_file_flags(struct merge_options *o, unlink(path); if (symlink(lnk, path)) ret = err(o, _("failed to symlink '%s': %s"), - path, strerror(errno)); + path, strerror(errno)); free(lnk); } else ret = err(o, _("do not know what to do with %06o %s '%s'"), mode, oid_to_hex(oid), path); - free_buf: + free_buf: free(buf); } - update_index: +update_index: if (!ret && update_cache) if (add_cacheinfo(o, mode, oid, path, 0, update_wd, ADD_CACHE_OK_TO_ADD)) @@ -1093,7 +1094,7 @@ static int merge_3way(struct merge_options *o, } static int find_first_merges(struct object_array *result, const char *path, - struct commit *a, struct commit *b) + struct commit *a, struct commit *b) { int i, j; struct object_array merges = OBJECT_ARRAY_INIT; @@ -1111,7 +1112,7 @@ static int find_first_merges(struct object_array *result, const char *path, /* get all revisions that merge commit a */ xsnprintf(merged_revision, sizeof(merged_revision), "^%s", - oid_to_hex(&a->object.oid)); + oid_to_hex(&a->object.oid)); init_revisions(&revs, NULL); rev_opts.submodule = path; /* FIXME: can't handle linked worktrees in submodules yet */ @@ -1253,12 +1254,12 @@ static int merge_submodule(struct merge_options *o, output(o, 2, _("Found a possible merge resolution for the submodule:\n")); print_commit((struct commit *) merges.objects[0].item); output(o, 2, _( - "If this is correct simply add it to the index " - "for example\n" - "by using:\n\n" - " git update-index --cacheinfo 160000 %s \"%s\"\n\n" - "which will accept this suggestion.\n"), - oid_to_hex(&merges.objects[0].item->oid), path); + "If this is correct simply add it to the index " + "for example\n" + "by using:\n\n" + " git update-index --cacheinfo 160000 %s \"%s\"\n\n" + "which will accept this suggestion.\n"), + oid_to_hex(&merges.objects[0].item->oid), path); break; default: @@ -1335,10 +1336,10 @@ static int merge_file_1(struct merge_options *o, result->clean = (merge_status == 0); } else if (S_ISGITLINK(a->mode)) { result->clean = merge_submodule(o, &result->oid, - one->path, - &one->oid, - &a->oid, - &b->oid); + one->path, + &one->oid, + &a->oid, + &b->oid); } else if (S_ISLNK(a->mode)) { switch (o->recursive_variant) { case MERGE_RECURSIVE_NORMAL: @@ -1413,11 +1414,17 @@ static int merge_file_one(struct merge_options *o, return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi); } -static int conflict_rename_dir(struct merge_options *o, - struct diff_filepair *pair, - const char *rename_branch, - const char *other_branch) +static int handle_rename_via_dir(struct merge_options *o, + struct diff_filepair *pair, + const char *rename_branch, + const char *other_branch) { + /* + * Handle file adds that need to be renamed due to directory rename + * detection. This differs from handle_rename_normal, because + * there is no content merge to do; just move the file into the + * desired final location. + */ const struct diff_filespec *dest = pair->two; if (!o->call_depth && would_lose_untracked(dest->path)) { @@ -1446,13 +1453,13 @@ static int conflict_rename_dir(struct merge_options *o, } static int handle_change_delete(struct merge_options *o, - const char *path, const char *old_path, - const struct object_id *o_oid, int o_mode, - const struct object_id *changed_oid, - int changed_mode, - const char *change_branch, - const char *delete_branch, - const char *change, const char *change_past) + const char *path, const char *old_path, + const struct object_id *o_oid, int o_mode, + const struct object_id *changed_oid, + int changed_mode, + const char *change_branch, + const char *delete_branch, + const char *change, const char *change_past) { char *alt_path = NULL; const char *update_path = path; @@ -1473,6 +1480,21 @@ static int handle_change_delete(struct merge_options *o, if (!ret) ret = update_file(o, 0, o_oid, o_mode, update_path); } else { + /* + * Despite the four nearly duplicate messages and argument + * lists below and the ugliness of the nested if-statements, + * having complete messages makes the job easier for + * translators. + * + * The slight variance among the cases is due to the fact + * that: + * 1) directory/file conflicts (in effect if + * !alt_path) could cause us to need to write the + * file to a different path. + * 2) renames (in effect if !old_path) could mean that + * there are two names for the path that the user + * may know the file by. + */ if (!alt_path) { if (!old_path) { output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " @@ -1512,10 +1534,10 @@ static int handle_change_delete(struct merge_options *o, return ret; } -static int conflict_rename_delete(struct merge_options *o, - struct diff_filepair *pair, - const char *rename_branch, - const char *delete_branch) +static int handle_rename_delete(struct merge_options *o, + struct diff_filepair *pair, + const char *rename_branch, + const char *delete_branch) { const struct diff_filespec *orig = pair->one; const struct diff_filespec *dest = pair->two; @@ -1617,8 +1639,8 @@ static int handle_file(struct merge_options *o, return ret; } -static int conflict_rename_rename_1to2(struct merge_options *o, - struct rename_conflict_info *ci) +static int handle_rename_rename_1to2(struct merge_options *o, + struct rename_conflict_info *ci) { /* One file was renamed in both branches, but to different names. */ struct diff_filespec *one = ci->pair1->one; @@ -1679,8 +1701,8 @@ static int conflict_rename_rename_1to2(struct merge_options *o, return 0; } -static int conflict_rename_rename_2to1(struct merge_options *o, - struct rename_conflict_info *ci) +static int handle_rename_rename_2to1(struct merge_options *o, + struct rename_conflict_info *ci) { /* Two files, a & b, were renamed to the same thing, c. */ struct diff_filespec *a = ci->pair1->one; @@ -2422,7 +2444,7 @@ static void apply_directory_rename_modifications(struct merge_options *o, * "NOTE" in update_stages(), doing so will modify the current * in-memory index which will break calls to would_lose_untracked() * that we need to make. Instead, we need to just make sure that - * the various conflict_rename_*() functions update the index + * the various handle_rename_*() functions update the index * explicitly rather than relying on unpack_trees() to have done it. */ get_tree_entry(&tree->object.oid, @@ -2695,7 +2717,7 @@ static int process_renames(struct merge_options *o, if (oid_eq(&src_other.oid, &null_oid) && ren1->add_turned_into_rename) { - setup_rename_conflict_info(RENAME_DIR, + setup_rename_conflict_info(RENAME_VIA_DIR, ren1->pair, NULL, branch1, @@ -2826,12 +2848,12 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs, free(pairs); } -static int handle_renames(struct merge_options *o, - struct tree *common, - struct tree *head, - struct tree *merge, - struct string_list *entries, - struct rename_info *ri) +static int detect_and_process_renames(struct merge_options *o, + struct tree *common, + struct tree *head, + struct tree *merge, + struct string_list *entries, + struct rename_info *ri) { struct diff_queue_struct *head_pairs, *merge_pairs; struct hashmap *dir_re_head, *dir_re_merge; @@ -2907,7 +2929,8 @@ static struct object_id *stage_oid(const struct object_id *oid, unsigned mode) } static int read_oid_strbuf(struct merge_options *o, - const struct object_id *oid, struct strbuf *dst) + const struct object_id *oid, + struct strbuf *dst) { void *buf; enum object_type type; @@ -2960,10 +2983,10 @@ error_return: } static int handle_modify_delete(struct merge_options *o, - const char *path, - struct object_id *o_oid, int o_mode, - struct object_id *a_oid, int a_mode, - struct object_id *b_oid, int b_mode) + const char *path, + struct object_id *o_oid, int o_mode, + struct object_id *a_oid, int a_mode, + struct object_id *b_oid, int b_mode) { const char *modify_branch, *delete_branch; struct object_id *changed_oid; @@ -3101,12 +3124,12 @@ static int merge_content(struct merge_options *o, return !is_dirty && mfi.clean; } -static int conflict_rename_normal(struct merge_options *o, - const char *path, - struct object_id *o_oid, unsigned int o_mode, - struct object_id *a_oid, unsigned int a_mode, - struct object_id *b_oid, unsigned int b_mode, - struct rename_conflict_info *ci) +static int handle_rename_normal(struct merge_options *o, + const char *path, + struct object_id *o_oid, unsigned int o_mode, + struct object_id *a_oid, unsigned int a_mode, + struct object_id *b_oid, unsigned int b_mode, + struct rename_conflict_info *ci) { /* Merge the content and write it out */ return merge_content(o, path, was_dirty(o, path), @@ -3133,37 +3156,37 @@ static int process_entry(struct merge_options *o, switch (conflict_info->rename_type) { case RENAME_NORMAL: case RENAME_ONE_FILE_TO_ONE: - clean_merge = conflict_rename_normal(o, - path, - o_oid, o_mode, - a_oid, a_mode, - b_oid, b_mode, - conflict_info); + clean_merge = handle_rename_normal(o, + path, + o_oid, o_mode, + a_oid, a_mode, + b_oid, b_mode, + conflict_info); break; - case RENAME_DIR: + case RENAME_VIA_DIR: clean_merge = 1; - if (conflict_rename_dir(o, - conflict_info->pair1, - conflict_info->branch1, - conflict_info->branch2)) + if (handle_rename_via_dir(o, + conflict_info->pair1, + conflict_info->branch1, + conflict_info->branch2)) clean_merge = -1; break; case RENAME_DELETE: clean_merge = 0; - if (conflict_rename_delete(o, - conflict_info->pair1, - conflict_info->branch1, - conflict_info->branch2)) + if (handle_rename_delete(o, + conflict_info->pair1, + conflict_info->branch1, + conflict_info->branch2)) clean_merge = -1; break; case RENAME_ONE_FILE_TO_TWO: clean_merge = 0; - if (conflict_rename_rename_1to2(o, conflict_info)) + if (handle_rename_rename_1to2(o, conflict_info)) clean_merge = -1; break; case RENAME_TWO_FILES_TO_ONE: clean_merge = 0; - if (conflict_rename_rename_2to1(o, conflict_info)) + if (handle_rename_rename_2to1(o, conflict_info)) clean_merge = -1; break; default: @@ -3303,8 +3326,8 @@ int merge_trees(struct merge_options *o, get_files_dirs(o, merge); entries = get_unmerged(); - clean = handle_renames(o, common, head, merge, entries, - &re_info); + clean = detect_and_process_renames(o, common, head, merge, + entries, &re_info); record_df_conflict_files(o, entries); if (clean < 0) goto cleanup; @@ -3328,7 +3351,7 @@ int merge_trees(struct merge_options *o, entries->items[i].string); } -cleanup: + cleanup: final_cleanup_renames(&re_info); string_list_clear(entries, 1); @@ -3496,14 +3519,14 @@ int merge_recursive_generic(struct merge_options *o, struct commit *base; if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i])))) return err(o, _("Could not parse object '%s'"), - oid_to_hex(base_list[i])); + oid_to_hex(base_list[i])); commit_list_insert(base, &ca); } } hold_locked_index(&lock, LOCK_DIE_ON_ERROR); clean = merge_recursive(o, head_commit, next_commit, ca, - result); + result); if (clean < 0) { rollback_lock_file(&lock); return clean; diff --git a/notes-cache.c b/notes-cache.c index e61988e503..d577003177 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -1,5 +1,6 @@ #include "cache.h" #include "notes-cache.h" +#include "object-store.h" #include "commit.h" #include "refs.h" diff --git a/notes-merge.c b/notes-merge.c index d613e06574..9cc2ee16a8 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -1,6 +1,7 @@ #include "cache.h" #include "commit.h" #include "refs.h" +#include "object-store.h" #include "diff.h" #include "diffcore.h" #include "xdiff-interface.h" @@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "notes.h" +#include "object-store.h" #include "blob.h" #include "tree.h" #include "utf8.h" diff --git a/object-store.h b/object-store.h index d683112fd7..a3db17bbf5 100644 --- a/object-store.h +++ b/object-store.h @@ -139,4 +139,121 @@ void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned cha void *map_sha1_file(struct repository *r, const unsigned char *sha1, unsigned long *size); +extern void *read_object_file_extended(const struct object_id *oid, + enum object_type *type, + unsigned long *size, int lookup_replace); +static inline void *read_object_file(const struct object_id *oid, enum object_type *type, unsigned long *size) +{ + return read_object_file_extended(oid, type, size, 1); +} + +/* Read and unpack an object file into memory, write memory to an object file */ +int oid_object_info(struct repository *r, const struct object_id *, unsigned long *); + +extern int hash_object_file(const void *buf, unsigned long len, + const char *type, struct object_id *oid); + +extern int write_object_file(const void *buf, unsigned long len, + const char *type, struct object_id *oid); + +extern int hash_object_file_literally(const void *buf, unsigned long len, + const char *type, struct object_id *oid, + unsigned flags); + +extern int pretend_object_file(void *, unsigned long, enum object_type, + struct object_id *oid); + +extern int force_object_loose(const struct object_id *oid, time_t mtime); + +/* + * Open the loose object at path, check its hash, and return the contents, + * type, and size. If the object is a blob, then "contents" may return NULL, + * to allow streaming of large blobs. + * + * Returns 0 on success, negative on error (details may be written to stderr). + */ +int read_loose_object(const char *path, + const struct object_id *expected_oid, + enum object_type *type, + unsigned long *size, + void **contents); + +/* + * Convenience for sha1_object_info_extended() with a NULL struct + * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass + * nonzero flags to also set other flags. + */ +extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags); +static inline int has_sha1_file(const unsigned char *sha1) +{ + return has_sha1_file_with_flags(sha1, 0); +} + +/* Same as the above, except for struct object_id. */ +extern int has_object_file(const struct object_id *oid); +extern int has_object_file_with_flags(const struct object_id *oid, int flags); + +/* + * Return true iff an alternate object database has a loose object + * with the specified name. This function does not respect replace + * references. + */ +extern int has_loose_object_nonlocal(const struct object_id *); + +extern void assert_oid_type(const struct object_id *oid, enum object_type expect); + +struct object_info { + /* Request */ + enum object_type *typep; + unsigned long *sizep; + off_t *disk_sizep; + unsigned char *delta_base_sha1; + struct strbuf *type_name; + void **contentp; + + /* Response */ + enum { + OI_CACHED, + OI_LOOSE, + OI_PACKED, + OI_DBCACHED + } whence; + union { + /* + * struct { + * ... Nothing to expose in this case + * } cached; + * struct { + * ... Nothing to expose in this case + * } loose; + */ + struct { + struct packed_git *pack; + off_t offset; + unsigned int is_delta; + } packed; + } u; +}; + +/* + * Initializer for a "struct object_info" that wants no items. You may + * also memset() the memory to all-zeroes. + */ +#define OBJECT_INFO_INIT {NULL} + +/* Invoke lookup_replace_object() on the given hash */ +#define OBJECT_INFO_LOOKUP_REPLACE 1 +/* Allow reading from a loose object file of unknown/bogus type */ +#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2 +/* Do not check cached storage */ +#define OBJECT_INFO_SKIP_CACHED 4 +/* Do not retry packed storage after checking packed and loose storage */ +#define OBJECT_INFO_QUICK 8 +/* Do not check loose object */ +#define OBJECT_INFO_IGNORE_LOOSE 16 + +int oid_object_info_extended(struct repository *r, + const struct object_id *, + struct object_info *, unsigned flags); + #endif /* OBJECT_STORE_H */ @@ -1,6 +1,7 @@ #include "cache.h" #include "object.h" #include "replace-object.h" +#include "object-store.h" #include "blob.h" #include "tree.h" #include "commit.h" @@ -463,6 +464,9 @@ struct parsed_object_pool *parsed_object_pool_new(void) o->tag_state = allocate_alloc_state(); o->object_state = allocate_alloc_state(); + o->is_shallow = -1; + o->shallow_stat = xcalloc(1, sizeof(*o->shallow_stat)); + return o; } @@ -12,6 +12,16 @@ struct parsed_object_pool { struct alloc_state *tag_state; struct alloc_state *object_state; unsigned commit_count; + + /* parent substitutions from .git/info/grafts and .git/shallow */ + struct commit_graft **grafts; + int grafts_alloc, grafts_nr; + + int is_shallow; + struct stat_validity *shallow_stat; + char *alternate_shallow_file; + + int commit_graft_prepared; }; struct parsed_object_pool *parsed_object_pool_new(void); diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 7b2dc3e7dc..d977e9bacb 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "object-store.h" #include "commit.h" #include "tag.h" #include "diff.h" @@ -360,11 +361,17 @@ static int date_compare(const void *_a, const void *_b) void bitmap_writer_reuse_bitmaps(struct packing_data *to_pack) { - if (prepare_bitmap_git() < 0) + struct bitmap_index *bitmap_git; + if (!(bitmap_git = prepare_bitmap_git())) return; writer.reused = kh_init_sha1(); - rebuild_existing_bitmaps(to_pack, writer.reused, writer.show_progress); + rebuild_existing_bitmaps(bitmap_git, to_pack, writer.reused, + writer.show_progress); + /* + * NEEDSWORK: rebuild_existing_bitmaps() makes writer.reused reference + * some bitmaps in bitmap_git, so we can't free the latter. + */ } static struct ewah_bitmap *find_reused_bitmap(const unsigned char *sha1) diff --git a/pack-bitmap.c b/pack-bitmap.c index 18f8b22aeb..f0a1937a1c 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -25,14 +25,14 @@ struct stored_bitmap { }; /* - * The currently active bitmap index. By design, repositories only have + * The active bitmap index for a repository. By design, repositories only have * a single bitmap index available (the index for the biggest packfile in * the repository), since bitmap indexes need full closure. * * If there is more than one bitmap index available (e.g. because of alternates), * the active bitmap index is the largest one. */ -static struct bitmap_index { +struct bitmap_index { /* Packfile to which this bitmap index belongs to */ struct packed_git *pack; @@ -66,7 +66,7 @@ static struct bitmap_index { /* Number of bitmapped commits */ uint32_t entry_count; - /* Name-hash cache (or NULL if not present). */ + /* If not NULL, this is a name-hash cache pointing into map. */ uint32_t *hashes; /* @@ -90,8 +90,7 @@ static struct bitmap_index { unsigned int version; unsigned loaded : 1; - -} bitmap_git; +}; static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st) { @@ -259,7 +258,7 @@ static char *pack_bitmap_filename(struct packed_git *p) return xstrfmt("%.*s.bitmap", (int)len, p->pack_name); } -static int open_pack_bitmap_1(struct packed_git *packfile) +static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git *packfile) { int fd; struct stat st; @@ -280,117 +279,122 @@ static int open_pack_bitmap_1(struct packed_git *packfile) return -1; } - if (bitmap_git.pack) { + if (bitmap_git->pack) { warning("ignoring extra bitmap file: %s", packfile->pack_name); close(fd); return -1; } - bitmap_git.pack = packfile; - bitmap_git.map_size = xsize_t(st.st_size); - bitmap_git.map = xmmap(NULL, bitmap_git.map_size, PROT_READ, MAP_PRIVATE, fd, 0); - bitmap_git.map_pos = 0; + bitmap_git->pack = packfile; + bitmap_git->map_size = xsize_t(st.st_size); + bitmap_git->map = xmmap(NULL, bitmap_git->map_size, PROT_READ, MAP_PRIVATE, fd, 0); + bitmap_git->map_pos = 0; close(fd); - if (load_bitmap_header(&bitmap_git) < 0) { - munmap(bitmap_git.map, bitmap_git.map_size); - bitmap_git.map = NULL; - bitmap_git.map_size = 0; + if (load_bitmap_header(bitmap_git) < 0) { + munmap(bitmap_git->map, bitmap_git->map_size); + bitmap_git->map = NULL; + bitmap_git->map_size = 0; return -1; } return 0; } -static int load_pack_bitmap(void) +static int load_pack_bitmap(struct bitmap_index *bitmap_git) { - assert(bitmap_git.map && !bitmap_git.loaded); + assert(bitmap_git->map && !bitmap_git->loaded); - bitmap_git.bitmaps = kh_init_sha1(); - bitmap_git.ext_index.positions = kh_init_sha1_pos(); - load_pack_revindex(bitmap_git.pack); + bitmap_git->bitmaps = kh_init_sha1(); + bitmap_git->ext_index.positions = kh_init_sha1_pos(); + load_pack_revindex(bitmap_git->pack); - if (!(bitmap_git.commits = read_bitmap_1(&bitmap_git)) || - !(bitmap_git.trees = read_bitmap_1(&bitmap_git)) || - !(bitmap_git.blobs = read_bitmap_1(&bitmap_git)) || - !(bitmap_git.tags = read_bitmap_1(&bitmap_git))) + if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) || + !(bitmap_git->trees = read_bitmap_1(bitmap_git)) || + !(bitmap_git->blobs = read_bitmap_1(bitmap_git)) || + !(bitmap_git->tags = read_bitmap_1(bitmap_git))) goto failed; - if (load_bitmap_entries_v1(&bitmap_git) < 0) + if (load_bitmap_entries_v1(bitmap_git) < 0) goto failed; - bitmap_git.loaded = 1; + bitmap_git->loaded = 1; return 0; failed: - munmap(bitmap_git.map, bitmap_git.map_size); - bitmap_git.map = NULL; - bitmap_git.map_size = 0; + munmap(bitmap_git->map, bitmap_git->map_size); + bitmap_git->map = NULL; + bitmap_git->map_size = 0; return -1; } -static int open_pack_bitmap(void) +static int open_pack_bitmap(struct bitmap_index *bitmap_git) { struct packed_git *p; int ret = -1; - assert(!bitmap_git.map && !bitmap_git.loaded); + assert(!bitmap_git->map && !bitmap_git->loaded); for (p = get_packed_git(the_repository); p; p = p->next) { - if (open_pack_bitmap_1(p) == 0) + if (open_pack_bitmap_1(bitmap_git, p) == 0) ret = 0; } return ret; } -int prepare_bitmap_git(void) +struct bitmap_index *prepare_bitmap_git(void) { - if (bitmap_git.loaded) - return 0; + struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git)); - if (!open_pack_bitmap()) - return load_pack_bitmap(); + if (!open_pack_bitmap(bitmap_git) && !load_pack_bitmap(bitmap_git)) + return bitmap_git; - return -1; + free_bitmap_index(bitmap_git); + return NULL; } struct include_data { + struct bitmap_index *bitmap_git; struct bitmap *base; struct bitmap *seen; }; -static inline int bitmap_position_extended(const unsigned char *sha1) +static inline int bitmap_position_extended(struct bitmap_index *bitmap_git, + const unsigned char *sha1) { - khash_sha1_pos *positions = bitmap_git.ext_index.positions; + khash_sha1_pos *positions = bitmap_git->ext_index.positions; khiter_t pos = kh_get_sha1_pos(positions, sha1); if (pos < kh_end(positions)) { int bitmap_pos = kh_value(positions, pos); - return bitmap_pos + bitmap_git.pack->num_objects; + return bitmap_pos + bitmap_git->pack->num_objects; } return -1; } -static inline int bitmap_position_packfile(const unsigned char *sha1) +static inline int bitmap_position_packfile(struct bitmap_index *bitmap_git, + const unsigned char *sha1) { - off_t offset = find_pack_entry_one(sha1, bitmap_git.pack); + off_t offset = find_pack_entry_one(sha1, bitmap_git->pack); if (!offset) return -1; - return find_revindex_position(bitmap_git.pack, offset); + return find_revindex_position(bitmap_git->pack, offset); } -static int bitmap_position(const unsigned char *sha1) +static int bitmap_position(struct bitmap_index *bitmap_git, + const unsigned char *sha1) { - int pos = bitmap_position_packfile(sha1); - return (pos >= 0) ? pos : bitmap_position_extended(sha1); + int pos = bitmap_position_packfile(bitmap_git, sha1); + return (pos >= 0) ? pos : bitmap_position_extended(bitmap_git, sha1); } -static int ext_index_add_object(struct object *object, const char *name) +static int ext_index_add_object(struct bitmap_index *bitmap_git, + struct object *object, const char *name) { - struct eindex *eindex = &bitmap_git.ext_index; + struct eindex *eindex = &bitmap_git->ext_index; khiter_t hash_pos; int hash_ret; @@ -413,27 +417,34 @@ static int ext_index_add_object(struct object *object, const char *name) bitmap_pos = kh_value(eindex->positions, hash_pos); } - return bitmap_pos + bitmap_git.pack->num_objects; + return bitmap_pos + bitmap_git->pack->num_objects; } -static void show_object(struct object *object, const char *name, void *data) +struct bitmap_show_data { + struct bitmap_index *bitmap_git; + struct bitmap *base; +}; + +static void show_object(struct object *object, const char *name, void *data_) { - struct bitmap *base = data; + struct bitmap_show_data *data = data_; int bitmap_pos; - bitmap_pos = bitmap_position(object->oid.hash); + bitmap_pos = bitmap_position(data->bitmap_git, object->oid.hash); if (bitmap_pos < 0) - bitmap_pos = ext_index_add_object(object, name); + bitmap_pos = ext_index_add_object(data->bitmap_git, object, + name); - bitmap_set(base, bitmap_pos); + bitmap_set(data->base, bitmap_pos); } static void show_commit(struct commit *commit, void *data) { } -static int add_to_include_set(struct include_data *data, +static int add_to_include_set(struct bitmap_index *bitmap_git, + struct include_data *data, const unsigned char *sha1, int bitmap_pos) { @@ -445,9 +456,9 @@ static int add_to_include_set(struct include_data *data, if (bitmap_get(data->base, bitmap_pos)) return 0; - hash_pos = kh_get_sha1(bitmap_git.bitmaps, sha1); - if (hash_pos < kh_end(bitmap_git.bitmaps)) { - struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, hash_pos); + hash_pos = kh_get_sha1(bitmap_git->bitmaps, sha1); + if (hash_pos < kh_end(bitmap_git->bitmaps)) { + struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, hash_pos); bitmap_or_ewah(data->base, lookup_stored_bitmap(st)); return 0; } @@ -461,11 +472,14 @@ static int should_include(struct commit *commit, void *_data) struct include_data *data = _data; int bitmap_pos; - bitmap_pos = bitmap_position(commit->object.oid.hash); + bitmap_pos = bitmap_position(data->bitmap_git, commit->object.oid.hash); if (bitmap_pos < 0) - bitmap_pos = ext_index_add_object((struct object *)commit, NULL); + bitmap_pos = ext_index_add_object(data->bitmap_git, + (struct object *)commit, + NULL); - if (!add_to_include_set(data, commit->object.oid.hash, bitmap_pos)) { + if (!add_to_include_set(data->bitmap_git, data, commit->object.oid.hash, + bitmap_pos)) { struct commit_list *parent = commit->parents; while (parent) { @@ -479,7 +493,8 @@ static int should_include(struct commit *commit, void *_data) return 1; } -static struct bitmap *find_objects(struct rev_info *revs, +static struct bitmap *find_objects(struct bitmap_index *bitmap_git, + struct rev_info *revs, struct object_list *roots, struct bitmap *seen) { @@ -501,10 +516,10 @@ static struct bitmap *find_objects(struct rev_info *revs, roots = roots->next; if (object->type == OBJ_COMMIT) { - khiter_t pos = kh_get_sha1(bitmap_git.bitmaps, object->oid.hash); + khiter_t pos = kh_get_sha1(bitmap_git->bitmaps, object->oid.hash); - if (pos < kh_end(bitmap_git.bitmaps)) { - struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, pos); + if (pos < kh_end(bitmap_git->bitmaps)) { + struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, pos); struct ewah_bitmap *or_with = lookup_stored_bitmap(st); if (base == NULL) @@ -543,7 +558,7 @@ static struct bitmap *find_objects(struct rev_info *revs, int pos; roots = roots->next; - pos = bitmap_position(object->oid.hash); + pos = bitmap_position(bitmap_git, object->oid.hash); if (pos < 0 || base == NULL || !bitmap_get(base, pos)) { object->flags &= ~UNINTERESTING; @@ -556,10 +571,12 @@ static struct bitmap *find_objects(struct rev_info *revs, if (needs_walk) { struct include_data incdata; + struct bitmap_show_data show_data; if (base == NULL) base = bitmap_new(); + incdata.bitmap_git = bitmap_git; incdata.base = base; incdata.seen = seen; @@ -569,22 +586,27 @@ static struct bitmap *find_objects(struct rev_info *revs, if (prepare_revision_walk(revs)) die("revision walk setup failed"); - traverse_commit_list(revs, show_commit, show_object, base); + show_data.bitmap_git = bitmap_git; + show_data.base = base; + + traverse_commit_list(revs, show_commit, show_object, + &show_data); } return base; } -static void show_extended_objects(struct bitmap *objects, +static void show_extended_objects(struct bitmap_index *bitmap_git, show_reachable_fn show_reach) { - struct eindex *eindex = &bitmap_git.ext_index; + struct bitmap *objects = bitmap_git->result; + struct eindex *eindex = &bitmap_git->ext_index; uint32_t i; for (i = 0; i < eindex->count; ++i) { struct object *obj; - if (!bitmap_get(objects, bitmap_git.pack->num_objects + i)) + if (!bitmap_get(objects, bitmap_git->pack->num_objects + i)) continue; obj = eindex->objects[i]; @@ -593,7 +615,7 @@ static void show_extended_objects(struct bitmap *objects, } static void show_objects_for_type( - struct bitmap *objects, + struct bitmap_index *bitmap_git, struct ewah_bitmap *type_filter, enum object_type object_type, show_reachable_fn show_reach) @@ -604,7 +626,9 @@ static void show_objects_for_type( struct ewah_iterator it; eword_t filter; - if (bitmap_git.reuse_objects == bitmap_git.pack->num_objects) + struct bitmap *objects = bitmap_git->result; + + if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) return; ewah_iterator_init(&it, type_filter); @@ -622,16 +646,16 @@ static void show_objects_for_type( offset += ewah_bit_ctz64(word >> offset); - if (pos + offset < bitmap_git.reuse_objects) + if (pos + offset < bitmap_git->reuse_objects) continue; - entry = &bitmap_git.pack->revindex[pos + offset]; - nth_packed_object_oid(&oid, bitmap_git.pack, entry->nr); + entry = &bitmap_git->pack->revindex[pos + offset]; + nth_packed_object_oid(&oid, bitmap_git->pack, entry->nr); - if (bitmap_git.hashes) - hash = get_be32(bitmap_git.hashes + entry->nr); + if (bitmap_git->hashes) + hash = get_be32(bitmap_git->hashes + entry->nr); - show_reach(&oid, object_type, 0, hash, bitmap_git.pack, entry->offset); + show_reach(&oid, object_type, 0, hash, bitmap_git->pack, entry->offset); } pos += BITS_IN_EWORD; @@ -639,20 +663,21 @@ static void show_objects_for_type( } } -static int in_bitmapped_pack(struct object_list *roots) +static int in_bitmapped_pack(struct bitmap_index *bitmap_git, + struct object_list *roots) { while (roots) { struct object *object = roots->item; roots = roots->next; - if (find_pack_entry_one(object->oid.hash, bitmap_git.pack) > 0) + if (find_pack_entry_one(object->oid.hash, bitmap_git->pack) > 0) return 1; } return 0; } -int prepare_bitmap_walk(struct rev_info *revs) +struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs) { unsigned int i; @@ -662,12 +687,11 @@ int prepare_bitmap_walk(struct rev_info *revs) struct bitmap *wants_bitmap = NULL; struct bitmap *haves_bitmap = NULL; - if (!bitmap_git.loaded) { - /* try to open a bitmapped pack, but don't parse it yet - * because we may not need to use it */ - if (open_pack_bitmap() < 0) - return -1; - } + struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git)); + /* try to open a bitmapped pack, but don't parse it yet + * because we may not need to use it */ + if (open_pack_bitmap(bitmap_git) < 0) + goto cleanup; for (i = 0; i < revs->pending.nr; ++i) { struct object *object = revs->pending.objects[i].item; @@ -699,26 +723,26 @@ int prepare_bitmap_walk(struct rev_info *revs) * in the packfile that has a bitmap, we don't have anything to * optimize here */ - if (haves && !in_bitmapped_pack(haves)) - return -1; + if (haves && !in_bitmapped_pack(bitmap_git, haves)) + goto cleanup; /* if we don't want anything, we're done here */ if (!wants) - return -1; + goto cleanup; /* * now we're going to use bitmaps, so load the actual bitmap entries * from disk. this is the point of no return; after this the rev_list * becomes invalidated and we must perform the revwalk through bitmaps */ - if (!bitmap_git.loaded && load_pack_bitmap() < 0) - return -1; + if (!bitmap_git->loaded && load_pack_bitmap(bitmap_git) < 0) + goto cleanup; object_array_clear(&revs->pending); if (haves) { revs->ignore_missing_links = 1; - haves_bitmap = find_objects(revs, haves, NULL); + haves_bitmap = find_objects(bitmap_git, revs, haves, NULL); reset_revision_walk(); revs->ignore_missing_links = 0; @@ -726,7 +750,7 @@ int prepare_bitmap_walk(struct rev_info *revs) BUG("failed to perform bitmap walk"); } - wants_bitmap = find_objects(revs, wants, haves_bitmap); + wants_bitmap = find_objects(bitmap_git, revs, wants, haves_bitmap); if (!wants_bitmap) BUG("failed to perform bitmap walk"); @@ -734,13 +758,18 @@ int prepare_bitmap_walk(struct rev_info *revs) if (haves_bitmap) bitmap_and_not(wants_bitmap, haves_bitmap); - bitmap_git.result = wants_bitmap; + bitmap_git->result = wants_bitmap; bitmap_free(haves_bitmap); - return 0; + return bitmap_git; + +cleanup: + free_bitmap_index(bitmap_git); + return NULL; } -int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, +int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, + struct packed_git **packfile, uint32_t *entries, off_t *up_to) { @@ -750,7 +779,7 @@ int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, */ static const double REUSE_PERCENT = 0.9; - struct bitmap *result = bitmap_git.result; + struct bitmap *result = bitmap_git->result; uint32_t reuse_threshold; uint32_t i, reuse_objects = 0; @@ -770,8 +799,8 @@ int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, const unsigned char *sha1; struct revindex_entry *entry; - entry = &bitmap_git.reverse_index->revindex[reuse_objects]; - sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr); + entry = &bitmap_git->reverse_index->revindex[reuse_objects]; + sha1 = nth_packed_object_sha1(bitmap_git->pack, entry->nr); fprintf(stderr, "Failed to reuse at %d (%016llx)\n", reuse_objects, result->words[i]); @@ -782,48 +811,50 @@ int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, if (!reuse_objects) return -1; - if (reuse_objects >= bitmap_git.pack->num_objects) { - bitmap_git.reuse_objects = *entries = bitmap_git.pack->num_objects; + if (reuse_objects >= bitmap_git->pack->num_objects) { + bitmap_git->reuse_objects = *entries = bitmap_git->pack->num_objects; *up_to = -1; /* reuse the full pack */ - *packfile = bitmap_git.pack; + *packfile = bitmap_git->pack; return 0; } - reuse_threshold = bitmap_popcount(bitmap_git.result) * REUSE_PERCENT; + reuse_threshold = bitmap_popcount(bitmap_git->result) * REUSE_PERCENT; if (reuse_objects < reuse_threshold) return -1; - bitmap_git.reuse_objects = *entries = reuse_objects; - *up_to = bitmap_git.pack->revindex[reuse_objects].offset; - *packfile = bitmap_git.pack; + bitmap_git->reuse_objects = *entries = reuse_objects; + *up_to = bitmap_git->pack->revindex[reuse_objects].offset; + *packfile = bitmap_git->pack; return 0; } -void traverse_bitmap_commit_list(show_reachable_fn show_reachable) +void traverse_bitmap_commit_list(struct bitmap_index *bitmap_git, + show_reachable_fn show_reachable) { - assert(bitmap_git.result); + assert(bitmap_git->result); - show_objects_for_type(bitmap_git.result, bitmap_git.commits, + show_objects_for_type(bitmap_git, bitmap_git->commits, OBJ_COMMIT, show_reachable); - show_objects_for_type(bitmap_git.result, bitmap_git.trees, + show_objects_for_type(bitmap_git, bitmap_git->trees, OBJ_TREE, show_reachable); - show_objects_for_type(bitmap_git.result, bitmap_git.blobs, + show_objects_for_type(bitmap_git, bitmap_git->blobs, OBJ_BLOB, show_reachable); - show_objects_for_type(bitmap_git.result, bitmap_git.tags, + show_objects_for_type(bitmap_git, bitmap_git->tags, OBJ_TAG, show_reachable); - show_extended_objects(bitmap_git.result, show_reachable); + show_extended_objects(bitmap_git, show_reachable); - bitmap_free(bitmap_git.result); - bitmap_git.result = NULL; + bitmap_free(bitmap_git->result); + bitmap_git->result = NULL; } -static uint32_t count_object_type(struct bitmap *objects, +static uint32_t count_object_type(struct bitmap_index *bitmap_git, enum object_type type) { - struct eindex *eindex = &bitmap_git.ext_index; + struct bitmap *objects = bitmap_git->result; + struct eindex *eindex = &bitmap_git->ext_index; uint32_t i = 0, count = 0; struct ewah_iterator it; @@ -831,19 +862,19 @@ static uint32_t count_object_type(struct bitmap *objects, switch (type) { case OBJ_COMMIT: - ewah_iterator_init(&it, bitmap_git.commits); + ewah_iterator_init(&it, bitmap_git->commits); break; case OBJ_TREE: - ewah_iterator_init(&it, bitmap_git.trees); + ewah_iterator_init(&it, bitmap_git->trees); break; case OBJ_BLOB: - ewah_iterator_init(&it, bitmap_git.blobs); + ewah_iterator_init(&it, bitmap_git->blobs); break; case OBJ_TAG: - ewah_iterator_init(&it, bitmap_git.tags); + ewah_iterator_init(&it, bitmap_git->tags); break; default: @@ -857,32 +888,34 @@ static uint32_t count_object_type(struct bitmap *objects, for (i = 0; i < eindex->count; ++i) { if (eindex->objects[i]->type == type && - bitmap_get(objects, bitmap_git.pack->num_objects + i)) + bitmap_get(objects, bitmap_git->pack->num_objects + i)) count++; } return count; } -void count_bitmap_commit_list(uint32_t *commits, uint32_t *trees, +void count_bitmap_commit_list(struct bitmap_index *bitmap_git, + uint32_t *commits, uint32_t *trees, uint32_t *blobs, uint32_t *tags) { - assert(bitmap_git.result); + assert(bitmap_git->result); if (commits) - *commits = count_object_type(bitmap_git.result, OBJ_COMMIT); + *commits = count_object_type(bitmap_git, OBJ_COMMIT); if (trees) - *trees = count_object_type(bitmap_git.result, OBJ_TREE); + *trees = count_object_type(bitmap_git, OBJ_TREE); if (blobs) - *blobs = count_object_type(bitmap_git.result, OBJ_BLOB); + *blobs = count_object_type(bitmap_git, OBJ_BLOB); if (tags) - *tags = count_object_type(bitmap_git.result, OBJ_TAG); + *tags = count_object_type(bitmap_git, OBJ_TAG); } struct bitmap_test_data { + struct bitmap_index *bitmap_git; struct bitmap *base; struct progress *prg; size_t seen; @@ -894,7 +927,7 @@ static void test_show_object(struct object *object, const char *name, struct bitmap_test_data *tdata = data; int bitmap_pos; - bitmap_pos = bitmap_position(object->oid.hash); + bitmap_pos = bitmap_position(tdata->bitmap_git, object->oid.hash); if (bitmap_pos < 0) die("Object not in bitmap: %s\n", oid_to_hex(&object->oid)); @@ -907,7 +940,8 @@ static void test_show_commit(struct commit *commit, void *data) struct bitmap_test_data *tdata = data; int bitmap_pos; - bitmap_pos = bitmap_position(commit->object.oid.hash); + bitmap_pos = bitmap_position(tdata->bitmap_git, + commit->object.oid.hash); if (bitmap_pos < 0) die("Object not in bitmap: %s\n", oid_to_hex(&commit->object.oid)); @@ -922,21 +956,22 @@ void test_bitmap_walk(struct rev_info *revs) khiter_t pos; size_t result_popcnt; struct bitmap_test_data tdata; + struct bitmap_index *bitmap_git; - if (prepare_bitmap_git()) + if (!(bitmap_git = prepare_bitmap_git())) die("failed to load bitmap indexes"); if (revs->pending.nr != 1) die("you must specify exactly one commit to test"); fprintf(stderr, "Bitmap v%d test (%d entries loaded)\n", - bitmap_git.version, bitmap_git.entry_count); + bitmap_git->version, bitmap_git->entry_count); root = revs->pending.objects[0].item; - pos = kh_get_sha1(bitmap_git.bitmaps, root->oid.hash); + pos = kh_get_sha1(bitmap_git->bitmaps, root->oid.hash); - if (pos < kh_end(bitmap_git.bitmaps)) { - struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, pos); + if (pos < kh_end(bitmap_git->bitmaps)) { + struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, pos); struct ewah_bitmap *bm = lookup_stored_bitmap(st); fprintf(stderr, "Found bitmap for %s. %d bits / %08x checksum\n", @@ -957,6 +992,7 @@ void test_bitmap_walk(struct rev_info *revs) if (prepare_revision_walk(revs)) die("revision walk setup failed"); + tdata.bitmap_git = bitmap_git; tdata.base = bitmap_new(); tdata.prg = start_progress("Verifying bitmap entries", result_popcnt); tdata.seen = 0; @@ -970,7 +1006,7 @@ void test_bitmap_walk(struct rev_info *revs) else fprintf(stderr, "Mismatch!\n"); - bitmap_free(result); + free_bitmap_index(bitmap_git); } static int rebuild_bitmap(uint32_t *reposition, @@ -1004,7 +1040,8 @@ static int rebuild_bitmap(uint32_t *reposition, return 0; } -int rebuild_existing_bitmaps(struct packing_data *mapping, +int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git, + struct packing_data *mapping, khash_sha1 *reused_bitmaps, int show_progress) { @@ -1017,10 +1054,7 @@ int rebuild_existing_bitmaps(struct packing_data *mapping, khiter_t hash_pos; int hash_ret; - if (prepare_bitmap_git() < 0) - return -1; - - num_objects = bitmap_git.pack->num_objects; + num_objects = bitmap_git->pack->num_objects; reposition = xcalloc(num_objects, sizeof(uint32_t)); for (i = 0; i < num_objects; ++i) { @@ -1028,8 +1062,8 @@ int rebuild_existing_bitmaps(struct packing_data *mapping, struct revindex_entry *entry; struct object_entry *oe; - entry = &bitmap_git.pack->revindex[i]; - sha1 = nth_packed_object_sha1(bitmap_git.pack, entry->nr); + entry = &bitmap_git->pack->revindex[i]; + sha1 = nth_packed_object_sha1(bitmap_git->pack, entry->nr); oe = packlist_find(mapping, sha1, NULL); if (oe) @@ -1042,7 +1076,7 @@ int rebuild_existing_bitmaps(struct packing_data *mapping, if (show_progress) progress = start_progress("Reusing bitmaps", 0); - kh_foreach_value(bitmap_git.bitmaps, stored, { + kh_foreach_value(bitmap_git->bitmaps, stored, { if (stored->flags & BITMAP_FLAG_REUSE) { if (!rebuild_bitmap(reposition, lookup_stored_bitmap(stored), @@ -1064,3 +1098,21 @@ int rebuild_existing_bitmaps(struct packing_data *mapping, bitmap_free(rebuild); return 0; } + +void free_bitmap_index(struct bitmap_index *b) +{ + if (!b) + return; + + if (b->map) + munmap(b->map, b->map_size); + ewah_pool_free(b->commits); + ewah_pool_free(b->trees); + ewah_pool_free(b->blobs); + ewah_pool_free(b->tags); + kh_destroy_sha1(b->bitmaps); + free(b->ext_index.objects); + free(b->ext_index.hashes); + bitmap_free(b->result); + free(b); +} diff --git a/pack-bitmap.h b/pack-bitmap.h index 5ded2f139a..4555907dee 100644 --- a/pack-bitmap.h +++ b/pack-bitmap.h @@ -34,13 +34,21 @@ typedef int (*show_reachable_fn)( struct packed_git *found_pack, off_t found_offset); -int prepare_bitmap_git(void); -void count_bitmap_commit_list(uint32_t *commits, uint32_t *trees, uint32_t *blobs, uint32_t *tags); -void traverse_bitmap_commit_list(show_reachable_fn show_reachable); +struct bitmap_index; + +struct bitmap_index *prepare_bitmap_git(void); +void count_bitmap_commit_list(struct bitmap_index *, uint32_t *commits, + uint32_t *trees, uint32_t *blobs, uint32_t *tags); +void traverse_bitmap_commit_list(struct bitmap_index *, + show_reachable_fn show_reachable); void test_bitmap_walk(struct rev_info *revs); -int prepare_bitmap_walk(struct rev_info *revs); -int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, uint32_t *entries, off_t *up_to); -int rebuild_existing_bitmaps(struct packing_data *mapping, khash_sha1 *reused_bitmaps, int show_progress); +struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs); +int reuse_partial_packfile_from_bitmap(struct bitmap_index *, + struct packed_git **packfile, + uint32_t *entries, off_t *up_to); +int rebuild_existing_bitmaps(struct bitmap_index *, struct packing_data *mapping, + khash_sha1 *reused_bitmaps, int show_progress); +void free_bitmap_index(struct bitmap_index *); void bitmap_writer_show_progress(int show); void bitmap_writer_set_checksum(unsigned char *sha1); diff --git a/packfile.h b/packfile.h index e0a38aba93..cc7eaffe1b 100644 --- a/packfile.h +++ b/packfile.h @@ -3,6 +3,11 @@ #include "oidset.h" +/* in object-store.h */ +struct packed_git; +struct object_info; +enum object_type; + /* * Generate the filename to be used for a pack file with checksum "sha1" and * extension "ext". The result is written into the strbuf "buf", overwriting @@ -1442,12 +1442,12 @@ char *xdg_cache_home(const char *filename) return NULL; } -GIT_PATH_FUNC(git_path_cherry_pick_head, "CHERRY_PICK_HEAD") -GIT_PATH_FUNC(git_path_revert_head, "REVERT_HEAD") -GIT_PATH_FUNC(git_path_squash_msg, "SQUASH_MSG") -GIT_PATH_FUNC(git_path_merge_msg, "MERGE_MSG") -GIT_PATH_FUNC(git_path_merge_rr, "MERGE_RR") -GIT_PATH_FUNC(git_path_merge_mode, "MERGE_MODE") -GIT_PATH_FUNC(git_path_merge_head, "MERGE_HEAD") -GIT_PATH_FUNC(git_path_fetch_head, "FETCH_HEAD") -GIT_PATH_FUNC(git_path_shallow, "shallow") +REPO_GIT_PATH_FUNC(cherry_pick_head, "CHERRY_PICK_HEAD") +REPO_GIT_PATH_FUNC(revert_head, "REVERT_HEAD") +REPO_GIT_PATH_FUNC(squash_msg, "SQUASH_MSG") +REPO_GIT_PATH_FUNC(merge_msg, "MERGE_MSG") +REPO_GIT_PATH_FUNC(merge_rr, "MERGE_RR") +REPO_GIT_PATH_FUNC(merge_mode, "MERGE_MODE") +REPO_GIT_PATH_FUNC(merge_head, "MERGE_HEAD") +REPO_GIT_PATH_FUNC(fetch_head, "FETCH_HEAD") +REPO_GIT_PATH_FUNC(shallow, "shallow") @@ -160,14 +160,36 @@ extern void report_linked_checkout_garbage(void); return ret; \ } -const char *git_path_cherry_pick_head(void); -const char *git_path_revert_head(void); -const char *git_path_squash_msg(void); -const char *git_path_merge_msg(void); -const char *git_path_merge_rr(void); -const char *git_path_merge_mode(void); -const char *git_path_merge_head(void); -const char *git_path_fetch_head(void); -const char *git_path_shallow(void); +#define REPO_GIT_PATH_FUNC(var, filename) \ + const char *git_path_##var(struct repository *r) \ + { \ + if (!r->cached_paths.var) \ + r->cached_paths.var = git_pathdup(filename); \ + return r->cached_paths.var; \ + } + +struct path_cache { + const char *cherry_pick_head; + const char *revert_head; + const char *squash_msg; + const char *merge_msg; + const char *merge_rr; + const char *merge_mode; + const char *merge_head; + const char *fetch_head; + const char *shallow; +}; + +#define PATH_CACHE_INIT { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } + +const char *git_path_cherry_pick_head(struct repository *r); +const char *git_path_revert_head(struct repository *r); +const char *git_path_squash_msg(struct repository *r); +const char *git_path_merge_msg(struct repository *r); +const char *git_path_merge_rr(struct repository *r); +const char *git_path_merge_mode(struct repository *r); +const char *git_path_merge_head(struct repository *r); +const char *git_path_fetch_head(struct repository *r); +const char *git_path_shallow(struct repository *r); #endif /* PATH_H */ diff --git a/read-cache.c b/read-cache.c index 372588260e..e865254bea 100644 --- a/read-cache.c +++ b/read-cache.c @@ -11,6 +11,7 @@ #include "cache-tree.h" #include "refs.h" #include "dir.h" +#include "object-store.h" #include "tree.h" #include "commit.h" #include "blob.h" diff --git a/ref-filter.c b/ref-filter.c index fa3685d91f..0ab893a250 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -3,6 +3,7 @@ #include "parse-options.h" #include "refs.h" #include "wildmatch.h" +#include "object-store.h" #include "commit.h" #include "remote.h" #include "color.h" @@ -9,6 +9,7 @@ #include "iterator.h" #include "refs.h" #include "refs/refs-internal.h" +#include "object-store.h" #include "object.h" #include "tag.h" #include "submodule.h" diff --git a/remote-testsvn.c b/remote-testsvn.c index 444d98059f..3af708c5b6 100644 --- a/remote-testsvn.c +++ b/remote-testsvn.c @@ -1,6 +1,7 @@ #include "cache.h" #include "refs.h" #include "remote.h" +#include "object-store.h" #include "strbuf.h" #include "url.h" #include "exec-cmd.h" @@ -3,6 +3,7 @@ #include "remote.h" #include "refs.h" #include "refspec.h" +#include "object-store.h" #include "commit.h" #include "diff.h" #include "revision.h" diff --git a/repository.h b/repository.h index dba3ddbfdd..b9413be50c 100644 --- a/repository.h +++ b/repository.h @@ -39,6 +39,11 @@ struct repository { struct ref_store *refs; /* + * Contains path to often used file names. + */ + struct path_cache cached_paths; + + /* * Path to the repository's graft file. * Cannot be NULL after initialization. */ @@ -9,6 +9,7 @@ #include "ll-merge.h" #include "attr.h" #include "pathspec.h" +#include "object-store.h" #include "sha1-lookup.h" #define RESOLVED 0 @@ -200,7 +201,7 @@ static struct rerere_id *new_rerere_id(unsigned char *sha1) static void read_rr(struct string_list *rr) { struct strbuf buf = STRBUF_INIT; - FILE *in = fopen_or_warn(git_path_merge_rr(), "r"); + FILE *in = fopen_or_warn(git_path_merge_rr(the_repository), "r"); if (!in) return; @@ -895,7 +896,8 @@ int setup_rerere(struct string_list *merge_rr, int flags) if (flags & RERERE_READONLY) fd = 0; else - fd = hold_lock_file_for_update(&write_lock, git_path_merge_rr(), + fd = hold_lock_file_for_update(&write_lock, + git_path_merge_rr(the_repository), LOCK_DIE_ON_ERROR); read_rr(merge_rr); return fd; @@ -1245,6 +1247,6 @@ void rerere_clear(struct string_list *merge_rr) rmdir(rerere_path(id, NULL)); } } - unlink_or_warn(git_path_merge_rr()); + unlink_or_warn(git_path_merge_rr(the_repository)); rollback_lock_file(&write_lock); } diff --git a/revision.c b/revision.c index 0afae4744a..72abe235e4 100644 --- a/revision.c +++ b/revision.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "object-store.h" #include "tag.h" #include "blob.h" #include "tree.h" diff --git a/send-pack.c b/send-pack.c index 19025a7aca..e920ca57df 100644 --- a/send-pack.c +++ b/send-pack.c @@ -2,6 +2,7 @@ #include "config.h" #include "commit.h" #include "refs.h" +#include "object-store.h" #include "pkt-line.h" #include "sideband.h" #include "run-command.h" @@ -75,7 +76,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struc argv_array_push(&po.args, "-q"); if (args->progress) argv_array_push(&po.args, "--progress"); - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) argv_array_push(&po.args, "--shallow"); po.in = -1; po.out = args->stateless_rpc ? -1 : fd; @@ -220,7 +221,7 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c static void advertise_shallow_grafts_buf(struct strbuf *sb) { - if (!is_repository_shallow()) + if (!is_repository_shallow(the_repository)) return; for_each_commit_graft(advertise_shallow_grafts_cb, sb); } @@ -537,7 +538,7 @@ int send_pack(struct send_pack_args *args, } if (args->stateless_rpc) { - if (!args->dry_run && (cmds_sent || is_repository_shallow())) { + if (!args->dry_run && (cmds_sent || is_repository_shallow(the_repository))) { packet_buf_flush(&req_buf); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); } diff --git a/sequencer.c b/sequencer.c index 5354d4d51e..03c47405fb 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2,6 +2,7 @@ #include "config.h" #include "lockfile.h" #include "dir.h" +#include "object-store.h" #include "object.h" #include "commit.h" #include "sequencer.h" @@ -357,7 +358,7 @@ static void print_advice(int show_hint, struct replay_opts *opts) * (typically rebase --interactive) wants to take care * of the commit itself so remove CHERRY_PICK_HEAD */ - unlink(git_path_cherry_pick_head()); + unlink(git_path_cherry_pick_head(the_repository)); return; } @@ -1324,8 +1325,8 @@ static int do_commit(const char *msg_file, const char *author, &oid); strbuf_release(&sb); if (!res) { - unlink(git_path_cherry_pick_head()); - unlink(git_path_merge_msg()); + unlink(git_path_cherry_pick_head(the_repository)); + unlink(git_path_merge_msg(the_repository)); if (!is_rebase_i(opts)) print_commit_summary(NULL, &oid, SUMMARY_SHOW_AUTHOR_DATE); @@ -1613,7 +1614,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, struct replay_opts *opts, int final_fixup) { unsigned int flags = opts->edit ? EDIT_MSG : 0; - const char *msg_file = opts->edit ? NULL : git_path_merge_msg(); + const char *msg_file = opts->edit ? NULL : git_path_merge_msg(the_repository); struct object_id head; struct commit *base, *next, *parent; const char *base_label, *next_label; @@ -1755,12 +1756,12 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, flags |= CLEANUP_MSG; msg_file = rebase_path_fixup_msg(); } else { - const char *dest = git_path_squash_msg(); + const char *dest = git_path_squash_msg(the_repository); unlink(dest); if (copy_file(dest, rebase_path_squash_msg(), 0666)) return error(_("could not rename '%s' to '%s'"), rebase_path_squash_msg(), dest); - unlink(git_path_merge_msg()); + unlink(git_path_merge_msg(the_repository)); msg_file = dest; flags |= EDIT_MSG; } @@ -1778,13 +1779,13 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, goto leave; res |= write_message(msgbuf.buf, msgbuf.len, - git_path_merge_msg(), 0); + git_path_merge_msg(the_repository), 0); } else { struct commit_list *common = NULL; struct commit_list *remotes = NULL; res = write_message(msgbuf.buf, msgbuf.len, - git_path_merge_msg(), 0); + git_path_merge_msg(the_repository), 0); commit_list_insert(base, &common); commit_list_insert(next, &remotes); @@ -2206,6 +2207,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data) static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf) { int i; + char *strategy_opts_string; strbuf_reset(buf); if (!read_oneliner(buf, rebase_path_strategy(), 0)) @@ -2214,7 +2216,11 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf) if (!read_oneliner(buf, rebase_path_strategy_opts(), 0)) return; - opts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts); + strategy_opts_string = buf->buf; + if (*strategy_opts_string == ' ') + strategy_opts_string++; + opts->xopts_nr = split_cmdline(strategy_opts_string, + (const char ***)&opts->xopts); for (i = 0; i < opts->xopts_nr; i++) { const char *arg = opts->xopts[i]; @@ -2394,8 +2400,8 @@ static int rollback_single_pick(void) { struct object_id head_oid; - if (!file_exists(git_path_cherry_pick_head()) && - !file_exists(git_path_revert_head())) + if (!file_exists(git_path_cherry_pick_head(the_repository)) && + !file_exists(git_path_revert_head(the_repository))) return error(_("no cherry-pick or revert in progress")); if (read_ref_full("HEAD", 0, &head_oid, NULL)) return error(_("cannot resolve HEAD")); @@ -2620,10 +2626,11 @@ static int error_failed_squash(struct commit *commit, if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666)) return error(_("could not copy '%s' to '%s'"), rebase_path_squash_msg(), rebase_path_message()); - unlink(git_path_merge_msg()); - if (copy_file(git_path_merge_msg(), rebase_path_message(), 0666)) + unlink(git_path_merge_msg(the_repository)); + if (copy_file(git_path_merge_msg(the_repository), rebase_path_message(), 0666)) return error(_("could not copy '%s' to '%s'"), - rebase_path_message(), git_path_merge_msg()); + rebase_path_message(), + git_path_merge_msg(the_repository)); return error_with_patch(commit, subject, subject_len, opts, 1, 0); } @@ -2913,11 +2920,11 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len, write_author_script(message); find_commit_subject(message, &body); len = strlen(body); - ret = write_message(body, len, git_path_merge_msg(), 0); + ret = write_message(body, len, git_path_merge_msg(the_repository), 0); unuse_commit_buffer(commit, message); if (ret) { error_errno(_("could not write '%s'"), - git_path_merge_msg()); + git_path_merge_msg(the_repository)); goto leave_merge; } } else { @@ -2938,11 +2945,11 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len, len = buf.len; } - ret = write_message(p, len, git_path_merge_msg(), 0); + ret = write_message(p, len, git_path_merge_msg(the_repository), 0); strbuf_release(&buf); if (ret) { error_errno(_("could not write '%s'"), - git_path_merge_msg()); + git_path_merge_msg(the_repository)); goto leave_merge; } } @@ -2979,8 +2986,8 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len, } write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ, - git_path_merge_head(), 0); - write_message("no-ff", 5, git_path_merge_mode(), 0); + git_path_merge_head(the_repository), 0); + write_message("no-ff", 5, git_path_merge_mode(the_repository), 0); bases = get_merge_bases(head_commit, merge_commit); if (bases && !oidcmp(&merge_commit->object.oid, @@ -3034,7 +3041,7 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len, * value (a negative one would indicate that the `merge` * command needs to be rescheduled). */ - ret = !!run_git_commit(git_path_merge_msg(), opts, + ret = !!run_git_commit(git_path_merge_msg(the_repository), opts, run_commit_flags); leave_merge: @@ -3217,10 +3224,27 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts) intend_to_amend(); return error_failed_squash(item->commit, opts, item->arg_len, item->arg); - } else if (res && is_rebase_i(opts) && item->commit) + } 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 && + !get_oid("HEAD", &oid) && + (!oidcmp(&item->commit->object.oid, &oid) || + (opts->have_squash_onto && + !oidcmp(&opts->squash_onto, &oid)))) + to_amend = 1; + return res | error_with_patch(item->commit, - item->arg, item->arg_len, opts, res, - item->command == TODO_REWORD); + item->arg, item->arg_len, opts, + res, to_amend); + } } else if (item->command == TODO_EXEC) { char *end_of_arg = (char *)(item->arg + item->arg_len); int saved = *end_of_arg; @@ -3401,8 +3425,8 @@ static int continue_single_pick(void) { const char *argv[] = { "commit", NULL }; - if (!file_exists(git_path_cherry_pick_head()) && - !file_exists(git_path_revert_head())) + if (!file_exists(git_path_cherry_pick_head(the_repository)) && + !file_exists(git_path_revert_head(the_repository))) return error(_("no cherry-pick or revert in progress")); return run_command_v_opt(argv, RUN_GIT_CMD); } @@ -3505,7 +3529,7 @@ static int commit_staged_changes(struct replay_opts *opts, } if (is_clean) { - const char *cherry_pick_head = git_path_cherry_pick_head(); + const char *cherry_pick_head = git_path_cherry_pick_head(the_repository); if (file_exists(cherry_pick_head) && unlink(cherry_pick_head)) return error(_("could not remove CHERRY_PICK_HEAD")); @@ -3555,8 +3579,8 @@ int sequencer_continue(struct replay_opts *opts) if (!is_rebase_i(opts)) { /* Verify that the conflict has been resolved */ - if (file_exists(git_path_cherry_pick_head()) || - file_exists(git_path_revert_head())) { + if (file_exists(git_path_cherry_pick_head(the_repository)) || + file_exists(git_path_revert_head(the_repository))) { res = continue_single_pick(); if (res) goto release_todo_list; @@ -1,6 +1,8 @@ #include "cache.h" +#include "repository.h" #include "tempfile.h" #include "lockfile.h" +#include "object-store.h" #include "commit.h" #include "tag.h" #include "pkt-line.h" @@ -13,22 +15,19 @@ #include "revision.h" #include "list-objects.h" #include "commit-slab.h" +#include "repository.h" -static int is_shallow = -1; -static struct stat_validity shallow_stat; -static char *alternate_shallow_file; - -void set_alternate_shallow_file(const char *path, int override) +void set_alternate_shallow_file(struct repository *r, const char *path, int override) { - if (is_shallow != -1) + if (r->parsed_objects->is_shallow != -1) BUG("is_repository_shallow must not be called before set_alternate_shallow_file"); - if (alternate_shallow_file && !override) + if (r->parsed_objects->alternate_shallow_file && !override) return; - free(alternate_shallow_file); - alternate_shallow_file = xstrdup_or_null(path); + free(r->parsed_objects->alternate_shallow_file); + r->parsed_objects->alternate_shallow_file = xstrdup_or_null(path); } -int register_shallow(const struct object_id *oid) +int register_shallow(struct repository *r, const struct object_id *oid) { struct commit_graft *graft = xmalloc(sizeof(struct commit_graft)); @@ -38,41 +37,41 @@ int register_shallow(const struct object_id *oid) graft->nr_parent = -1; if (commit && commit->object.parsed) commit->parents = NULL; - return register_commit_graft(graft, 0); + return register_commit_graft(r, graft, 0); } -int is_repository_shallow(void) +int is_repository_shallow(struct repository *r) { FILE *fp; char buf[1024]; - const char *path = alternate_shallow_file; + const char *path = r->parsed_objects->alternate_shallow_file; - if (is_shallow >= 0) - return is_shallow; + if (r->parsed_objects->is_shallow >= 0) + return r->parsed_objects->is_shallow; if (!path) - path = git_path_shallow(); + path = git_path_shallow(r); /* * fetch-pack sets '--shallow-file ""' as an indicator that no * shallow file should be used. We could just open it and it * will likely fail. But let's do an explicit check instead. */ if (!*path || (fp = fopen(path, "r")) == NULL) { - stat_validity_clear(&shallow_stat); - is_shallow = 0; - return is_shallow; + stat_validity_clear(r->parsed_objects->shallow_stat); + r->parsed_objects->is_shallow = 0; + return r->parsed_objects->is_shallow; } - stat_validity_update(&shallow_stat, fileno(fp)); - is_shallow = 1; + stat_validity_update(r->parsed_objects->shallow_stat, fileno(fp)); + r->parsed_objects->is_shallow = 1; while (fgets(buf, sizeof(buf), fp)) { struct object_id oid; if (get_oid_hex(buf, &oid)) die("bad shallow line: %s", buf); - register_shallow(&oid); + register_shallow(r, &oid); } fclose(fp); - return is_shallow; + return r->parsed_objects->is_shallow; } /* @@ -116,8 +115,8 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth, parse_commit_or_die(commit); cur_depth++; if ((depth != INFINITE_DEPTH && cur_depth >= depth) || - (is_repository_shallow() && !commit->parents && - (graft = lookup_commit_graft(&commit->object.oid)) != NULL && + (is_repository_shallow(the_repository) && !commit->parents && + (graft = lookup_commit_graft(the_repository, &commit->object.oid)) != NULL && graft->nr_parent < 0)) { commit_list_insert(commit, &result); commit->object.flags |= shallow_flag; @@ -181,7 +180,7 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, */ clear_object_flags(both_flags); - is_repository_shallow(); /* make sure shallows are read */ + is_repository_shallow(the_repository); /* make sure shallows are read */ init_revisions(&revs, NULL); save_commit_buffer = 0; @@ -234,12 +233,12 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, return result; } -static void check_shallow_file_for_update(void) +static void check_shallow_file_for_update(struct repository *r) { - if (is_shallow == -1) + if (r->parsed_objects->is_shallow == -1) BUG("shallow must be initialized by now"); - if (!stat_validity_check(&shallow_stat, git_path_shallow())) + if (!stat_validity_check(r->parsed_objects->shallow_stat, git_path_shallow(the_repository))) die("shallow file has changed since we read it"); } @@ -334,9 +333,10 @@ void setup_alternate_shallow(struct lock_file *shallow_lock, struct strbuf sb = STRBUF_INIT; int fd; - fd = hold_lock_file_for_update(shallow_lock, git_path_shallow(), + fd = hold_lock_file_for_update(shallow_lock, + git_path_shallow(the_repository), LOCK_DIE_ON_ERROR); - check_shallow_file_for_update(); + check_shallow_file_for_update(the_repository); if (write_shallow_commits(&sb, 0, extra)) { if (write_in_full(fd, sb.buf, sb.len) < 0) die_errno("failed to write to %s", @@ -361,7 +361,7 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c void advertise_shallow_grafts(int fd) { - if (!is_repository_shallow()) + if (!is_repository_shallow(the_repository)) return; for_each_commit_graft(advertise_shallow_grafts_cb, &fd); } @@ -381,16 +381,17 @@ void prune_shallow(int show_only) strbuf_release(&sb); return; } - fd = hold_lock_file_for_update(&shallow_lock, git_path_shallow(), + fd = hold_lock_file_for_update(&shallow_lock, + git_path_shallow(the_repository), LOCK_DIE_ON_ERROR); - check_shallow_file_for_update(); + check_shallow_file_for_update(the_repository); if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) { if (write_in_full(fd, sb.buf, sb.len) < 0) die_errno("failed to write to %s", get_lock_file_path(&shallow_lock)); commit_lock_file(&shallow_lock); } else { - unlink(git_path_shallow()); + unlink(git_path_shallow(the_repository)); rollback_lock_file(&shallow_lock); } strbuf_release(&sb); @@ -415,7 +416,8 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa) for (i = 0; i < sa->nr; i++) { if (has_object_file(sa->oid + i)) { struct commit_graft *graft; - graft = lookup_commit_graft(&sa->oid[i]); + graft = lookup_commit_graft(the_repository, + &sa->oid[i]); if (graft && graft->nr_parent < 0) continue; info->ours[info->nr_ours++] = i; diff --git a/submodule-config.c b/submodule-config.c index 388ef1f892..2a7259ba8b 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -4,6 +4,7 @@ #include "submodule-config.h" #include "submodule.h" #include "strbuf.h" +#include "object-store.h" #include "parse-options.h" /* @@ -591,6 +592,23 @@ static void submodule_cache_check_init(struct repository *repo) submodule_cache_init(repo->submodule_cache); } +/* + * Note: This function is private for a reason, the '.gitmodules' file should + * not be used as as a mechanism to retrieve arbitrary configuration stored in + * the repository. + * + * Runs the provided config function on the '.gitmodules' file found in the + * working directory. + */ +static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data) +{ + if (repo->worktree) { + char *file = repo_worktree_path(repo, GITMODULES_FILE); + git_config_from_file(fn, file, data); + free(file); + } +} + static int gitmodules_cb(const char *var, const char *value, void *data) { struct repository *repo = data; @@ -608,19 +626,11 @@ void repo_read_gitmodules(struct repository *repo) { submodule_cache_check_init(repo); - if (repo->worktree) { - char *gitmodules; - - if (repo_read_index(repo) < 0) - return; - - gitmodules = repo_worktree_path(repo, GITMODULES_FILE); - - if (!is_gitmodules_unmerged(repo->index)) - git_config_from_file(gitmodules_cb, gitmodules, repo); + if (repo_read_index(repo) < 0) + return; - free(gitmodules); - } + if (!is_gitmodules_unmerged(repo->index)) + config_from_gitmodules(gitmodules_cb, repo, repo); repo->submodule_cache->gitmodules_read = 1; } @@ -671,3 +681,45 @@ void submodule_free(struct repository *r) if (r->submodule_cache) submodule_cache_clear(r->submodule_cache); } + +struct fetch_config { + int *max_children; + int *recurse_submodules; +}; + +static int gitmodules_fetch_config(const char *var, const char *value, void *cb) +{ + struct fetch_config *config = cb; + if (!strcmp(var, "submodule.fetchjobs")) { + *(config->max_children) = parse_submodule_fetchjobs(var, value); + return 0; + } else if (!strcmp(var, "fetch.recursesubmodules")) { + *(config->recurse_submodules) = parse_fetch_recurse_submodules_arg(var, value); + return 0; + } + + return 0; +} + +void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules) +{ + struct fetch_config config = { + .max_children = max_children, + .recurse_submodules = recurse_submodules + }; + config_from_gitmodules(gitmodules_fetch_config, the_repository, &config); +} + +static int gitmodules_update_clone_config(const char *var, const char *value, + void *cb) +{ + int *max_jobs = cb; + if (!strcmp(var, "submodule.fetchjobs")) + *max_jobs = parse_submodule_fetchjobs(var, value); + return 0; +} + +void update_clone_config_from_gitmodules(int *max_jobs) +{ + config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs); +} diff --git a/submodule-config.h b/submodule-config.h index ca1f94e2d2..dc7278eea4 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -2,6 +2,7 @@ #define SUBMODULE_CONFIG_CACHE_H #include "cache.h" +#include "config.h" #include "hashmap.h" #include "submodule.h" #include "strbuf.h" @@ -55,4 +56,15 @@ void submodule_free(struct repository *r); */ int check_submodule_name(const char *name); +/* + * Note: these helper functions exist solely to maintain backward + * compatibility with 'fetch' and 'update_clone' storing configuration in + * '.gitmodules'. + * + * New helpers to retrieve arbitrary configuration from the '.gitmodules' file + * should NOT be added. + */ +extern void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules); +extern void update_clone_config_from_gitmodules(int *max_jobs); + #endif /* SUBMODULE_CONFIG_H */ diff --git a/submodule.c b/submodule.c index 0998ea2345..2a6381864e 100644 --- a/submodule.c +++ b/submodule.c @@ -1534,6 +1534,18 @@ out: return ret; } +void submodule_unset_core_worktree(const struct submodule *sub) +{ + char *config_path = xstrfmt("%s/modules/%s/config", + get_git_common_dir(), sub->name); + + if (git_config_set_in_file_gently(config_path, "core.worktree", NULL)) + warning(_("Could not unset core.worktree setting in submodule '%s'"), + sub->path); + + free(config_path); +} + static const char *get_super_prefix_or_empty(void) { const char *s = get_super_prefix(); @@ -1670,7 +1682,7 @@ int submodule_move_head(const char *path, argv_array_push(&cp.args, new_head ? new_head : empty_tree_oid_hex()); if (run_command(&cp)) { - ret = -1; + ret = error(_("Submodule '%s' could not be updated."), path); goto out; } @@ -1699,6 +1711,8 @@ int submodule_move_head(const char *path, if (is_empty_dir(path)) rmdir_or_warn(path); + + submodule_unset_core_worktree(sub); } } out: diff --git a/submodule.h b/submodule.h index 7856b8a0b3..4644683e6c 100644 --- a/submodule.h +++ b/submodule.h @@ -121,6 +121,8 @@ extern int submodule_move_head(const char *path, const char *new_head, unsigned flags); +void submodule_unset_core_worktree(const struct submodule *sub); + /* * Prepare the "env_array" parameter of a "struct child_process" for executing * a submodule by clearing any repo-specific environment variables, but diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 1f38a85371..be78cdc1ff 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -235,7 +235,7 @@ reset_work_tree_to_interested () { then mkdir -p submodule_update/.git/modules/sub1/modules && cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2 - GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree + # core.worktree is unset for sub2 as it is not checked out fi && # indicate we are interested in the submodule: git -C submodule_update config submodule.sub1.url "bogus" && @@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() { git branch -t remove_sub1 origin/remove_sub1 && $command remove_sub1 && test_superproject_content origin/remove_sub1 && - ! test -e sub1 + ! test -e sub1 && + test_must_fail git config -f .git/modules/sub1/config core.worktree ) ' # ... absorbing a .git directory along the way. @@ -781,7 +782,8 @@ test_submodule_recursing_with_args_common() { ( cd submodule_update && git branch -t invalid_sub1 origin/invalid_sub1 && - test_must_fail $command invalid_sub1 && + test_must_fail $command invalid_sub1 2>err && + test_i18ngrep sub1 err && test_superproject_content origin/add_sub1 && test_submodule_content sub1 origin/add_sub1 ) diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 553e26d9ce..8293131001 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -339,8 +339,8 @@ test_expect_failure 'reflog with non-commit entries displays all entries' ' ' test_expect_success 'reflog expire operates on symref not referrent' ' - git branch -l the_symref && - git branch -l referrent && + git branch --create-reflog the_symref && + git branch --create-reflog referrent && git update-ref referrent HEAD && git symbolic-ref refs/heads/the_symref refs/heads/referrent && test_when_finished "rm -f .git/refs/heads/referrent.lock" && diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 08467982f6..dbca665da4 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -49,9 +49,9 @@ test_expect_success 'git branch HEAD should fail' ' cat >expect <<EOF $ZERO_OID $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master EOF -test_expect_success 'git branch -l d/e/f should create a branch and a log' ' +test_expect_success 'git branch --create-reflog d/e/f should create a branch and a log' ' GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git branch -l d/e/f && + git -c core.logallrefupdates=false branch --create-reflog d/e/f && test_path_is_file .git/refs/heads/d/e/f && test_path_is_file .git/logs/refs/heads/d/e/f && test_cmp expect .git/logs/refs/heads/d/e/f @@ -82,7 +82,7 @@ test_expect_success 'git branch -m dumps usage' ' test_expect_success 'git branch -m m broken_symref should work' ' test_when_finished "git branch -D broken_symref" && - git branch -l m && + git branch --create-reflog m && git symbolic-ref refs/heads/broken_symref refs/heads/i_am_broken && git branch -m m broken_symref && git reflog exists refs/heads/broken_symref && @@ -90,13 +90,13 @@ test_expect_success 'git branch -m m broken_symref should work' ' ' test_expect_success 'git branch -m m m/m should work' ' - git branch -l m && + git branch --create-reflog m && git branch -m m m/m && git reflog exists refs/heads/m/m ' test_expect_success 'git branch -m n/n n should work' ' - git branch -l n/n && + git branch --create-reflog n/n && git branch -m n/n n && git reflog exists refs/heads/n ' @@ -378,9 +378,9 @@ mv .git/config-saved .git/config git config branch.s/s.dummy Hello test_expect_success 'git branch -m s/s s should work when s/t is deleted' ' - git branch -l s/s && + git branch --create-reflog s/s && git reflog exists refs/heads/s/s && - git branch -l s/t && + git branch --create-reflog s/t && git reflog exists refs/heads/s/t && git branch -d s/t && git branch -m s/s s && @@ -444,7 +444,7 @@ test_expect_success 'git branch --copy dumps usage' ' ' test_expect_success 'git branch -c d e should work' ' - git branch -l d && + git branch --create-reflog d && git reflog exists refs/heads/d && git config branch.d.dummy Hello && git branch -c d e && @@ -459,7 +459,7 @@ test_expect_success 'git branch -c d e should work' ' ' test_expect_success 'git branch --copy is a synonym for -c' ' - git branch -l copy && + git branch --create-reflog copy && git reflog exists refs/heads/copy && git config branch.copy.dummy Hello && git branch --copy copy copy-to && @@ -486,7 +486,7 @@ test_expect_success 'git branch -c ee ef should copy ee to create branch ef' ' ' test_expect_success 'git branch -c f/f g/g should work' ' - git branch -l f/f && + git branch --create-reflog f/f && git reflog exists refs/heads/f/f && git config branch.f/f.dummy Hello && git branch -c f/f g/g && @@ -497,7 +497,7 @@ test_expect_success 'git branch -c f/f g/g should work' ' ' test_expect_success 'git branch -c m2 m2 should work' ' - git branch -l m2 && + git branch --create-reflog m2 && git reflog exists refs/heads/m2 && git config branch.m2.dummy Hello && git branch -c m2 m2 && @@ -506,18 +506,18 @@ test_expect_success 'git branch -c m2 m2 should work' ' ' test_expect_success 'git branch -c zz zz/zz should fail' ' - git branch -l zz && + git branch --create-reflog zz && git reflog exists refs/heads/zz && test_must_fail git branch -c zz zz/zz ' test_expect_success 'git branch -c b/b b should fail' ' - git branch -l b/b && + git branch --create-reflog b/b && test_must_fail git branch -c b/b b ' test_expect_success 'git branch -C o/q o/p should work when o/p exists' ' - git branch -l o/q && + git branch --create-reflog o/q && git reflog exists refs/heads/o/q && git reflog exists refs/heads/o/p && git branch -C o/q o/p @@ -570,10 +570,10 @@ test_expect_success 'git branch -C master5 master5 should work when master is ch ' test_expect_success 'git branch -C ab cd should overwrite existing config for cd' ' - git branch -l cd && + git branch --create-reflog cd && git reflog exists refs/heads/cd && git config branch.cd.dummy CD && - git branch -l ab && + git branch --create-reflog ab && git reflog exists refs/heads/ab && git config branch.ab.dummy AB && git branch -C ab cd && @@ -685,7 +685,7 @@ test_expect_success 'renaming a symref is not allowed' ' ' test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for u is a symlink' ' - git branch -l u && + git branch --create-reflog u && mv .git/logs/refs/heads/u real-u && ln -s real-u .git/logs/refs/heads/u && test_must_fail git branch -m u v diff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh new file mode 100755 index 0000000000..8f832957fc --- /dev/null +++ b/t/t3401-rebase-and-am-rename.sh @@ -0,0 +1,105 @@ +#!/bin/sh + +test_description='git rebase + directory rename tests' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + +test_expect_success 'setup testcase' ' + test_create_repo dir-rename && + ( + cd dir-rename && + + mkdir x && + test_seq 1 10 >x/a && + test_seq 11 20 >x/b && + test_seq 21 30 >x/c && + test_write_lines a b c d e f g h i >l && + git add x l && + git commit -m "Initial" && + + git branch O && + git branch A && + git branch B && + + git checkout A && + git mv x y && + git mv l letters && + git commit -m "Rename x to y, l to letters" && + + git checkout B && + echo j >>l && + test_seq 31 40 >x/d && + git add l x/d && + git commit -m "Modify l, add x/d" + ) +' + +test_expect_success 'rebase --interactive: directory rename detected' ' + ( + cd dir-rename && + + git checkout B^0 && + + set_fake_editor && + FAKE_LINES="1" git rebase --interactive A && + + git ls-files -s >out && + test_line_count = 5 out && + + test_path_is_file y/d && + test_path_is_missing x/d + ) +' + +test_expect_failure 'rebase (am): directory rename detected' ' + ( + cd dir-rename && + + git checkout B^0 && + + git rebase A && + + git ls-files -s >out && + test_line_count = 5 out && + + test_path_is_file y/d && + test_path_is_missing x/d + ) +' + +test_expect_success 'rebase --merge: directory rename detected' ' + ( + cd dir-rename && + + git checkout B^0 && + + git rebase --merge A && + + git ls-files -s >out && + test_line_count = 5 out && + + test_path_is_file y/d && + test_path_is_missing x/d + ) +' + +test_expect_failure 'am: directory rename detected' ' + ( + cd dir-rename && + + git checkout A^0 && + + git format-patch -1 B && + + git am --3way 0001*.patch && + + git ls-files -s >out && + test_line_count = 5 out && + + test_path_is_file y/d && + test_path_is_missing x/d + ) +' + +test_done diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 352a52e59d..c5d39e2b23 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for "edit"' ' ' test_expect_success 'aborted --continue does not squash commits after "edit"' ' + test_when_finished "git rebase --abort" && old=$(git rev-parse HEAD) && test_tick && set_fake_editor && FAKE_LINES="edit 1" git rebase -i HEAD^ && echo "edited again" > file7 && git add file7 && - test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue && - test $old = $(git rev-parse HEAD) && - git rebase --abort + echo all the things >>conflict && + test_must_fail git rebase --continue && + test $old = $(git rev-parse HEAD) ' test_expect_success 'auto-amend only edited commits after "edit"' ' @@ -981,7 +982,35 @@ test_expect_success 'rebase -i --root reword root commit' ' test -z "$(git show -s --format=%p HEAD^)" ' +test_expect_success 'rebase -i --root when root has untracked file confilct' ' + test_when_finished "reset_rebase" && + git checkout -b failing-root-pick A && + echo x >file2 && + git rm file1 && + git commit -m "remove file 1 add file 2" && + echo z >file1 && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2" git rebase -i --root && + rm file1 && + git rebase --continue && + test "$(git log -1 --format=%B)" = "remove file 1 add file 2" && + test "$(git rev-list --count HEAD)" = 2 +' + +test_expect_success 'rebase -i --root reword root when root has untracked file conflict' ' + test_when_finished "reset_rebase" && + echo z>file1 && + set_fake_editor && + test_must_fail env FAKE_LINES="reword 1 2" \ + FAKE_COMMIT_MESSAGE="Modified A" git rebase -i --root && + rm file1 && + FAKE_COMMIT_MESSAGE="Reworded A" git rebase --continue && + test "$(git log -1 --format=%B HEAD^)" = "Reworded A" && + test "$(git rev-list --count HEAD)" = 2 +' + test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' ' + git checkout reword-root-branch && git reset --hard && git checkout conflict-branch && set_fake_editor && diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index cb7c6de84a..da94dddc86 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' ' ' test_expect_success 'rebase -m commit with empty message' ' - test_must_fail git rebase -m master empty-message-merge && - git rebase --abort && - git rebase -m --allow-empty-message master empty-message-merge + git rebase -m master empty-message-merge ' test_expect_success 'rebase -i commit with empty message' ' git checkout diff-in-message && set_fake_editor && - test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ - git rebase -i HEAD^ && - git rebase --abort && - FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ - git rebase -i --allow-empty-message HEAD^ + env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ + git rebase -i HEAD^ ' test_done diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 03bf1b8a3b..c145dbac38 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' ' test -f funny.was.run ' +test_expect_success 'rebase -i --continue handles merge strategy and options' ' + rm -fr .git/rebase-* && + git reset --hard commit-new-file-F2-on-topic-branch && + test_commit "commit-new-file-F3-on-topic-branch-for-dash-i" F3 32 && + test_when_finished "rm -fr test-bin funny.was.run funny.args" && + mkdir test-bin && + cat >test-bin/git-merge-funny <<-EOF && + #!$SHELL_PATH + echo "\$@" >>funny.args + case "\$1" in --opt) ;; *) exit 2 ;; esac + case "\$2" in --foo) ;; *) exit 2 ;; esac + case "\$4" in --) ;; *) exit 2 ;; esac + shift 2 && + >funny.was.run && + exec git merge-recursive "\$@" + EOF + chmod +x test-bin/git-merge-funny && + ( + PATH=./test-bin:$PATH && + test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic + ) && + test -f funny.was.run && + rm funny.was.run && + echo "Resolved" >F2 && + git add F2 && + ( + PATH=./test-bin:$PATH && + git rebase --continue + ) && + test -f funny.was.run +' + test_expect_success 'rebase passes merge strategy options correctly' ' rm -fr .git/rebase-* && git reset --hard commit-new-file-F3-on-topic-branch && diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh new file mode 100755 index 0000000000..bb78a6ec86 --- /dev/null +++ b/t/t3422-rebase-incompatible-options.sh @@ -0,0 +1,88 @@ +#!/bin/sh + +test_description='test if rebase detects and aborts on incompatible options' +. ./test-lib.sh + +test_expect_success 'setup' ' + test_seq 2 9 >foo && + git add foo && + git commit -m orig && + + git branch A && + git branch B && + + git checkout A && + test_seq 1 9 >foo && + git add foo && + git commit -m A && + + git checkout B && + echo "q qfoo();" | q_to_tab >>foo && + git add foo && + git commit -m B +' + +# +# Rebase has lots of useful options like --whitepsace=fix, which are +# actually all built in terms of flags to git-am. Since neither +# --merge nor --interactive (nor any options that imply those two) use +# git-am, using them together will result in flags like --whitespace=fix +# being ignored. Make sure rebase warns the user and aborts instead. +# + +test_rebase_am_only () { + opt=$1 + shift + test_expect_success "$opt incompatible with --merge" " + git checkout B^0 && + test_must_fail git rebase $opt --merge A + " + + test_expect_success "$opt incompatible with --strategy=ours" " + git checkout B^0 && + test_must_fail git rebase $opt --strategy=ours A + " + + test_expect_success "$opt incompatible with --strategy-option=ours" " + git checkout B^0 && + test_must_fail git rebase $opt --strategy-option=ours A + " + + test_expect_success "$opt incompatible with --interactive" " + git checkout B^0 && + test_must_fail git rebase $opt --interactive A + " + + test_expect_success "$opt incompatible with --exec" " + git checkout B^0 && + test_must_fail git rebase $opt --exec 'true' A + " + +} + +test_rebase_am_only --whitespace=fix +test_rebase_am_only --ignore-whitespace +test_rebase_am_only --committer-date-is-author-date +test_rebase_am_only -C4 + +test_expect_success '--preserve-merges incompatible with --signoff' ' + git checkout B^0 && + test_must_fail git rebase --preserve-merges --signoff A +' + +test_expect_success '--preserve-merges incompatible with --rebase-merges' ' + git checkout B^0 && + test_must_fail git rebase --preserve-merges --rebase-merges A +' + +test_expect_success '--rebase-merges incompatible with --strategy' ' + git checkout B^0 && + test_must_fail git rebase --rebase-merges -s resolve A +' + +test_expect_success '--rebase-merges incompatible with --strategy-option' ' + git checkout B^0 && + test_must_fail git rebase --rebase-merges -Xignore-space-change A +' + +test_done diff --git a/t/t3423-rebase-reword.sh b/t/t3423-rebase-reword.sh new file mode 100755 index 0000000000..6963750794 --- /dev/null +++ b/t/t3423-rebase-reword.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +test_description='git rebase interactive with rewording' + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/lib-rebase.sh + +test_expect_success 'setup' ' + test_commit master file-1 test && + + git checkout -b stuff && + + test_commit feature_a file-2 aaa && + test_commit feature_b file-2 ddd +' + +test_expect_success 'reword without issues functions as intended' ' + test_when_finished "reset_rebase" && + + git checkout stuff^0 && + + set_fake_editor && + FAKE_LINES="pick 1 reword 2" FAKE_COMMIT_MESSAGE="feature_b_reworded" \ + git rebase -i -v master && + + test "$(git log -1 --format=%B)" = "feature_b_reworded" && + test $(git rev-list --count HEAD) = 3 +' + +test_expect_success 'reword after a conflict preserves commit' ' + test_when_finished "reset_rebase" && + + git checkout stuff^0 && + + set_fake_editor && + test_must_fail env FAKE_LINES="reword 2" \ + git rebase -i -v master && + + git checkout --theirs file-2 && + git add file-2 && + FAKE_COMMIT_MESSAGE="feature_b_reworded" git rebase --continue && + + test "$(git log -1 --format=%B)" = "feature_b_reworded" && + test $(git rev-list --count HEAD) = 2 +' + +test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 028d5507a6..53880da7bb 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1554,13 +1554,15 @@ test_expect_success 'format-patch -o overrides format.outputDirectory' ' test_expect_success 'format-patch --base' ' git checkout side && - git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual && + git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 && + git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 && echo >expected && echo "base-commit: $(git rev-parse HEAD~3)" >>expected && echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected && echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected && signature >> expected && - test_cmp expected actual + test_cmp expected actual1 && + test_cmp expected actual2 ' test_expect_success 'format-patch --base errors out when base commit is in revision list' ' diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index ec4b160ddb..e23de7d0b5 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -107,6 +107,21 @@ test_expect_success 'test that the directory was renamed' ' test dir/D = "$(cat diroh/D.t)" ' +V=$(git rev-parse HEAD) + +test_expect_success 'populate --state-branch' ' + git filter-branch --state-branch state -f --tree-filter "touch file || :" HEAD +' + +W=$(git rev-parse HEAD) + +test_expect_success 'using --state-branch to skip already rewritten commits' ' + test_when_finished git reset --hard $V && + git reset --hard $V && + git filter-branch --state-branch state -f --tree-filter "touch file || :" HEAD && + test_cmp_rev $W HEAD +' + git tag oldD HEAD~4 test_expect_success 'rewrite one branch, keeping a side branch' ' git branch modD oldD && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 812db137b8..48fd14fae6 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -993,6 +993,11 @@ test_expect_success 'submodule deinit should remove the whole submodule section rmdir init ' +test_expect_success 'submodule deinit should unset core.worktree' ' + test_path_is_file .git/modules/example/config && + test_must_fail git config -f .git/modules/example/config core.worktree +' + test_expect_success 'submodule deinit from subdirectory' ' git submodule update --init && git config submodule.example.foo bar && diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 1797f632a3..9312c8daf5 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -99,6 +99,101 @@ do test_cmp expected actual ' + test_expect_success "grep -w $L (with --column)" ' + { + echo ${HC}file:5:foo mmap bar + echo ${HC}file:14:foo_mmap bar mmap + echo ${HC}file:5:foo mmap bar_mmap + echo ${HC}file:14:foo_mmap bar mmap baz + } >expected && + git grep --column -w -e mmap $H >actual && + test_cmp expected actual + ' + + test_expect_success "grep -w $L (with --column, extended OR)" ' + { + echo ${HC}file:14:foo_mmap bar mmap + echo ${HC}file:19:foo_mmap bar mmap baz + } >expected && + git grep --column -w -e mmap$ --or -e baz $H >actual && + test_cmp expected actual + ' + + test_expect_success "grep -w $L (with --column, --invert)" ' + { + echo ${HC}file:1:foo mmap bar + echo ${HC}file:1:foo_mmap bar + echo ${HC}file:1:foo_mmap bar mmap + echo ${HC}file:1:foo mmap bar_mmap + } >expected && + git grep --column --invert -w -e baz $H -- file >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L (with --column, --invert, extended OR)" ' + { + echo ${HC}hello_world:6:HeLLo_world + } >expected && + git grep --column --invert -e ll --or --not -e _ $H -- hello_world \ + >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L (with --column, --invert, extended AND)" ' + { + echo ${HC}hello_world:3:Hello world + echo ${HC}hello_world:3:Hello_world + echo ${HC}hello_world:6:HeLLo_world + } >expected && + git grep --column --invert --not -e _ --and --not -e ll $H -- hello_world \ + >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L (with --column, double-negation)" ' + { + echo ${HC}file:1:foo_mmap bar mmap baz + } >expected && + git grep --column --not \( --not -e foo --or --not -e baz \) $H -- file \ + >actual && + test_cmp expected actual + ' + + test_expect_success "grep -w $L (with --column, -C)" ' + { + echo ${HC}file:5:foo mmap bar + echo ${HC}file-foo_mmap bar + echo ${HC}file:14:foo_mmap bar mmap + echo ${HC}file:5:foo mmap bar_mmap + echo ${HC}file:14:foo_mmap bar mmap baz + } >expected && + git grep --column -w -C1 -e mmap $H >actual && + test_cmp expected actual + ' + + test_expect_success "grep -w $L (with --line-number, --column)" ' + { + echo ${HC}file:1:5:foo mmap bar + echo ${HC}file:3:14:foo_mmap bar mmap + echo ${HC}file:4:5:foo mmap bar_mmap + echo ${HC}file:5:14:foo_mmap bar mmap baz + } >expected && + git grep -n --column -w -e mmap $H >actual && + test_cmp expected actual + ' + + test_expect_success "grep -w $L (with non-extended patterns, --column)" ' + { + echo ${HC}file:5:foo mmap bar + echo ${HC}file:10:foo_mmap bar + echo ${HC}file:10:foo_mmap bar mmap + echo ${HC}file:5:foo mmap bar_mmap + echo ${HC}file:10:foo_mmap bar mmap baz + } >expected && + git grep --column -w -e bar -e mmap $H >actual && + test_cmp expected actual + ' + test_expect_success "grep -w $L" ' { echo ${HC}file:1:foo mmap bar @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "blob.h" diff --git a/tree-walk.c b/tree-walk.c index 8f5090862b..ecd6e53b85 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "unpack-trees.h" #include "dir.h" +#include "object-store.h" #include "tree.h" #include "pathspec.h" @@ -2,6 +2,7 @@ #include "cache.h" #include "cache-tree.h" #include "tree.h" +#include "object-store.h" #include "blob.h" #include "commit.h" #include "tag.h" diff --git a/unpack-trees.c b/unpack-trees.c index 3a85a02a77..66741130ae 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -16,6 +16,7 @@ #include "submodule.h" #include "submodule-config.h" #include "fsmonitor.h" +#include "object-store.h" #include "fetch-object.h" /* diff --git a/upload-pack.c b/upload-pack.c index 87c6722ea5..936acabbdd 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -3,6 +3,7 @@ #include "refs.h" #include "pkt-line.h" #include "sideband.h" +#include "object-store.h" #include "tag.h" #include "object.h" #include "commit.h" @@ -658,7 +659,7 @@ static void send_shallow(struct commit_list *result) if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write_fmt(1, "shallow %s", oid_to_hex(&object->oid)); - register_shallow(&object->oid); + register_shallow(the_repository, &object->oid); shallow_nr++; } result = result->next; @@ -695,14 +696,14 @@ static void send_unshallow(const struct object_array *shallows) add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ - register_shallow(&object->oid); + register_shallow(the_repository, &object->oid); } } static void deepen(int depth, int deepen_relative, struct object_array *shallows) { - if (depth == INFINITE_DEPTH && !is_repository_shallow()) { + if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) { int i; for (i = 0; i < shallows->nr; i++) { @@ -782,7 +783,8 @@ static int send_shallow_list(int depth, int deepen_rev_list, if (shallows->nr > 0) { int i; for (i = 0; i < shallows->nr; i++) - register_shallow(&shallows->objects[i].item->oid); + register_shallow(the_repository, + &shallows->objects[i].item->oid); } } @@ -1356,14 +1358,15 @@ static void send_shallow_info(struct upload_pack_data *data) { /* No shallow info needs to be sent */ if (!data->depth && !data->deepen_rev_list && !data->shallows.nr && - !is_repository_shallow()) + !is_repository_shallow(the_repository)) return; packet_write_fmt(1, "shallow-info\n"); if (!send_shallow_list(data->depth, data->deepen_rev_list, data->deepen_since, &data->deepen_not, - &data->shallows) && is_repository_shallow()) + &data->shallows) && + is_repository_shallow(the_repository)) deepen(INFINITE_DEPTH, data->deepen_relative, &data->shallows); packet_delim(1); @@ -1,5 +1,6 @@ #include "cache.h" #include "walker.h" +#include "object-store.h" #include "commit.h" #include "tree.h" #include "tree-walk.h" diff --git a/wt-status.c b/wt-status.c index d1c05145a4..8827a256d3 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1317,7 +1317,7 @@ static void show_rebase_in_progress(struct wt_status *s, status_printf_ln(s, color, _(" (use \"git rebase --abort\" to check out the original branch)")); } - } else if (state->rebase_in_progress || !stat(git_path_merge_msg(), &st)) { + } else if (state->rebase_in_progress || !stat(git_path_merge_msg(the_repository), &st)) { print_rebase_state(s, state, color); if (s->hints) status_printf_ln(s, color, @@ -1552,17 +1552,17 @@ void wt_status_get_state(struct wt_status_state *state, struct stat st; struct object_id oid; - if (!stat(git_path_merge_head(), &st)) { + if (!stat(git_path_merge_head(the_repository), &st)) { state->merge_in_progress = 1; } else if (wt_status_check_rebase(NULL, state)) { ; /* all set */ - } else if (!stat(git_path_cherry_pick_head(), &st) && + } else if (!stat(git_path_cherry_pick_head(the_repository), &st) && !get_oid("CHERRY_PICK_HEAD", &oid)) { state->cherry_pick_in_progress = 1; oidcpy(&state->cherry_pick_head_oid, &oid); } wt_status_check_bisect(NULL, state); - if (!stat(git_path_revert_head(), &st) && + if (!stat(git_path_revert_head(the_repository), &st) && !get_oid("REVERT_HEAD", &oid)) { state->revert_in_progress = 1; oidcpy(&state->revert_head_oid, &oid); diff --git a/xdiff-interface.c b/xdiff-interface.c index 9315bc0ede..ec6e574e4a 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -1,5 +1,6 @@ #include "cache.h" #include "config.h" +#include "object-store.h" #include "xdiff-interface.h" #include "xdiff/xtypes.h" #include "xdiff/xdiffi.h" |