Benoit Sigoure <tsunanet@gmail.com> <tsuna@lrde.epita.fr>
Bernt Hansen <bernt@norang.ca> <bernt@alumni.uwaterloo.ca>
Brandon Casey <drafnel@gmail.com> <casey@nrlssc.navy.mil>
+Brandon Williams <bwilliams.eng@gmail.com> <bmwill@google.com>
brian m. carlson <sandals@crustytoothpaste.net>
brian m. carlson <sandals@crustytoothpaste.net> <sandals@crustytoothpaste.ath.cx>
Bryan Larsen <bryan@larsen.st> <bryan.larsen@gmail.com>
UI, Workflows & Features
+ * The "http.version" configuration variable can be used with recent
+ enough cURL library to force the version of HTTP used to talk when
+ fetching and pushing.
+
+ * Small fixes and features for fast-export and fast-import, mostly on
+ the fast-export side.
+
+ * "git push $there $src:$dst" rejects when $dst is not a fully
+ qualified refname and not clear what the end user meant. The
+ codepath has been taught to give a clearer error message, and also
+ guess where the push should go by taking the type of the pushed
+ object into account (e.g. a tag object would want to go under
+ refs/tags/).
+
+ * "git checkout [<tree-ish>] path..." learned to report the number of
+ paths that have been checked out of the index or the tree-ish,
+ which gives it the same degree of noisy-ness as the case in which
+ the command checks out a branch.
Performance, Internal Implementation, Development Support etc.
+ * Code clean-up with optimization for the codepath that checks
+ (non-)existence of loose objects.
+
+ * More codepaths become aware of working with in-core repository
+ instance other than the default "the_repository".
Fixes since v2.20
-----------------
+ * Updates for corner cases in merge-recursive.
+ (merge cc4cb0902c en/merge-path-collision later to maint).
+
+ * "git checkout frotz" (without any double-dash) avoids ambiguity by
+ making sure 'frotz' cannot be interpreted as a revision and as a
+ path at the same time. This safety has been updated to check also
+ a unique remote-tracking branch 'frotz' in a remote, when dwimming
+ to create a local branch 'frotz' out of a remote-tracking branch
+ 'frotz' from a remote.
+ (merge be4908f103 nd/checkout-dwim-fix later to maint).
+
+ * Refspecs configured with "git -c var=val clone" did not propagate
+ to the resulting repository, which has been corrected.
+ (merge 7eae4a3ac4 sg/clone-initial-fetch-configuration later to maint).
+
+ * A properly configured username/email is required under
+ user.useConfigOnly in order to create commits; now "git stash"
+ (even though it creates commit objects to represent stash entries)
+ command is exempt from the requirement.
+ (merge 3bc2111fc2 sd/stash-wo-user-name later to maint).
+
+ * The http-backend CGI process did not correctly clean up the child
+ processes it spawns to run upload-pack etc. when it dies itself,
+ which has been corrected.
+ (merge 02818a98d7 mk/http-backend-kill-children-before-exit later to maint).
+
+ * "git rev-list --exclude-promisor-objects" had to take an object
+ that does not exist locally (and is lazily available) from the
+ command line without barfing, but the code dereferenced NULL.
+ (merge 4cf67869b2 md/list-lazy-objects-fix later to maint).
+
+ * The traversal over tree objects has learned to honor
+ ":(attr:label)" pathspec match, which has been implemented only for
+ enumerating paths on the filesystem.
+ (merge 5a0b97b34c nd/attr-pathspec-in-tree-walk later to maint).
+
+ * BSD port updates.
+ (merge 4e3ecbd439 cb/openbsd-allows-reading-directory later to maint).
+ (merge b6bdc2a0f5 cb/t5004-empty-tar-archive-fix later to maint).
+ (merge 82cbc8cde2 cb/test-lint-cp-a later to maint).
+
+ * Lines that begin with a certain keyword that come over the wire, as
+ well as lines that consist only of one of these keywords, ought to
+ be painted in color for easier eyeballing, but the latter was
+ broken ever since the feature was introduced in 2.19, which has
+ been corrected.
+ (merge 1f67290450 hn/highlight-sideband-keywords later to maint).
+
+ * "git log -G<regex>" looked for a hunk in the "git log -p" patch
+ output that contained a string that matches the given pattern.
+ Optimize this code to ignore binary files, which by default will
+ not show any hunk that would match any pattern (unless textconv or
+ the --text option is in effect, that is).
+ (merge e0e7cb8080 tb/log-G-binary later to maint).
+
* Code cleanup, docfix, build fix, etc.
+ (merge 89ba9a79ae hb/t0061-dot-in-path-fix later to maint).
+ (merge d173e799ea sb/diff-color-moved-config-option-fixup later to maint).
+ (merge a8f5a59067 en/directory-renames-nothanks-doc-update later to maint).
+ (merge ec36c42a63 nd/indentation-fix later to maint).
+ (merge f116ee21cd do/gitweb-strict-export-conf-doc later to maint).
+ (merge 112ea42663 fd/gitweb-snapshot-conf-doc-fix later to maint).
+ (merge 1cadad6f65 tb/use-common-win32-pathfuncs-on-cygwin later to maint).
+ (merge 57e9dcaa65 km/rebase-doc-typofix later to maint).
tries to overwrite a remote ref that points at an
object that is not a commit-ish, or make the remote
ref point at an object that is not a commit-ish.
+ pushUnqualifiedRefname::
+ Shown when linkgit:git-push[1] gives up trying to
+ guess based on the source and destination refs what
+ remote ref namespace the source belongs in, but where
+ we can still suggest that the user push to either
+ refs/heads/* or refs/tags/* based on the type of the
+ source object.
statusHints::
Show directions on how to proceed from the current
state in the output of linkgit:git-status[1], in
If set, store cookies received during requests to the file specified by
http.cookieFile. Has no effect if http.cookieFile is unset.
+http.version::
+ Use the specified HTTP protocol version when communicating with a server.
+ If you want to force the default. The available and default version depend
+ on libcurl. Actually the possible values of
+ this option are:
+
+ - HTTP/2
+ - HTTP/1.1
+
http.sslVersion::
The SSL version to use when negotiating an SSL connection, if you
want to force the default. The available and default version
worktree.guessRemote::
- With `add`, if no branch argument, and neither of `-b` nor
- `-B` nor `--detach` are given, the command defaults to
+ If no branch is specified and neither `-b` nor `-B` nor
+ `--detach` is used, then `git worktree add` defaults to
creating a new branch from HEAD. If `worktree.guessRemote` is
set to true, `worktree add` tries to find a remote-tracking
branch whose name uniquely matches the new branch name. If
came into being: use the feature iteratively to feed the interesting
block in the preimage back into `-S`, and keep going until you get the
very first version of the block.
++
+Binary files are searched as well.
-G<regex>::
Look for differences whose patch text contains added/removed
-S"regexec\(regexp" --pickaxe-regex` will not (because the number of
occurrences of that string did not change).
+
+Unless `--text` is supplied patches of binary files without a textconv
+filter will be ignored.
++
See the 'pickaxe' entry in linkgit:gitdiffcore[7] for more
information.
Just like linkgit:git-submodule[1], this will detach the
submodules HEAD.
+--no-guess::
+ Do not attempt to create a branch if a remote tracking branch
+ of the same name exists.
+
<branch>::
Branch to checkout; if it refers to a branch (i.e., a name that,
when prepended with "refs/heads/", is a valid ref), then that
values are given for the same key, each value will be written to
the config file. This makes it safe, for example, to add
additional fetch refspecs to the origin remote.
++
+Due to limitations of the current implementation, some configuration
+variables do not take effect until after the initial fetch and checkout.
+Configuration variables known to not take effect are:
+`remote.<name>.mirror` and `remote.<name>.tagOpt`. Use the
+corresponding `--mirror` and `--no-tags` options instead.
--depth <depth>::
Create a 'shallow' clone with a history truncated to the
The number of spaces between columns. One space by default.
EXAMPLES
-------
+--------
Format data by columns:
------------
the shape of the history and stored tree. See the section on
`ANONYMIZING` below.
+--reference-excluded-parents::
+ By default, running a command such as `git fast-export
+ master~5..master` will not include the commit master{tilde}5
+ and will make master{tilde}4 no longer have master{tilde}5 as
+ a parent (though both the old master{tilde}4 and new
+ master{tilde}4 will have all the same files). Use
+ --reference-excluded-parents to instead have the the stream
+ refer to commits in the excluded range of history by their
+ sha1sum. Note that the resulting stream can only be used by a
+ repository which already contains the necessary parent
+ commits.
+
+--show-original-ids::
+ Add an extra directive to the output for commits and blobs,
+ `original-oid <SHA1SUM>`. While such directives will likely be
+ ignored by importers such as git-fast-import, it may be useful
+ for intermediary filters (e.g. for rewriting commit messages
+ which refer to older commits, or for stripping blobs by id).
+
--refspec::
Apply the specified refspec to each ref exported. Multiple of them can
be specified.
'git rev-list', that specifies the specific objects and references
to export. For example, `master~10..master` causes the
current master reference to be exported along with all objects
- added since its 10th ancestor commit.
+ added since its 10th ancestor commit and (unless the
+ --reference-excluded-parents option is specified) all files
+ common to master{tilde}9 and master{tilde}10.
EXAMPLES
--------
not contain the old commit).
--quiet::
- Disable all non-fatal output, making fast-import silent when it
- is successful. This option disables the output shown by
- --stats.
+ Disable the output shown by --stats, making fast-import usually
+ be silent when it is successful. However, if the import stream
+ has directives intended to show user output (e.g. `progress`
+ directives), the corresponding messages will still be shown.
--stats::
Display some basic statistics about the objects fast-import has
....
'commit' SP <ref> LF
mark?
+ original-oid?
('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
'committer' (SP <name>)? SP LT <email> GT SP <when> LF
data
to another object simply by reusing the same `<idnum>` in another
`mark` command.
+`original-oid`
+~~~~~~~~~~~~~~
+Provides the name of the object in the original source control system.
+fast-import will simply ignore this directive, but filter processes
+which operate on and modify the stream before feeding to fast-import
+may have uses for this information
+
+....
+ 'original-oid' SP <object-identifier> LF
+....
+
+where `<object-identifer>` is any string not containing LF.
+
`tag`
~~~~~
Creates an annotated tag referring to a specific commit. To create
....
'tag' SP <name> LF
'from' SP <commit-ish> LF
+ original-oid?
'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
data
....
....
'blob' LF
mark?
+ original-oid?
data
....
it within all non-bare repos or it can be set to a boolean value.
This defaults to true.
-The optional configuration variable `gc.commitGraph` determines if
+The optional configuration variable `gc.writeCommitGraph` determines if
'git gc' should run 'git commit-graph write'. This can be set to a
boolean value. This defaults to false.
OPTIONS
-------
---
-
-q::
--quiet::
If you provide a 'directory', the command is run inside it. If this directory
does not exist, it will be created.
---
-
TEMPLATE DIRECTORY
------------------
without any `<refspec>` on the command line. Otherwise, missing
`:<dst>` means to update the same ref as the `<src>`.
+
+If <dst> doesn't start with `refs/` (e.g. `refs/heads/master`) we will
+try to infer where in `refs/*` on the destination <repository> it
+belongs based on the the type of <src> being pushed and whether <dst>
+is ambiguous.
++
+--
+* If <dst> unambiguously refers to a ref on the <repository> remote,
+ then push to that ref.
+
+* If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
+ then prepend that to <dst>.
+
+* Other ambiguity resolutions might be added in the future, but for
+ now any other cases will error out with an error indicating what we
+ tried, and depending on the `advice.pushUnqualifiedRefname`
+ configuration (see linkgit:git-config[1]) suggest what refs/
+ namespace you may have wanted to push to.
+
+--
++
The object referenced by <src> is used to update the <dst> reference
on the remote side. Whether this is allowed depends on where in
`refs/*` the <dst> reference lives as described in detail below, in
`refs/remotes/satellite/master`) in the `mothership` repository;
do the same for `dev` and `satellite/dev`.
+
+See the section describing `<refspec>...` above for a discussion of
+the matching semantics.
++
This is to emulate `git fetch` run on the `mothership` using `git
push` that is run in the opposite direction in order to integrate
the work done on `satellite`, and is often necessary when you can
--------
[verse]
'git quiltimport' [--dry-run | -n] [--author <author>] [--patches <dir>]
- [--series <file>]
+ [--series <file>] [--keep-non-patch]
DESCRIPTION
or the value of the `$QUILT_SERIES` environment
variable.
+--keep-non-patch::
+ Pass `-b` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
GIT
---
Part of the linkgit:git[1] suite
Directory rename detection
~~~~~~~~~~~~~~~~~~~~~~~~~~
-The merge and interactive backends work fine with
-directory rename detection. The am backend sometimes does not.
+Directory rename heuristics are enabled in the merge and interactive
+backends. Due to the lack of accurate tree information, directory
+rename detection is disabled in the am backend.
include::merge-strategies.txt[]
At this time, the `merge` command will *always* use the `recursive`
merge strategy for regular merges, and `octopus` for octopus merges,
-strategy, with no way to choose a different one. To work around
+with no way to choose a different one. To work around
this, an `exec` command can be used to call `git merge` explicitly,
using the fact that the labels are worktree-local refs (the ref
`refs/rewritten/onto` would correspond to the label `onto`, for example).
Ignored files are not listed, unless `--ignored` option is in effect,
in which case `XY` are `!!`.
- X Y Meaning
- -------------------------------------------------
- [AMD] not updated
- M [ MD] updated in index
- A [ MD] added to index
- D deleted from index
- R [ MD] renamed in index
- C [ MD] copied in index
- [MARC] index and work tree matches
- [ MARC] M work tree changed since index
- [ MARC] D deleted in work tree
- [ D] R renamed in work tree
- [ D] C copied in work tree
- -------------------------------------------------
- D D unmerged, both deleted
- A U unmerged, added by us
- U D unmerged, deleted by them
- U A unmerged, added by them
- D U unmerged, deleted by us
- A A unmerged, both added
- U U unmerged, both modified
- -------------------------------------------------
- ? ? untracked
- ! ! ignored
- -------------------------------------------------
+....
+X Y Meaning
+-------------------------------------------------
+ [AMD] not updated
+M [ MD] updated in index
+A [ MD] added to index
+D deleted from index
+R [ MD] renamed in index
+C [ MD] copied in index
+[MARC] index and work tree matches
+[ MARC] M work tree changed since index
+[ MARC] D deleted in work tree
+[ D] R renamed in work tree
+[ D] C copied in work tree
+-------------------------------------------------
+D D unmerged, both deleted
+A U unmerged, added by us
+U D unmerged, deleted by them
+U A unmerged, added by them
+D U unmerged, deleted by us
+A A unmerged, both added
+U U unmerged, both modified
+-------------------------------------------------
+? ? untracked
+! ! ignored
+-------------------------------------------------
+....
Submodules have more state and instead report
M the submodule has a different HEAD than
If `--branch` is given, a series of header lines are printed with
information about the current branch.
- Line Notes
- ------------------------------------------------------------
- # branch.oid <commit> | (initial) Current commit.
- # branch.head <branch> | (detached) Current branch.
- # branch.upstream <upstream_branch> If upstream is set.
- # branch.ab +<ahead> -<behind> If upstream is set and
- the commit is present.
- ------------------------------------------------------------
+....
+Line Notes
+------------------------------------------------------------
+# branch.oid <commit> | (initial) Current commit.
+# branch.head <branch> | (detached) Current branch.
+# branch.upstream <upstream_branch> If upstream is set.
+# branch.ab +<ahead> -<behind> If upstream is set and
+ the commit is present.
+------------------------------------------------------------
+....
### Changed Tracked Entries
2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><sep><origPath>
- Field Meaning
- --------------------------------------------------------
- <XY> A 2 character field containing the staged and
- unstaged XY values described in the short format,
- with unchanged indicated by a "." rather than
- a space.
- <sub> A 4 character field describing the submodule state.
- "N..." when the entry is not a submodule.
- "S<c><m><u>" when the entry is a submodule.
- <c> is "C" if the commit changed; otherwise ".".
- <m> is "M" if it has tracked changes; otherwise ".".
- <u> is "U" if there are untracked changes; otherwise ".".
- <mH> The octal file mode in HEAD.
- <mI> The octal file mode in the index.
- <mW> The octal file mode in the worktree.
- <hH> The object name in HEAD.
- <hI> The object name in the index.
- <X><score> The rename or copy score (denoting the percentage
- of similarity between the source and target of the
- move or copy). For example "R100" or "C75".
- <path> The pathname. In a renamed/copied entry, this
- is the target path.
- <sep> When the `-z` option is used, the 2 pathnames are separated
- with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
- byte separates them.
- <origPath> The pathname in the commit at HEAD or in the index.
- This is only present in a renamed/copied entry, and
- tells where the renamed/copied contents came from.
- --------------------------------------------------------
+....
+Field Meaning
+--------------------------------------------------------
+<XY> A 2 character field containing the staged and
+ unstaged XY values described in the short format,
+ with unchanged indicated by a "." rather than
+ a space.
+<sub> A 4 character field describing the submodule state.
+ "N..." when the entry is not a submodule.
+ "S<c><m><u>" when the entry is a submodule.
+ <c> is "C" if the commit changed; otherwise ".".
+ <m> is "M" if it has tracked changes; otherwise ".".
+ <u> is "U" if there are untracked changes; otherwise ".".
+<mH> The octal file mode in HEAD.
+<mI> The octal file mode in the index.
+<mW> The octal file mode in the worktree.
+<hH> The object name in HEAD.
+<hI> The object name in the index.
+<X><score> The rename or copy score (denoting the percentage
+ of similarity between the source and target of the
+ move or copy). For example "R100" or "C75".
+<path> The pathname. In a renamed/copied entry, this
+ is the target path.
+<sep> When the `-z` option is used, the 2 pathnames are separated
+ with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
+ byte separates them.
+<origPath> The pathname in the commit at HEAD or in the index.
+ This is only present in a renamed/copied entry, and
+ tells where the renamed/copied contents came from.
+--------------------------------------------------------
+....
Unmerged entries have the following format; the first character is
a "u" to distinguish from ordinary changed entries.
u <xy> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>
- Field Meaning
- --------------------------------------------------------
- <XY> A 2 character field describing the conflict type
- as described in the short format.
- <sub> A 4 character field describing the submodule state
- as described above.
- <m1> The octal file mode in stage 1.
- <m2> The octal file mode in stage 2.
- <m3> The octal file mode in stage 3.
- <mW> The octal file mode in the worktree.
- <h1> The object name in stage 1.
- <h2> The object name in stage 2.
- <h3> The object name in stage 3.
- <path> The pathname.
- --------------------------------------------------------
+....
+Field Meaning
+--------------------------------------------------------
+<XY> A 2 character field describing the conflict type
+ as described in the short format.
+<sub> A 4 character field describing the submodule state
+ as described above.
+<m1> The octal file mode in stage 1.
+<m2> The octal file mode in stage 2.
+<m3> The octal file mode in stage 3.
+<mW> The octal file mode in the worktree.
+<h1> The object name in stage 1.
+<h2> The object name in stage 2.
+<h3> The object name in stage 3.
+<path> The pathname.
+--------------------------------------------------------
+....
### Other Items
regular expression. This means that it will detect in-file (or what
rename-detection considers the same file) moves, which is noise. The
implementation runs diff twice and greps, and this can be quite
-expensive.
+expensive. To speed things up binary files without textconv filters
+will be ignored.
When `-S` or `-G` are used without `--pickaxe-all`, only filepairs
that match their respective criterion are kept in the output. When
$strict_export::
Only allow viewing of repositories also shown on the overview page.
- This for example makes `$gitweb_export_ok` file decide if repository is
- available and not only if it is shown. If `$gitweb_list` points to
+ This for example makes `$export_ok` file decide if repository is
+ available and not only if it is shown. If `$projects_list` points to
file with list of project, only those repositories listed would be
available for gitweb. Can be set during building gitweb via
`GITWEB_STRICT_EXPORT`. By default this variable is not set, which
a definitive list. By default only "tgz" is offered.
+
This feature can be configured on a per-repository basis via
-repository's `gitweb.blame` configuration variable, which contains
+repository's `gitweb.snapshot` configuration variable, which contains
a comma separated list of formats or "none" to disable snapshots.
Unknown values are ignored.
- "`!ATTR`" requires that the attribute `ATTR` be
unspecified.
+
+Note that when matching against a tree object, attributes are still
+obtained from working tree, not from the given tree object.
exclude;;
After a path matches any non-exclude pathspec, it will be run
Note that these are applied before commit
ordering and formatting options, such as `--reverse`.
---
-
-<number>::
-n <number>::
--max-count=<number>::
`<header>` text will be printed with each progress update.
endif::git-rev-list[]
---
-
History Simplification
~~~~~~~~~~~~~~~~~~~~~~
int advice_push_already_exists = 1;
int advice_push_fetch_first = 1;
int advice_push_needs_force = 1;
+int advice_push_unqualified_ref_name = 1;
int advice_status_hints = 1;
int advice_status_u_option = 1;
int advice_commit_before_merge = 1;
{ "pushAlreadyExists", &advice_push_already_exists },
{ "pushFetchFirst", &advice_push_fetch_first },
{ "pushNeedsForce", &advice_push_needs_force },
+ { "pushUnqualifiedRefName", &advice_push_unqualified_ref_name },
{ "statusHints", &advice_status_hints },
{ "statusUoption", &advice_status_u_option },
{ "commitBeforeMerge", &advice_commit_before_merge },
extern int advice_push_already_exists;
extern int advice_push_fetch_first;
extern int advice_push_needs_force;
+extern int advice_push_unqualified_ref_name;
extern int advice_status_hints;
extern int advice_status_u_option;
extern int advice_commit_before_merge;
#define SPLIT_CMDLINE_BAD_ENDING 1
#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
static const char *split_cmdline_errors[] = {
- "cmdline ends with \\",
- "unclosed quote"
+ N_("cmdline ends with \\"),
+ N_("unclosed quote")
};
int split_cmdline(char *cmdline, const char ***argv)
costate.refresh_cache = 1;
costate.istate = istate;
- if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+ if (checkout_entry(ce, &costate, NULL, NULL) ||
+ lstat(ce->name, st))
return error(_("cannot checkout %s"), ce->name);
return 0;
}
* string and appends it to a struct strbuf.
*/
static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
- const char *value, unsigned int valuelen)
+ const char *value, unsigned int valuelen)
{
int len, tmp;
}
static void format_subst(const struct commit *commit,
- const char *src, size_t len,
- struct strbuf *buf)
+ const char *src, size_t len,
+ struct strbuf *buf)
{
char *to_free = NULL;
struct strbuf fmt = STRBUF_INIT;
git_attr_set_direction(GIT_ATTR_INDEX);
}
- err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
+ err = read_tree_recursive(args->repo, args->tree, "",
+ 0, 0, &args->pathspec,
queue_or_write_archive_entry,
&context);
if (err == READ_TREE_RECURSIVE)
ctx.args = args;
parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
ctx.pathspec.recursive = 1;
- ret = read_tree_recursive(args->tree, "", 0, 0, &ctx.pathspec,
+ ret = read_tree_recursive(args->repo, args->tree, "",
+ 0, 0, &ctx.pathspec,
reject_entry, &ctx);
clear_pathspec(&ctx.pathspec);
return ret != 0;
int refnamelen = colon - name;
if (!dwim_ref(name, refnamelen, &oid, &ref))
- die("no such ref: %.*s", refnamelen, name);
+ die(_("no such ref: %.*s"), refnamelen, name);
free(ref);
}
if (get_oid(name, &oid))
- die("Not a valid object name");
+ die(_("not a valid object name: %s"), name);
commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1);
if (commit) {
tree = parse_tree_indirect(&oid);
if (tree == NULL)
- die("not a tree object");
+ die(_("not a tree object: %s"), oid_to_hex(&oid));
if (prefix) {
struct object_id tree_oid;
err = get_tree_entry(&tree->object.oid, prefix, &tree_oid,
&mode);
if (err || !S_ISDIR(mode))
- die("current working directory is untracked");
+ die(_("current working directory is untracked"));
tree = parse_tree_indirect(&tree_oid);
}
if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&
starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {
if (!macro_ok) {
- fprintf(stderr, "%s not allowed: %s:%d\n",
- name, src, lineno);
+ fprintf_ln(stderr, _("%s not allowed: %s:%d"),
+ name, src, lineno);
goto fail_return;
}
is_macro = 1;
#define strcat(x,y) BANNED(strcat)
#undef strncpy
#define strncpy(x,y,n) BANNED(strncpy)
+#undef strncat
+#define strncat(x,y,n) BANNED(strncat)
#undef sprintf
#undef vsprintf
* is increased by one between each call, but that should not matter
* for this application.
*/
-static unsigned get_prn(unsigned count) {
+static unsigned get_prn(unsigned count)
+{
count = count * 1103515245 + 12345;
return (count/65536) % PRN_MODULO;
}
return skip_away(list, count);
}
-static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
+static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
+ const char *prefix,
const char *bad_format, const char *good_format,
int read_paths)
{
struct argv_array rev_argv = ARGV_ARRAY_INIT;
int i;
- repo_init_revisions(the_repository, revs, prefix);
+ repo_init_revisions(r, revs, prefix);
revs->abbrev = 0;
revs->commit_format = CMIT_FMT_UNSPECIFIED;
return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
}
-static struct commit *get_commit_reference(const struct object_id *oid)
+static struct commit *get_commit_reference(struct repository *r,
+ const struct object_id *oid)
{
- struct commit *r = lookup_commit_reference(the_repository, oid);
- if (!r)
+ struct commit *c = lookup_commit_reference(r, oid);
+ if (!c)
die(_("Not a valid commit name %s"), oid_to_hex(oid));
- return r;
+ return c;
}
-static struct commit **get_bad_and_good_commits(int *rev_nr)
+static struct commit **get_bad_and_good_commits(struct repository *r,
+ int *rev_nr)
{
struct commit **rev;
int i, n = 0;
ALLOC_ARRAY(rev, 1 + good_revs.nr);
- rev[n++] = get_commit_reference(current_bad_oid);
+ rev[n++] = get_commit_reference(r, current_bad_oid);
for (i = 0; i < good_revs.nr; i++)
- rev[n++] = get_commit_reference(good_revs.oid + i);
+ rev[n++] = get_commit_reference(r, good_revs.oid + i);
*rev_nr = n;
return rev;
free_commit_list(result);
}
-static int check_ancestors(int rev_nr, struct commit **rev, const char *prefix)
+static int check_ancestors(struct repository *r, int rev_nr,
+ struct commit **rev, const char *prefix)
{
struct rev_info revs;
int res;
- bisect_rev_setup(&revs, prefix, "^%s", "%s", 0);
+ bisect_rev_setup(r, &revs, prefix, "^%s", "%s", 0);
bisect_common(&revs);
res = (revs.commits != NULL);
* If a merge base must be tested by the user, its source code will be
* checked out to be tested by the user and we will exit.
*/
-static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
+static void check_good_are_ancestors_of_bad(struct repository *r,
+ const char *prefix,
+ int no_checkout)
{
char *filename = git_pathdup("BISECT_ANCESTORS_OK");
struct stat st;
goto done;
/* Check if all good revs are ancestor of the bad rev. */
- rev = get_bad_and_good_commits(&rev_nr);
- if (check_ancestors(rev_nr, rev, prefix))
+ rev = get_bad_and_good_commits(r, &rev_nr);
+ if (check_ancestors(r, rev_nr, rev, prefix))
check_merge_bases(rev_nr, rev, no_checkout);
free(rev);
/*
* This does "git diff-tree --pretty COMMIT" without one fork+exec.
*/
-static void show_diff_tree(const char *prefix, struct commit *commit)
+static void show_diff_tree(struct repository *r,
+ const char *prefix,
+ struct commit *commit)
{
struct rev_info opt;
/* diff-tree init */
- repo_init_revisions(the_repository, &opt, prefix);
+ repo_init_revisions(r, &opt, prefix);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
opt.abbrev = 0;
opt.diff = 1;
* If no_checkout is non-zero, the bisection process does not
* checkout the trial commit but instead simply updates BISECT_HEAD.
*/
-int bisect_next_all(const char *prefix, int no_checkout)
+int bisect_next_all(struct repository *r, const char *prefix, int no_checkout)
{
struct rev_info revs;
struct commit_list *tried;
if (read_bisect_refs())
die(_("reading bisect refs failed"));
- check_good_are_ancestors_of_bad(prefix, no_checkout);
+ check_good_are_ancestors_of_bad(r, prefix, no_checkout);
- bisect_rev_setup(&revs, prefix, "%s", "^%s", 1);
+ bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
revs.limited = 1;
bisect_common(&revs);
exit_if_skipped_commits(tried, current_bad_oid);
printf("%s is the first %s commit\n", oid_to_hex(bisect_rev),
term_bad);
- show_diff_tree(prefix, revs.commits->item);
+ show_diff_tree(r, prefix, revs.commits->item);
/* This means the bisection process succeeded. */
exit(10);
}
#define BISECT_H
struct commit_list;
+struct repository;
/*
* Find bisection. If something is found, `reaches` will be the number of
const char *header_prefix;
};
-extern int bisect_next_all(const char *prefix, int no_checkout);
+extern int bisect_next_all(struct repository *r,
+ const char *prefix,
+ int no_checkout);
extern int estimate_bisect_steps(int all);
die("no such path '%s' in HEAD", path);
}
-static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid)
+static struct commit_list **append_parent(struct repository *r,
+ struct commit_list **tail,
+ const struct object_id *oid)
{
struct commit *parent;
- parent = lookup_commit_reference(the_repository, oid);
+ parent = lookup_commit_reference(r, oid);
if (!parent)
die("no such commit %s", oid_to_hex(oid));
return &commit_list_insert(parent, tail)->next;
}
-static void append_merge_parents(struct commit_list **tail)
+static void append_merge_parents(struct repository *r,
+ struct commit_list **tail)
{
int merge_head;
struct strbuf line = STRBUF_INIT;
- merge_head = open(git_path_merge_head(the_repository), O_RDONLY);
+ merge_head = open(git_path_merge_head(r), O_RDONLY);
if (merge_head < 0) {
if (errno == ENOENT)
return;
die("cannot open '%s' for reading",
- git_path_merge_head(the_repository));
+ git_path_merge_head(r));
}
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(the_repository), line.buf);
- tail = append_parent(tail, &oid);
+ git_path_merge_head(r), line.buf);
+ tail = append_parent(r, tail, &oid);
}
close(merge_head);
strbuf_release(&line);
* want to transfer ownership of the buffer to the commit (so we
* must use detach).
*/
-static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
+static void set_commit_buffer_from_strbuf(struct repository *r,
+ struct commit *c,
+ struct strbuf *sb)
{
size_t len;
void *buf = strbuf_detach(sb, &len);
- set_commit_buffer(the_repository, c, buf, len);
+ set_commit_buffer(r, c, buf, len);
}
/*
read_index(r->index);
time(&now);
- commit = alloc_commit_node(the_repository);
+ commit = alloc_commit_node(r);
commit->object.parsed = 1;
commit->date = now;
parent_tail = &commit->parents;
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
die("no such ref: HEAD");
- parent_tail = append_parent(parent_tail, &head_oid);
- append_merge_parents(parent_tail);
+ parent_tail = append_parent(r, parent_tail, &head_oid);
+ append_merge_parents(r, parent_tail);
verify_working_tree_path(r, commit, path);
origin = make_origin(commit, path);
ident, ident, path,
(!contents_from ? path :
(!strcmp(contents_from, "-") ? "standard input" : contents_from)));
- set_commit_buffer_from_strbuf(commit, &msg);
+ set_commit_buffer_from_strbuf(r, commit, &msg);
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;
struct object *obj = revs->pending.objects[i].item;
if (obj->flags & UNINTERESTING)
continue;
- obj = deref_tag(the_repository, obj, NULL, 0);
+ obj = deref_tag(revs->repo, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
/* Is that sole rev a committish? */
obj = revs->pending.objects[0].item;
- obj = deref_tag(the_repository, obj, NULL, 0);
+ obj = deref_tag(revs->repo, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
return NULL;
/* Do we have HEAD? */
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return NULL;
- head_commit = lookup_commit_reference_gently(the_repository,
+ head_commit = lookup_commit_reference_gently(revs->repo,
&head_oid, 1);
if (!head_commit)
return NULL;
struct object *obj = revs->pending.objects[i].item;
if (!(obj->flags & UNINTERESTING))
continue;
- obj = deref_tag(the_repository, obj, NULL, 0);
+ obj = deref_tag(revs->repo, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
"will track its remote counterpart, you may want to use\n"
"\"git push -u\" to set the upstream config as you push.");
-void create_branch(const char *name, const char *start_name,
+void create_branch(struct repository *r,
+ const char *name, const char *start_name,
int force, int clobber_head_ok, int reflog,
int quiet, enum branch_track track)
{
break;
}
- if ((commit = lookup_commit_reference(the_repository, &oid)) == NULL)
+ if ((commit = lookup_commit_reference(r, &oid)) == NULL)
die(_("Not a valid branch point: '%s'."), start_name);
oidcpy(&oid, &commit->object.oid);
free(real_ref);
}
-void remove_branch_state(void)
+void remove_branch_state(struct repository *r)
{
- 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));
+ unlink(git_path_cherry_pick_head(r));
+ unlink(git_path_revert_head(r));
+ unlink(git_path_merge_head(r));
+ unlink(git_path_merge_rr(r));
+ unlink(git_path_merge_msg(r));
+ unlink(git_path_merge_mode(r));
+ unlink(git_path_squash_msg(r));
}
void die_if_checked_out(const char *branch, int ignore_current_worktree)
#ifndef BRANCH_H
#define BRANCH_H
+struct repository;
struct strbuf;
enum branch_track {
/*
* Creates a new branch, where:
*
+ * - r is the repository to add a branch to
+ *
* - name is the new branch name
*
* - start_name is the name of the existing branch that the new branch should
* that start_name is a tracking branch for (if any).
*
*/
-void create_branch(const char *name, const char *start_name,
+void create_branch(struct repository *r,
+ const char *name, const char *start_name,
int force, int clobber_head_ok,
int reflog, int quiet, enum branch_track track);
* Remove information about the state of working on the current
* branch. (E.g., MERGE_HEAD)
*/
-void remove_branch_state(void);
+void remove_branch_state(struct repository *r);
/*
* Configure local branch "local" as downstream to branch "remote"
die(_("pathspec '%s' did not match any files"),
pathspec->items[i].match);
}
- free(seen);
+ free(seen);
}
int run_add_interactive(const char *revision, const char *patch_mode,
if (merge_tree(remote_tree))
return -1;
- remove_branch_state();
+ remove_branch_state(the_repository);
return 0;
}
static void am_rerere_clear(void)
{
struct string_list merge_rr = STRING_LIST_INIT_DUP;
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
}
switch (cmdmode) {
case NEXT_ALL:
- return bisect_next_all(prefix, no_checkout);
+ return bisect_next_all(the_repository, prefix, no_checkout);
case WRITE_TERMS:
if (argc != 2)
return error(_("--write-terms requires two arguments"));
* create_branch takes care of setting up the tracking
* info and making sure new_upstream is correct
*/
- create_branch(branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
+ create_branch(the_repository, branch->name, new_upstream,
+ 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
} else if (unset_upstream) {
struct branch *branch = branch_get(argv[0]);
struct strbuf buf = STRBUF_INIT;
if (track == BRANCH_TRACK_OVERRIDE)
die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
- create_branch(argv[0], (argc == 2) ? argv[1] : head,
+ create_branch(the_repository,
+ argv[0], (argc == 2) ? argv[1] : head,
force, 0, reflog, quiet, track);
} else
usage(builtin_bundle_usage);
return 1;
}
- if (verify_bundle(&header, 1))
+ if (verify_bundle(the_repository, &header, 1))
return 1;
fprintf(stderr, _("%s is okay\n"), bundle_file);
return 0;
}
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
- return !!create_bundle(&header, bundle_file, argc, argv);
+ return !!create_bundle(the_repository, &header,
+ bundle_file, argc, argv);
} else if (!strcmp(cmd, "unbundle")) {
if (!startup_info->have_repository)
die(_("Need a repository to unbundle."));
- return !!unbundle(&header, bundle_fd, 0) ||
+ return !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
} else
usage(builtin_bundle_usage);
continue;
did_checkout = 1;
if (checkout_entry(ce, &state,
- to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
+ to_tempfile ? topath[ce_stage(ce)] : NULL,
+ NULL) < 0)
errs++;
}
write_tempfile_record(last_ce->name, prefix);
}
if (checkout_entry(ce, &state,
- to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
+ to_tempfile ? topath[ce_stage(ce)] : NULL,
+ NULL) < 0)
errs++;
last_ce = ce;
}
int ignore_skipworktree;
int ignore_other_worktrees;
int show_progress;
+ int count_checkout_paths;
/*
* If new checkout options are added, skip_merge_working_tree
* should be updated accordingly.
static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
{
- read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
+ read_tree_recursive(the_repository, tree, "", 0, 0,
+ pathspec, update_some, NULL);
/* update the index with the given tree's info
* for all args, expanding wildcards, and exit
}
static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
- const struct checkout *state)
+ const struct checkout *state, int *nr_checkouts)
{
while (pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name)) {
if (ce_stage(active_cache[pos]) == stage)
- return checkout_entry(active_cache[pos], state, NULL);
+ return checkout_entry(active_cache[pos], state,
+ NULL, nr_checkouts);
pos++;
}
if (stage == 2)
return error(_("path '%s' does not have their version"), ce->name);
}
-static int checkout_merged(int pos, const struct checkout *state)
+static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts)
{
struct cache_entry *ce = active_cache[pos];
const char *path = ce->name;
ce = make_transient_cache_entry(mode, &oid, path, 2);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), path);
- status = checkout_entry(ce, state, NULL);
+ status = checkout_entry(ce, state, NULL, nr_checkouts);
discard_cache_entry(ce);
return status;
}
struct commit *head;
int errs = 0;
struct lock_file lock_file = LOCK_INIT;
+ int nr_checkouts = 0;
if (opts->track != BRANCH_TRACK_UNSPECIFIED)
die(_("'%s' cannot be used with updating paths"), "--track");
struct cache_entry *ce = active_cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce)) {
- errs |= checkout_entry(ce, &state, NULL);
+ errs |= checkout_entry(ce, &state,
+ NULL, &nr_checkouts);
continue;
}
if (opts->writeout_stage)
- errs |= checkout_stage(opts->writeout_stage, ce, pos, &state);
+ errs |= checkout_stage(opts->writeout_stage,
+ ce, pos,
+ &state, &nr_checkouts);
else if (opts->merge)
- errs |= checkout_merged(pos, &state);
+ errs |= checkout_merged(pos, &state,
+ &nr_checkouts);
pos = skip_same_name(ce, pos) - 1;
}
}
- errs |= finish_delayed_checkout(&state);
+ errs |= finish_delayed_checkout(&state, &nr_checkouts);
+
+ if (opts->count_checkout_paths) {
+ if (opts->source_tree)
+ fprintf_ln(stderr, Q_("Checked out %d path out of %s",
+ "Checked out %d paths out of %s",
+ nr_checkouts),
+ nr_checkouts,
+ find_unique_abbrev(&opts->source_tree->object.oid,
+ DEFAULT_ABBREV));
+ else
+ fprintf_ln(stderr, Q_("Checked out %d path out of the index",
+ "Checked out %d paths out of the index",
+ nr_checkouts),
+ nr_checkouts);
+ }
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
free(refname);
}
else
- create_branch(opts->new_branch, new_branch_info->name,
+ create_branch(the_repository,
+ opts->new_branch, new_branch_info->name,
opts->new_branch_force ? 1 : 0,
opts->new_branch_force ? 1 : 0,
opts->new_branch_log,
delete_reflog(old_branch_info->path);
}
}
- remove_branch_state();
+ remove_branch_state(the_repository);
strbuf_release(&msg);
if (!opts->quiet &&
(new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, "HEAD"))))
has_dash_dash = 1; /* case (3) or (1) */
else if (dash_dash_pos >= 2)
die(_("only one reference expected, %d given."), dash_dash_pos);
+ opts->count_checkout_paths = !opts->quiet && !has_dash_dash;
if (!strcmp(arg, "-"))
arg = "@{-1}";
*/
int recover_with_dwim = dwim_new_local_branch_ok;
- if (!has_dash_dash &&
- (check_filename(opts->prefix, arg) || !no_wildcard(arg)))
+ int could_be_checkout_paths = !has_dash_dash &&
+ check_filename(opts->prefix, arg);
+
+ if (!has_dash_dash && !no_wildcard(arg))
recover_with_dwim = 0;
+
/*
* Accept "git checkout foo" and "git checkout foo --"
* as candidates for dwim.
const char *remote = unique_tracking_name(arg, rev,
dwim_remotes_matched);
if (remote) {
+ if (could_be_checkout_paths)
+ die(_("'%s' could be both a local file and a tracking branch.\n"
+ "Please use -- (and optionally --no-guess) to disambiguate"),
+ arg);
*new_branch = arg;
arg = remote;
/* DWIMmed to create local branch, case (3).(b) */
struct checkout_opts opts;
struct branch_info new_branch_info;
char *conflict_style = NULL;
- int dwim_new_local_branch = 1;
+ int dwim_new_local_branch, no_dwim_new_local_branch = 0;
int dwim_remotes_matched = 0;
struct option options[] = {
OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
- OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
- N_("second guess 'git checkout <no-such-branch>'")),
+ OPT_BOOL(0, "no-guess", &no_dwim_new_local_branch,
+ N_("do not second guess 'git checkout <no-such-branch>'")),
OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
N_("do not check if another worktree is holding the given ref")),
{ OPTION_CALLBACK, 0, "recurse-submodules", NULL,
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
+ dwim_new_local_branch = !no_dwim_new_local_branch;
if (opts.show_progress < 0) {
if (opts.quiet)
opts.show_progress = 0;
}
static struct ref *wanted_peer_refs(const struct ref *refs,
- struct refspec_item *refspec)
+ struct refspec *refspec)
{
struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
struct ref *local_refs = head;
warning(_("Could not find remote branch %s to clone."),
option_branch);
else {
- get_fetch_map(remote_head, refspec, &tail, 0);
+ int i;
+ for (i = 0; i < refspec->nr; i++)
+ get_fetch_map(remote_head, &refspec->items[i],
+ &tail, 0);
/* if --branch=tag, pull the requested tag explicitly */
get_fetch_map(remote_head, tag_refspec, &tail, 0);
}
- } else
- get_fetch_map(refs, refspec, &tail, 0);
+ } else {
+ int i;
+ for (i = 0; i < refspec->nr; i++)
+ get_fetch_map(refs, &refspec->items[i], &tail, 0);
+ }
if (!option_mirror && !option_single_branch && !option_no_tags)
get_fetch_map(refs, tag_refspec, &tail, 0);
const struct ref *our_head_points_at;
struct ref *mapped_refs;
const struct ref *ref;
- struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
+ struct strbuf key = STRBUF_INIT;
+ struct strbuf default_refspec = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
const char *src_ref_prefix = "refs/heads/";
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
- struct refspec rs = REFSPEC_INIT_FETCH;
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
fetch_if_missing = 0;
strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
}
- strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
strbuf_addf(&key, "remote.%s.url", option_origin);
git_config_set(key.buf, repo);
strbuf_reset(&key);
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- refspec_append(&rs, value.buf);
+ remote = remote_get(option_origin);
- strbuf_reset(&value);
+ strbuf_addf(&default_refspec, "+%s*:%s*", src_ref_prefix,
+ branch_top.buf);
+ refspec_append(&remote->fetch, default_refspec.buf);
- remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
transport_set_verbosity(transport, option_verbosity, option_progress);
transport->family = family;
argv_array_push(&ref_prefixes, "HEAD");
- refspec_ref_prefixes(&rs, &ref_prefixes);
+ refspec_ref_prefixes(&remote->fetch, &ref_prefixes);
if (option_branch)
expand_ref_prefix(&ref_prefixes, option_branch);
if (!option_no_tags)
refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
- mapped_refs = wanted_peer_refs(refs, &rs.items[0]);
+ mapped_refs = wanted_peer_refs(refs, &remote->fetch);
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
strbuf_release(&key);
- strbuf_release(&value);
+ strbuf_release(&default_refspec);
junk_mode = JUNK_LEAVE_ALL;
- refspec_clear(&rs);
argv_array_clear(&ref_prefixes);
return err;
}
static void status_init_config(struct wt_status *s, config_fn_t fn)
{
- wt_status_prepare(s);
+ wt_status_prepare(the_repository, s);
init_diff_ui_defaults();
git_config(fn, s);
determine_whence(s);
if (ignore_submodule_arg &&
!strcmp(ignore_submodule_arg, "all"))
flags.ignore_submodules = 1;
- committable = index_differs_from(parent, &flags, 1);
+ committable = index_differs_from(the_repository,
+ parent, &flags, 1);
}
}
strbuf_release(&committer_ident);
flags |= SUMMARY_INITIAL_COMMIT;
if (author_date_is_interesting())
flags |= SUMMARY_SHOW_AUTHOR_DATE;
- print_commit_summary(prefix, &oid, flags);
+ print_commit_summary(the_repository, prefix,
+ &oid, flags);
}
UNLEAK(err);
usage_with_options(builtin_config_usage, builtin_config_options);
}
-static void check_argc(int argc, int min, int max) {
+static void check_argc(int argc, int min, int max)
+{
if (argc >= min && argc <= max)
return;
if (min == max)
return 0;
}
-static int print_alternate(struct alternate_object_database *alt, void *data)
+static int print_alternate(struct object_directory *odb, void *data)
{
printf("alternate: ");
- quote_c_style(alt->path, NULL, stdout, 0);
+ quote_c_style(odb->path, NULL, stdout, 0);
putchar('\n');
return 0;
}
int ret;
ce = make_transient_cache_entry(mode, oid, path, 0);
- ret = checkout_entry(ce, state, NULL);
+ ret = checkout_entry(ce, state, NULL, NULL);
discard_cache_entry(ce);
return ret;
};
static int progress;
-static enum { ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = ABORT;
-static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ERROR;
+static enum { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
+static enum { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
static int fake_missing_tagger;
static int use_done_feature;
static int no_data;
static int full_tree;
+static int reference_excluded_commits;
+static int show_original_ids;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
+static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
static struct revision_sources revision_sources;
const char *arg, int unset)
{
if (unset || !strcmp(arg, "abort"))
- signed_tag_mode = ABORT;
+ signed_tag_mode = SIGNED_TAG_ABORT;
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
signed_tag_mode = VERBATIM;
else if (!strcmp(arg, "warn"))
const char *arg, int unset)
{
if (unset || !strcmp(arg, "abort"))
- tag_of_filtered_mode = ERROR;
+ tag_of_filtered_mode = TAG_FILTERING_ABORT;
else if (!strcmp(arg, "drop"))
tag_of_filtered_mode = DROP;
else if (!strcmp(arg, "rewrite"))
return ptr_to_mark(decoration);
}
+static struct commit *rewrite_commit(struct commit *p)
+{
+ for (;;) {
+ if (p->parents && p->parents->next)
+ break;
+ if (p->object.flags & UNINTERESTING)
+ break;
+ if (!(p->object.flags & TREESAME))
+ break;
+ if (!p->parents)
+ return NULL;
+ p = p->parents->item;
+ }
+ return p;
+}
+
static void show_progress(void)
{
static int counter = 0;
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(oid, buf, size, type_name(type)) < 0)
- die("sha1 mismatch in blob %s", oid_to_hex(oid));
+ die("oid mismatch in blob %s", oid_to_hex(oid));
object = parse_object_buffer(the_repository, oid, type,
size, buf, &eaten);
}
mark_next_object(object);
- printf("blob\nmark :%"PRIu32"\ndata %"PRIuMAX"\n", last_idnum, (uintmax_t)size);
+ printf("blob\nmark :%"PRIu32"\n", last_idnum);
+ if (show_original_ids)
+ printf("original-oid %s\n", oid_to_hex(oid));
+ printf("data %"PRIuMAX"\n", (uintmax_t)size);
if (size && fwrite(buf, size, 1, stdout) != 1)
die_errno("could not write blob '%s'", oid_to_hex(oid));
printf("\n");
static void *generate_fake_oid(const void *old, size_t *len)
{
- static uint32_t counter = 1; /* avoid null sha1 */
- unsigned char *out = xcalloc(GIT_SHA1_RAWSZ, 1);
- put_be32(out + GIT_SHA1_RAWSZ - 4, counter++);
+ static uint32_t counter = 1; /* avoid null oid */
+ const unsigned hashsz = the_hash_algo->rawsz;
+ unsigned char *out = xcalloc(hashsz, 1);
+ put_be32(out + hashsz - 4, counter++);
return out;
}
-static const unsigned char *anonymize_sha1(const struct object_id *oid)
+static const struct object_id *anonymize_oid(const struct object_id *oid)
{
- static struct hashmap sha1s;
- size_t len = GIT_SHA1_RAWSZ;
- return anonymize_mem(&sha1s, generate_fake_oid, oid, &len);
+ static struct hashmap objs;
+ size_t len = the_hash_algo->rawsz;
+ return anonymize_mem(&objs, generate_fake_oid, oid, &len);
}
static void show_filemodify(struct diff_queue_struct *q,
*/
if (no_data || S_ISGITLINK(spec->mode))
printf("M %06o %s ", spec->mode,
- sha1_to_hex(anonymize ?
- anonymize_sha1(&spec->oid) :
- spec->oid.hash));
+ oid_to_hex(anonymize ?
+ anonymize_oid(&spec->oid) :
+ &spec->oid));
else {
struct object *object = lookup_object(the_repository,
spec->oid.hash);
message += 2;
if (commit->parents &&
- get_object_mark(&commit->parents->item->object) != 0 &&
+ (get_object_mark(&commit->parents->item->object) != 0 ||
+ reference_excluded_commits) &&
!full_tree) {
parse_commit_or_die(commit->parents->item);
diff_tree_oid(get_commit_tree_oid(commit->parents->item),
export_blob(&diff_queued_diff.queue[i]->two->oid);
refname = *revision_sources_at(&revision_sources, commit);
+ /*
+ * FIXME: string_list_remove() below for each ref is overall
+ * O(N^2). Compared to a history walk and diffing trees, this is
+ * just lost in the noise in practice. However, theoretically a
+ * repo may have enough refs for this to become slow.
+ */
+ string_list_remove(&extra_refs, refname, 0);
if (anonymize) {
refname = anonymize_refname(refname);
anonymize_ident_line(&committer, &committer_end);
reencoded = reencode_string(message, "UTF-8", encoding);
if (!commit->parents)
printf("reset %s\n", refname);
- printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
- refname, last_idnum,
+ printf("commit %s\nmark :%"PRIu32"\n", refname, last_idnum);
+ if (show_original_ids)
+ printf("original-oid %s\n", oid_to_hex(&commit->object.oid));
+ printf("%.*s\n%.*s\ndata %u\n%s",
(int)(author_end - author), author,
(int)(committer_end - committer), committer,
(unsigned)(reencoded
unuse_commit_buffer(commit, commit_buffer);
for (i = 0, p = commit->parents; p; p = p->next) {
- int mark = get_object_mark(&p->item->object);
- if (!mark)
+ struct object *obj = &p->item->object;
+ int mark = get_object_mark(obj);
+
+ if (!mark && !reference_excluded_commits)
continue;
if (i == 0)
- printf("from :%d\n", mark);
+ printf("from ");
+ else
+ printf("merge ");
+ if (mark)
+ printf(":%d\n", mark);
else
- printf("merge :%d\n", mark);
+ printf("%s\n", oid_to_hex(anonymize ?
+ anonymize_oid(&obj->oid) :
+ &obj->oid));
i++;
}
"\n-----BEGIN PGP SIGNATURE-----\n");
if (signature)
switch(signed_tag_mode) {
- case ABORT:
+ case SIGNED_TAG_ABORT:
die("encountered signed tag %s; use "
"--signed-tags=<mode> to handle it",
oid_to_hex(&tag->object.oid));
tagged_mark = get_object_mark(tagged);
if (!tagged_mark) {
switch(tag_of_filtered_mode) {
- case ABORT:
+ case TAG_FILTERING_ABORT:
die("tag %s tags unexported object; use "
"--tag-of-filtered-object=<mode> to handle it",
oid_to_hex(&tag->object.oid));
oid_to_hex(&tag->object.oid),
type_name(tagged->type));
}
- p = (struct commit *)tagged;
- for (;;) {
- if (p->parents && p->parents->next)
- break;
- if (p->object.flags & UNINTERESTING)
- break;
- if (!(p->object.flags & TREESAME))
- break;
- if (!p->parents)
- die("can't find replacement commit for tag %s",
- oid_to_hex(&tag->object.oid));
- p = p->parents->item;
+ p = rewrite_commit((struct commit *)tagged);
+ if (!p) {
+ printf("reset %s\nfrom %s\n\n",
+ name, oid_to_hex(&null_oid));
+ free(buf);
+ return;
}
tagged_mark = get_object_mark(&p->object);
}
if (starts_with(name, "refs/tags/"))
name += 10;
- printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
- name, tagged_mark,
+ printf("tag %s\nfrom :%d\n", name, tagged_mark);
+ if (show_original_ids)
+ printf("original-oid %s\n", oid_to_hex(&tag->object.oid));
+ printf("%.*s%sdata %d\n%.*s\n",
(int)(tagger_end - tagger), tagger,
tagger == tagger_end ? "" : "\n",
(int)message_size, (int)message_size, message ? message : "");
/* handle nested tags */
while (tag && tag->object.type == OBJ_TAG) {
parse_object(the_repository, &tag->object.oid);
- string_list_append(&extra_refs, full_name)->util = tag;
+ string_list_append(&tag_refs, full_name)->util = tag;
tag = (struct tag *)tag->tagged;
}
if (!tag)
}
/*
- * This ref will not be updated through a commit, lets make
- * sure it gets properly updated eventually.
+ * Make sure this ref gets properly updated eventually, whether
+ * through a commit or manually at the end.
*/
- if (*revision_sources_at(&revision_sources, commit) ||
- commit->object.flags & SHOWN)
+ if (e->item->type != OBJ_TAG)
string_list_append(&extra_refs, full_name)->util = commit;
+
if (!*revision_sources_at(&revision_sources, commit))
*revision_sources_at(&revision_sources, commit) = full_name;
}
+
+ string_list_sort(&extra_refs);
+ string_list_remove_duplicates(&extra_refs, 0);
}
-static void handle_tags_and_duplicates(void)
+static void handle_tags_and_duplicates(struct string_list *extras)
{
struct commit *commit;
int i;
- for (i = extra_refs.nr - 1; i >= 0; i--) {
- const char *name = extra_refs.items[i].string;
- struct object *object = extra_refs.items[i].util;
+ for (i = extras->nr - 1; i >= 0; i--) {
+ const char *name = extras->items[i].string;
+ struct object *object = extras->items[i].util;
+ int mark;
+
switch (object->type) {
case OBJ_TAG:
handle_tag(name, (struct tag *)object);
if (anonymize)
name = anonymize_refname(name);
/* create refs pointing to already seen commits */
- commit = (struct commit *)object;
- printf("reset %s\nfrom :%d\n\n", name,
- get_object_mark(&commit->object));
+ commit = rewrite_commit((struct commit *)object);
+ if (!commit) {
+ /*
+ * Neither this object nor any of its
+ * ancestors touch any relevant paths, so
+ * it has been filtered to nothing. Delete
+ * it.
+ */
+ printf("reset %s\nfrom %s\n\n",
+ name, oid_to_hex(&null_oid));
+ continue;
+ }
+
+ mark = get_object_mark(&commit->object);
+ if (!mark) {
+ /*
+ * Getting here means we have a commit which
+ * was excluded by a negative refspec (e.g.
+ * fast-export ^master master). If we are
+ * referencing excluded commits, set the ref
+ * to the exact commit. Otherwise, the user
+ * wants the branch exported but every commit
+ * in its history to be deleted, which basically
+ * just means deletion of the ref.
+ */
+ if (!reference_excluded_commits) {
+ /* delete the ref */
+ printf("reset %s\nfrom %s\n\n",
+ name, oid_to_hex(&null_oid));
+ continue;
+ }
+ /* set ref to commit using oid, not mark */
+ printf("reset %s\nfrom %s\n\n", name,
+ oid_to_hex(&commit->object.oid));
+ continue;
+ }
+
+ printf("reset %s\nfrom :%d\n\n", name, mark
+ );
show_progress();
break;
}
continue;
printf("reset %s\nfrom %s\n\n",
- refspec->dst, sha1_to_hex(null_sha1));
+ refspec->dst, oid_to_hex(&null_oid));
}
}
OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
N_("Apply refspec to exported refs")),
OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
+ OPT_BOOL(0, "reference-excluded-parents",
+ &reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
+ OPT_BOOL(0, "show-original-ids", &show_original_ids,
+ N_("Show original object ids of blobs/commits")),
+
OPT_END()
};
}
}
- handle_tags_and_duplicates();
+ handle_tags_and_duplicates(&extra_refs);
+ handle_tags_and_duplicates(&tag_refs);
handle_deletes();
if (export_filename && lastimportid != last_idnum)
static const char *describe_object(struct object *obj)
{
- static struct strbuf buf = STRBUF_INIT;
- char *name = name_objects ?
- lookup_decoration(fsck_walk_options.object_names, obj) : NULL;
+ static struct strbuf bufs[] = {
+ STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+ };
+ static int b = 0;
+ struct strbuf *buf;
+ char *name = NULL;
- strbuf_reset(&buf);
- strbuf_addstr(&buf, oid_to_hex(&obj->oid));
+ if (name_objects)
+ name = lookup_decoration(fsck_walk_options.object_names, obj);
+
+ buf = bufs + b;
+ b = (b + 1) % ARRAY_SIZE(bufs);
+ strbuf_reset(buf);
+ strbuf_addstr(buf, oid_to_hex(&obj->oid));
if (name)
- strbuf_addf(&buf, " (%s)", name);
+ strbuf_addf(buf, " (%s)", name);
- return buf.buf;
+ return buf->buf;
}
static const char *printable_type(struct object *obj)
ret = type_name(obj->type);
if (!ret)
- ret = "unknown";
+ ret = _("unknown");
return ret;
}
return git_default_config(var, value, cb);
}
-static void objreport(struct object *obj, const char *msg_type,
- const char *err)
-{
- fprintf(stderr, "%s in %s %s: %s\n",
- msg_type, printable_type(obj), describe_object(obj), err);
-}
-
static int objerror(struct object *obj, const char *err)
{
errors_found |= ERROR_OBJECT;
- objreport(obj, "error", err);
+ /* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
+ fprintf_ln(stderr, _("error in %s %s: %s"),
+ printable_type(obj), describe_object(obj), err);
return -1;
}
static int fsck_error_func(struct fsck_options *o,
struct object *obj, int type, const char *message)
{
- objreport(obj, (type == FSCK_WARN) ? "warning" : "error", message);
- return (type == FSCK_WARN) ? 0 : 1;
+ switch (type) {
+ case FSCK_WARN:
+ /* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
+ fprintf_ln(stderr, _("warning in %s %s: %s"),
+ printable_type(obj), describe_object(obj), message);
+ return 0;
+ case FSCK_ERROR:
+ /* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
+ fprintf_ln(stderr, _("error in %s %s: %s"),
+ printable_type(obj), describe_object(obj), message);
+ return 1;
+ default:
+ BUG("%d (FSCK_IGNORE?) should never trigger this callback", type);
+ }
}
static struct object_array pending;
*/
if (!obj) {
/* ... these references to parent->fld are safe here */
- printf("broken link from %7s %s\n",
- printable_type(parent), describe_object(parent));
- printf("broken link from %7s %s\n",
- (type == OBJ_ANY ? "unknown" : type_name(type)), "unknown");
+ printf_ln(_("broken link from %7s %s"),
+ printable_type(parent), describe_object(parent));
+ printf_ln(_("broken link from %7s %s"),
+ (type == OBJ_ANY ? _("unknown") : type_name(type)),
+ _("unknown"));
errors_found |= ERROR_REACHABLE;
return 1;
}
if (type != OBJ_ANY && obj->type != type)
/* ... and the reference to parent is safe here */
- objerror(parent, "wrong object type in link");
+ objerror(parent, _("wrong object type in link"));
if (obj->flags & REACHABLE)
return 0;
if (!(obj->flags & HAS_OBJ)) {
if (parent && !has_object_file(&obj->oid)) {
- printf("broken link from %7s %s\n",
- printable_type(parent), describe_object(parent));
- printf(" to %7s %s\n",
- printable_type(obj), describe_object(obj));
+ printf_ln(_("broken link from %7s %s\n"
+ " to %7s %s"),
+ printable_type(parent),
+ describe_object(parent),
+ printable_type(obj),
+ describe_object(obj));
errors_found |= ERROR_REACHABLE;
}
return 1;
return;
if (has_object_pack(&obj->oid))
return; /* it is in pack - forget about it */
- printf("missing %s %s\n", printable_type(obj),
- describe_object(obj));
+ printf_ln(_("missing %s %s"), printable_type(obj),
+ describe_object(obj));
errors_found |= ERROR_REACHABLE;
return;
}
* since this is something that is prunable.
*/
if (show_unreachable) {
- printf("unreachable %s %s\n", printable_type(obj),
- describe_object(obj));
+ printf_ln(_("unreachable %s %s"), printable_type(obj),
+ describe_object(obj));
return;
}
*/
if (!(obj->flags & USED)) {
if (show_dangling)
- printf("dangling %s %s\n", printable_type(obj),
- describe_object(obj));
+ printf_ln(_("dangling %s %s"), printable_type(obj),
+ describe_object(obj));
if (write_lost_and_found) {
char *filename = git_pathdup("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
FILE *f;
if (safe_create_leading_directories_const(filename)) {
- error("Could not create lost-found");
+ error(_("could not create lost-found"));
free(filename);
return;
}
f = xfopen(filename, "w");
if (obj->type == OBJ_BLOB) {
if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
- die_errno("Could not write '%s'", filename);
+ die_errno(_("could not write '%s'"), filename);
} else
fprintf(f, "%s\n", describe_object(obj));
if (fclose(f))
- die_errno("Could not finish '%s'",
+ die_errno(_("could not finish '%s'"),
filename);
free(filename);
}
static void check_object(struct object *obj)
{
if (verbose)
- fprintf(stderr, "Checking %s\n", describe_object(obj));
+ fprintf_ln(stderr, _("Checking %s"), describe_object(obj));
if (obj->flags & REACHABLE)
check_reachable_object(obj);
/* Look up all the requirements, warn about missing objects.. */
max = get_max_object_index();
if (verbose)
- fprintf(stderr, "Checking connectivity (%d objects)\n", max);
+ fprintf_ln(stderr, _("Checking connectivity (%d objects)"), max);
for (i = 0; i < max; i++) {
struct object *obj = get_indexed_object(i);
obj->flags |= SEEN;
if (verbose)
- fprintf(stderr, "Checking %s %s\n",
- printable_type(obj), describe_object(obj));
+ fprintf_ln(stderr, _("Checking %s %s"),
+ printable_type(obj), describe_object(obj));
if (fsck_walk(obj, NULL, &fsck_obj_options))
- objerror(obj, "broken links");
+ objerror(obj, _("broken links"));
err = fsck_object(obj, buffer, size, &fsck_obj_options);
if (err)
goto out;
struct commit *commit = (struct commit *) obj;
if (!commit->parents && show_root)
- printf("root %s\n", describe_object(&commit->object));
+ printf_ln(_("root %s"),
+ describe_object(&commit->object));
}
if (obj->type == OBJ_TAG) {
struct tag *tag = (struct tag *) obj;
if (show_tags && tag->tagged) {
- printf("tagged %s %s", printable_type(tag->tagged),
- describe_object(tag->tagged));
- printf(" (%s) in %s\n", tag->tag,
- describe_object(&tag->object));
+ printf_ln(_("tagged %s %s (%s) in %s"),
+ printable_type(tag->tagged),
+ describe_object(tag->tagged),
+ tag->tag,
+ describe_object(&tag->object));
}
}
eaten);
if (!obj) {
errors_found |= ERROR_OBJECT;
- return error("%s: object corrupt or missing", oid_to_hex(oid));
+ return error(_("%s: object corrupt or missing"),
+ oid_to_hex(oid));
}
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
obj->flags |= USED;
mark_object_reachable(obj);
} else if (!is_promisor_object(oid)) {
- error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
+ error(_("%s: invalid reflog entry %s"),
+ refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
}
}
const char *refname = cb_data;
if (verbose)
- fprintf(stderr, "Checking reflog %s->%s\n",
- oid_to_hex(ooid), oid_to_hex(noid));
+ fprintf_ln(stderr, _("Checking reflog %s->%s"),
+ oid_to_hex(ooid), oid_to_hex(noid));
fsck_handle_reflog_oid(refname, ooid, 0);
fsck_handle_reflog_oid(refname, noid, timestamp);
default_refs++;
return 0;
}
- error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid));
+ error(_("%s: invalid sha1 pointer %s"),
+ refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
/* We'll continue with the rest despite the error.. */
return 0;
}
if (obj->type != OBJ_COMMIT && is_branch(refname)) {
- error("%s: not a commit", refname);
+ error(_("%s: not a commit"), refname);
errors_found |= ERROR_REFS;
}
default_refs++;
* "show_unreachable" flag.
*/
if (!default_refs) {
- fprintf(stderr, "notice: No default references\n");
+ fprintf_ln(stderr, _("notice: No default references"));
show_unreachable = 0;
}
}
if (read_loose_object(path, oid, &type, &size, &contents) < 0) {
errors_found |= ERROR_OBJECT;
- error("%s: object corrupt or missing: %s",
+ error(_("%s: object corrupt or missing: %s"),
oid_to_hex(oid), path);
return 0; /* keep checking other objects */
}
if (!obj) {
errors_found |= ERROR_OBJECT;
- error("%s: object could not be parsed: %s",
+ error(_("%s: object could not be parsed: %s"),
oid_to_hex(oid), path);
if (!eaten)
free(contents);
static int fsck_cruft(const char *basename, const char *path, void *data)
{
if (!starts_with(basename, "tmp_obj_"))
- fprintf(stderr, "bad sha1 file: %s\n", path);
+ fprintf_ln(stderr, _("bad sha1 file: %s"), path);
return 0;
}
struct progress *progress = NULL;
if (verbose)
- fprintf(stderr, "Checking object directory\n");
+ fprintf_ln(stderr, _("Checking object directory"));
if (show_progress)
progress = start_progress(_("Checking object directories"), 256);
int null_is_error = 0;
if (verbose)
- fprintf(stderr, "Checking %s link\n", head_ref_name);
+ fprintf_ln(stderr, _("Checking %s link"), head_ref_name);
*head_points_at = resolve_ref_unsafe(head_ref_name, 0, head_oid, NULL);
if (!*head_points_at) {
errors_found |= ERROR_REFS;
- return error("Invalid %s", head_ref_name);
+ return error(_("invalid %s"), head_ref_name);
}
if (!strcmp(*head_points_at, head_ref_name))
/* detached HEAD */
null_is_error = 1;
else if (!starts_with(*head_points_at, "refs/heads/")) {
errors_found |= ERROR_REFS;
- return error("%s points to something strange (%s)",
+ return error(_("%s points to something strange (%s)"),
head_ref_name, *head_points_at);
}
if (is_null_oid(head_oid)) {
if (null_is_error) {
errors_found |= ERROR_REFS;
- return error("%s: detached HEAD points at nothing",
+ return error(_("%s: detached HEAD points at nothing"),
head_ref_name);
}
- fprintf(stderr, "notice: %s points to an unborn branch (%s)\n",
- head_ref_name, *head_points_at + 11);
+ fprintf_ln(stderr,
+ _("notice: %s points to an unborn branch (%s)"),
+ head_ref_name, *head_points_at + 11);
}
return 0;
}
int err = 0;
if (verbose)
- fprintf(stderr, "Checking cache tree\n");
+ fprintf_ln(stderr, _("Checking cache tree"));
if (0 <= it->entry_count) {
struct object *obj = parse_object(the_repository, &it->oid);
if (!obj) {
- error("%s: invalid sha1 pointer in cache-tree",
+ error(_("%s: invalid sha1 pointer in cache-tree"),
oid_to_hex(&it->oid));
errors_found |= ERROR_REFS;
return 1;
obj, xstrdup(":"));
mark_object_reachable(obj);
if (obj->type != OBJ_TREE)
- err |= objerror(obj, "non-tree in cache-tree");
+ err |= objerror(obj, _("non-tree in cache-tree"));
}
for (i = 0; i < it->subtree_nr; i++)
err |= fsck_cache_tree(it->down[i]->cache_tree);
int cmd_fsck(int argc, const char **argv, const char *prefix)
{
int i;
- struct alternate_object_database *alt;
+ struct object_directory *odb;
/* fsck knows how to handle missing promisor objects */
fetch_if_missing = 0;
for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
} else {
- struct alternate_object_database *alt_odb_list;
-
- fsck_object_dir(get_object_directory());
-
prepare_alt_odb(the_repository);
- alt_odb_list = the_repository->objects->alt_odb_list;
- for (alt = alt_odb_list; alt; alt = alt->next)
- fsck_object_dir(alt->path);
+ for (odb = the_repository->objects->odb; odb; odb = odb->next)
+ fsck_object_dir(odb->path);
if (check_full) {
struct packed_git *p;
for (p = get_all_packs(the_repository); p;
p = p->next) {
/* verify gives error messages itself */
- if (verify_pack(p, fsck_obj_buffer,
+ if (verify_pack(the_repository,
+ p, fsck_obj_buffer,
progress, count))
errors_found |= ERROR_PACK;
count += p->num_objects;
if (!obj || !(obj->flags & HAS_OBJ)) {
if (is_promisor_object(&oid))
continue;
- error("%s: object missing", oid_to_hex(&oid));
+ error(_("%s: object missing"), oid_to_hex(&oid));
errors_found |= ERROR_OBJECT;
continue;
}
mark_object_reachable(obj);
continue;
}
- error("invalid parameter: expected sha1, got '%s'", arg);
+ error(_("invalid parameter: expected sha1, got '%s'"), arg);
errors_found |= ERROR_OBJECT;
}
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL };
- commit_graph_verify.argv = verify_argv;
- commit_graph_verify.git_cmd = 1;
- if (run_command(&commit_graph_verify))
- errors_found |= ERROR_COMMIT_GRAPH;
-
prepare_alt_odb(the_repository);
- for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+ for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+ child_process_init(&commit_graph_verify);
+ commit_graph_verify.argv = verify_argv;
+ commit_graph_verify.git_cmd = 1;
verify_argv[2] = "--object-dir";
- verify_argv[3] = alt->path;
+ verify_argv[3] = odb->path;
if (run_command(&commit_graph_verify))
errors_found |= ERROR_COMMIT_GRAPH;
}
struct child_process midx_verify = CHILD_PROCESS_INIT;
const char *midx_argv[] = { "multi-pack-index", "verify", NULL, NULL, NULL };
- midx_verify.argv = midx_argv;
- midx_verify.git_cmd = 1;
- if (run_command(&midx_verify))
- errors_found |= ERROR_COMMIT_GRAPH;
-
prepare_alt_odb(the_repository);
- for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+ for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+ child_process_init(&midx_verify);
+ midx_verify.argv = midx_argv;
+ midx_verify.git_cmd = 1;
midx_argv[2] = "--object-dir";
- midx_argv[3] = alt->path;
+ midx_argv[3] = odb->path;
if (run_command(&midx_verify))
errors_found |= ERROR_COMMIT_GRAPH;
}
static void add_repack_incremental_option(void)
{
- argv_array_push(&repack, "--no-write-bitmap-index");
+ argv_array_push(&repack, "--no-write-bitmap-index");
}
static int need_to_gc(void)
* store is no longer global and instead is a member of the repository
* object.
*/
- add_to_alternates_memory(submodule.objects->objectdir);
+ add_to_alternates_memory(submodule.objects->odb->path);
grep_read_unlock();
if (oid) {
if (match != all_entries_interesting) {
strbuf_addstr(&name, base->buf + tn_len);
- match = tree_entry_interesting(&entry, &name,
+ match = tree_entry_interesting(repo->index,
+ &entry, &name,
0, pathspec);
strbuf_setlen(&name, name_base_len);
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
name,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
- read_tree_recursive((struct tree *)o, "", 0, 0, &match_all,
- show_tree_object, rev.diffopt.file);
+ read_tree_recursive(the_repository, (struct tree *)o, "",
+ 0, 0, &match_all, show_tree_object,
+ rev.diffopt.file);
rev.shown_one = 1;
break;
case OBJ_COMMIT:
PATHSPEC_PREFER_CWD, prefix, matchbuf);
} else
memset(&pathspec, 0, sizeof(pathspec));
- if (read_tree(tree, 1, &pathspec, istate))
+ if (read_tree(the_repository, tree, 1, &pathspec, istate))
die("unable to read tree entries %s", tree_name);
for (i = 0; i < istate->cache_nr; i++) {
tree = parse_tree_indirect(&oid);
if (!tree)
die("not a tree object");
- return !!read_tree_recursive(tree, "", 0, 0, &pathspec, show_tree, NULL);
+ return !!read_tree_recursive(the_repository, tree, "", 0, 0,
+ &pathspec, show_tree, NULL);
}
*/
if (read_cache() < 0)
die_errno("read_cache failed");
- if (index_differs_from("HEAD", NULL, 0))
+ if (index_differs_from(the_repository, "HEAD", NULL, 0))
exit(2);
exit(0);
}
setup_traverse_info(&info, base);
info.fn = threeway_callback;
- traverse_trees(3, t, &info);
+ traverse_trees(&the_index, 3, t, &info);
}
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
ctx->argc--;
arg = *++ctx->argv;
} else
- return opterror(opt, "requires a value", 0);
+ return error(_("option `%s' requires a value"), opt->long_name);
if (buf->len)
strbuf_addch(buf, '\n');
argc = split_cmdline(bmo, &argv);
if (argc < 0)
die(_("Bad branch.%s.mergeoptions string: %s"), branch,
- split_cmdline_strerror(argc));
+ _(split_cmdline_strerror(argc)));
REALLOC_ARRAY(argv, argc + 2);
MOVE_ARRAY(argv + 1, argv, argc + 1);
argc++;
filename = git_path_merge_msg(the_repository);
fp = xfopen(filename, "a");
- append_conflicts_hint(&msgbuf);
+ append_conflicts_hint(&the_index, &msgbuf);
fputs(msgbuf.buf, fp);
strbuf_release(&msgbuf);
fclose(fp);
usage_with_options(git_notes_merge_usage, options);
}
- init_notes_merge_options(&o);
+ init_notes_merge_options(the_repository, &o);
o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT;
if (do_abort)
unsigned n;
if (use_delta_islands)
- resolve_tree_islands(progress, &to_pack);
+ resolve_tree_islands(the_repository, progress, &to_pack);
get_object_details();
static void get_object_list(int ac, const char **av)
{
struct rev_info revs;
+ struct setup_revision_opt s_r_opt = {
+ .allow_exclude_promisor_objects = 1,
+ };
char line[1000];
int flags = 0;
int save_warning;
repo_init_revisions(the_repository, &revs, NULL);
save_commit_buffer = 0;
- revs.allow_exclude_promisor_objects_opt = 1;
- setup_revisions(ac, av, &revs, NULL);
+ setup_revisions(ac, av, &revs, &s_r_opt);
/* make sure shallows are read */
is_repository_shallow(the_repository);
return;
if (use_delta_islands)
- load_delta_islands();
+ load_delta_islands(the_repository);
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
}
}
- prepare_packing_data(&to_pack);
+ prepare_packing_data(the_repository, &to_pack);
if (progress)
progress_state = start_progress(_("Enumerating objects"), 0);
save_commit_buffer = 0;
read_replace_refs = 0;
ref_paranoia = 1;
- revs.allow_exclude_promisor_objects_opt = 1;
repo_init_revisions(the_repository, &revs, prefix);
argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
die(_("Updating an unborn branch with changes added to the index."));
if (!autostash)
- require_clean_work_tree(N_("pull with rebase"),
+ require_clean_work_tree(the_repository,
+ N_("pull with rebase"),
_("please commit or stash them."), 1, 0);
if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
return remote->url_nr;
}
-static NORETURN int die_push_simple(struct branch *branch, struct remote *remote) {
+static NORETURN int die_push_simple(struct branch *branch,
+ struct remote *remote)
+{
/*
* There's no point in using shorten_unambiguous_ref here,
* as the ambiguity would be on the remote side, not what
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
- err = transport_push(transport, rs, flags, &reject_reasons);
+ err = transport_push(the_repository, transport,
+ rs, flags, &reject_reasons);
if (err != 0) {
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
error(_("failed to push some refs to '%s'"), transport->url);
* what came from the tree.
*/
if (nr_trees == 1 && !opts.prefix)
- prime_cache_tree(&the_index, trees[0]);
+ prime_cache_tree(the_repository,
+ the_repository->index,
+ trees[0]);
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die("unable to write new index file");
if (restrict_revision)
argv_array_push(&make_script_args, restrict_revision);
- ret = sequencer_make_script(todo_list,
+ ret = sequencer_make_script(the_repository, todo_list,
make_script_args.argc, make_script_args.argv,
flags);
fclose(todo_list);
error(_("could not generate todo list"));
else {
discard_cache();
- ret = complete_action(opts, flags, shortrevisions, onto_name, onto,
+ ret = complete_action(the_repository, opts, flags,
+ shortrevisions, onto_name, onto,
head_hash, cmd, autosquash);
}
case SKIP: {
struct string_list merge_rr = STRING_LIST_INIT_DUP;
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
/* fallthrough */
case CONTINUE:
- ret = sequencer_continue(&opts);
+ ret = sequencer_continue(the_repository, &opts);
break;
}
case EDIT_TODO:
- ret = edit_todo_list(flags);
+ ret = edit_todo_list(the_repository, flags);
break;
case SHOW_CURRENT_PATCH: {
struct child_process cmd = CHILD_PROCESS_INIT;
}
case SHORTEN_OIDS:
case EXPAND_OIDS:
- ret = transform_todos(flags);
+ ret = transform_todos(the_repository, flags);
break;
case CHECK_TODO_LIST:
- ret = check_todo_list();
+ ret = check_todo_list(the_repository);
break;
case REARRANGE_SQUASH:
- ret = rearrange_squash();
+ ret = rearrange_squash(the_repository);
break;
case ADD_EXEC:
- ret = sequencer_add_exec_commands(cmd);
+ ret = sequencer_add_exec_commands(the_repository, cmd);
break;
default:
BUG("invalid command '%d'", command);
}
tree = parse_tree_indirect(oid);
- prime_cache_tree(the_repository->index, tree);
+ prime_cache_tree(the_repository, the_repository->index, tree);
if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
ret = error(_("could not write index"));
&lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(1)) {
+ if (has_unstaged_changes(the_repository, 1)) {
puts(_("You must edit all merge conflicts and then\n"
"mark them as resolved using git add"));
exit(1);
options.action = "skip";
set_reflog_action(&options);
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD,
NULL, NULL) < 0)
die(_("could not discard worktree changes"));
- remove_branch_state();
+ remove_branch_state(the_repository);
if (read_basic_state(&options))
exit(1);
goto run_rebase;
options.action = "abort";
set_reflog_action(&options);
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
if (read_basic_state(&options))
NULL, NULL) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head));
- remove_branch_state();
+ remove_branch_state(the_repository);
ret = finish_rebase(&options);
goto cleanup;
}
update_index_if_able(&the_index, &lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(1) || has_uncommitted_changes(1)) {
+ if (has_unstaged_changes(the_repository, 1) ||
+ has_uncommitted_changes(the_repository, 1)) {
const char *autostash =
state_dir_path("autostash", &options);
struct child_process stash = CHILD_PROCESS_INIT;
}
}
- if (require_clean_work_tree("rebase",
+ if (require_clean_work_tree(the_repository, "rebase",
_("Please commit or stash them."), 1, 1)) {
ret = 1;
goto cleanup;
/* NEEDSWORK: switch to using parse_options */
static const char reflog_expire_usage[] =
-"git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...";
+N_("git reflog expire [--expire=<time>] "
+ "[--expire-unreachable=<time>] "
+ "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
+ "[--verbose] [--all] <refs>...");
static const char reflog_delete_usage[] =
-"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...";
+N_("git reflog delete [--rewrite] [--updateref] "
+ "[--dry-run | -n] [--verbose] <refs>...");
static const char reflog_exists_usage[] =
-"git reflog exists <ref>";
+N_("git reflog exists <ref>");
static timestamp_t default_reflog_expire;
static timestamp_t default_reflog_expire_unreachable;
break;
}
else if (arg[0] == '-')
- usage(reflog_expire_usage);
+ usage(_(reflog_expire_usage));
else
break;
}
if (cb.cmd.stalefix) {
repo_init_revisions(the_repository, &cb.cmd.revs, prefix);
if (flags & EXPIRE_REFLOGS_VERBOSE)
- printf("Marking reachable objects...");
+ printf(_("Marking reachable objects..."));
mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL);
if (flags & EXPIRE_REFLOGS_VERBOSE)
putchar('\n');
char *ref;
struct object_id oid;
if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) {
- status |= error("%s points nowhere!", argv[i]);
+ status |= error(_("%s points nowhere!"), argv[i]);
continue;
}
set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
break;
}
else if (arg[0] == '-')
- usage(reflog_delete_usage);
+ usage(_(reflog_delete_usage));
else
break;
}
if (argc - i < 1)
- return error("Nothing to delete?");
+ return error(_("no reflog specified to delete"));
for ( ; i < argc; i++) {
const char *spec = strstr(argv[i], "@{");
int recno;
if (!spec) {
- status |= error("Not a reflog: %s", argv[i]);
+ status |= error(_("not a reflog: %s"), argv[i]);
continue;
}
if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) {
- status |= error("no reflog for '%s'", argv[i]);
+ status |= error(_("no reflog for '%s'"), argv[i]);
continue;
}
break;
}
else if (arg[0] == '-')
- usage(reflog_exists_usage);
+ usage(_(reflog_exists_usage));
else
break;
}
start = i;
if (argc - start != 1)
- usage(reflog_exists_usage);
+ usage(_(reflog_exists_usage));
if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
- die("invalid ref format: %s", argv[start]);
+ die(_("invalid ref format: %s"), argv[start]);
return !reflog_exists(argv[start]);
}
*/
static const char reflog_usage[] =
-"git reflog [ show | expire | delete | exists ]";
+N_("git reflog [ show | expire | delete | exists ]");
int cmd_reflog(int argc, const char **argv, const char *prefix)
{
if (argc > 1 && !strcmp(argv[1], "-h"))
- usage(reflog_usage);
+ usage(_(reflog_usage));
/* With no command, we default to showing it. */
if (argc < 2 || *argv[1] == '-')
if (cmd->in == -1) {
if (start_command(cmd))
- die("Could not start pack-objects to repack promisor objects");
+ die(_("could not start pack-objects to repack promisor objects"));
}
xwrite(cmd->in, oid_to_hex(oid), GIT_SHA1_HEXSZ);
char *promisor_name;
int fd;
if (line.len != the_hash_algo->hexsz)
- die("repack: Expecting full hex object ID lines only from pack-objects.");
+ die(_("repack: Expecting full hex object ID lines only from pack-objects."));
string_list_append(names, line.buf);
/*
line.buf);
fd = open(promisor_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd < 0)
- die_errno("unable to create '%s'", promisor_name);
+ die_errno(_("unable to create '%s'"), promisor_name);
close(fd);
free(promisor_name);
}
fclose(out);
if (finish_command(&cmd))
- die("Could not finish pack-objects to repack promisor objects");
+ die(_("could not finish pack-objects to repack promisor objects"));
}
#define ALL_INTO_ONE 1
out = xfdopen(cmd.out, "r");
while (strbuf_getline_lf(&line, out) != EOF) {
if (line.len != the_hash_algo->hexsz)
- die("repack: Expecting full hex object ID lines only from pack-objects.");
+ die(_("repack: Expecting full hex object ID lines only from pack-objects."));
string_list_append(&names, line.buf);
}
fclose(out);
return ret;
if (!names.nr && !po_args.quiet)
- printf("Nothing new to pack.\n");
+ printf_ln(_("Nothing new to pack."));
/*
* Ok we have prepared all new packfiles.
if (rollback_failure.nr) {
int i;
fprintf(stderr,
- "WARNING: Some packs in use have been renamed by\n"
- "WARNING: prefixing old- to their name, in order to\n"
- "WARNING: replace them with the new version of the\n"
- "WARNING: file. But the operation failed, and the\n"
- "WARNING: attempt to rename them back to their\n"
- "WARNING: original names also failed.\n"
- "WARNING: Please rename them in %s manually:\n", packdir);
+ _("WARNING: Some packs in use have been renamed by\n"
+ "WARNING: prefixing old- to their name, in order to\n"
+ "WARNING: replace them with the new version of the\n"
+ "WARNING: file. But the operation failed, and the\n"
+ "WARNING: attempt to rename them back to their\n"
+ "WARNING: original names also failed.\n"
+ "WARNING: Please rename them in %s manually:\n"), packdir);
for (i = 0; i < rollback_failure.nr; i++)
fprintf(stderr, "WARNING: old-%s -> %s\n",
rollback_failure.items[i].string,
}
if (!strcmp(argv[0], "clear")) {
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
} else if (!strcmp(argv[0], "gc"))
- rerere_gc(&merge_rr);
+ rerere_gc(the_repository, &merge_rr);
else if (!strcmp(argv[0], "status")) {
- if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0)
+ if (setup_rerere(the_repository, &merge_rr,
+ flags | RERERE_READONLY) < 0)
return 0;
for (i = 0; i < merge_rr.nr; i++)
printf("%s\n", merge_rr.items[i].string);
merge_rr.items[i].util = NULL;
}
} else if (!strcmp(argv[0], "diff")) {
- if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0)
+ if (setup_rerere(the_repository, &merge_rr,
+ flags | RERERE_READONLY) < 0)
return 0;
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
if (reset_type == MIXED || reset_type == HARD) {
tree = parse_tree_indirect(oid);
- prime_cache_tree(&the_index, tree);
+ prime_cache_tree(the_repository, the_repository->index, tree);
}
ret = 0;
print_new_head_line(lookup_commit_reference(the_repository, &oid));
}
if (!pathspec.nr)
- remove_branch_state();
+ remove_branch_state(the_repository);
return update_ref_status;
}
{
struct rev_info revs;
struct rev_list_info info;
+ struct setup_revision_opt s_r_opt = {
+ .allow_exclude_promisor_objects = 1,
+ };
int i;
int bisect_list = 0;
int bisect_show_vars = 0;
git_config(git_default_config, NULL);
repo_init_revisions(the_repository, &revs, prefix);
revs.abbrev = DEFAULT_ABBREV;
- revs.allow_exclude_promisor_objects_opt = 1;
revs.commit_format = CMIT_FMT_UNSPECIFIED;
revs.do_not_die_on_missing_tree = 1;
}
}
- argc = setup_revisions(argc, argv, &revs, NULL);
+ argc = setup_revisions(argc, argv, &revs, &s_r_opt);
memset(&info, 0, sizeof(info));
info.revs = &revs;
replay->mainline = strtol(arg, &end, 10);
if (*end || replay->mainline <= 0)
- return opterror(opt, "expects a number greater than zero", 0);
+ return error(_("option `%s' expects a number greater than zero"),
+ opt->long_name);
return 0;
}
if (cmd == 'q') {
int ret = sequencer_remove_state(opts);
if (!ret)
- remove_branch_state();
+ remove_branch_state(the_repository);
return ret;
}
if (cmd == 'c')
- return sequencer_continue(opts);
+ return sequencer_continue(the_repository, opts);
if (cmd == 'a')
- return sequencer_rollback(opts);
- return sequencer_pick_revisions(opts);
+ return sequencer_rollback(the_repository, opts);
+ return sequencer_pick_revisions(the_repository, opts);
}
int cmd_revert(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
enum stripspace_mode mode = STRIP_DEFAULT;
+ int nongit;
const struct option options[] = {
OPT_CMDMODE('s', "strip-comments", &mode,
usage_with_options(stripspace_usage, options);
if (mode == STRIP_COMMENTS || mode == COMMENT_LINES) {
- setup_git_directory_gently(NULL);
+ setup_git_directory_gently(&nongit);
git_config(git_default_config, NULL);
}
if (!(flags & OPT_QUIET))
printf(format, displaypath);
+ submodule_unset_core_worktree(sub);
+
strbuf_release(&sb_rm);
}
SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL }
static int add_possible_reference_from_superproject(
- struct alternate_object_database *alt, void *sas_cb)
+ struct object_directory *odb, void *sas_cb)
{
struct submodule_alternate_setup *sas = sas_cb;
+ size_t len;
/*
* If the alternate object store is another repository, try the
* standard layout with .git/(modules/<name>)+/objects
*/
- if (ends_with(alt->path, "/objects")) {
+ if (strip_suffix(odb->path, "/objects", &len)) {
char *sm_alternate;
struct strbuf sb = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
- strbuf_add(&sb, alt->path, strlen(alt->path) - strlen("objects"));
+ strbuf_add(&sb, odb->path, len);
/*
* We need to end the new path with '/' to mark it as a dir,
* as the last part of a missing submodule reference would
* be taken as a file name.
*/
- strbuf_addf(&sb, "modules/%s/", sas->submodule_name);
+ strbuf_addf(&sb, "/modules/%s/", sas->submodule_name);
sm_alternate = compute_alternate_path(sb.buf, &err);
if (sm_alternate) {
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
NULL, NULL, NULL, \
- NULL, 0, 0, 0, NULL, 0, 0, 0}
+ NULL, 0, 0, 0, NULL, 0, 0, 1}
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
struct repository subrepo;
if (argc != 2)
- BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
+ BUG("submodule--helper ensure-core-worktree <path>");
path = argv[1];
/* Remember to update object flag allocation in object.h */
#define PREREQ_MARK (1u<<16)
-int verify_bundle(struct bundle_header *header, int verbose)
+int verify_bundle(struct repository *r,
+ struct bundle_header *header,
+ int verbose)
{
/*
* Do fast check, then if any prereqs are missing then go line by line
int i, ret = 0, req_nr;
const char *message = _("Repository lacks these prerequisite commits:");
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(r, &revs, NULL);
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- struct object *o = parse_object(the_repository, &e->oid);
+ struct object *o = parse_object(r, &e->oid);
if (o) {
o->flags |= PREREQ_MARK;
add_pending_object(&revs, o, e->name);
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- struct object *o = parse_object(the_repository, &e->oid);
+ struct object *o = parse_object(r, &e->oid);
assert(o); /* otherwise we'd have returned early */
if (o->flags & SHOWN)
continue;
/* Clean up objects used, as they will be reused. */
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- commit = lookup_commit_reference_gently(the_repository, &e->oid, 1);
+ commit = lookup_commit_reference_gently(r, &e->oid, 1);
if (commit)
clear_commit_marks(commit, ALL_REV_FLAGS);
}
* in terms of a tag (e.g. v2.0 from the range
* "v1.0..v2.0")?
*/
- struct commit *one = lookup_commit_reference(the_repository,
- &oid);
+ struct commit *one = lookup_commit_reference(revs->repo, &oid);
struct object *obj;
if (e->item == &(one->object)) {
return ref_count;
}
-int create_bundle(struct bundle_header *header, const char *path,
- int argc, const char **argv)
+int create_bundle(struct repository *r, struct bundle_header *header,
+ const char *path, int argc, const char **argv)
{
struct lock_file lock = LOCK_INIT;
int bundle_fd = -1;
/* init revs to list objects for pack-objects later */
save_commit_buffer = 0;
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(r, &revs, NULL);
/* write prerequisites */
if (compute_and_write_prerequisites(bundle_fd, &revs, argc, argv))
return -1;
}
-int unbundle(struct bundle_header *header, int bundle_fd, int flags)
+int unbundle(struct repository *r, struct bundle_header *header,
+ int bundle_fd, int flags)
{
const char *argv_index_pack[] = {"index-pack",
"--fix-thin", "--stdin", NULL, NULL};
if (flags & BUNDLE_VERBOSE)
argv_index_pack[3] = "-v";
- if (verify_bundle(header, 0))
+ if (verify_bundle(r, header, 0))
return -1;
ip.argv = argv_index_pack;
ip.in = bundle_fd;
int is_bundle(const char *path, int quiet);
int read_bundle_header(const char *path, struct bundle_header *header);
-int create_bundle(struct bundle_header *header, const char *path,
- int argc, const char **argv);
-int verify_bundle(struct bundle_header *header, int verbose);
+int create_bundle(struct repository *r, struct bundle_header *header,
+ const char *path, int argc, const char **argv);
+int verify_bundle(struct repository *r, struct bundle_header *header, int verbose);
#define BUNDLE_VERBOSE 1
-int unbundle(struct bundle_header *header, int bundle_fd, int flags);
+int unbundle(struct repository *r, struct bundle_header *header,
+ int bundle_fd, int flags);
int list_bundle_refs(struct bundle_header *header,
int argc, const char **argv);
}
static void write_one(struct strbuf *buffer, struct cache_tree *it,
- const char *path, int pathlen)
+ const char *path, int pathlen)
{
int i;
return ret;
}
-static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
+static void prime_cache_tree_rec(struct repository *r,
+ struct cache_tree *it,
+ struct tree *tree)
{
struct tree_desc desc;
struct name_entry entry;
cnt++;
else {
struct cache_tree_sub *sub;
- struct tree *subtree = lookup_tree(the_repository,
- entry.oid);
+ struct tree *subtree = lookup_tree(r, entry.oid);
if (!subtree->object.parsed)
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
sub->cache_tree = cache_tree();
- prime_cache_tree_rec(sub->cache_tree, subtree);
+ prime_cache_tree_rec(r, sub->cache_tree, subtree);
cnt += sub->cache_tree->entry_count;
}
}
it->entry_count = cnt;
}
-void prime_cache_tree(struct index_state *istate, struct tree *tree)
+void prime_cache_tree(struct repository *r,
+ struct index_state *istate,
+ struct tree *tree)
{
cache_tree_free(&istate->cache_tree);
istate->cache_tree = cache_tree();
- prime_cache_tree_rec(istate->cache_tree, tree);
+ prime_cache_tree_rec(r, istate->cache_tree, tree);
istate->cache_changed |= CACHE_TREE_CHANGED;
}
return 0;
}
-static void verify_one(struct index_state *istate,
+static void verify_one(struct repository *r,
+ struct index_state *istate,
struct cache_tree *it,
struct strbuf *path)
{
for (i = 0; i < it->subtree_nr; i++) {
strbuf_addf(path, "%s/", it->down[i]->name);
- verify_one(istate, it->down[i]->cache_tree, path);
+ verify_one(r, istate, it->down[i]->cache_tree, path);
strbuf_setlen(path, len);
}
if (it->entry_count < 0 ||
/* no verification on tests (t7003) that replace trees */
- lookup_replace_object(the_repository, &it->oid) != &it->oid)
+ lookup_replace_object(r, &it->oid) != &it->oid)
return;
if (path->len) {
strbuf_release(&tree_buf);
}
-void cache_tree_verify(struct index_state *istate)
+void cache_tree_verify(struct repository *r, struct index_state *istate)
{
struct strbuf path = STRBUF_INIT;
if (!istate->cache_tree)
return;
- verify_one(istate, istate->cache_tree, &path);
+ verify_one(r, istate, istate->cache_tree, &path);
strbuf_release(&path);
}
int cache_tree_fully_valid(struct cache_tree *);
int cache_tree_update(struct index_state *, int);
-void cache_tree_verify(struct index_state *);
+void cache_tree_verify(struct repository *, struct index_state *);
/* bitmasks to write_cache_as_tree flags */
#define WRITE_TREE_MISSING_OK 1
#define WRITE_TREE_PREFIX_ERROR (-3)
int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix);
-void prime_cache_tree(struct index_state *, struct tree *);
+void prime_cache_tree(struct repository *, struct index_state *, struct tree *);
int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
#define CHECKOUT_INIT { NULL, "" }
#define TEMPORARY_FILENAME_LENGTH 25
-extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
+extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts);
extern void enable_delayed_checkout(struct checkout *state);
-extern int finish_delayed_checkout(struct checkout *state);
+extern int finish_delayed_checkout(struct checkout *state, int *nr_checkouts);
struct cache_def {
struct strbuf path;
if (!userdiff)
userdiff = userdiff_find_by_name("default");
if (opt->flags.allow_textconv)
- textconv = userdiff_get_textconv(userdiff);
+ textconv = userdiff_get_textconv(opt->repo, userdiff);
/* Read the result of merge first */
if (!working_tree_file)
#define GRAPH_OID_LEN GRAPH_OID_LEN_SHA1
#define GRAPH_OCTOPUS_EDGES_NEEDED 0x80000000
-#define GRAPH_PARENT_MISSING 0x7fffffff
#define GRAPH_EDGE_LAST_MASK 0x7fffffff
#define GRAPH_PARENT_NONE 0x70000000
*/
static int prepare_commit_graph(struct repository *r)
{
- struct alternate_object_database *alt;
- char *obj_dir;
+ struct object_directory *odb;
int config_value;
if (r->objects->commit_graph_attempted)
if (!commit_graph_compatible(r))
return 0;
- obj_dir = r->objects->objectdir;
- prepare_commit_graph_one(r, obj_dir);
prepare_alt_odb(r);
- for (alt = r->objects->alt_odb_list;
- !r->objects->commit_graph && alt;
- alt = alt->next)
- prepare_commit_graph_one(r, alt->path);
+ for (odb = r->objects->odb;
+ !r->objects->commit_graph && odb;
+ odb = odb->next)
+ prepare_commit_graph_one(r, odb->path);
return !!r->objects->commit_graph;
}
commit_to_sha1);
if (edge_value < 0)
- edge_value = GRAPH_PARENT_MISSING;
+ BUG("missing parent %s for commit %s",
+ oid_to_hex(&parent->item->object.oid),
+ oid_to_hex(&(*list)->object.oid));
}
hashwrite_be32(f, edge_value);
nr_commits,
commit_to_sha1);
if (edge_value < 0)
- edge_value = GRAPH_PARENT_MISSING;
+ BUG("missing parent %s for commit %s",
+ oid_to_hex(&parent->item->object.oid),
+ oid_to_hex(&(*list)->object.oid));
}
hashwrite_be32(f, edge_value);
commit_to_sha1);
if (edge_value < 0)
- edge_value = GRAPH_PARENT_MISSING;
+ BUG("missing parent %s for commit %s",
+ oid_to_hex(&parent->item->object.oid),
+ oid_to_hex(&(*list)->object.oid));
else if (!parent->next)
edge_value |= GRAPH_LAST_EDGE;
static void close_reachable(struct packed_oid_list *oids, int report_progress)
{
- int i;
+ int i, j;
struct commit *commit;
struct progress *progress = NULL;
- int j = 0;
if (report_progress)
progress = start_delayed_progress(
- _("Annotating commits in commit graph"), 0);
+ _("Loading known commits in commit graph"), j = 0);
for (i = 0; i < oids->nr; i++) {
display_progress(progress, ++j);
commit = lookup_commit(the_repository, &oids->list[i]);
if (commit)
commit->object.flags |= UNINTERESTING;
}
+ stop_progress(&progress);
/*
* As this loop runs, oids->nr may grow, but not more
* than the number of missing commits in the reachable
* closure.
*/
+ if (report_progress)
+ progress = start_delayed_progress(
+ _("Expanding reachable commits in commit graph"), j = 0);
for (i = 0; i < oids->nr; i++) {
display_progress(progress, ++j);
commit = lookup_commit(the_repository, &oids->list[i]);
if (commit && !parse_commit(commit))
add_missing_parents(oids, commit);
}
+ stop_progress(&progress);
+ if (report_progress)
+ progress = start_delayed_progress(
+ _("Clearing commit marks in commit graph"), j = 0);
for (i = 0; i < oids->nr; i++) {
display_progress(progress, ++j);
commit = lookup_commit(the_repository, &oids->list[i]);
count_distinct++;
}
- if (count_distinct >= GRAPH_PARENT_MISSING)
+ if (count_distinct >= GRAPH_EDGE_LAST_MASK)
die(_("the commit graph format cannot write %d commits"), count_distinct);
commits.nr = 0;
}
num_chunks = num_extra_edges ? 4 : 3;
- if (commits.nr >= GRAPH_PARENT_MISSING)
+ if (commits.nr >= GRAPH_EDGE_LAST_MASK)
die(_("too many commits to write graph"));
compute_generation_numbers(&commits, report_progress);
+++ /dev/null
-#include "../git-compat-util.h"
-#include "../cache.h"
-
-int cygwin_offset_1st_component(const char *path)
-{
- const char *pos = path;
- /* unc paths */
- if (is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
- /* skip server name */
- pos = strchr(pos + 2, '/');
- if (!pos)
- return 0; /* Error: malformed unc path */
-
- do {
- pos++;
- } while (*pos && pos[0] != '/');
- }
- return pos + is_dir_sep(*pos) - path;
-}
+++ /dev/null
-int cygwin_offset_1st_component(const char *path);
-#define offset_1st_component cygwin_offset_1st_component
return 0;
/* We cannot use basename(), as it would remove trailing slashes */
- mingw_skip_dos_drive_prefix((char **)&path);
+ win32_skip_dos_drive_prefix((char **)&path);
if (!*path)
return 0;
return -1;
}
-int mingw_skip_dos_drive_prefix(char **path)
-{
- int ret = has_dos_drive_prefix(*path);
- *path += ret;
- return ret;
-}
-
-int mingw_offset_1st_component(const char *path)
-{
- char *pos = (char *)path;
-
- /* unc paths */
- if (!skip_dos_drive_prefix(&pos) &&
- is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
- /* skip server name */
- pos = strpbrk(pos + 2, "\\/");
- if (!pos)
- return 0; /* Error: malformed unc path */
-
- do {
- pos++;
- } while (*pos && !is_dir_sep(*pos));
- }
-
- return pos + is_dir_sep(*pos) - path;
-}
-
int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
{
int upos = 0, wpos = 0;
* git specific compatibility
*/
-#define has_dos_drive_prefix(path) \
- (isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
-int mingw_skip_dos_drive_prefix(char **path);
-#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
-static inline int mingw_is_dir_sep(int c)
-{
- return c == '/' || c == '\\';
-}
-#define is_dir_sep mingw_is_dir_sep
-static inline char *mingw_find_last_dir_sep(const char *path)
-{
- char *ret = NULL;
- for (; *path; ++path)
- if (is_dir_sep(*path))
- ret = (char *)path;
- return ret;
-}
static inline void convert_slashes(char *path)
{
for (; *path; path++)
if (*path == '\\')
*path = '/';
}
-#define find_last_dir_sep mingw_find_last_dir_sep
-int mingw_offset_1st_component(const char *path);
-#define offset_1st_component mingw_offset_1st_component
#define PATH_SEP ';'
extern char *mingw_query_user_email(void);
#define query_user_email mingw_query_user_email
--- /dev/null
+#include "../../git-compat-util.h"
+
+int win32_skip_dos_drive_prefix(char **path)
+{
+ int ret = has_dos_drive_prefix(*path);
+ *path += ret;
+ return ret;
+}
+
+int win32_offset_1st_component(const char *path)
+{
+ char *pos = (char *)path;
+
+ /* unc paths */
+ if (!skip_dos_drive_prefix(&pos) &&
+ is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
+ /* skip server name */
+ pos = strpbrk(pos + 2, "\\/");
+ if (!pos)
+ return 0; /* Error: malformed unc path */
+
+ do {
+ pos++;
+ } while (*pos && !is_dir_sep(*pos));
+ }
+
+ return pos + is_dir_sep(*pos) - path;
+}
--- /dev/null
+#define has_dos_drive_prefix(path) \
+ (isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
+int win32_skip_dos_drive_prefix(char **path);
+#define skip_dos_drive_prefix win32_skip_dos_drive_prefix
+static inline int win32_is_dir_sep(int c)
+{
+ return c == '/' || c == '\\';
+}
+#define is_dir_sep win32_is_dir_sep
+static inline char *win32_find_last_dir_sep(const char *path)
+{
+ char *ret = NULL;
+ for (; *path; ++path)
+ if (is_dir_sep(*path))
+ ret = (char *)path;
+ return ret;
+}
+#define find_last_dir_sep win32_find_last_dir_sep
+int win32_offset_1st_component(const char *path);
+#define offset_1st_component win32_offset_1st_component
UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
MMAP_PREVENTS_DELETE = UnfortunatelyYes
- COMPAT_OBJS += compat/cygwin.o
+ COMPAT_OBJS += compat/win32/path-utils.o
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),FreeBSD)
HAVE_BSD_SYSCTL = YesPlease
HAVE_BSD_KERN_PROC_SYSCTL = YesPlease
PROCFS_EXECUTABLE_PATH = /proc/curproc/file
+ FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),MirBSD)
NO_STRCASESTR = YesPlease
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
+ compat/win32/path-utils.o \
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/dirent.o
BASIC_CFLAGS += -DWIN32 -DPROTECT_NTFS_DEFAULT=1
# Callers must take care of providing only paths that match the current path
# to be completed and adding any prefix path components, if necessary.
# 1: List of newline-separated matching paths, complete with all prefix
-# path componens.
+# path components.
__gitcomp_file_direct ()
{
local IFS=$'\n'
}
static int apply_single_file_filter(const char *path, const char *src, size_t len, int fd,
- struct strbuf *dst, const char *cmd)
+ struct strbuf *dst, const char *cmd)
{
/*
* Create a pipeline to have the command filter the buffer's
static void handle_filter_error(const struct strbuf *filter_status,
struct cmd2process *entry,
- const unsigned int wanted_capability) {
+ const unsigned int wanted_capability)
+{
if (!strcmp(filter_status->buf, "error"))
; /* The filter signaled a problem with the file. */
else if (!strcmp(filter_status->buf, "abort") && wanted_capability) {
}
static int ident_to_git(const char *path, const char *src, size_t len,
- struct strbuf *buf, int ident)
+ struct strbuf *buf, int ident)
{
char *dst, *dollar;
}
static int ident_to_worktree(const char *path, const char *src, size_t len,
- struct strbuf *buf, int ident)
+ struct strbuf *buf, int ident)
{
struct object_id oid;
char *to_free = NULL, *dollar, *spc;
}
static int read_request(FILE *fh, struct credential *c,
- struct strbuf *action, int *timeout) {
+ struct strbuf *action, int *timeout)
+{
static struct strbuf item = STRBUF_INIT;
const char *p;
island_bitmap_or(b, marks);
}
-static void mark_remote_island_1(struct remote_island *rl, int is_core_island)
+static void mark_remote_island_1(struct repository *r,
+ struct remote_island *rl,
+ int is_core_island)
{
uint32_t i;
for (i = 0; i < rl->oids.nr; ++i) {
struct island_bitmap *marks;
- struct object *obj = parse_object(the_repository, &rl->oids.oid[i]);
+ struct object *obj = parse_object(r, &rl->oids.oid[i]);
if (!obj)
continue;
while (obj && obj->type == OBJ_TAG) {
obj = ((struct tag *)obj)->tagged;
if (obj) {
- parse_object(the_repository, &obj->oid);
+ parse_object(r, &obj->oid);
marks = create_or_get_island_marks(obj);
island_bitmap_set(marks, island_counter);
}
return todo_a->depth - todo_b->depth;
}
-void resolve_tree_islands(int progress, struct packing_data *to_pack)
+void resolve_tree_islands(struct repository *r,
+ int progress,
+ struct packing_data *to_pack)
{
struct progress *progress_state = NULL;
struct tree_islands_todo *todo;
root_marks = kh_value(island_marks, pos);
- tree = lookup_tree(the_repository, &ent->idx.oid);
+ tree = lookup_tree(r, &ent->idx.oid);
if (!tree || parse_tree(tree) < 0)
die(_("bad tree object %s"), oid_to_hex(&ent->idx.oid));
if (S_ISGITLINK(entry.mode))
continue;
- obj = lookup_object(the_repository, entry.oid->hash);
+ obj = lookup_object(r, entry.oid->hash);
if (!obj)
continue;
return NULL;
}
-static void deduplicate_islands(void)
+static void deduplicate_islands(struct repository *r)
{
struct remote_island *island, *core = NULL, **list;
unsigned int island_count, dst, src, ref, i = 0;
core = get_core_island();
for (i = 0; i < island_count; ++i) {
- mark_remote_island_1(list[i], core && list[i]->hash == core->hash);
+ mark_remote_island_1(r, list[i], core && list[i]->hash == core->hash);
}
free(list);
}
-void load_delta_islands(void)
+void load_delta_islands(struct repository *r)
{
island_marks = kh_init_sha1();
remote_islands = kh_init_str();
git_config(island_config_callback, NULL);
for_each_ref(find_island_for_ref, NULL);
- deduplicate_islands();
+ deduplicate_islands(r);
fprintf(stderr, _("Marked %d islands, done.\n"), island_counter);
}
#ifndef DELTA_ISLANDS_H
#define DELTA_ISLANDS_H
+struct commit;
struct object_id;
struct packing_data;
-struct commit;
+struct repository;
int island_delta_cmp(const struct object_id *a, const struct object_id *b);
int in_same_island(const struct object_id *, const struct object_id *);
-void resolve_tree_islands(int progress, struct packing_data *to_pack);
-void load_delta_islands(void);
+void resolve_tree_islands(struct repository *r,
+ int progress,
+ struct packing_data *to_pack);
+void load_delta_islands(struct repository *r);
void propagate_island_marks(struct commit *commit);
int compute_pack_layers(struct packing_data *to_pack);
{
struct rev_info revs;
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(opt->repo, &revs, NULL);
copy_pathspec(&revs.prune_data, &opt->pathspec);
revs.diffopt = *opt;
return 0;
}
-int index_differs_from(const char *def, const struct diff_flags *flags,
+int index_differs_from(struct repository *r,
+ const char *def, const struct diff_flags *flags,
int ita_invisible_in_index)
{
struct rev_info rev;
struct setup_revision_opt opt;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(r, &rev, NULL);
memset(&opt, 0, sizeof(opt));
opt.def = def;
setup_revisions(0, NULL, &rev, &opt);
return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed-zebra', 'plain'"));
}
-static int parse_color_moved_ws(const char *arg)
+static unsigned parse_color_moved_ws(const char *arg)
{
int ret = 0;
struct string_list l = STRING_LIST_INIT_DUP;
ret |= XDF_IGNORE_WHITESPACE;
else if (!strcmp(sb.buf, "allow-indentation-change"))
ret |= COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE;
- else
- error(_("ignoring unknown color-moved-ws mode '%s'"), sb.buf);
+ else {
+ ret |= COLOR_MOVED_WS_ERROR;
+ error(_("unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', 'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"), sb.buf);
+ }
strbuf_release(&sb);
}
if ((ret & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) &&
- (ret & XDF_WHITESPACE_FLAGS))
- die(_("color-moved-ws: allow-indentation-change cannot be combined with other white space modes"));
+ (ret & XDF_WHITESPACE_FLAGS)) {
+ error(_("color-moved-ws: allow-indentation-change cannot be combined with other white space modes"));
+ ret |= COLOR_MOVED_WS_ERROR;
+ }
string_list_clear(&l, 0);
return 0;
}
if (!strcmp(var, "diff.colormovedws")) {
- int cm = parse_color_moved_ws(value);
- if (cm < 0)
+ unsigned cm = parse_color_moved_ws(value);
+ if (cm & COLOR_MOVED_WS_ERROR)
return -1;
diff_color_moved_ws_default = cm;
return 0;
strbuf_release(&msgbuf);
}
-static struct diff_tempfile *claim_diff_tempfile(void) {
+static struct diff_tempfile *claim_diff_tempfile(void)
+{
int i;
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
if (!diff_temp[i].name)
options->b_prefix = b;
}
-struct userdiff_driver *get_textconv(struct index_state *istate,
+struct userdiff_driver *get_textconv(struct repository *r,
struct diff_filespec *one)
{
if (!DIFF_FILE_VALID(one))
return NULL;
- diff_filespec_load_driver(one, istate);
- return userdiff_get_textconv(one->driver);
+ diff_filespec_load_driver(one, r->index);
+ return userdiff_get_textconv(r, one->driver);
}
static void builtin_diff(const char *name_a,
}
if (o->flags.allow_textconv) {
- textconv_one = get_textconv(o->repo->index, one);
- textconv_two = get_textconv(o->repo->index, two);
+ textconv_one = get_textconv(o->repo, one);
+ textconv_two = get_textconv(o->repo, two);
}
/* Never use a non-valid filename anywhere if at all possible */
return 0;
}
-static void enable_patch_output(int *fmt) {
+static void enable_patch_output(int *fmt)
+{
*fmt &= ~DIFF_FORMAT_NO_OUTPUT;
*fmt |= DIFF_FORMAT_PATCH;
}
else if (skip_prefix(arg, "--color-moved=", &arg)) {
int cm = parse_color_moved(arg);
if (cm < 0)
- die("bad --color-moved argument: %s", arg);
+ return error("bad --color-moved argument: %s", arg);
options->color_moved = cm;
} else if (skip_prefix(arg, "--color-moved-ws=", &arg)) {
- options->color_moved_ws_handling = parse_color_moved_ws(arg);
+ unsigned cm = parse_color_moved_ws(arg);
+ if (cm & COLOR_MOVED_WS_ERROR)
+ return -1;
+ options->color_moved_ws_handling = cm;
} else if (skip_to_optional_arg_default(arg, "--color-words", &options->word_regex, NULL)) {
options->use_color = 1;
options->word_diff = DIFF_WORDS_COLOR;
df = alloc_filespec(path);
fill_filespec(df, oid, oid_valid, mode);
- textconv = get_textconv(r->index, df);
+ textconv = get_textconv(r, df);
if (!textconv) {
free_filespec(df);
return 0;
/* XDF_WHITESPACE_FLAGS regarding block detection are set at 2, 3, 4 */
#define COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE (1<<5)
- int color_moved_ws_handling;
+ #define COLOR_MOVED_WS_ERROR (1<<0)
+ unsigned color_moved_ws_handling;
struct repository *repo;
};
void diff_no_index(struct repository *, struct rev_info *, int, const char **);
-int index_differs_from(const char *def, const struct diff_flags *flags,
+int index_differs_from(struct repository *r, const char *def,
+ const struct diff_flags *flags,
int ita_invisible_in_index);
/*
* and only if it has textconv enabled (otherwise return NULL). The result
* can be passed to fill_textconv().
*/
-struct userdiff_driver *get_textconv(struct index_state *istate,
+struct userdiff_driver *get_textconv(struct repository *r,
struct diff_filespec *one);
/*
return 0;
if (o->flags.allow_textconv) {
- textconv_one = get_textconv(o->repo->index, p->one);
- textconv_two = get_textconv(o->repo->index, p->two);
+ textconv_one = get_textconv(o->repo, p->one);
+ textconv_two = get_textconv(o->repo, p->two);
}
/*
if (textconv_one == textconv_two && diff_unmodified_pair(p))
return 0;
+ if ((o->pickaxe_opts & DIFF_PICKAXE_KIND_G) &&
+ !o->flags.text &&
+ ((!textconv_one && diff_filespec_is_binary(o->repo, p->one)) ||
+ (!textconv_two && diff_filespec_is_binary(o->repo, p->two))))
+ return 0;
+
mf1.size = fill_textconv(o->repo, textconv_one, p->one, &mf1.ptr);
mf2.size = fill_textconv(o->repo, textconv_two, p->two, &mf2.ptr);
#define DO_MATCH_DIRECTORY (1<<1)
#define DO_MATCH_SUBMODULE (1<<2)
-static int match_attrs(const struct index_state *istate,
- const char *name, int namelen,
- const struct pathspec_item *item)
-{
- int i;
- char *to_free = NULL;
-
- if (name[namelen])
- name = to_free = xmemdupz(name, namelen);
-
- git_check_attr(istate, name, item->attr_check);
-
- free(to_free);
-
- for (i = 0; i < item->attr_match_nr; i++) {
- const char *value;
- int matched;
- enum attr_match_mode match_mode;
-
- value = item->attr_check->items[i].value;
- match_mode = item->attr_match[i].match_mode;
-
- if (ATTR_TRUE(value))
- matched = (match_mode == MATCH_SET);
- else if (ATTR_FALSE(value))
- matched = (match_mode == MATCH_UNSET);
- else if (ATTR_UNSET(value))
- matched = (match_mode == MATCH_UNSPECIFIED);
- else
- matched = (match_mode == MATCH_VALUE &&
- !strcmp(item->attr_match[i].value, value));
- if (!matched)
- return 0;
- }
-
- return 1;
-}
-
/*
* Does 'match' match the given name?
* A match is found if
strncmp(item->match, name - prefix, item->prefix))
return 0;
- if (item->attr_match_nr && !match_attrs(istate, name, namelen, item))
+ if (item->attr_match_nr &&
+ !match_pathspec_attrs(istate, name, namelen, item))
return 0;
/* If the match was just the prefix, we matched */
return !available;
}
-int finish_delayed_checkout(struct checkout *state)
+int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
{
int errs = 0;
unsigned delayed_object_count;
ce = index_file_exists(state->istate, path->string,
strlen(path->string), 0);
if (ce) {
- errs |= checkout_entry(ce, state, NULL);
+ errs |= checkout_entry(ce, state, NULL, nr_checkouts);
filtered_bytes += ce->ce_stat_data.sd_size;
display_throughput(progress, filtered_bytes);
} else
* its name is returned in topath[], which must be able to hold at
* least TEMPORARY_FILENAME_LENGTH bytes long.
*/
-int checkout_entry(struct cache_entry *ce,
- const struct checkout *state, char *topath)
+int checkout_entry(struct cache_entry *ce, const struct checkout *state,
+ char *topath, int *nr_checkouts)
{
static struct strbuf path = STRBUF_INIT;
struct stat st;
return 0;
create_directories(path.buf, path.len, state);
+ if (nr_checkouts)
+ (*nr_checkouts)++;
return write_entry(ce, path.buf, state, 0);
}
char *get_object_directory(void)
{
- if (!the_repository->objects->objectdir)
+ if (!the_repository->objects->odb)
BUG("git environment hasn't been setup");
- return the_repository->objects->objectdir;
+ return the_repository->objects->odb->path;
}
int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
-/*
-(See Documentation/git-fast-import.txt for maintained documentation.)
-Format of STDIN stream:
-
- stream ::= cmd*;
-
- cmd ::= new_blob
- | new_commit
- | new_tag
- | reset_branch
- | checkpoint
- | progress
- ;
-
- new_blob ::= 'blob' lf
- mark?
- file_content;
- file_content ::= data;
-
- new_commit ::= 'commit' sp ref_str lf
- mark?
- ('author' (sp name)? sp '<' email '>' sp when lf)?
- 'committer' (sp name)? sp '<' email '>' sp when lf
- commit_msg
- ('from' sp commit-ish lf)?
- ('merge' sp commit-ish lf)*
- (file_change | ls)*
- lf?;
- commit_msg ::= data;
-
- ls ::= 'ls' sp '"' quoted(path) '"' lf;
-
- file_change ::= file_clr
- | file_del
- | file_rnm
- | file_cpy
- | file_obm
- | file_inm;
- file_clr ::= 'deleteall' lf;
- file_del ::= 'D' sp path_str lf;
- file_rnm ::= 'R' sp path_str sp path_str lf;
- file_cpy ::= 'C' sp path_str sp path_str lf;
- file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
- file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
- data;
- note_obm ::= 'N' sp (hexsha1 | idnum) sp commit-ish lf;
- note_inm ::= 'N' sp 'inline' sp commit-ish lf
- data;
-
- new_tag ::= 'tag' sp tag_str lf
- 'from' sp commit-ish lf
- ('tagger' (sp name)? sp '<' email '>' sp when lf)?
- tag_msg;
- tag_msg ::= data;
-
- reset_branch ::= 'reset' sp ref_str lf
- ('from' sp commit-ish lf)?
- lf?;
-
- checkpoint ::= 'checkpoint' lf
- lf?;
-
- progress ::= 'progress' sp not_lf* lf
- lf?;
-
- # note: the first idnum in a stream should be 1 and subsequent
- # idnums should not have gaps between values as this will cause
- # the stream parser to reserve space for the gapped values. An
- # idnum can be updated in the future to a new object by issuing
- # a new mark directive with the old idnum.
- #
- mark ::= 'mark' sp idnum lf;
- data ::= (delimited_data | exact_data)
- lf?;
-
- # note: delim may be any string but must not contain lf.
- # data_line may contain any data but must not be exactly
- # delim.
- delimited_data ::= 'data' sp '<<' delim lf
- (data_line lf)*
- delim lf;
-
- # note: declen indicates the length of binary_data in bytes.
- # declen does not include the lf preceding the binary data.
- #
- exact_data ::= 'data' sp declen lf
- binary_data;
-
- # note: quoted strings are C-style quoting supporting \c for
- # common escapes of 'c' (e..g \n, \t, \\, \") or \nnn where nnn
- # is the signed byte value in octal. Note that the only
- # characters which must actually be escaped to protect the
- # stream formatting is: \, " and LF. Otherwise these values
- # are UTF8.
- #
- commit-ish ::= (ref_str | hexsha1 | sha1exp_str | idnum);
- ref_str ::= ref;
- sha1exp_str ::= sha1exp;
- tag_str ::= tag;
- path_str ::= path | '"' quoted(path) '"' ;
- mode ::= '100644' | '644'
- | '100755' | '755'
- | '120000'
- ;
-
- declen ::= # unsigned 32 bit value, ascii base10 notation;
- bigint ::= # unsigned integer value, ascii base10 notation;
- binary_data ::= # file content, not interpreted;
-
- when ::= raw_when | rfc2822_when;
- raw_when ::= ts sp tz;
- rfc2822_when ::= # Valid RFC 2822 date and time;
-
- sp ::= # ASCII space character;
- lf ::= # ASCII newline (LF) character;
-
- # note: a colon (':') must precede the numerical value assigned to
- # an idnum. This is to distinguish it from a ref or tag name as
- # GIT does not permit ':' in ref or tag strings.
- #
- idnum ::= ':' bigint;
- path ::= # GIT style file path, e.g. "a/b/c";
- ref ::= # GIT ref name, e.g. "refs/heads/MOZ_GECKO_EXPERIMENT";
- tag ::= # GIT tag name, e.g. "FIREFOX_1_5";
- sha1exp ::= # Any valid GIT SHA1 expression;
- hexsha1 ::= # SHA1 in hexadecimal format;
-
- # note: name and email are UTF8 strings, however name must not
- # contain '<' or lf and email must not contain any of the
- # following: '<', '>', lf.
- #
- name ::= # valid GIT author/committer name;
- email ::= # valid GIT author/committer email;
- ts ::= # time since the epoch in seconds, ascii base10 notation;
- tz ::= # GIT style timezone;
-
- # note: comments, get-mark, ls-tree, and cat-blob requests may
- # appear anywhere in the input, except within a data command. Any
- # form of the data command always escapes the related input from
- # comment processing.
- #
- # In case it is not clear, the '#' that starts the comment
- # must be the first character on that line (an lf
- # preceded it).
- #
-
- get_mark ::= 'get-mark' sp idnum lf;
- cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
- ls_tree ::= 'ls' sp (hexsha1 | idnum) sp path_str lf;
-
- comment ::= '#' not_lf* lf;
- not_lf ::= # Any byte that is not ASCII newline (LF);
-*/
-
#include "builtin.h"
#include "cache.h"
#include "repository.h"
next_mark = 0;
}
+static void parse_original_identifier(void)
+{
+ const char *v;
+ if (skip_prefix(command_buf.buf, "original-oid ", &v))
+ read_next_command();
+}
+
static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
{
const char *data;
{
read_next_command();
parse_mark();
+ parse_original_identifier();
parse_and_store_blob(&last_blob, NULL, next_mark);
}
read_next_command();
parse_mark();
+ parse_original_identifier();
if (skip_prefix(command_buf.buf, "author ", &v)) {
author = parse_ident(v);
read_next_command();
die("Invalid ref name or SHA1 expression: %s", from);
read_next_command();
+ /* original-oid ... */
+ parse_original_identifier();
+
/* tagger ... */
if (skip_prefix(command_buf.buf, "tagger ", &v)) {
tagger = parse_ident(v);
struct ref *refs;
};
-/*
- * If the number of refs is not larger than the number of loose objects,
- * this function stops inserting.
- */
-static int add_loose_objects_to_set(const struct object_id *oid,
- const char *path,
- void *data)
-{
- struct loose_object_iter *iter = data;
- oidset_insert(iter->loose_object_set, oid);
- if (iter->refs == NULL)
- return 1;
-
- iter->refs = iter->refs->next;
- return 0;
-}
-
/*
* Mark recent commits available locally and reachable from a local ref as
* COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
struct ref *ref;
int old_save_commit_buffer = save_commit_buffer;
timestamp_t cutoff = 0;
- struct oidset loose_oid_set = OIDSET_INIT;
- int use_oidset = 0;
- struct loose_object_iter iter = {&loose_oid_set, *refs};
-
- /* Enumerate all loose objects or know refs are not so many. */
- use_oidset = !for_each_loose_object(add_loose_objects_to_set,
- &iter, 0);
save_commit_buffer = 0;
for (ref = *refs; ref; ref = ref->next) {
struct object *o;
- unsigned int flags = OBJECT_INFO_QUICK;
- if (use_oidset &&
- !oidset_contains(&loose_oid_set, &ref->old_oid)) {
- /*
- * I know this does not exist in the loose form,
- * so check if it exists in a non-loose form.
- */
- flags |= OBJECT_INFO_IGNORE_LOOSE;
- }
-
- if (!has_object_file_with_flags(&ref->old_oid, flags))
+ if (!has_object_file_with_flags(&ref->old_oid,
+ OBJECT_INFO_QUICK))
continue;
o = parse_object(the_repository, &ref->old_oid);
if (!o)
}
}
- oidset_clear(&loose_oid_set);
-
if (!args->deepen) {
for_each_ref(mark_complete_oid, NULL);
for_each_cached_alternate(NULL, mark_alternate_complete);
#endif
#if defined(__CYGWIN__)
-#include "compat/cygwin.h"
+#include "compat/win32/path-utils.h"
#endif
#if defined(__MINGW32__)
/* pull in Windows compatibility stuff */
+#include "compat/win32/path-utils.h"
#include "compat/mingw.h"
#elif defined(_MSC_VER)
#include "compat/msvc.h"
#ifdef NO_MEMMEM
#define memmem gitmemmem
void *gitmemmem(const void *haystack, size_t haystacklen,
- const void *needle, size_t needlelen);
+ const void *needle, size_t needlelen);
#endif
#ifdef OVERRIDE_STRDUP
author= author name and email address for patches without any
patches= path to the quilt patches
series= path to the quilt series file
+keep-non-patch Pass -b to git mailinfo
"
SUBDIRECTORY_ON=Yes
. git-sh-setup
shift
QUILT_SERIES="$1"
;;
+ --keep-non-patch)
+ MAILINFO_OPT="-b"
+ ;;
--)
shift
break;;
continue
fi
echo $patch_name
- git mailinfo "$tmp_msg" "$tmp_patch" \
+ git mailinfo $MAILINFO_OPT "$tmp_msg" "$tmp_patch" \
<"$QUILT_PATCHES/$patch_name" >"$tmp_info" || exit 3
test -s "$tmp_patch" || {
echo "Patch is empty. Was it split wrong?"
git ls-files -o $z $excl_opt -- "$@"
}
+prepare_fallback_ident () {
+ if ! git -c user.useconfigonly=yes var GIT_COMMITTER_IDENT >/dev/null 2>&1
+ then
+ GIT_AUTHOR_NAME="git stash"
+ GIT_AUTHOR_EMAIL=git@stash
+ GIT_COMMITTER_NAME="git stash"
+ GIT_COMMITTER_EMAIL=git@stash
+ export GIT_AUTHOR_NAME
+ export GIT_AUTHOR_EMAIL
+ export GIT_COMMITTER_NAME
+ export GIT_COMMITTER_EMAIL
+ fi
+}
+
clear_stash () {
if test $# != 0
then
}
create_stash () {
+
+ prepare_fallback_ident
+
stash_msg=
untracked=
while test $# != 0
return 0;
}
-static void commit_pager_choice(void) {
+static void commit_pager_choice(void)
+{
switch (use_pager) {
case 0:
setenv("GIT_PAGER", "cat", 1);
if (ret >= 0) /* normal exit */
exit(ret);
- die_errno("while expanding alias '%s': '%s'",
- alias_command, alias_string + 1);
+ die_errno(_("while expanding alias '%s': '%s'"),
+ alias_command, alias_string + 1);
}
count = split_cmdline(alias_string, &new_argv);
if (count < 0)
- die("Bad alias.%s string: %s", alias_command,
- split_cmdline_strerror(count));
+ die(_("bad alias.%s string: %s"), alias_command,
+ _(split_cmdline_strerror(count)));
option_count = handle_options(&new_argv, &count, &envchanged);
if (envchanged)
- die("alias '%s' changes environment variables.\n"
- "You can use '!git' in the alias to do this",
- alias_command);
+ die(_("alias '%s' changes environment variables.\n"
+ "You can use '!git' in the alias to do this"),
+ alias_command);
memmove(new_argv - option_count, new_argv,
count * sizeof(char *));
new_argv -= option_count;
if (count < 1)
- die("empty alias for %s", alias_command);
+ die(_("empty alias for %s"), alias_command);
if (!strcmp(alias_command, new_argv[0]))
- die("recursive alias: %s", alias_command);
+ die(_("recursive alias: %s"), alias_command);
trace_argv_printf(new_argv,
"trace: alias expansion: %s =>",
if (!help && get_super_prefix()) {
if (!(p->option & SUPPORT_SUPER_PREFIX))
- die("%s doesn't support --super-prefix", p->cmd);
+ die(_("%s doesn't support --super-prefix"), p->cmd);
}
if (!help && p->option & NEED_WORK_TREE)
/* Check for ENOSPC and EIO errors.. */
if (fflush(stdout))
- die_errno("write failure on standard output");
+ die_errno(_("write failure on standard output"));
if (ferror(stdout))
- die("unknown write failure on standard output");
+ die(_("unknown write failure on standard output"));
if (fclose(stdout))
- die_errno("close failed on standard output");
+ die_errno(_("close failed on standard output"));
return 0;
}
int status;
if (get_super_prefix())
- die("%s doesn't support --super-prefix", argv[0]);
+ die(_("%s doesn't support --super-prefix"), argv[0]);
if (use_pager == -1 && !is_builtin(argv[0]))
use_pager = check_pager_config(argv[0]);
if (skip_prefix(cmd, "git-", &cmd)) {
argv[0] = cmd;
handle_builtin(argc, argv);
- die("cannot handle %s as a builtin", cmd);
+ die(_("cannot handle %s as a builtin"), cmd);
}
/* Look for flags.. */
} else {
/* The user didn't specify a command; give them help */
commit_pager_choice();
- printf("usage: %s\n\n", git_usage_string);
+ printf(_("usage: %s\n\n"), git_usage_string);
list_common_cmds_help();
printf("\n%s\n", _(git_more_info_string));
exit(1);
* is not thread-safe.
*/
grep_attr_lock();
- textconv = userdiff_get_textconv(gs->driver);
+ textconv = userdiff_get_textconv(opt->repo, gs->driver);
grep_attr_unlock();
}
if (buffer_input || gzipped_request || req_len >= 0)
cld.in = -1;
cld.git_cmd = 1;
+ cld.clean_on_exit = 1;
+ cld.wait_after_clean = 1;
if (start_command(&cld))
exit(1);
ret = error("File %s has bad hash", hex);
} else if (req->rename < 0) {
struct strbuf buf = STRBUF_INIT;
- sha1_file_name(the_repository, &buf, req->sha1);
+ loose_object_path(the_repository, &buf, req->sha1);
ret = error("unable to write sha1 filename %s", buf.buf);
strbuf_release(&buf);
}
static int curl_ssl_verify = -1;
static int curl_ssl_try;
+static const char *curl_http_version = NULL;
static const char *ssl_cert;
static const char *ssl_cipherlist;
static const char *ssl_version;
static int http_options(const char *var, const char *value, void *cb)
{
+ if (!strcmp("http.version", var)) {
+ return git_config_string(&curl_http_version, var, value);
+ }
if (!strcmp("http.sslverify", var)) {
curl_ssl_verify = git_config_bool(var, value);
return 0;
}
#endif
+#if LIBCURL_VERSION_NUM >=0x072f00
+static int get_curl_http_version_opt(const char *version_string, long *opt)
+{
+ int i;
+ static struct {
+ const char *name;
+ long opt_token;
+ } choice[] = {
+ { "HTTP/1.1", CURL_HTTP_VERSION_1_1 },
+ { "HTTP/2", CURL_HTTP_VERSION_2 }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(choice); i++) {
+ if (!strcmp(version_string, choice[i].name)) {
+ *opt = choice[i].opt_token;
+ return 0;
+ }
+ }
+
+ warning("unknown value given to http.version: '%s'", version_string);
+ return -1; /* not found */
+}
+
+#endif
+
static CURL *get_curl_handle(void)
{
CURL *result = curl_easy_init();
curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2);
}
+#if LIBCURL_VERSION_NUM >= 0x072f00 // 7.47.0
+ if (curl_http_version) {
+ long opt;
+ if (!get_curl_http_version_opt(curl_http_version, &opt)) {
+ /* Set request use http version */
+ curl_easy_setopt(result, CURLOPT_HTTP_VERSION, opt);
+ }
+ }
+#endif
+
#if LIBCURL_VERSION_NUM >= 0x070907
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
#endif
hashcpy(freq->sha1, sha1);
freq->localfile = -1;
- sha1_file_name(the_repository, &filename, sha1);
+ loose_object_path(the_repository, &filename, sha1);
strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
strbuf_addf(&prevfile, "%s.prev", filename.buf);
unlink_or_warn(freq->tmpfile.buf);
return -1;
}
- sha1_file_name(the_repository, &filename, freq->sha1);
+ loose_object_path(the_repository, &filename, freq->sha1);
freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
strbuf_release(&filename);
}
static int curl_append_msgs_to_imap(struct imap_server_conf *server,
- struct strbuf* all_msgs, int total) {
+ struct strbuf* all_msgs, int total)
+{
int ofs = 0;
int n = 0;
struct buffer msgbuf = { STRBUF_INIT, 0 };
struct object *obj = revs->pending.objects[i].item;
if (obj->flags & UNINTERESTING)
continue;
- obj = deref_tag(the_repository, obj, NULL, 0);
+ obj = deref_tag(revs->repo, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (commit)
};
static enum list_objects_filter_result filter_blobs_none(
+ struct repository *r,
enum list_objects_filter_situation filter_situation,
struct object *obj,
const char *pathname,
};
static enum list_objects_filter_result filter_trees_none(
+ struct repository *r,
enum list_objects_filter_situation filter_situation,
struct object *obj,
const char *pathname,
};
static enum list_objects_filter_result filter_blobs_limit(
+ struct repository *r,
enum list_objects_filter_situation filter_situation,
struct object *obj,
const char *pathname,
assert(obj->type == OBJ_BLOB);
assert((obj->flags & SEEN) == 0);
- t = oid_object_info(the_repository, &obj->oid, &object_length);
+ t = oid_object_info(r, &obj->oid, &object_length);
if (t != OBJ_BLOB) { /* probably OBJ_NONE */
/*
* We DO NOT have the blob locally, so we cannot
};
static enum list_objects_filter_result filter_sparse(
+ struct repository *r,
enum list_objects_filter_situation filter_situation,
struct object *obj,
const char *pathname,
dtype = DT_DIR;
val = is_excluded_from_list(pathname, strlen(pathname),
filename, &dtype, &filter_data->el,
- &the_index);
+ r->index);
if (val < 0)
val = filter_data->array_frame[filter_data->nr].defval;
dtype = DT_REG;
val = is_excluded_from_list(pathname, strlen(pathname),
filename, &dtype, &filter_data->el,
- &the_index);
+ r->index);
if (val < 0)
val = frame->defval;
if (val > 0) {
struct list_objects_filter_options;
struct object;
struct oidset;
+struct repository;
/*
* During list-object traversal we allow certain objects to be
};
typedef enum list_objects_filter_result (*filter_object_fn)(
+ struct repository *r,
enum list_objects_filter_situation filter_situation,
struct object *obj,
const char *pathname,
pathlen = path->len;
strbuf_addstr(path, name);
if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn)
- r = ctx->filter_fn(LOFS_BLOB, obj,
+ r = ctx->filter_fn(ctx->revs->repo,
+ LOFS_BLOB, obj,
path->buf, &path->buf[pathlen],
ctx->filter_data);
if (r & LOFR_MARK_SEEN)
while (tree_entry(&desc, &entry)) {
if (match != all_entries_interesting) {
- match = tree_entry_interesting(&entry, base, 0,
+ match = tree_entry_interesting(ctx->revs->repo->index,
+ &entry, base, 0,
&ctx->revs->diffopt.pathspec);
if (match == all_entries_not_interesting)
break;
}
if (S_ISDIR(entry.mode)) {
- struct tree *t = lookup_tree(the_repository, entry.oid);
+ struct tree *t = lookup_tree(ctx->revs->repo, entry.oid);
t->object.flags |= NOT_USER_GIVEN;
process_tree(ctx, t, base, entry.path);
}
process_gitlink(ctx, entry.oid->hash,
base, entry.path);
else {
- struct blob *b = lookup_blob(the_repository, entry.oid);
+ struct blob *b = lookup_blob(ctx->revs->repo, entry.oid);
b->object.flags |= NOT_USER_GIVEN;
process_blob(ctx, b, base, entry.path);
}
strbuf_addstr(base, name);
if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn)
- r = ctx->filter_fn(LOFS_BEGIN_TREE, obj,
+ r = ctx->filter_fn(ctx->revs->repo,
+ LOFS_BEGIN_TREE, obj,
base->buf, &base->buf[baselen],
ctx->filter_data);
if (r & LOFR_MARK_SEEN)
process_tree_contents(ctx, tree, base);
if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn) {
- r = ctx->filter_fn(LOFS_END_TREE, obj,
+ r = ctx->filter_fn(ctx->revs->repo,
+ LOFS_END_TREE, obj,
base->buf, &base->buf[baselen],
ctx->filter_data);
if (r & LOFR_MARK_SEEN)
if (opts->virtual_ancestor) {
if (driver->recursive)
driver = find_ll_merge_driver(driver->recursive);
- marker_size += 2;
+ }
+ if (opts->extra_marker_size) {
+ marker_size += opts->extra_marker_size;
}
return driver->fn(driver, result_buf, path, ancestor, ancestor_label,
ours, our_label, theirs, their_label,
unsigned virtual_ancestor : 1;
unsigned variant : 2; /* favor ours, favor theirs, or union merge */
unsigned renormalize : 1;
+ unsigned extra_marker_size;
long xdl_opts;
};
enum rename_type {
RENAME_NORMAL = 0,
RENAME_VIA_DIR,
+ RENAME_ADD,
RENAME_DELETE,
RENAME_ONE_FILE_TO_ONE,
RENAME_ONE_FILE_TO_TWO,
struct stage_data *src_entry1,
struct stage_data *src_entry2)
{
+ int ostage1 = 0, ostage2;
struct rename_conflict_info *ci;
/*
dst_entry2->rename_conflict_info = ci;
}
- if (rename_type == RENAME_TWO_FILES_TO_ONE) {
- /*
- * For each rename, there could have been
- * modifications on the side of history where that
- * file was not renamed.
- */
- int ostage1 = o->branch1 == branch1 ? 3 : 2;
- int ostage2 = ostage1 ^ 1;
+ /*
+ * For each rename, there could have been
+ * modifications on the side of history where that
+ * file was not renamed.
+ */
+ if (rename_type == RENAME_ADD ||
+ rename_type == RENAME_TWO_FILES_TO_ONE) {
+ ostage1 = o->branch1 == branch1 ? 3 : 2;
ci->ren1_other.path = pair1->one->path;
oidcpy(&ci->ren1_other.oid, &src_entry1->stages[ostage1].oid);
ci->ren1_other.mode = src_entry1->stages[ostage1].mode;
+ }
+
+ if (rename_type == RENAME_TWO_FILES_TO_ONE) {
+ ostage2 = ostage1 ^ 1;
ci->ren2_other.path = pair2->one->path;
oidcpy(&ci->ren2_other.oid, &src_entry2->stages[ostage2].oid);
{
struct pathspec match_all;
memset(&match_all, 0, sizeof(match_all));
- read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o);
+ read_tree_recursive(the_repository, tree, "", 0, 0,
+ &match_all, save_files_dirs, o);
}
static int get_tree_entry_if_blob(const struct object_id *tree,
return 0;
}
-static int update_stages_for_stage_data(struct merge_options *opt,
- const char *path,
- const struct stage_data *stage_data)
-{
- struct diff_filespec o, a, b;
-
- o.mode = stage_data->stages[1].mode;
- oidcpy(&o.oid, &stage_data->stages[1].oid);
-
- a.mode = stage_data->stages[2].mode;
- oidcpy(&a.oid, &stage_data->stages[2].oid);
-
- b.mode = stage_data->stages[3].mode;
- oidcpy(&b.oid, &stage_data->stages[3].oid);
-
- return update_stages(opt, path,
- is_null_oid(&o.oid) ? NULL : &o,
- is_null_oid(&a.oid) ? NULL : &a,
- is_null_oid(&b.oid) ? NULL : &b);
-}
-
static void update_entry(struct stage_data *entry,
struct diff_filespec *o,
struct diff_filespec *a,
const struct diff_filespec *a,
const struct diff_filespec *b,
const char *branch1,
- const char *branch2)
+ const char *branch2,
+ const int extra_marker_size)
{
mmfile_t orig, src1, src2;
struct ll_merge_options ll_opts = {0};
int merge_status;
ll_opts.renormalize = o->renormalize;
+ ll_opts.extra_marker_size = extra_marker_size;
ll_opts.xdl_opts = o->xdl_opts;
if (o->call_depth) {
const char *filename,
const char *branch1,
const char *branch2,
+ const int extra_marker_size,
struct merge_file_info *result)
{
if (o->branch1 != branch1) {
*/
return merge_mode_and_contents(o, one, b, a,
filename,
- branch2, branch1, result);
+ branch2, branch1,
+ extra_marker_size, result);
}
result->merge = 0;
int ret = 0, merge_status;
merge_status = merge_3way(o, &result_buf, one, a, b,
- branch1, branch2);
+ branch1, branch2,
+ extra_marker_size);
if ((merge_status < 0) || !result_buf.ptr)
ret = err(o, _("Failed to execute internal merge"));
return target;
}
-static int handle_file(struct merge_options *o,
- struct diff_filespec *rename,
- int stage,
- struct rename_conflict_info *ci)
+static int handle_file_collision(struct merge_options *o,
+ const char *collide_path,
+ const char *prev_path1,
+ const char *prev_path2,
+ const char *branch1, const char *branch2,
+ const struct object_id *a_oid,
+ unsigned int a_mode,
+ const struct object_id *b_oid,
+ unsigned int b_mode)
{
- char *dst_name = rename->path;
- struct stage_data *dst_entry;
- const char *cur_branch, *other_branch;
- struct diff_filespec other;
- struct diff_filespec *add;
- int ret;
+ struct merge_file_info mfi;
+ struct diff_filespec null, a, b;
+ char *alt_path = NULL;
+ const char *update_path = collide_path;
- if (stage == 2) {
- dst_entry = ci->dst_entry1;
- cur_branch = ci->branch1;
- other_branch = ci->branch2;
- } else {
- dst_entry = ci->dst_entry2;
- cur_branch = ci->branch2;
- other_branch = ci->branch1;
+ /*
+ * It's easiest to get the correct things into stage 2 and 3, and
+ * to make sure that the content merge puts HEAD before the other
+ * branch if we just ensure that branch1 == o->branch1. So, simply
+ * flip arguments around if we don't have that.
+ */
+ if (branch1 != o->branch1) {
+ return handle_file_collision(o, collide_path,
+ prev_path2, prev_path1,
+ branch2, branch1,
+ b_oid, b_mode,
+ a_oid, a_mode);
}
- add = filespec_from_entry(&other, dst_entry, stage ^ 1);
- if (add) {
- int ren_src_was_dirty = was_dirty(o, rename->path);
- char *add_name = unique_path(o, rename->path, other_branch);
- if (update_file(o, 0, &add->oid, add->mode, add_name))
- return -1;
+ /*
+ * In the recursive case, we just opt to undo renames
+ */
+ if (o->call_depth && (prev_path1 || prev_path2)) {
+ /* Put first file (a_oid, a_mode) in its original spot */
+ if (prev_path1) {
+ if (update_file(o, 1, a_oid, a_mode, prev_path1))
+ return -1;
+ } else {
+ if (update_file(o, 1, a_oid, a_mode, collide_path))
+ return -1;
+ }
- if (ren_src_was_dirty) {
- output(o, 1, _("Refusing to lose dirty file at %s"),
- rename->path);
+ /* Put second file (b_oid, b_mode) in its original spot */
+ if (prev_path2) {
+ if (update_file(o, 1, b_oid, b_mode, prev_path2))
+ return -1;
+ } else {
+ if (update_file(o, 1, b_oid, b_mode, collide_path))
+ return -1;
}
+
+ /* Don't leave something at collision path if unrenaming both */
+ if (prev_path1 && prev_path2)
+ remove_file(o, 1, collide_path, 0);
+
+ return 0;
+ }
+
+ /* Remove rename sources if rename/add or rename/rename(2to1) */
+ if (prev_path1)
+ remove_file(o, 1, prev_path1,
+ o->call_depth || would_lose_untracked(prev_path1));
+ if (prev_path2)
+ remove_file(o, 1, prev_path2,
+ o->call_depth || would_lose_untracked(prev_path2));
+
+ /*
+ * Remove the collision path, if it wouldn't cause dirty contents
+ * or an untracked file to get lost. We'll either overwrite with
+ * merged contents, or just write out to differently named files.
+ */
+ if (was_dirty(o, collide_path)) {
+ output(o, 1, _("Refusing to lose dirty file at %s"),
+ collide_path);
+ update_path = alt_path = unique_path(o, collide_path, "merged");
+ } else if (would_lose_untracked(collide_path)) {
/*
- * Because the double negatives somehow keep confusing me...
- * 1) update_wd iff !ren_src_was_dirty.
- * 2) no_wd iff !update_wd
- * 3) so, no_wd == !!ren_src_was_dirty == ren_src_was_dirty
+ * Only way we get here is if both renames were from
+ * a directory rename AND user had an untracked file
+ * at the location where both files end up after the
+ * two directory renames. See testcase 10d of t6043.
*/
- remove_file(o, 0, rename->path, ren_src_was_dirty);
- dst_name = unique_path(o, rename->path, cur_branch);
+ output(o, 1, _("Refusing to lose untracked file at "
+ "%s, even though it's in the way."),
+ collide_path);
+ update_path = alt_path = unique_path(o, collide_path, "merged");
} else {
- if (dir_in_way(rename->path, !o->call_depth, 0)) {
- dst_name = unique_path(o, rename->path, cur_branch);
- output(o, 1, _("%s is a directory in %s adding as %s instead"),
- rename->path, other_branch, dst_name);
- } else if (!o->call_depth &&
- would_lose_untracked(rename->path)) {
- dst_name = unique_path(o, rename->path, cur_branch);
- output(o, 1, _("Refusing to lose untracked file at %s; "
- "adding as %s instead"),
- rename->path, dst_name);
- }
+ /*
+ * FIXME: It's possible that the two files are identical
+ * and that the current working copy happens to match, in
+ * which case we are unnecessarily touching the working
+ * tree file. It's not a likely enough scenario that I
+ * want to code up the checks for it and a better fix is
+ * available if we restructure how unpack_trees() and
+ * merge-recursive interoperate anyway, so punting for
+ * now...
+ */
+ remove_file(o, 0, collide_path, 0);
}
- if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
- ; /* fall through, do allow dst_name to be released */
- else if (stage == 2)
- ret = update_stages(o, rename->path, NULL, rename, add);
- else
- ret = update_stages(o, rename->path, NULL, add, rename);
- if (dst_name != rename->path)
- free(dst_name);
+ /* Store things in diff_filespecs for functions that need it */
+ memset(&a, 0, sizeof(struct diff_filespec));
+ memset(&b, 0, sizeof(struct diff_filespec));
+ null.path = a.path = b.path = (char *)collide_path;
+ oidcpy(&null.oid, &null_oid);
+ null.mode = 0;
+ oidcpy(&a.oid, a_oid);
+ a.mode = a_mode;
+ a.oid_valid = 1;
+ oidcpy(&b.oid, b_oid);
+ b.mode = b_mode;
+ b.oid_valid = 1;
- return ret;
+ if (merge_mode_and_contents(o, &null, &a, &b, collide_path,
+ branch1, branch2, o->call_depth * 2, &mfi))
+ return -1;
+ mfi.clean &= !alt_path;
+ if (update_file(o, mfi.clean, &mfi.oid, mfi.mode, update_path))
+ return -1;
+ if (!mfi.clean && !o->call_depth &&
+ update_stages(o, collide_path, NULL, &a, &b))
+ return -1;
+ free(alt_path);
+ /*
+ * FIXME: If both a & b both started with conflicts (only possible
+ * if they came from a rename/rename(2to1)), but had IDENTICAL
+ * contents including those conflicts, then in the next line we claim
+ * it was clean. If someone cares about this case, we should have the
+ * caller notify us if we started with conflicts.
+ */
+ return mfi.clean;
+}
+
+static int handle_rename_add(struct merge_options *o,
+ struct rename_conflict_info *ci)
+{
+ /* a was renamed to c, and a separate c was added. */
+ struct diff_filespec *a = ci->pair1->one;
+ struct diff_filespec *c = ci->pair1->two;
+ char *path = c->path;
+ char *prev_path_desc;
+ struct merge_file_info mfi;
+
+ int other_stage = (ci->branch1 == o->branch1 ? 3 : 2);
+
+ output(o, 1, _("CONFLICT (rename/add): "
+ "Rename %s->%s in %s. Added %s in %s"),
+ a->path, c->path, ci->branch1,
+ c->path, ci->branch2);
+
+ prev_path_desc = xstrfmt("version of %s from %s", path, a->path);
+ if (merge_mode_and_contents(o, a, c, &ci->ren1_other, prev_path_desc,
+ o->branch1, o->branch2,
+ 1 + o->call_depth * 2, &mfi))
+ return -1;
+ free(prev_path_desc);
+
+ return handle_file_collision(o,
+ c->path, a->path, NULL,
+ ci->branch1, ci->branch2,
+ &mfi.oid, mfi.mode,
+ &ci->dst_entry1->stages[other_stage].oid,
+ ci->dst_entry1->stages[other_stage].mode);
+}
+
+static char *find_path_for_conflict(struct merge_options *o,
+ const char *path,
+ const char *branch1,
+ const char *branch2)
+{
+ char *new_path = NULL;
+ if (dir_in_way(path, !o->call_depth, 0)) {
+ new_path = unique_path(o, path, branch1);
+ output(o, 1, _("%s is a directory in %s adding "
+ "as %s instead"),
+ path, branch2, new_path);
+ } else if (would_lose_untracked(path)) {
+ new_path = unique_path(o, path, branch1);
+ output(o, 1, _("Refusing to lose untracked file"
+ " at %s; adding as %s instead"),
+ path, new_path);
+ }
+
+ return new_path;
}
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 merge_file_info mfi;
+ struct diff_filespec other;
+ struct diff_filespec *add;
struct diff_filespec *one = ci->pair1->one;
struct diff_filespec *a = ci->pair1->two;
struct diff_filespec *b = ci->pair2->two;
+ char *path_desc;
output(o, 1, _("CONFLICT (rename/rename): "
"Rename \"%s\"->\"%s\" in branch \"%s\" "
one->path, a->path, ci->branch1,
one->path, b->path, ci->branch2,
o->call_depth ? _(" (left unresolved)") : "");
- if (o->call_depth) {
- struct merge_file_info mfi;
- struct diff_filespec other;
- struct diff_filespec *add;
- if (merge_mode_and_contents(o, one, a, b, one->path,
- ci->branch1, ci->branch2, &mfi))
- return -1;
+ path_desc = xstrfmt("%s and %s, both renamed from %s",
+ a->path, b->path, one->path);
+ if (merge_mode_and_contents(o, one, a, b, path_desc,
+ ci->branch1, ci->branch2,
+ o->call_depth * 2, &mfi))
+ return -1;
+ free(path_desc);
+
+ if (o->call_depth) {
/*
* FIXME: For rename/add-source conflicts (if we could detect
* such), this is wrong. We should instead find a unique
}
else
remove_file_from_cache(b->path);
- } else if (handle_file(o, a, 2, ci) || handle_file(o, b, 3, ci))
- return -1;
+ } else {
+ /*
+ * For each destination path, we need to see if there is a
+ * rename/add collision. If not, we can write the file out
+ * to the specified location.
+ */
+ add = filespec_from_entry(&other, ci->dst_entry1, 2 ^ 1);
+ if (add) {
+ if (handle_file_collision(o, a->path,
+ NULL, NULL,
+ ci->branch1, ci->branch2,
+ &mfi.oid, mfi.mode,
+ &add->oid, add->mode) < 0)
+ return -1;
+ } else {
+ char *new_path = find_path_for_conflict(o, a->path,
+ ci->branch1,
+ ci->branch2);
+ if (update_file(o, 0, &mfi.oid, mfi.mode, new_path ? new_path : a->path))
+ return -1;
+ free(new_path);
+ if (update_stages(o, a->path, NULL, a, NULL))
+ return -1;
+ }
+
+ add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);
+ if (add) {
+ if (handle_file_collision(o, b->path,
+ NULL, NULL,
+ ci->branch1, ci->branch2,
+ &add->oid, add->mode,
+ &mfi.oid, mfi.mode) < 0)
+ return -1;
+ } else {
+ char *new_path = find_path_for_conflict(o, b->path,
+ ci->branch2,
+ ci->branch1);
+ if (update_file(o, 0, &mfi.oid, mfi.mode, new_path ? new_path : b->path))
+ return -1;
+ free(new_path);
+ if (update_stages(o, b->path, NULL, NULL, b))
+ return -1;
+ }
+ }
return 0;
}
char *path_side_2_desc;
struct merge_file_info mfi_c1;
struct merge_file_info mfi_c2;
- int ret;
output(o, 1, _("CONFLICT (rename/rename): "
"Rename %s->%s in %s. "
a->path, c1->path, ci->branch1,
b->path, c2->path, ci->branch2);
- remove_file(o, 1, a->path, o->call_depth || would_lose_untracked(a->path));
- remove_file(o, 1, b->path, o->call_depth || would_lose_untracked(b->path));
-
path_side_1_desc = xstrfmt("version of %s from %s", path, a->path);
path_side_2_desc = xstrfmt("version of %s from %s", path, b->path);
if (merge_mode_and_contents(o, a, c1, &ci->ren1_other, path_side_1_desc,
- o->branch1, o->branch2, &mfi_c1) ||
+ o->branch1, o->branch2,
+ 1 + o->call_depth * 2, &mfi_c1) ||
merge_mode_and_contents(o, b, &ci->ren2_other, c2, path_side_2_desc,
- o->branch1, o->branch2, &mfi_c2))
+ o->branch1, o->branch2,
+ 1 + o->call_depth * 2, &mfi_c2))
return -1;
free(path_side_1_desc);
free(path_side_2_desc);
- if (o->call_depth) {
- /*
- * If mfi_c1.clean && mfi_c2.clean, then it might make
- * sense to do a two-way merge of those results. But, I
- * think in all cases, it makes sense to have the virtual
- * merge base just undo the renames; they can be detected
- * again later for the non-recursive merge.
- */
- remove_file(o, 0, path, 0);
- ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, a->path);
- if (!ret)
- ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
- b->path);
- } else {
- char *new_path1 = unique_path(o, path, ci->branch1);
- char *new_path2 = unique_path(o, path, ci->branch2);
- output(o, 1, _("Renaming %s to %s and %s to %s instead"),
- a->path, new_path1, b->path, new_path2);
- if (was_dirty(o, path))
- output(o, 1, _("Refusing to lose dirty file at %s"),
- path);
- else if (would_lose_untracked(path))
- /*
- * Only way we get here is if both renames were from
- * a directory rename AND user had an untracked file
- * at the location where both files end up after the
- * two directory renames. See testcase 10d of t6043.
- */
- output(o, 1, _("Refusing to lose untracked file at "
- "%s, even though it's in the way."),
- path);
- else
- remove_file(o, 0, path, 0);
- ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, new_path1);
- if (!ret)
- ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
- new_path2);
- /*
- * unpack_trees() actually populates the index for us for
- * "normal" rename/rename(2to1) situtations so that the
- * correct entries are at the higher stages, which would
- * make the call below to update_stages_for_stage_data
- * unnecessary. However, if either of the renames came
- * from a directory rename, then unpack_trees() will not
- * have gotten the right data loaded into the index, so we
- * need to do so now. (While it'd be tempting to move this
- * call to update_stages_for_stage_data() to
- * apply_directory_rename_modifications(), that would break
- * our intermediate calls to would_lose_untracked() since
- * those rely on the current in-memory index. See also the
- * big "NOTE" in update_stages()).
- */
- if (update_stages_for_stage_data(o, path, ci->dst_entry1))
- ret = -1;
-
- free(new_path2);
- free(new_path1);
- }
-
- return ret;
+ return handle_file_collision(o, path, a->path, b->path,
+ ci->branch1, ci->branch2,
+ &mfi_c1.oid, mfi_c1.mode,
+ &mfi_c2.oid, mfi_c2.mode);
}
/*
0 /* update_wd */))
clean_merge = -1;
} else if (!oid_eq(&dst_other.oid, &null_oid)) {
- clean_merge = 0;
- try_merge = 1;
- output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
- "%s added in %s"),
- ren1_src, ren1_dst, branch1,
- ren1_dst, branch2);
- if (o->call_depth) {
- struct merge_file_info mfi;
- struct diff_filespec one, a, b;
-
- oidcpy(&one.oid, &null_oid);
- one.mode = 0;
- one.path = ren1->pair->two->path;
-
- oidcpy(&a.oid, &ren1->pair->two->oid);
- a.mode = ren1->pair->two->mode;
- a.path = one.path;
-
- oidcpy(&b.oid, &dst_other.oid);
- b.mode = dst_other.mode;
- b.path = one.path;
-
- if (merge_mode_and_contents(o, &one, &a, &b, ren1_dst,
- branch1, branch2,
- &mfi)) {
- clean_merge = -1;
- goto cleanup_and_return;
- }
- output(o, 1, _("Adding merged %s"), ren1_dst);
- if (update_file(o, 0, &mfi.oid,
- mfi.mode, ren1_dst))
- clean_merge = -1;
- try_merge = 0;
- } else {
- char *new_path = unique_path(o, ren1_dst, branch2);
- output(o, 1, _("Adding as %s instead"), new_path);
- if (update_file(o, 0, &dst_other.oid,
- dst_other.mode, new_path))
- clean_merge = -1;
- free(new_path);
- }
+ /*
+ * Probably not a clean merge, but it's
+ * premature to set clean_merge to 0 here,
+ * because if the rename merges cleanly and
+ * the merge exactly matches the newly added
+ * file, then the merge will be clean.
+ */
+ setup_rename_conflict_info(RENAME_ADD,
+ ren1->pair,
+ NULL,
+ branch1,
+ branch2,
+ ren1->dst_entry,
+ NULL,
+ o,
+ ren1->src_entry,
+ NULL);
} else
try_merge = 1;
df_conflict_remains = 1;
}
if (merge_mode_and_contents(o, &one, &a, &b, path,
- o->branch1, o->branch2, &mfi))
+ o->branch1, o->branch2,
+ o->call_depth * 2, &mfi))
return -1;
/*
conflict_info->branch2))
clean_merge = -1;
break;
+ case RENAME_ADD:
+ /*
+ * Probably unclean merge, but if the renamed file
+ * merges cleanly and the result can then be
+ * two-way merged cleanly with the added file, I
+ * guess it's a clean merge?
+ */
+ clean_merge = handle_rename_add(o, conflict_info);
+ break;
case RENAME_DELETE:
clean_merge = 0;
if (handle_rename_delete(o,
clean_merge = -1;
break;
case RENAME_TWO_FILES_TO_ONE:
- clean_merge = 0;
- if (handle_rename_rename_2to1(o, conflict_info))
- clean_merge = -1;
+ /*
+ * Probably unclean merge, but if the two renamed
+ * files merge cleanly and the two resulting files
+ * can then be two-way merged cleanly, I guess it's
+ * a clean merge?
+ */
+ clean_merge = handle_rename_rename_2to1(o,
+ conflict_info);
break;
default:
entry->processed = 0;
clean_merge = -1;
}
} else if (a_oid && b_oid) {
- /* Case C: Added in both (check for same permissions) and */
- /* case D: Modified in both, but differently. */
- int is_dirty = 0; /* unpack_trees would have bailed if dirty */
- clean_merge = handle_content_merge(o, path, is_dirty,
- o_oid, o_mode,
- a_oid, a_mode,
- b_oid, b_mode,
- NULL);
+ if (!o_oid) {
+ /* Case C: Added in both (check for same permissions) */
+ output(o, 1,
+ _("CONFLICT (add/add): Merge conflict in %s"),
+ path);
+ clean_merge = handle_file_collision(o,
+ path, NULL, NULL,
+ o->branch1,
+ o->branch2,
+ a_oid, a_mode,
+ b_oid, b_mode);
+ } else {
+ /* case D: Modified in both, but differently. */
+ int is_dirty = 0; /* unpack_trees would have bailed if dirty */
+ clean_merge = handle_content_merge(o, path,
+ is_dirty,
+ o_oid, o_mode,
+ a_oid, a_mode,
+ b_oid, b_mode,
+ NULL);
+ }
} else if (!o_oid && !a_oid && !b_oid) {
/*
* this entry was deleted altogether. a_mode == 0 means
void clear_midx_file(struct repository *r)
{
- char *midx = get_midx_filename(r->objects->objectdir);
+ char *midx = get_midx_filename(r->objects->odb->path);
if (r->objects && r->objects->multi_pack_index) {
close_midx(r->objects->multi_pack_index);
#include "commit.h"
#include "refs.h"
-static int notes_cache_match_validity(const char *ref, const char *validity)
+static int notes_cache_match_validity(struct repository *r,
+ const char *ref,
+ const char *validity)
{
struct object_id oid;
struct commit *commit;
if (read_ref(ref, &oid) < 0)
return 0;
- commit = lookup_commit_reference_gently(the_repository, &oid, 1);
+ commit = lookup_commit_reference_gently(r, &oid, 1);
if (!commit)
return 0;
return ret;
}
-void notes_cache_init(struct notes_cache *c, const char *name,
- const char *validity)
+void notes_cache_init(struct repository *r, struct notes_cache *c,
+ const char *name, const char *validity)
{
struct strbuf ref = STRBUF_INIT;
int flags = NOTES_INIT_WRITABLE;
c->validity = xstrdup(validity);
strbuf_addf(&ref, "refs/notes/%s", name);
- if (!notes_cache_match_validity(ref.buf, validity))
+ if (!notes_cache_match_validity(r, ref.buf, validity))
flags |= NOTES_INIT_EMPTY;
init_notes(&c->tree, ref.buf, combine_notes_overwrite, flags);
strbuf_release(&ref);
#include "notes.h"
+struct repository;
+
struct notes_cache {
struct notes_tree tree;
char *validity;
};
-void notes_cache_init(struct notes_cache *c, const char *name,
- const char *validity);
+void notes_cache_init(struct repository *r, struct notes_cache *c,
+ const char *name, const char *validity);
int notes_cache_write(struct notes_cache *c);
char *notes_cache_get(struct notes_cache *c, struct object_id *oid, size_t
struct object_id obj, base, local, remote;
};
-void init_notes_merge_options(struct notes_merge_options *o)
+void init_notes_merge_options(struct repository *r,
+ struct notes_merge_options *o)
{
memset(o, 0, sizeof(struct notes_merge_options));
strbuf_init(&(o->commit_msg), 0);
o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
+ o->repo = r;
}
static int path_to_oid(const char *path, struct object_id *oid)
trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n",
oid_to_hex(base), oid_to_hex(remote));
- repo_diff_setup(the_repository, &opt);
+ repo_diff_setup(o->repo, &opt);
opt.flags.recursive = 1;
opt.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_setup_done(&opt);
trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n",
len, oid_to_hex(base), oid_to_hex(local));
- repo_diff_setup(the_repository, &opt);
+ repo_diff_setup(o->repo, &opt);
opt.flags.recursive = 1;
opt.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_setup_done(&opt);
status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL,
&local, o->local_ref, &remote, o->remote_ref,
- &the_index, NULL);
+ o->repo->index, NULL);
free(base.ptr);
free(local.ptr);
else if (!check_refname_format(o->local_ref, 0) &&
is_null_oid(&local_oid))
local = NULL; /* local_oid == null_oid indicates unborn ref */
- else if (!(local = lookup_commit_reference(the_repository, &local_oid)))
+ else if (!(local = lookup_commit_reference(o->repo, &local_oid)))
die("Could not parse local commit %s (%s)",
oid_to_hex(&local_oid), o->local_ref);
trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid));
die("Failed to resolve remote notes ref '%s'",
o->remote_ref);
}
- } else if (!(remote = lookup_commit_reference(the_repository, &remote_oid))) {
+ } else if (!(remote = lookup_commit_reference(o->repo, &remote_oid))) {
die("Could not parse remote commit %s (%s)",
oid_to_hex(&remote_oid), o->remote_ref);
}
/* write file as blob, and add to partial_tree */
if (stat(path.buf, &st))
die_errno("Failed to stat '%s'", path.buf);
- if (index_path(&the_index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
+ if (index_path(o->repo->index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
die("Failed to write blob object from '%s'", path.buf);
if (add_note(partial_tree, &obj_oid, &blob_oid, NULL))
die("Failed to add resolved note '%s' to notes tree",
struct commit;
struct object_id;
+struct repository;
#define NOTES_MERGE_WORKTREE "NOTES_MERGE_WORKTREE"
};
struct notes_merge_options {
+ struct repository *repo;
const char *local_ref;
const char *remote_ref;
struct strbuf commit_msg;
unsigned has_worktree:1;
};
-void init_notes_merge_options(struct notes_merge_options *o);
+void init_notes_merge_options(struct repository *r,
+ struct notes_merge_options *o);
/*
* Merge notes from o->remote_ref into o->local_ref
#include "sha1-array.h"
#include "strbuf.h"
-struct alternate_object_database {
- struct alternate_object_database *next;
-
- /* see alt_scratch_buf() */
- struct strbuf scratch;
- size_t base_len;
+struct object_directory {
+ struct object_directory *next;
/*
- * Used to store the results of readdir(3) calls when searching
- * for unique abbreviated hashes. This cache is never
- * invalidated, thus it's racy and not necessarily accurate.
- * That's fine for its purpose; don't use it for tasks requiring
- * greater accuracy!
+ * Used to store the results of readdir(3) calls when we are OK
+ * sacrificing accuracy due to races for speed. That includes
+ * object existence with OBJECT_INFO_QUICK, as well as
+ * our search for unique abbreviated hashes. Don't use it for tasks
+ * requiring greater accuracy!
+ *
+ * Be sure to call odb_load_loose_cache() before using.
*/
char loose_objects_subdir_seen[256];
struct oid_array loose_objects_cache;
* Path to the alternative object store. If this is a relative path,
* it is relative to the current working directory.
*/
- char path[FLEX_ARRAY];
+ char *path;
};
+
void prepare_alt_odb(struct repository *r);
char *compute_alternate_path(const char *path, struct strbuf *err);
-typedef int alt_odb_fn(struct alternate_object_database *, void *);
+typedef int alt_odb_fn(struct object_directory *, void *);
int foreach_alt_odb(alt_odb_fn, void*);
-/*
- * Allocate a "struct alternate_object_database" but do _not_ actually
- * add it to the list of alternates.
- */
-struct alternate_object_database *alloc_alt_odb(const char *dir);
-
/*
* Add the directory to the on-disk alternates file; the new entry will also
* take effect in the current process.
void add_to_alternates_memory(const char *dir);
/*
- * Returns a scratch strbuf pre-filled with the alternate object directory,
- * including a trailing slash, which can be used to access paths in the
- * alternate. Always use this over direct access to alt->scratch, as it
- * cleans up any previous use of the scratch buffer.
+ * Populate an odb's loose object cache for one particular subdirectory (i.e.,
+ * the one that corresponds to the first byte of objects you're interested in,
+ * from 0 to 255 inclusive).
*/
-struct strbuf *alt_scratch_buf(struct alternate_object_database *alt);
+void odb_load_loose_cache(struct object_directory *odb, int subdir_nr);
struct packed_git {
struct packed_git *next;
struct raw_object_store {
/*
- * Path to the repository's object store.
- * Cannot be NULL after initialization.
+ * Set of all object directories; the main directory is first (and
+ * cannot be NULL after initialization). Subsequent directories are
+ * alternates.
*/
- char *objectdir;
+ struct object_directory *odb;
+ struct object_directory **odb_tail;
+ int loaded_alternates;
- /* Path to extra alternate object database if not NULL */
+ /*
+ * A list of alternate object directories loaded from the environment;
+ * this should not generally need to be accessed directly, but will
+ * populate the "odb" list when prepare_alt_odb() is run.
+ */
char *alternate_db;
- struct alternate_object_database *alt_odb_list;
- struct alternate_object_database **alt_odb_tail;
-
/*
* Objects that should be substituted by other objects
* (see git-replace(1)).
* Put in `buf` the name of the file in the local object database that
* would be used to store a loose object with the specified sha1.
*/
-void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1);
+const char *loose_object_path(struct repository *r, struct strbuf *buf, const unsigned char *sha1);
void *map_sha1_file(struct repository *r, const unsigned char *sha1, unsigned long *size);
return o;
}
-static void free_alt_odb(struct alternate_object_database *alt)
+static void free_object_directory(struct object_directory *odb)
{
- strbuf_release(&alt->scratch);
- oid_array_clear(&alt->loose_objects_cache);
- free(alt);
+ free(odb->path);
+ oid_array_clear(&odb->loose_objects_cache);
+ free(odb);
}
-static void free_alt_odbs(struct raw_object_store *o)
+static void free_object_directories(struct raw_object_store *o)
{
- while (o->alt_odb_list) {
- struct alternate_object_database *next;
+ while (o->odb) {
+ struct object_directory *next;
- next = o->alt_odb_list->next;
- free_alt_odb(o->alt_odb_list);
- o->alt_odb_list = next;
+ next = o->odb->next;
+ free_object_directory(o->odb);
+ o->odb = next;
}
}
void raw_object_store_clear(struct raw_object_store *o)
{
- FREE_AND_NULL(o->objectdir);
FREE_AND_NULL(o->alternate_db);
oidmap_free(o->replace_map, 1);
o->commit_graph = NULL;
o->commit_graph_attempted = 0;
- free_alt_odbs(o);
- o->alt_odb_tail = NULL;
+ free_object_directories(o);
+ o->odb_tail = NULL;
+ o->loaded_alternates = 0;
INIT_LIST_HEAD(&o->packed_git_mru);
close_all_packs(o);
break;
default:
- real_type = oid_object_info(the_repository,
+ real_type = oid_object_info(to_pack->repo,
&entry->idx.oid, NULL);
break;
}
if (writer.show_progress)
writer.progress = start_progress("Building bitmaps", writer.selected_nr);
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(to_pack->repo, &revs, NULL);
revs.tag_objects = 1;
revs.tree_objects = 1;
revs.blob_objects = 1;
void bitmap_writer_reuse_bitmaps(struct packing_data *to_pack)
{
struct bitmap_index *bitmap_git;
- if (!(bitmap_git = prepare_bitmap_git()))
+ if (!(bitmap_git = prepare_bitmap_git(to_pack->repo)))
return;
writer.reused = kh_init_sha1();
return -1;
}
-static int open_pack_bitmap(struct bitmap_index *bitmap_git)
+static int open_pack_bitmap(struct repository *r,
+ struct bitmap_index *bitmap_git)
{
struct packed_git *p;
int ret = -1;
assert(!bitmap_git->map);
- for (p = get_all_packs(the_repository); p; p = p->next) {
+ for (p = get_all_packs(r); p; p = p->next) {
if (open_pack_bitmap_1(bitmap_git, p) == 0)
ret = 0;
}
return ret;
}
-struct bitmap_index *prepare_bitmap_git(void)
+struct bitmap_index *prepare_bitmap_git(struct repository *r)
{
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
- if (!open_pack_bitmap(bitmap_git) && !load_pack_bitmap(bitmap_git))
+ if (!open_pack_bitmap(r, bitmap_git) && !load_pack_bitmap(bitmap_git))
return bitmap_git;
free_bitmap_index(bitmap_git);
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)
+ if (open_pack_bitmap(revs->repo, bitmap_git) < 0)
goto cleanup;
for (i = 0; i < revs->pending.nr; ++i) {
struct bitmap_test_data tdata;
struct bitmap_index *bitmap_git;
- if (!(bitmap_git = prepare_bitmap_git()))
+ if (!(bitmap_git = prepare_bitmap_git(revs->repo)))
die("failed to load bitmap indexes");
if (revs->pending.nr != 1)
#include "pack-objects.h"
struct commit;
+struct repository;
struct rev_info;
struct bitmap_disk_header {
struct bitmap_index;
-struct bitmap_index *prepare_bitmap_git(void);
+struct bitmap_index *prepare_bitmap_git(struct repository *r);
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 *,
return data_crc != ntohl(*index_crc);
}
-static int verify_packfile(struct packed_git *p,
+static int verify_packfile(struct repository *r,
+ struct packed_git *p,
struct pack_window **w_curs,
verify_fn fn,
struct progress *progress, uint32_t base_count)
data = NULL;
data_valid = 0;
} else {
- data = unpack_entry(the_repository, p, entries[i].offset, &type, &size);
+ data = unpack_entry(r, p, entries[i].offset, &type, &size);
data_valid = 1;
}
return err;
}
-int verify_pack(struct packed_git *p, verify_fn fn,
+int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,
struct progress *progress, uint32_t base_count)
{
int err = 0;
if (!p->index_data)
return -1;
- err |= verify_packfile(p, &w_curs, fn, progress, base_count);
+ err |= verify_packfile(r, p, &w_curs, fn, progress, base_count);
unuse_pack(&w_curs);
return err;
* (i.e. in_pack_idx also zero) should return NULL.
*/
mapping[cnt++] = NULL;
- for (p = get_all_packs(the_repository); p; p = p->next, cnt++) {
+ for (p = get_all_packs(pdata->repo); p; p = p->next, cnt++) {
if (cnt == nr) {
free(mapping);
return;
}
/* assume pdata is already zero'd by caller */
-void prepare_packing_data(struct packing_data *pdata)
+void prepare_packing_data(struct repository *r, struct packing_data *pdata)
{
+ pdata->repo = r;
+
if (git_env_bool("GIT_TEST_FULL_IN_PACK_ARRAY", 0)) {
/*
* do not initialize in_pack_by_idx[] to force the
#include "thread-utils.h"
#include "pack.h"
+struct repository;
+
#define DEFAULT_DELTA_CACHE_SIZE (256 * 1024 * 1024)
#define OE_DFS_STATE_BITS 2
};
struct packing_data {
+ struct repository *repo;
struct object_entry *objects;
uint32_t nr_objects, nr_alloc;
unsigned char *layer;
};
-void prepare_packing_data(struct packing_data *pdata);
+void prepare_packing_data(struct repository *r, struct packing_data *pdata);
static inline void packing_data_lock(struct packing_data *pdata)
{
#include "object.h"
#include "csum-file.h"
+struct repository;
+
/*
* Packed object header
*/
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1);
extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
extern int verify_pack_index(struct packed_git *);
-extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uint32_t);
+extern int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t);
extern off_t write_pack_header(struct hashfile *f, uint32_t);
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
extern char *index_pack_lockfile(int fd);
static void prepare_packed_git(struct repository *r)
{
- struct alternate_object_database *alt;
+ struct object_directory *odb;
if (r->objects->packed_git_initialized)
return;
- prepare_multi_pack_index_one(r, r->objects->objectdir, 1);
- prepare_packed_git_one(r, r->objects->objectdir, 1);
+
prepare_alt_odb(r);
- for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
- prepare_multi_pack_index_one(r, alt->path, 0);
- prepare_packed_git_one(r, alt->path, 0);
+ for (odb = r->objects->odb; odb; odb = odb->next) {
+ int local = (odb == r->objects->odb);
+ prepare_multi_pack_index_one(r, odb->path, local);
+ prepare_packed_git_one(r, odb->path, local);
}
rearrange_packed_git(r);
void reprepare_packed_git(struct repository *r)
{
+ struct object_directory *odb;
+
+ for (odb = r->objects->odb; odb; odb = odb->next) {
+ oid_array_clear(&odb->loose_objects_cache);
+ memset(&odb->loose_objects_subdir_seen, 0,
+ sizeof(odb->loose_objects_subdir_seen));
+ }
+
r->objects->approximate_object_count_valid = 0;
r->objects->packed_git_initialized = 0;
prepare_packed_git(r);
} else {
v = strtol(arg, (char **)&arg, 10);
if (*arg)
- return opterror(opt, "expects a numerical value", 0);
+ return error(_("option `%s' expects a numerical value"),
+ opt->long_name);
if (v && v < MINIMUM_ABBREV)
v = MINIMUM_ABBREV;
else if (v > 40)
arg = unset ? "never" : (const char *)opt->defval;
value = git_config_colorbool(NULL, arg);
if (value < 0)
- return opterror(opt,
- "expects \"always\", \"auto\", or \"never\"", 0);
+ return error(_("option `%s' expects \"always\", \"auto\", or \"never\""),
+ opt->long_name);
*(int *)opt->value = value;
return 0;
}
p->argc--;
*arg = *++p->argv;
} else
- return opterror(opt, "requires a value", flags);
+ return error(_("%s requires a value"), optname(opt, flags));
return 0;
}
int flags)
{
const struct option *that;
- struct strbuf message = STRBUF_INIT;
struct strbuf that_name = STRBUF_INIT;
/*
strbuf_addf(&that_name, "--%s", that->long_name);
else
strbuf_addf(&that_name, "-%c", that->short_name);
- strbuf_addf(&message, ": incompatible with %s", that_name.buf);
+ error(_("%s is incompatible with %s"),
+ optname(opt, flags), that_name.buf);
strbuf_release(&that_name);
- opterror(opt, message.buf, flags);
- strbuf_release(&message);
return -1;
}
- return opterror(opt, ": incompatible with something else", flags);
+ return error(_("%s : incompatible with something else"),
+ optname(opt, flags));
}
static int get_value(struct parse_opt_ctx_t *p,
int err;
if (unset && p->opt)
- return opterror(opt, "takes no value", flags);
+ return error(_("%s takes no value"), optname(opt, flags));
if (unset && (opt->flags & PARSE_OPT_NONEG))
- return opterror(opt, "isn't available", flags);
+ return error(_("%s isn't available"), optname(opt, flags));
if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG))
- return opterror(opt, "takes no value", flags);
+ return error(_("%s takes no value"), optname(opt, flags));
switch (opt->type) {
case OPTION_LOWLEVEL_CALLBACK:
return -1;
*(int *)opt->value = strtol(arg, (char **)&s, 10);
if (*s)
- return opterror(opt, "expects a numerical value", flags);
+ return error(_("%s expects a numerical value"),
+ optname(opt, flags));
return 0;
case OPTION_MAGNITUDE:
if (get_arg(p, opt, flags, &arg))
return -1;
if (!git_parse_ulong(arg, opt->value))
- return opterror(opt,
- "expects a non-negative integer value with an optional k/m/g suffix",
- flags);
+ return error(_("%s expects a non-negative integer value"
+ " with an optional k/m/g suffix"),
+ optname(opt, flags));
return 0;
default:
- die("should not happen, someone must be hit on the forehead");
+ BUG("opt->type %d should not happen", opt->type);
}
}
}
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
- const struct option *options)
+ const struct option *options)
{
const struct option *all_opts = options;
const char *arg_end = strchrnul(arg, '=');
if (!rest)
continue;
if (*rest == '=')
- return opterror(options, "takes no value", flags);
+ return error(_("%s takes no value"),
+ optname(options, flags));
if (*rest)
continue;
p->out[p->cpidx++] = arg - 2;
}
if (ambiguous_option) {
- error("Ambiguous option: %s "
- "(could be --%s%s or --%s%s)",
+ error(_("ambiguous option: %s "
+ "(could be --%s%s or --%s%s)"),
arg,
(ambiguous_flags & OPT_UNSET) ? "no-" : "",
ambiguous_option->long_name,
return;
if (starts_with(arg, "no-")) {
- error ("did you mean `--%s` (with two dashes ?)", arg);
+ error(_("did you mean `--%s` (with two dashes ?)"), arg);
exit(129);
}
if (!options->long_name)
continue;
if (starts_with(options->long_name, arg)) {
- error ("did you mean `--%s` (with two dashes ?)", arg);
+ error(_("did you mean `--%s` (with two dashes ?)"), arg);
exit(129);
}
}
ctx->flags = flags;
if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
(flags & PARSE_OPT_STOP_AT_NON_OPTION))
- die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
+ BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
parse_options_check(options);
}
break;
default: /* PARSE_OPT_UNKNOWN */
if (ctx.argv[0][1] == '-') {
- error("unknown option `%s'", ctx.argv[0] + 2);
+ error(_("unknown option `%s'"), ctx.argv[0] + 2);
} else if (isascii(*ctx.opt)) {
- error("unknown switch `%c'", *ctx.opt);
+ error(_("unknown switch `%c'"), *ctx.opt);
} else {
- error("unknown non-ascii option in string: `%s'",
+ error(_("unknown non-ascii option in string: `%s'"),
ctx.argv[0]);
}
usage_with_options(usagestr, options);
usage_with_options(usagestr, options);
}
-#undef opterror
-int opterror(const struct option *opt, const char *reason, int flags)
+const char *optname(const struct option *opt, int flags)
{
+ static struct strbuf sb = STRBUF_INIT;
+
+ strbuf_reset(&sb);
if (flags & OPT_SHORT)
- return error("switch `%c' %s", opt->short_name, reason);
- if (flags & OPT_UNSET)
- return error("option `no-%s' %s", opt->long_name, reason);
- return error("option `%s' %s", opt->long_name, reason);
+ strbuf_addf(&sb, "switch `%c'", opt->short_name);
+ else if (flags & OPT_UNSET)
+ strbuf_addf(&sb, "option `no-%s'", opt->long_name);
+ else
+ strbuf_addf(&sb, "option `%s'", opt->long_name);
+
+ return sb.buf;
}
* Returns the number of arguments left in argv[].
*/
extern int parse_options(int argc, const char **argv, const char *prefix,
- const struct option *options,
- const char * const usagestr[], int flags);
+ const struct option *options,
+ const char * const usagestr[], int flags);
extern NORETURN void usage_with_options(const char * const *usagestr,
- const struct option *options);
+ const struct option *options);
extern NORETURN void usage_msg_opt(const char *msg,
const char * const *usagestr,
const struct option *options);
extern int optbug(const struct option *opt, const char *reason);
-extern int opterror(const struct option *opt, const char *reason, int flags);
-#if defined(__GNUC__)
-#define opterror(o,r,f) (opterror((o),(r),(f)), const_error())
-#endif
+const char *optname(const struct option *opt, int flags);
/*
* Use these assertions for callbacks that expect to be called with NONEG and
strbuf_splice(buf, 0, buf->len,
repo->index_file, strlen(repo->index_file));
else if (dir_prefix(base, "objects"))
- replace_dir(buf, git_dir_len + 7, repo->objects->objectdir);
+ replace_dir(buf, git_dir_len + 7, repo->objects->odb->path);
else if (git_hooks_path && dir_prefix(base, "hooks"))
replace_dir(buf, git_dir_len + 5, git_hooks_path);
else if (repo->different_commondir)
FREE_AND_NULL(pathspec->items);
pathspec->nr = 0;
}
+
+int match_pathspec_attrs(const struct index_state *istate,
+ const char *name, int namelen,
+ const struct pathspec_item *item)
+{
+ int i;
+ char *to_free = NULL;
+
+ if (name[namelen])
+ name = to_free = xmemdupz(name, namelen);
+
+ git_check_attr(istate, name, item->attr_check);
+
+ free(to_free);
+
+ for (i = 0; i < item->attr_match_nr; i++) {
+ const char *value;
+ int matched;
+ enum attr_match_mode match_mode;
+
+ value = item->attr_check->items[i].value;
+ match_mode = item->attr_match[i].match_mode;
+
+ if (ATTR_TRUE(value))
+ matched = (match_mode == MATCH_SET);
+ else if (ATTR_FALSE(value))
+ matched = (match_mode == MATCH_UNSET);
+ else if (ATTR_UNSET(value))
+ matched = (match_mode == MATCH_UNSPECIFIED);
+ else
+ matched = (match_mode == MATCH_VALUE &&
+ !strcmp(item->attr_match[i].value, value));
+ if (!matched)
+ return 0;
+ }
+
+ return 1;
+}
* Any arguments used are copied. It is safe for the caller to modify
* or free 'prefix' and 'args' after calling this function.
*/
-extern void parse_pathspec(struct pathspec *pathspec,
- unsigned magic_mask,
- unsigned flags,
- const char *prefix,
- const char **args);
-extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
-extern void clear_pathspec(struct pathspec *);
+void parse_pathspec(struct pathspec *pathspec,
+ unsigned magic_mask,
+ unsigned flags,
+ const char *prefix,
+ const char **args);
+void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
+void clear_pathspec(struct pathspec *);
static inline int ps_strncmp(const struct pathspec_item *item,
const char *s1, const char *s2, size_t n)
return strcmp(s1, s2);
}
-extern void add_pathspec_matches_against_index(const struct pathspec *pathspec,
- const struct index_state *istate,
- char *seen);
-extern char *find_pathspecs_matching_against_index(const struct pathspec *pathspec,
- const struct index_state *istate);
+void add_pathspec_matches_against_index(const struct pathspec *pathspec,
+ const struct index_state *istate,
+ char *seen);
+char *find_pathspecs_matching_against_index(const struct pathspec *pathspec,
+ const struct index_state *istate);
+int match_pathspec_attrs(const struct index_state *istate,
+ const char *name, int namelen,
+ const struct pathspec_item *item);
#endif /* PATHSPEC_H */
* Return value is the same as in (1).
*/
static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
- struct strbuf *sb, FILE *fp, int no_dq)
+ struct strbuf *sb, FILE *fp, int no_dq)
{
#undef EMIT
#define EMIT(c) \
changed |= DATA_CHANGED;
return changed;
default:
- die("internal error: ce_mode is %o", ce->ce_mode);
+ BUG("unsupported ce_mode: %o", ce->ce_mode);
}
changed |= match_stat_data(&ce->ce_stat_data, st);
struct cache_entry *new_entry;
if (alias->ce_flags & CE_ADDED)
- die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
+ die(_("will not add file alias '%s' ('%s' already exists in index)"),
+ ce->name, alias->name);
/* Ok, create the new entry using the name of the existing alias */
len = ce_namelen(alias);
{
struct object_id oid;
if (write_object_file("", 0, blob_type, &oid))
- die("cannot create an empty blob in the object database");
+ die(_("cannot create an empty blob in the object database"));
oidcpy(&ce->oid, &oid);
}
newflags |= HASH_RENORMALIZE;
if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
- return error("%s: can only add regular files, symbolic links or git-directories", path);
+ return error(_("%s: can only add regular files, symbolic links or git-directories"), path);
namelen = strlen(path);
if (S_ISDIR(st_mode)) {
if (!intent_only) {
if (index_path(istate, &ce->oid, path, st, newflags)) {
discard_cache_entry(ce);
- return error("unable to index file %s", path);
+ return error(_("unable to index file '%s'"), path);
}
} else
set_object_name_for_intent_to_add_entry(ce);
discard_cache_entry(ce);
else if (add_index_entry(istate, ce, add_option)) {
discard_cache_entry(ce);
- return error("unable to add %s to index", path);
+ return error(_("unable to add '%s' to index"), path);
}
if (verbose && !was_same)
printf("add '%s'\n", path);
{
struct stat st;
if (lstat(path, &st))
- die_errno("unable to stat '%s'", path);
+ die_errno(_("unable to stat '%s'"), path);
return add_to_index(istate, path, &st, flags);
}
int len;
if (!verify_path(path, mode)) {
- error("Invalid path '%s'", path);
+ error(_("invalid path '%s'"), path);
return NULL;
}
int len;
if (!verify_path(path, mode)) {
- error("Invalid path '%s'", path);
+ error(_("invalid path '%s'"), path);
return NULL;
}
if (!ok_to_add)
return -1;
if (!verify_path(ce->name, ce->ce_mode))
- return error("Invalid path '%s'", ce->name);
+ return error(_("invalid path '%s'"), ce->name);
if (!skip_df_check &&
check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
if (!ok_to_replace)
- return error("'%s' appears as both a file and as a directory",
+ return error(_("'%s' appears as both a file and as a directory"),
ce->name);
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
pos = -pos-1;
istate->cache_nr);
trace_performance_enter();
- modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
- deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
- typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n");
- added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
- unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
+ modified_fmt = in_porcelain ? "M\t%s\n" : "%s: needs update\n";
+ deleted_fmt = in_porcelain ? "D\t%s\n" : "%s: needs update\n";
+ typechange_fmt = in_porcelain ? "T\t%s\n" : "%s: needs update\n";
+ added_fmt = in_porcelain ? "A\t%s\n" : "%s: needs update\n";
+ unmerged_fmt = in_porcelain ? "U\t%s\n" : "%s: needs merge\n";
/*
* Use the multi-threaded preload_index() to refresh most of the
* cache entries quickly then in the single threaded loop below,
int hdr_version;
if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
- return error("bad signature");
+ return error(_("bad signature 0x%08x"), hdr->hdr_signature);
hdr_version = ntohl(hdr->hdr_version);
if (hdr_version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < hdr_version)
- return error("bad index version %d", hdr_version);
+ return error(_("bad index version %d"), hdr_version);
if (!verify_index_checksum)
return 0;
the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
the_hash_algo->final_fn(hash, &c);
if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
- return error("bad index file sha1 signature");
+ return error(_("bad index file sha1 signature"));
return 0;
}
break;
default:
if (*ext < 'A' || 'Z' < *ext)
- return error("index uses %.4s extension, which we do not understand",
+ return error(_("index uses %.4s extension, which we do not understand"),
ext);
- fprintf(stderr, "ignoring %.4s extension\n", ext);
+ fprintf_ln(stderr, _("ignoring %.4s extension"), ext);
break;
}
return 0;
extended_flags = get_be16(&ondisk2->flags2) << 16;
/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
if (extended_flags & ~CE_EXTENDED_FLAGS)
- die("Unknown index entry format %08x", extended_flags);
+ die(_("unknown index entry format 0x%08x"), extended_flags);
flags |= extended_flags;
name = ondisk2->name;
}
int name_compare = strcmp(ce->name, next_ce->name);
if (0 < name_compare)
- die("unordered stage entries in index");
+ die(_("unordered stage entries in index"));
if (!name_compare) {
if (!ce_stage(ce))
- die("multiple stage entries for merged file '%s'",
+ die(_("multiple stage entries for merged file '%s'"),
ce->name);
if (ce_stage(ce) > ce_stage(next_ce))
- die("unordered stage entries for '%s'",
+ die(_("unordered stage entries for '%s'"),
ce->name);
}
}
if (fd < 0) {
if (!must_exist && errno == ENOENT)
return 0;
- die_errno("%s: index file open failed", path);
+ die_errno(_("%s: index file open failed"), path);
}
if (fstat(fd, &st))
- die_errno("cannot stat the open index");
+ die_errno(_("%s: cannot stat the open index"), path);
mmap_size = xsize_t(st.st_size);
if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
- die("index file smaller than expected");
+ die(_("%s: index file smaller than expected"), path);
mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mmap == MAP_FAILED)
- die_errno("unable to map index file");
+ die_errno(_("%s: unable to map index file"), path);
close(fd);
hdr = (const struct cache_header *)mmap;
unmap:
munmap((void *)mmap, mmap_size);
- die("index file corrupt");
+ die(_("index file corrupt"));
}
/*
static void freshen_shared_index(const char *shared_index, int warn)
{
if (!check_and_freshen_file(shared_index, 1) && warn)
- warning("could not freshen shared index '%s'", shared_index);
+ warning(_("could not freshen shared index '%s'"), shared_index);
}
int read_index_from(struct index_state *istate, const char *path,
base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
ret = do_read_index(split_index->base, base_path, 1);
if (!oideq(&split_index->base_oid, &split_index->base->oid))
- die("broken index, expect %s in %s, got %s",
+ die(_("broken index, expect %s in %s, got %s"),
base_oid_hex, base_path,
oid_to_hex(&split_index->base->oid));
for (i = 0; i < istate->cache_nr; i++) {
if (!istate) {
- die("internal error: cache entry is not allocated from expected memory pool");
+ BUG("cache entry is not allocated from expected memory pool");
} else if (!istate->ce_mem_pool ||
!mem_pool_contains(istate->ce_mem_pool, istate->cache[i])) {
if (!istate->split_index ||
!istate->split_index->base ||
!istate->split_index->base->ce_mem_pool ||
!mem_pool_contains(istate->split_index->base->ce_mem_pool, istate->cache[i])) {
- die("internal error: cache entry is not allocated from expected memory pool");
+ BUG("cache entry is not allocated from expected memory pool");
}
}
}
return ret;
ret = adjust_shared_perm(get_tempfile_path(*temp));
if (ret) {
- error("cannot fix permission bits on %s", get_tempfile_path(*temp));
+ error(_("cannot fix permission bits on '%s'"), get_tempfile_path(*temp));
return ret;
}
ret = rename_tempfile(temp,
struct split_index *si = istate->split_index;
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
- cache_tree_verify(istate);
+ cache_tree_verify(the_repository, istate);
if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
if (flags & COMMIT_LOCK)
new_ce->ce_namelen = len;
new_ce->ce_mode = ce->ce_mode;
if (add_index_entry(istate, new_ce, ADD_CACHE_SKIP_DFCHECK))
- return error("%s: cannot drop to stage #0",
+ return error(_("%s: cannot drop to stage #0"),
new_ce->name);
}
return unmerged;
static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset)
{
- const char *index = NULL;
- uint32_t extsize, ext_version;
- struct index_entry_offset_table *ieot;
- int i, nr;
-
- /* find the IEOT extension */
- if (!offset)
- return NULL;
- while (offset <= mmap_size - the_hash_algo->rawsz - 8) {
- extsize = get_be32(mmap + offset + 4);
- if (CACHE_EXT((mmap + offset)) == CACHE_EXT_INDEXENTRYOFFSETTABLE) {
- index = mmap + offset + 4 + 4;
- break;
- }
- offset += 8;
- offset += extsize;
- }
- if (!index)
- return NULL;
-
- /* validate the version is IEOT_VERSION */
- ext_version = get_be32(index);
- if (ext_version != IEOT_VERSION) {
- error("invalid IEOT version %d", ext_version);
- return NULL;
- }
- index += sizeof(uint32_t);
-
- /* extension size - version bytes / bytes per entry */
- nr = (extsize - sizeof(uint32_t)) / (sizeof(uint32_t) + sizeof(uint32_t));
- if (!nr) {
- error("invalid number of IEOT entries %d", nr);
- return NULL;
- }
- ieot = xmalloc(sizeof(struct index_entry_offset_table)
- + (nr * sizeof(struct index_entry_offset)));
- ieot->nr = nr;
- for (i = 0; i < nr; i++) {
- ieot->entries[i].offset = get_be32(index);
- index += sizeof(uint32_t);
- ieot->entries[i].nr = get_be32(index);
- index += sizeof(uint32_t);
- }
-
- return ieot;
+ const char *index = NULL;
+ uint32_t extsize, ext_version;
+ struct index_entry_offset_table *ieot;
+ int i, nr;
+
+ /* find the IEOT extension */
+ if (!offset)
+ return NULL;
+ while (offset <= mmap_size - the_hash_algo->rawsz - 8) {
+ extsize = get_be32(mmap + offset + 4);
+ if (CACHE_EXT((mmap + offset)) == CACHE_EXT_INDEXENTRYOFFSETTABLE) {
+ index = mmap + offset + 4 + 4;
+ break;
+ }
+ offset += 8;
+ offset += extsize;
+ }
+ if (!index)
+ return NULL;
+
+ /* validate the version is IEOT_VERSION */
+ ext_version = get_be32(index);
+ if (ext_version != IEOT_VERSION) {
+ error("invalid IEOT version %d", ext_version);
+ return NULL;
+ }
+ index += sizeof(uint32_t);
+
+ /* extension size - version bytes / bytes per entry */
+ nr = (extsize - sizeof(uint32_t)) / (sizeof(uint32_t) + sizeof(uint32_t));
+ if (!nr) {
+ error("invalid number of IEOT entries %d", nr);
+ return NULL;
+ }
+ ieot = xmalloc(sizeof(struct index_entry_offset_table)
+ + (nr * sizeof(struct index_entry_offset)));
+ ieot->nr = nr;
+ for (i = 0; i < nr; i++) {
+ ieot->entries[i].offset = get_be32(index);
+ index += sizeof(uint32_t);
+ ieot->entries[i].nr = get_be32(index);
+ index += sizeof(uint32_t);
+ }
+
+ return ieot;
}
static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot)
{
- uint32_t buffer;
- int i;
+ uint32_t buffer;
+ int i;
- /* version */
- put_be32(&buffer, IEOT_VERSION);
- strbuf_add(sb, &buffer, sizeof(uint32_t));
+ /* version */
+ put_be32(&buffer, IEOT_VERSION);
+ strbuf_add(sb, &buffer, sizeof(uint32_t));
- /* ieot */
- for (i = 0; i < ieot->nr; i++) {
+ /* ieot */
+ for (i = 0; i < ieot->nr; i++) {
- /* offset */
- put_be32(&buffer, ieot->entries[i].offset);
- strbuf_add(sb, &buffer, sizeof(uint32_t));
+ /* offset */
+ put_be32(&buffer, ieot->entries[i].offset);
+ strbuf_add(sb, &buffer, sizeof(uint32_t));
- /* count */
- put_be32(&buffer, ieot->entries[i].nr);
- strbuf_add(sb, &buffer, sizeof(uint32_t));
- }
+ /* count */
+ put_be32(&buffer, ieot->entries[i].nr);
+ strbuf_add(sb, &buffer, sizeof(uint32_t));
+ }
}
}
}
-int edit_todo_list(unsigned flags)
+int edit_todo_list(struct repository *r, unsigned flags)
{
struct strbuf buf = STRBUF_INIT;
const char *todo_file = rebase_path_todo();
strbuf_release(&buf);
- transform_todos(flags | TODO_LIST_SHORTEN_IDS);
+ transform_todos(r, flags | TODO_LIST_SHORTEN_IDS);
if (strbuf_read_file(&buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
if (launch_sequence_editor(todo_file, NULL, NULL))
return -1;
- transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));
+ transform_todos(r, flags & ~(TODO_LIST_SHORTEN_IDS));
return 0;
}
#ifndef REBASE_INTERACTIVE_H
#define REBASE_INTERACTIVE_H
+struct strbuf;
+struct repository;
+
void append_todo_help(unsigned edit_todo, unsigned keep_empty,
struct strbuf *buf);
-int edit_todo_list(unsigned flags);
+int edit_todo_list(struct repository *r, unsigned flags);
#endif
struct strbuf desc = STRBUF_INIT;
struct wt_status_state state;
memset(&state, 0, sizeof(state));
- wt_status_get_state(&state, 1);
+ wt_status_get_state(the_repository, &state, 1);
if (state.rebase_in_progress ||
state.rebase_interactive_in_progress) {
if (state.branch)
if (rf->merge) {
if (no_merged) {
- return opterror(opt, "is incompatible with --merged", 0);
+ return error(_("option `%s' is incompatible with --merged"),
+ opt->long_name);
} else {
- return opterror(opt, "is incompatible with --no-merged", 0);
+ return error(_("option `%s' is incompatible with --no-merged"),
+ opt->long_name);
}
}
rf->merge_commit = lookup_commit_reference_gently(the_repository,
&oid, 0);
if (!rf->merge_commit)
- return opterror(opt, "must point to a commit", 0);
+ return error(_("option `%s' must point to a commit"), opt->long_name);
return 0;
}
return err;
}
-static curl_off_t xcurl_off_t(size_t len) {
+static curl_off_t xcurl_off_t(size_t len)
+{
uintmax_t size = len;
if (size > maximum_signed_value_of_type(curl_off_t))
die("cannot handle pushes this big");
#include "mergesort.h"
#include "argv-array.h"
#include "commit-reach.h"
+#include "advice.h"
enum map_direction { FROM_SRC, FROM_DST };
return 0;
/* Handle remote.<name>.* variables */
if (*name == '/') {
- warning("Config remote shorthand cannot begin with '/': %s",
+ warning(_("config remote shorthand cannot begin with '/': %s"),
name);
return 0;
}
if (!remote->receivepack)
remote->receivepack = v;
else
- error("more than one receivepack given, using the first");
+ error(_("more than one receivepack given, using the first"));
} else if (!strcmp(subkey, "uploadpack")) {
const char *v;
if (git_config_string(&v, key, value))
if (!remote->uploadpack)
remote->uploadpack = v;
else
- error("more than one uploadpack given, using the first");
+ error(_("more than one uploadpack given, using the first"));
} else if (!strcmp(subkey, "tagopt")) {
if (!strcmp(value, "--no-tags"))
remote->fetch_tags = -1;
* FETCH_HEAD_IGNORE entries always appear at
* the end of the list.
*/
- die(_("Internal error"));
+ BUG("Internal error");
}
}
free(ref2->peer_ref);
size_t namelen;
int ret;
if (!kstar)
- die("Key '%s' of pattern had no '*'", key);
+ die(_("key '%s' of pattern had no '*'"), key);
klen = kstar - key;
ksuffixlen = strlen(kstar + 1);
namelen = strlen(name);
struct strbuf sb = STRBUF_INIT;
const char *vstar = strchr(value, '*');
if (!vstar)
- die("Value '%s' of pattern has no '*'", value);
+ die(_("value '%s' of pattern has no '*'"), value);
strbuf_add(&sb, value, vstar - value);
strbuf_add(&sb, name + klen, namelen - klen - ksuffixlen);
strbuf_addstr(&sb, vstar + 1);
int find_src = !query->src;
if (find_src && !query->dst)
- error("query_refspecs_multiple: need either src or dst");
+ BUG("query_refspecs_multiple: need either src or dst");
for (i = 0; i < rs->nr; i++) {
struct refspec_item *refspec = &rs->items[i];
char **result = find_src ? &query->src : &query->dst;
if (find_src && !query->dst)
- return error("query_refspecs: need either src or dst");
+ BUG("query_refspecs: need either src or dst");
for (i = 0; i < rs->nr; i++) {
struct refspec_item *refspec = &rs->items[i];
if (!r)
return NULL;
- if (starts_with(r, "refs/heads/"))
+ if (starts_with(r, "refs/heads/")) {
strbuf_addstr(&buf, "refs/heads/");
- else if (starts_with(r, "refs/tags/"))
+ } else if (starts_with(r, "refs/tags/")) {
strbuf_addstr(&buf, "refs/tags/");
- else
+ } else {
return NULL;
+ }
strbuf_addstr(&buf, name);
return strbuf_detach(&buf, NULL);
* way to delete 'other' ref at the remote end.
*/
if (try_explicit_object_name(rs->src, match) < 0)
- return error("src refspec %s does not match any.", rs->src);
+ return error(_("src refspec %s does not match any"), rs->src);
if (allocated_match)
*allocated_match = 1;
return 0;
default:
- return error("src refspec %s matches more than one.", rs->src);
+ return error(_("src refspec %s matches more than one"), rs->src);
+ }
+}
+
+static void show_push_unqualified_ref_name_error(const char *dst_value,
+ const char *matched_src_name)
+{
+ struct object_id oid;
+ enum object_type type;
+
+ /*
+ * TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
+ * <remote> <src>:<dst>" push, and "being pushed ('%s')" is
+ * the <src>.
+ */
+ error(_("The destination you provided is not a full refname (i.e.,\n"
+ "starting with \"refs/\"). We tried to guess what you meant by:\n"
+ "\n"
+ "- Looking for a ref that matches '%s' on the remote side.\n"
+ "- Checking if the <src> being pushed ('%s')\n"
+ " is a ref in \"refs/{heads,tags}/\". If so we add a corresponding\n"
+ " refs/{heads,tags}/ prefix on the remote side.\n"
+ "\n"
+ "Neither worked, so we gave up. You must fully qualify the ref."),
+ dst_value, matched_src_name);
+
+ if (!advice_push_unqualified_ref_name)
+ return;
+
+ if (get_oid(matched_src_name, &oid))
+ BUG("'%s' is not a valid object, "
+ "match_explicit_lhs() should catch this!",
+ matched_src_name);
+ type = oid_object_info(the_repository, &oid, NULL);
+ if (type == OBJ_COMMIT) {
+ advise(_("The <src> part of the refspec is a commit object.\n"
+ "Did you mean to create a new branch by pushing to\n"
+ "'%s:refs/heads/%s'?"),
+ matched_src_name, dst_value);
+ } else if (type == OBJ_TAG) {
+ advise(_("The <src> part of the refspec is a tag object.\n"
+ "Did you mean to create a new tag by pushing to\n"
+ "'%s:refs/tags/%s'?"),
+ matched_src_name, dst_value);
+ } else if (type == OBJ_TREE) {
+ advise(_("The <src> part of the refspec is a tree object.\n"
+ "Did you mean to tag a new tree by pushing to\n"
+ "'%s:refs/tags/%s'?"),
+ matched_src_name, dst_value);
+ } else if (type == OBJ_BLOB) {
+ advise(_("The <src> part of the refspec is a blob object.\n"
+ "Did you mean to tag a new blob by pushing to\n"
+ "'%s:refs/tags/%s'?"),
+ matched_src_name, dst_value);
+ } else {
+ BUG("'%s' should be commit/tag/tree/blob, is '%d'",
+ matched_src_name, type);
}
}
if (!dst_value ||
((flag & REF_ISSYMREF) &&
!starts_with(dst_value, "refs/heads/")))
- die("%s cannot be resolved to branch.",
+ die(_("%s cannot be resolved to branch"),
matched_src->name);
}
case 1:
break;
case 0:
- if (starts_with(dst_value, "refs/"))
+ if (starts_with(dst_value, "refs/")) {
matched_dst = make_linked_ref(dst_value, dst_tail);
- else if (is_null_oid(&matched_src->new_oid))
- error("unable to delete '%s': remote ref does not exist",
+ } else if (is_null_oid(&matched_src->new_oid)) {
+ error(_("unable to delete '%s': remote ref does not exist"),
dst_value);
- else if ((dst_guess = guess_ref(dst_value, matched_src))) {
+ } else if ((dst_guess = guess_ref(dst_value, matched_src))) {
matched_dst = make_linked_ref(dst_guess, dst_tail);
free(dst_guess);
- } else
- error("unable to push to unqualified destination: %s\n"
- "The destination refspec neither matches an "
- "existing ref on the remote nor\n"
- "begins with refs/, and we are unable to "
- "guess a prefix based on the source ref.",
- dst_value);
+ } else {
+ show_push_unqualified_ref_name_error(dst_value,
+ matched_src->name);
+ }
break;
default:
matched_dst = NULL;
- error("dst refspec %s matches more than one.",
+ error(_("dst refspec %s matches more than one"),
dst_value);
break;
}
if (!matched_dst)
return -1;
if (matched_dst->peer_ref)
- return error("dst ref %s receives from more than one src.",
- matched_dst->name);
+ return error(_("dst ref %s receives from more than one src"),
+ matched_dst->name);
else {
matched_dst->peer_ref = allocated_src ?
matched_src :
ref_map = get_remote_ref(remote_refs, name);
}
if (!missing_ok && !ref_map)
- die("Couldn't find remote ref %s", name);
+ die(_("couldn't find remote ref %s"), name);
if (ref_map) {
ref_map->peer_ref = get_local_ref(refspec->dst);
if (ref_map->peer_ref && refspec->force)
if (!starts_with((*rmp)->peer_ref->name, "refs/") ||
check_refname_format((*rmp)->peer_ref->name, 0)) {
struct ref *ignore = *rmp;
- error("* Ignoring funny ref '%s' locally",
+ error(_("* Ignoring funny ref '%s' locally"),
(*rmp)->peer_ref->name);
*rmp = (*rmp)->next;
free(ignore->peer_ref);
repo_init_revisions(the_repository, &revs, NULL);
setup_revisions(argv.argc, argv.argv, &revs, NULL);
if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
+ die(_("revision walk setup failed"));
/* ... and count the commits on each side. */
while (1) {
else if (!colon[1])
oidclr(&entry->expect);
else if (get_oid(colon + 1, &entry->expect))
- return error("cannot parse expected object name '%s'", colon + 1);
+ return error(_("cannot parse expected object name '%s'"),
+ colon + 1);
return 0;
}
free(old_gitdir);
repo_set_commondir(repo, o->commondir);
- expand_base_dir(&repo->objects->objectdir, o->object_dir,
+
+ if (!repo->objects->odb) {
+ repo->objects->odb = xcalloc(1, sizeof(*repo->objects->odb));
+ repo->objects->odb_tail = &repo->objects->odb->next;
+ }
+ expand_base_dir(&repo->objects->odb->path, o->object_dir,
repo->commondir, "objects");
+
free(repo->objects->alternate_db);
repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);
expand_base_dir(&repo->graft_file, o->graft_file,
* work on (i.e. what is left by the previous invocation of "git
* rerere" during the current conflict resolution session).
*/
-static void read_rr(struct string_list *rr)
+static void read_rr(struct repository *r, struct string_list *rr)
{
struct strbuf buf = STRBUF_INIT;
- FILE *in = fopen_or_warn(git_path_merge_rr(the_repository), "r");
+ FILE *in = fopen_or_warn(git_path_merge_rr(r), "r");
if (!in)
return;
{
int i;
- if (setup_rerere(merge_rr, RERERE_READONLY))
+ if (setup_rerere(r, merge_rr, RERERE_READONLY))
return 0;
if (read_index(r->index) < 0)
return error(_("index file corrupt"));
return 1;
}
-int setup_rerere(struct string_list *merge_rr, int flags)
+int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
{
int fd;
fd = 0;
else
fd = hold_lock_file_for_update(&write_lock,
- git_path_merge_rr(the_repository),
+ git_path_merge_rr(r),
LOCK_DIE_ON_ERROR);
- read_rr(merge_rr);
+ read_rr(r, merge_rr);
return fd;
}
struct string_list merge_rr = STRING_LIST_INIT_DUP;
int fd, status;
- fd = setup_rerere(&merge_rr, flags);
+ fd = setup_rerere(r, &merge_rr, flags);
if (fd < 0)
return 0;
status = do_plain_rerere(r, &merge_rr, fd);
if (read_index(r->index) < 0)
return error(_("index file corrupt"));
- fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
+ fd = setup_rerere(r, &merge_rr, RERERE_NOAUTOUPDATE);
if (fd < 0)
return 0;
unlink_rr_item(id);
}
-void rerere_gc(struct string_list *rr)
+void rerere_gc(struct repository *r, struct string_list *rr)
{
struct string_list to_remove = STRING_LIST_INIT_DUP;
DIR *dir;
timestamp_t cutoff_noresolve = now - 15 * 86400;
timestamp_t cutoff_resolve = now - 60 * 86400;
- if (setup_rerere(rr, 0) < 0)
+ if (setup_rerere(r, rr, 0) < 0)
return;
git_config_get_expiry_in_days("gc.rerereresolved", &cutoff_resolve, now);
*
* NEEDSWORK: shouldn't we be calling this from "reset --hard"?
*/
-void rerere_clear(struct string_list *merge_rr)
+void rerere_clear(struct repository *r, struct string_list *merge_rr)
{
int i;
- if (setup_rerere(merge_rr, 0) < 0)
+ if (setup_rerere(r, merge_rr, 0) < 0)
return;
for (i = 0; i < merge_rr->nr; i++) {
rmdir(rerere_path(id, NULL));
}
}
- unlink_or_warn(git_path_merge_rr(the_repository));
+ unlink_or_warn(git_path_merge_rr(r));
rollback_lock_file(&write_lock);
}
int variant;
};
-int setup_rerere(struct string_list *, int);
+int setup_rerere(struct repository *,struct string_list *, int);
#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
#define rerere(flags) repo_rerere(the_repository, flags)
#endif
const char *rerere_path(const struct rerere_id *, const char *file);
int rerere_forget(struct repository *, struct pathspec *);
int rerere_remaining(struct repository *, struct string_list *);
-void rerere_clear(struct string_list *);
-void rerere_gc(struct string_list *);
+void rerere_clear(struct repository *, struct string_list *);
+void rerere_gc(struct repository *, struct string_list *);
#define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
N_("update the index with reused conflict resolution if possible"))
revs->abbrev = DEFAULT_ABBREV;
revs->ignore_merges = 1;
revs->simplify_history = 1;
+ revs->pruning.repo = r;
revs->pruning.flags.recursive = 1;
revs->pruning.flags.quick = 1;
revs->pruning.add_remove = file_add_remove;
}
static void add_pending_commit_list(struct rev_info *revs,
- struct commit_list *commit_list,
- unsigned int flags)
+ struct commit_list *commit_list,
+ unsigned int flags)
{
while (commit_list) {
struct object *object = &commit_list->item->object;
if (!cant_be_filename)
verify_non_filename(revs->prefix, arg);
object = get_reference(revs, arg, &oid, flags ^ local_flags);
+ if (!object)
+ return revs->ignore_missing ? 0 : -1;
add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
free(oc.path);
}
static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
- int *unkc, const char **unkv)
+ int *unkc, const char **unkv,
+ const struct setup_revision_opt* opt)
{
const char *arg = argv[0];
const char *optarg;
revs->limited = 1;
} else if (!strcmp(arg, "--ignore-missing")) {
revs->ignore_missing = 1;
- } else if (revs->allow_exclude_promisor_objects_opt &&
+ } else if (opt && opt->allow_exclude_promisor_objects &&
!strcmp(arg, "--exclude-promisor-objects")) {
if (fetch_if_missing)
BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
const char * const usagestr[])
{
int n = handle_revision_opt(revs, ctx->argc, ctx->argv,
- &ctx->cpidx, ctx->out);
+ &ctx->cpidx, ctx->out, NULL);
if (n <= 0) {
error("unknown option `%s'", ctx->argv[0]);
usage_with_options(usagestr, options);
continue;
}
- opts = handle_revision_opt(revs, argc - i, argv + i, &left, argv);
+ opts = handle_revision_opt(revs, argc - i, argv + i,
+ &left, argv, opt);
if (opts > 0) {
i += opts - 1;
continue;
do_not_die_on_missing_tree:1,
/* for internal use only */
- allow_exclude_promisor_objects_opt:1,
exclude_promisor_objects:1;
/* Diff flags */
const char *def;
void (*tweak)(struct rev_info *, struct setup_revision_opt *);
const char *submodule; /* TODO: drop this and use rev_info->repo */
- int assume_dashdash;
+ unsigned int assume_dashdash:1,
+ allow_exclude_promisor_objects:1;
unsigned revarg_opt;
};
unuse_commit_buffer(commit, msg->message);
}
-static void print_advice(int show_hint, struct replay_opts *opts)
+static void print_advice(struct repository *r, int show_hint,
+ struct replay_opts *opts)
{
char *msg = getenv("GIT_CHERRY_PICK_HELP");
* (typically rebase --interactive) wants to take care
* of the commit itself so remove CHERRY_PICK_HEAD
*/
- unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_cherry_pick_head(r));
return;
}
return 1;
}
-static struct tree *empty_tree(void)
+static struct tree *empty_tree(struct repository *r)
{
- return lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
+ return lookup_tree(r, the_hash_algo->empty_tree);
}
-static int error_dirty_index(struct replay_opts *opts)
+static int error_dirty_index(struct index_state *istate, struct replay_opts *opts)
{
- if (read_cache_unmerged())
+ if (read_index_unmerged(istate))
return error_resolve_conflict(_(action_name(opts)));
error(_("your local changes would be overwritten by %s."),
write_file(git_path_abort_safety_file(), "%s", "");
}
-static int fast_forward_to(const struct object_id *to, const struct object_id *from,
- int unborn, struct replay_opts *opts)
+static int fast_forward_to(struct repository *r,
+ const struct object_id *to,
+ const struct object_id *from,
+ int unborn,
+ struct replay_opts *opts)
{
struct ref_transaction *transaction;
struct strbuf sb = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
- read_index(&the_index);
- if (checkout_fast_forward(the_repository, from, to, 1))
+ read_index(r->index);
+ if (checkout_fast_forward(r, from, to, 1))
return -1; /* the callee should have complained already */
strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
return 0;
}
-void append_conflicts_hint(struct strbuf *msgbuf)
+void append_conflicts_hint(struct index_state *istate,
+ struct strbuf *msgbuf)
{
int i;
strbuf_addch(msgbuf, '\n');
strbuf_commented_addf(msgbuf, "Conflicts:\n");
- for (i = 0; i < active_nr;) {
- const struct cache_entry *ce = active_cache[i++];
+ for (i = 0; i < istate->cache_nr;) {
+ const struct cache_entry *ce = istate->cache[i++];
if (ce_stage(ce)) {
strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
+ while (i < istate->cache_nr &&
+ !strcmp(ce->name, istate->cache[i]->name))
i++;
}
}
}
-static int do_recursive_merge(struct commit *base, struct commit *next,
+static int do_recursive_merge(struct repository *r,
+ struct commit *base, struct commit *next,
const char *base_label, const char *next_label,
struct object_id *head, struct strbuf *msgbuf,
struct replay_opts *opts)
if (hold_locked_index(&index_lock, LOCK_REPORT_ON_ERROR) < 0)
return -1;
- read_cache();
+ read_index(r->index);
init_merge_options(&o);
o.ancestor = base ? base_label : "(empty tree)";
o.show_rename_progress = 1;
head_tree = parse_tree_indirect(head);
- next_tree = next ? get_commit_tree(next) : empty_tree();
- base_tree = base ? get_commit_tree(base) : empty_tree();
+ next_tree = next ? get_commit_tree(next) : empty_tree(r);
+ base_tree = base ? get_commit_tree(base) : empty_tree(r);
for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
parse_merge_opt(&o, *xopt);
return clean;
}
- if (write_locked_index(&the_index, &index_lock,
+ if (write_locked_index(r->index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
/*
* TRANSLATORS: %s will be "revert", "cherry-pick" or
_(action_name(opts)));
if (!clean)
- append_conflicts_hint(msgbuf);
+ append_conflicts_hint(r->index, msgbuf);
return !clean;
}
-static struct object_id *get_cache_tree_oid(void)
+static struct object_id *get_cache_tree_oid(struct index_state *istate)
{
- if (!active_cache_tree)
- active_cache_tree = cache_tree();
+ if (!istate->cache_tree)
+ istate->cache_tree = cache_tree();
- if (!cache_tree_fully_valid(active_cache_tree))
- if (cache_tree_update(&the_index, 0)) {
+ if (!cache_tree_fully_valid(istate->cache_tree))
+ if (cache_tree_update(istate, 0)) {
error(_("unable to update cache tree"));
return NULL;
}
- return &active_cache_tree->oid;
+ return &istate->cache_tree->oid;
}
-static int is_index_unchanged(void)
+static int is_index_unchanged(struct repository *r)
{
struct object_id head_oid, *cache_tree_oid;
struct commit *head_commit;
+ struct index_state *istate = r->index;
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return error(_("could not resolve HEAD commit"));
- head_commit = lookup_commit(the_repository, &head_oid);
+ head_commit = lookup_commit(r, &head_oid);
/*
* If head_commit is NULL, check_commit, called from
if (parse_commit(head_commit))
return -1;
- if (!(cache_tree_oid = get_cache_tree_oid()))
+ if (!(cache_tree_oid = get_cache_tree_oid(istate)))
return -1;
return oideq(cache_tree_oid, get_commit_tree_oid(head_commit));
* interactive rebase: in that case, we will want to retain the
* author metadata.
*/
-static int run_git_commit(const char *defmsg, struct replay_opts *opts,
+static int run_git_commit(struct repository *r,
+ const char *defmsg,
+ struct replay_opts *opts,
unsigned int flags)
{
struct child_process cmd = CHILD_PROCESS_INIT;
if (!defmsg)
BUG("root commit without message");
- if (!(cache_tree_oid = get_cache_tree_oid()))
+ if (!(cache_tree_oid = get_cache_tree_oid(r->index)))
res = -1;
if (!res)
run_rewrite_hook(&old_head->object.oid, new_head);
}
-static int run_prepare_commit_msg_hook(struct strbuf *msg, const char *commit)
+static int run_prepare_commit_msg_hook(struct repository *r,
+ struct strbuf *msg,
+ const char *commit)
{
struct argv_array hook_env = ARGV_ARRAY_INIT;
int ret;
if (write_message(msg->buf, msg->len, name, 0))
return -1;
- argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", get_index_file());
+ argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", r->index_file);
argv_array_push(&hook_env, "GIT_EDITOR=:");
if (commit)
ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
}
-void print_commit_summary(const char *prefix, const struct object_id *oid,
+void print_commit_summary(struct repository *r,
+ const char *prefix,
+ const struct object_id *oid,
unsigned int flags)
{
struct rev_info rev;
struct strbuf author_ident = STRBUF_INIT;
struct strbuf committer_ident = STRBUF_INIT;
- commit = lookup_commit(the_repository, oid);
+ commit = lookup_commit(r, oid);
if (!commit)
die(_("couldn't look up newly created commit"));
if (parse_commit(commit))
strbuf_release(&author_ident);
strbuf_release(&committer_ident);
- repo_init_revisions(the_repository, &rev, prefix);
+ repo_init_revisions(r, &rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
rev.diff = 1;
strbuf_release(&format);
}
-static int parse_head(struct commit **head)
+static int parse_head(struct repository *r, struct commit **head)
{
struct commit *current_head;
struct object_id oid;
if (get_oid("HEAD", &oid)) {
current_head = NULL;
} else {
- current_head = lookup_commit_reference(the_repository, &oid);
+ current_head = lookup_commit_reference(r, &oid);
if (!current_head)
return error(_("could not parse HEAD"));
if (!oideq(&oid, ¤t_head->object.oid)) {
* 0 - success
* 1 - run 'git commit'
*/
-static int try_to_commit(struct strbuf *msg, const char *author,
+static int try_to_commit(struct repository *r,
+ struct strbuf *msg, const char *author,
struct replay_opts *opts, unsigned int flags,
struct object_id *oid)
{
enum commit_msg_cleanup_mode cleanup;
int res = 0;
- if (parse_head(¤t_head))
+ if (parse_head(r, ¤t_head))
return -1;
if (flags & AMEND_MSG) {
commit_list_insert(current_head, &parents);
}
- if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL)) {
+ if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
res = error(_("git write-tree failed to write a tree"));
goto out;
}
}
if (find_hook("prepare-commit-msg")) {
- res = run_prepare_commit_msg_hook(msg, hook_commit);
+ res = run_prepare_commit_msg_hook(r, msg, hook_commit);
if (res)
goto out;
if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
return res;
}
-static int do_commit(const char *msg_file, const char *author,
+static int do_commit(struct repository *r,
+ const char *msg_file, const char *author,
struct replay_opts *opts, unsigned int flags)
{
int res = 1;
"from '%s'"),
msg_file);
- res = try_to_commit(msg_file ? &sb : NULL, author, opts, flags,
- &oid);
+ res = try_to_commit(r, msg_file ? &sb : NULL,
+ author, opts, flags, &oid);
strbuf_release(&sb);
if (!res) {
- unlink(git_path_cherry_pick_head(the_repository));
- unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_cherry_pick_head(r));
+ unlink(git_path_merge_msg(r));
if (!is_rebase_i(opts))
- print_commit_summary(NULL, &oid,
+ print_commit_summary(r, NULL, &oid,
SUMMARY_SHOW_AUTHOR_DATE);
return res;
}
}
if (res == 1)
- return run_git_commit(msg_file, opts, flags);
+ return run_git_commit(r, msg_file, opts, flags);
return res;
}
/*
* Do we run "git commit" with "--allow-empty"?
*/
-static int allow_empty(struct replay_opts *opts, struct commit *commit)
+static int allow_empty(struct repository *r,
+ struct replay_opts *opts,
+ struct commit *commit)
{
int index_unchanged, empty_commit;
if (!opts->allow_empty)
return 0; /* let "git commit" barf as necessary */
- index_unchanged = is_index_unchanged();
+ index_unchanged = is_index_unchanged(r);
if (index_unchanged < 0)
return index_unchanged;
if (!index_unchanged)
}
}
-static int update_squash_messages(enum todo_command command,
- struct commit *commit, struct replay_opts *opts)
+static int update_squash_messages(struct repository *r,
+ enum todo_command command,
+ struct commit *commit,
+ struct replay_opts *opts)
{
struct strbuf buf = STRBUF_INIT;
int res;
if (get_oid("HEAD", &head))
return error(_("need a HEAD to fixup"));
- if (!(head_commit = lookup_commit_reference(the_repository, &head)))
+ if (!(head_commit = lookup_commit_reference(r, &head)))
return error(_("could not read HEAD"));
if (!(head_message = get_commit_buffer(head_commit, NULL)))
return error(_("could not read HEAD's commit message"));
return res;
}
-static void flush_rewritten_pending(void) {
+static void flush_rewritten_pending(void)
+{
struct strbuf buf = STRBUF_INIT;
struct object_id newoid;
FILE *out;
}
static void record_in_rewritten(struct object_id *oid,
- enum todo_command next_command) {
+ enum todo_command next_command)
+{
FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a");
if (!out)
flush_rewritten_pending();
}
-static int do_pick_commit(enum todo_command command, struct commit *commit,
- struct replay_opts *opts, int final_fixup)
+static int do_pick_commit(struct repository *r,
+ 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(the_repository);
+ const char *msg_file = opts->edit ? NULL : git_path_merge_msg(r);
struct object_id head;
struct commit *base, *next, *parent;
const char *base_label, *next_label;
* that represents the "current" state for merge-recursive
* to work on.
*/
- if (write_index_as_tree(&head, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL))
return error(_("your index file is unmerged."));
} else {
unborn = get_oid("HEAD", &head);
unborn = 1;
} else if (unborn)
oidcpy(&head, the_hash_algo->empty_tree);
- if (index_differs_from(unborn ? empty_tree_oid_hex() : "HEAD",
+ if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD",
NULL, 0))
- return error_dirty_index(opts);
+ return error_dirty_index(r->index, opts);
}
- discard_cache();
+ discard_index(r->index);
if (!commit->parents)
parent = NULL;
(!parent && unborn))) {
if (is_rebase_i(opts))
write_author_script(msg.message);
- res = fast_forward_to(&commit->object.oid, &head, unborn,
+ res = fast_forward_to(r, &commit->object.oid, &head, unborn,
opts);
if (res || command != TODO_REWORD)
goto leave;
if (command == TODO_REWORD)
flags |= EDIT_MSG | VERIFY_MSG;
else if (is_fixup(command)) {
- if (update_squash_messages(command, commit, opts))
+ if (update_squash_messages(r, command, commit, opts))
return -1;
flags |= AMEND_MSG;
if (!final_fixup)
flags |= CLEANUP_MSG;
msg_file = rebase_path_fixup_msg();
} else {
- const char *dest = git_path_squash_msg(the_repository);
+ const char *dest = git_path_squash_msg(r);
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(the_repository));
+ unlink(git_path_merge_msg(r));
msg_file = dest;
flags |= EDIT_MSG;
}
if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
res = -1;
else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
- res = do_recursive_merge(base, next, base_label, next_label,
+ res = do_recursive_merge(r, base, next, base_label, next_label,
&head, &msgbuf, opts);
if (res < 0)
goto leave;
res |= write_message(msgbuf.buf, msgbuf.len,
- git_path_merge_msg(the_repository), 0);
+ git_path_merge_msg(r), 0);
} else {
struct commit_list *common = NULL;
struct commit_list *remotes = NULL;
res = write_message(msgbuf.buf, msgbuf.len,
- git_path_merge_msg(the_repository), 0);
+ git_path_merge_msg(r), 0);
commit_list_insert(base, &common);
commit_list_insert(next, &remotes);
- res |= try_merge_command(the_repository, opts->strategy,
+ res |= try_merge_command(r, opts->strategy,
opts->xopts_nr, (const char **)opts->xopts,
common, oid_to_hex(&head), remotes);
free_commit_list(common);
? _("could not revert %s... %s")
: _("could not apply %s... %s"),
short_commit_name(commit), msg.subject);
- print_advice(res == 1, opts);
- repo_rerere(the_repository, opts->allow_rerere_auto);
+ print_advice(r, res == 1, opts);
+ repo_rerere(r, opts->allow_rerere_auto);
goto leave;
}
- allow = allow_empty(opts, commit);
+ allow = allow_empty(r, opts, commit);
if (allow < 0) {
res = allow;
goto leave;
if (!opts->no_commit) {
fast_forward_edit:
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
- res = do_commit(msg_file, author, opts, flags);
+ res = do_commit(r, msg_file, author, opts, flags);
else
res = error(_("unable to parse commit author"));
}
return 0;
}
-static int read_and_refresh_cache(struct replay_opts *opts)
+static int read_and_refresh_cache(struct repository *r,
+ struct replay_opts *opts)
{
struct lock_file index_lock = LOCK_INIT;
int index_fd = hold_locked_index(&index_lock, 0);
- if (read_index(&the_index) < 0) {
+ if (read_index(r->index) < 0) {
rollback_lock_file(&index_lock);
return error(_("git %s: failed to read the index"),
_(action_name(opts)));
}
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
+ refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
if (index_fd >= 0) {
- if (write_locked_index(&the_index, &index_lock,
+ if (write_locked_index(r->index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED)) {
return error(_("git %s: failed to refresh the index"),
_(action_name(opts)));
return todo_list->items + todo_list->nr++;
}
-static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
+static int parse_insn_line(struct repository *r, struct todo_item *item,
+ const char *bol, char *eol)
{
struct object_id commit_oid;
char *end_of_object_name;
if (status < 0)
return -1;
- item->commit = lookup_commit_reference(the_repository, &commit_oid);
+ item->commit = lookup_commit_reference(r, &commit_oid);
return !item->commit;
}
-static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
+static int parse_insn_buffer(struct repository *r, char *buf,
+ struct todo_list *todo_list)
{
struct todo_item *item;
char *p = buf, *next_p;
item = append_new_todo(todo_list);
item->offset_in_buf = p - todo_list->buf.buf;
- if (parse_insn_line(item, p, eol)) {
+ if (parse_insn_line(r, item, p, eol)) {
res = error(_("invalid line %d: %.*s"),
i, (int)(eol - p), p);
item->command = TODO_NOOP;
return len;
}
-static int read_populate_todo(struct todo_list *todo_list,
- struct replay_opts *opts)
+static int read_populate_todo(struct repository *r,
+ struct todo_list *todo_list,
+ struct replay_opts *opts)
{
struct stat st;
const char *todo_file = get_todo_path(opts);
return error(_("could not stat '%s'"), todo_file);
fill_stat_data(&todo_list->stat, &st);
- res = parse_insn_buffer(todo_list->buf.buf, todo_list);
+ res = parse_insn_buffer(r, todo_list->buf.buf, todo_list);
if (res) {
if (is_rebase_i(opts))
return error(_("please fix this using "
FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
- !parse_insn_buffer(done.buf.buf, &done))
+ !parse_insn_buffer(r, done.buf.buf, &done))
todo_list->done_nr = count_commands(&done);
else
todo_list->done_nr = 0;
return run_command_v_opt(argv, RUN_GIT_CMD);
}
-static int rollback_single_pick(void)
+static int rollback_single_pick(struct repository *r)
{
struct object_id head_oid;
- if (!file_exists(git_path_cherry_pick_head(the_repository)) &&
- !file_exists(git_path_revert_head(the_repository)))
+ if (!file_exists(git_path_cherry_pick_head(r)) &&
+ !file_exists(git_path_revert_head(r)))
return error(_("no cherry-pick or revert in progress"));
if (read_ref_full("HEAD", 0, &head_oid, NULL))
return error(_("cannot resolve HEAD"));
return reset_for_rollback(&head_oid);
}
-int sequencer_rollback(struct replay_opts *opts)
+int sequencer_rollback(struct repository *r, struct replay_opts *opts)
{
FILE *f;
struct object_id oid;
* If CHERRY_PICK_HEAD or REVERT_HEAD indicates
* a single-cherry-pick in progress, abort that.
*/
- return rollback_single_pick();
+ return rollback_single_pick(r);
}
if (!f)
return error_errno(_("cannot open '%s'"), git_path_head_file());
return res;
}
-static int make_patch(struct commit *commit, struct replay_opts *opts)
+static int make_patch(struct repository *r,
+ struct commit *commit,
+ struct replay_opts *opts)
{
struct strbuf buf = STRBUF_INIT;
struct rev_info log_tree_opt;
strbuf_addf(&buf, "%s/patch", get_dir(opts));
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
- repo_init_revisions(the_repository, &log_tree_opt, NULL);
+ repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.abbrev = 0;
log_tree_opt.diff = 1;
log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
return write_message(p, strlen(p), rebase_path_amend(), 1);
}
-static int error_with_patch(struct commit *commit,
- const char *subject, int subject_len,
- struct replay_opts *opts, int exit_code, int to_amend)
+static int error_with_patch(struct repository *r,
+ struct commit *commit,
+ const char *subject, int subject_len,
+ struct replay_opts *opts,
+ int exit_code, int to_amend)
{
if (commit) {
- if (make_patch(commit, opts))
+ if (make_patch(r, commit, opts))
return -1;
} else if (copy_file(rebase_path_message(),
- git_path_merge_msg(the_repository), 0666))
+ git_path_merge_msg(r), 0666))
return error(_("unable to copy '%s' to '%s'"),
- git_path_merge_msg(the_repository), rebase_path_message());
+ git_path_merge_msg(r), rebase_path_message());
if (to_amend) {
if (intend_to_amend())
return exit_code;
}
-static int error_failed_squash(struct commit *commit,
- struct replay_opts *opts, int subject_len, const char *subject)
+static int error_failed_squash(struct repository *r,
+ struct commit *commit,
+ struct replay_opts *opts,
+ int subject_len,
+ const char *subject)
{
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(the_repository));
- if (copy_file(git_path_merge_msg(the_repository), rebase_path_message(), 0666))
+ unlink(git_path_merge_msg(r));
+ if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
return error(_("could not copy '%s' to '%s'"),
rebase_path_message(),
- git_path_merge_msg(the_repository));
- return error_with_patch(commit, subject, subject_len, opts, 1, 0);
+ git_path_merge_msg(r));
+ return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
}
-static int do_exec(const char *command_line)
+static int do_exec(struct repository *r, const char *command_line)
{
struct argv_array child_env = ARGV_ARRAY_INIT;
const char *child_argv[] = { NULL, NULL };
child_env.argv);
/* force re-reading of the cache */
- if (discard_cache() < 0 || read_cache() < 0)
+ if (discard_index(r->index) < 0 || read_index(r->index) < 0)
return error(_("could not read index"));
- dirty = require_clean_work_tree("rebase", NULL, 1, 1);
+ dirty = require_clean_work_tree(r, "rebase", NULL, 1, 1);
if (status) {
warning(_("execution failed: %s\n%s"
return 0;
}
-static int do_label(const char *name, int len)
+static int do_label(struct repository *r, const char *name, int len)
{
- struct ref_store *refs = get_main_ref_store(the_repository);
+ struct ref_store *refs = get_main_ref_store(r);
struct ref_transaction *transaction;
struct strbuf ref_name = STRBUF_INIT, err = STRBUF_INIT;
struct strbuf msg = STRBUF_INIT;
static const char *reflog_message(struct replay_opts *opts,
const char *sub_action, const char *fmt, ...);
-static int do_reset(const char *name, int len, struct replay_opts *opts)
+static int do_reset(struct repository *r,
+ const char *name, int len,
+ struct replay_opts *opts)
{
struct strbuf ref_name = STRBUF_INIT;
struct object_id oid;
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
setup_unpack_trees_porcelain(&unpack_tree_opts, "reset");
unpack_tree_opts.head_idx = 1;
- unpack_tree_opts.src_index = &the_index;
- unpack_tree_opts.dst_index = &the_index;
+ unpack_tree_opts.src_index = r->index;
+ unpack_tree_opts.dst_index = r->index;
unpack_tree_opts.fn = oneway_merge;
unpack_tree_opts.merge = 1;
unpack_tree_opts.update = 1;
- if (read_cache_unmerged()) {
+ if (read_index_unmerged(r->index)) {
rollback_lock_file(&lock);
strbuf_release(&ref_name);
return error_resolve_conflict(_(action_name(opts)));
}
tree = parse_tree_indirect(&oid);
- prime_cache_tree(&the_index, tree);
+ prime_cache_tree(r, r->index, tree);
- if (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)
+ if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
ret = error(_("could not write index"));
free((void *)desc.buffer);
return commit;
}
-static int do_merge(struct commit *commit, const char *arg, int arg_len,
+static int do_merge(struct repository *r,
+ struct commit *commit,
+ const char *arg, int arg_len,
int flags, struct replay_opts *opts)
{
int run_commit_flags = (flags & TODO_EDIT_MERGE_MSG) ?
ret = error(_("octopus merge cannot be executed on "
"top of a [new root]"));
else
- ret = fast_forward_to(&to_merge->item->object.oid,
+ ret = fast_forward_to(r, &to_merge->item->object.oid,
&head_commit->object.oid, 0,
opts);
goto leave_merge;
write_author_script(message);
find_commit_subject(message, &body);
len = strlen(body);
- ret = write_message(body, len, git_path_merge_msg(the_repository), 0);
+ ret = write_message(body, len, git_path_merge_msg(r), 0);
unuse_commit_buffer(commit, message);
if (ret) {
error_errno(_("could not write '%s'"),
- git_path_merge_msg(the_repository));
+ git_path_merge_msg(r));
goto leave_merge;
}
} else {
len = buf.len;
}
- ret = write_message(p, len, git_path_merge_msg(the_repository), 0);
+ ret = write_message(p, len, git_path_merge_msg(r), 0);
strbuf_release(&buf);
if (ret) {
error_errno(_("could not write '%s'"),
- git_path_merge_msg(the_repository));
+ git_path_merge_msg(r));
goto leave_merge;
}
}
if (can_fast_forward) {
rollback_lock_file(&lock);
- ret = fast_forward_to(&commit->object.oid,
+ ret = fast_forward_to(r, &commit->object.oid,
&head_commit->object.oid, 0, opts);
goto leave_merge;
}
argv_array_push(&cmd.args, "--no-log");
argv_array_push(&cmd.args, "--no-stat");
argv_array_push(&cmd.args, "-F");
- argv_array_push(&cmd.args, git_path_merge_msg(the_repository));
+ argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
oid_to_hex(&j->item->object.oid));
strbuf_release(&ref_name);
- unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_cherry_pick_head(r));
rollback_lock_file(&lock);
rollback_lock_file(&lock);
ret = run_command(&cmd);
/* force re-reading of the cache */
- if (!ret && (discard_cache() < 0 || read_cache() < 0))
+ if (!ret && (discard_index(r->index) < 0 ||
+ read_index(r->index) < 0))
ret = error(_("could not read index"));
goto leave_merge;
}
}
write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
- git_path_merge_head(the_repository), 0);
- write_message("no-ff", 5, git_path_merge_mode(the_repository), 0);
+ git_path_merge_head(r), 0);
+ write_message("no-ff", 5, git_path_merge_mode(r), 0);
for (j = bases; j; j = j->next)
commit_list_insert(j->item, &reversed);
free_commit_list(bases);
- read_cache();
+ read_index(r->index);
init_merge_options(&o);
o.branch1 = "HEAD";
o.branch2 = ref_name.buf;
*/
ret = !ret;
- if (active_cache_changed &&
- write_locked_index(&the_index, &lock, COMMIT_LOCK)) {
+ if (r->index->cache_changed &&
+ write_locked_index(r->index, &lock, COMMIT_LOCK)) {
ret = error(_("merge: Unable to write new index file"));
goto leave_merge;
}
rollback_lock_file(&lock);
if (ret)
- repo_rerere(the_repository, opts->allow_rerere_auto);
+ repo_rerere(r, opts->allow_rerere_auto);
else
/*
* In case of problems, we now want to return a positive
* value (a negative one would indicate that the `merge`
* command needs to be rescheduled).
*/
- ret = !!run_git_commit(git_path_merge_msg(the_repository), opts,
- run_commit_flags);
+ ret = !!run_git_commit(r, git_path_merge_msg(r), opts,
+ run_commit_flags);
leave_merge:
strbuf_release(&ref_name);
return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);
}
-static int stopped_at_head(void)
+static int stopped_at_head(struct repository *r)
{
struct object_id head;
struct commit *commit;
struct commit_message message;
if (get_oid("HEAD", &head) ||
- !(commit = lookup_commit(the_repository, &head)) ||
+ !(commit = lookup_commit(r, &head)) ||
parse_commit(commit) || get_message(commit, &message))
fprintf(stderr, _("Stopped at HEAD\n"));
else {
" git rebase --edit-todo\n"
" git rebase --continue\n");
-static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
+static int pick_commits(struct repository *r,
+ struct todo_list *todo_list,
+ struct replay_opts *opts)
{
int res = 0, reschedule = 0;
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit));
- if (read_and_refresh_cache(opts))
+ if (read_and_refresh_cache(r, opts))
return -1;
while (todo_list->current < todo_list->nr) {
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
if (item->command == TODO_BREAK)
- return stopped_at_head();
+ return stopped_at_head(r);
}
if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts))
setenv("GIT_REFLOG_ACTION", reflog_message(opts,
command_to_string(item->command), NULL),
1);
- res = do_pick_commit(item->command, item->commit,
+ res = do_pick_commit(r, item->command, item->commit,
opts, is_final_fixup(todo_list));
if (is_rebase_i(opts) && res < 0) {
/* Reschedule */
_("Stopped at %s... %.*s\n"),
short_commit_name(commit),
item->arg_len, item->arg);
- return error_with_patch(commit,
+ return error_with_patch(r, commit,
item->arg, item->arg_len, opts, res,
!res);
}
if (res && is_fixup(item->command)) {
if (res == 1)
intend_to_amend();
- return error_failed_squash(item->commit, opts,
+ return error_failed_squash(r, item->commit, opts,
item->arg_len, item->arg);
} else if (res && is_rebase_i(opts) && item->commit) {
int to_amend = 0;
oideq(&opts->squash_onto, &oid))))
to_amend = 1;
- return res | error_with_patch(item->commit,
+ return res | error_with_patch(r, item->commit,
item->arg, item->arg_len, opts,
res, to_amend);
}
struct stat st;
*end_of_arg = '\0';
- res = do_exec(item->arg);
+ res = do_exec(r, item->arg);
*end_of_arg = saved;
/* Reread the todo file if it has changed. */
get_todo_path(opts));
else if (match_stat_data(&todo_list->stat, &st)) {
todo_list_release(todo_list);
- if (read_populate_todo(todo_list, opts))
+ if (read_populate_todo(r, todo_list, opts))
res = -1; /* message was printed */
/* `current` will be incremented below */
todo_list->current = -1;
}
} else if (item->command == TODO_LABEL) {
- if ((res = do_label(item->arg, item->arg_len)))
+ if ((res = do_label(r, item->arg, item->arg_len)))
reschedule = 1;
} else if (item->command == TODO_RESET) {
- if ((res = do_reset(item->arg, item->arg_len, opts)))
+ if ((res = do_reset(r, item->arg, item->arg_len, opts)))
reschedule = 1;
} else if (item->command == TODO_MERGE) {
- if ((res = do_merge(item->commit,
+ if ((res = do_merge(r, item->commit,
item->arg, item->arg_len,
item->flags, opts)) < 0)
reschedule = 1;
peek_command(todo_list, 1));
if (res > 0)
/* failed with merge conflicts */
- return error_with_patch(item->commit,
+ return error_with_patch(r, item->commit,
item->arg,
item->arg_len, opts,
res, 0);
if (save_todo(todo_list, opts))
return -1;
if (item->commit)
- return error_with_patch(item->commit,
+ return error_with_patch(r,
+ item->commit,
item->arg,
item->arg_len, opts,
res, 0);
struct object_id orig, head;
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
- repo_init_revisions(the_repository, &log_tree_opt, NULL);
+ repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.diff = 1;
log_tree_opt.diffopt.output_format =
DIFF_FORMAT_DIFFSTAT;
return sequencer_remove_state(opts);
}
-static int continue_single_pick(void)
+static int continue_single_pick(struct repository *r)
{
const char *argv[] = { "commit", NULL };
- if (!file_exists(git_path_cherry_pick_head(the_repository)) &&
- !file_exists(git_path_revert_head(the_repository)))
+ if (!file_exists(git_path_cherry_pick_head(r)) &&
+ !file_exists(git_path_revert_head(r)))
return error(_("no cherry-pick or revert in progress"));
return run_command_v_opt(argv, RUN_GIT_CMD);
}
-static int commit_staged_changes(struct replay_opts *opts,
+static int commit_staged_changes(struct repository *r,
+ struct replay_opts *opts,
struct todo_list *todo_list)
{
unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
unsigned int final_fixup = 0, is_clean;
- if (has_unstaged_changes(1))
+ if (has_unstaged_changes(r, 1))
return error(_("cannot rebase: You have unstaged changes."));
- is_clean = !has_uncommitted_changes(0);
+ is_clean = !has_uncommitted_changes(r, 0);
if (file_exists(rebase_path_amend())) {
struct strbuf rev = STRBUF_INIT;
struct commit *commit;
const char *path = rebase_path_squash_msg();
- if (parse_head(&commit) ||
+ if (parse_head(r, &commit) ||
!(p = get_commit_buffer(commit, NULL)) ||
write_message(p, strlen(p), path, 0)) {
unuse_commit_buffer(commit, p);
}
if (is_clean) {
- const char *cherry_pick_head = git_path_cherry_pick_head(the_repository);
+ const char *cherry_pick_head = git_path_cherry_pick_head(r);
if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
return error(_("could not remove CHERRY_PICK_HEAD"));
return 0;
}
- if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
+ if (run_git_commit(r, final_fixup ? NULL : rebase_path_message(),
opts, flags))
return error(_("could not commit staged changes."));
unlink(rebase_path_amend());
return 0;
}
-int sequencer_continue(struct replay_opts *opts)
+int sequencer_continue(struct repository *r, struct replay_opts *opts)
{
struct todo_list todo_list = TODO_LIST_INIT;
int res;
- if (read_and_refresh_cache(opts))
+ if (read_and_refresh_cache(r, opts))
return -1;
if (read_populate_opts(opts))
return -1;
if (is_rebase_i(opts)) {
- if ((res = read_populate_todo(&todo_list, opts)))
+ if ((res = read_populate_todo(r, &todo_list, opts)))
goto release_todo_list;
- if (commit_staged_changes(opts, &todo_list))
+ if (commit_staged_changes(r, opts, &todo_list))
return -1;
} else if (!file_exists(get_todo_path(opts)))
- return continue_single_pick();
- else if ((res = read_populate_todo(&todo_list, opts)))
+ return continue_single_pick(r);
+ else if ((res = read_populate_todo(r, &todo_list, opts)))
goto release_todo_list;
if (!is_rebase_i(opts)) {
/* Verify that the conflict has been resolved */
- if (file_exists(git_path_cherry_pick_head(the_repository)) ||
- file_exists(git_path_revert_head(the_repository))) {
- res = continue_single_pick();
+ if (file_exists(git_path_cherry_pick_head(r)) ||
+ file_exists(git_path_revert_head(r))) {
+ res = continue_single_pick(r);
if (res)
goto release_todo_list;
}
- if (index_differs_from("HEAD", NULL, 0)) {
- res = error_dirty_index(opts);
+ if (index_differs_from(r, "HEAD", NULL, 0)) {
+ res = error_dirty_index(r->index, opts);
goto release_todo_list;
}
todo_list.current++;
strbuf_release(&buf);
}
- res = pick_commits(&todo_list, opts);
+ res = pick_commits(r, &todo_list, opts);
release_todo_list:
todo_list_release(&todo_list);
return res;
}
-static int single_pick(struct commit *cmit, struct replay_opts *opts)
+static int single_pick(struct repository *r,
+ struct commit *cmit,
+ struct replay_opts *opts)
{
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
- return do_pick_commit(opts->action == REPLAY_PICK ?
+ return do_pick_commit(r, opts->action == REPLAY_PICK ?
TODO_PICK : TODO_REVERT, cmit, opts, 0);
}
-int sequencer_pick_revisions(struct replay_opts *opts)
+int sequencer_pick_revisions(struct repository *r,
+ struct replay_opts *opts)
{
struct todo_list todo_list = TODO_LIST_INIT;
struct object_id oid;
int i, res;
assert(opts->revs);
- if (read_and_refresh_cache(opts))
+ if (read_and_refresh_cache(r, opts))
return -1;
for (i = 0; i < opts->revs->pending.nr; i++) {
continue;
if (!get_oid(name, &oid)) {
- if (!lookup_commit_reference_gently(the_repository, &oid, 1)) {
- enum object_type type = oid_object_info(the_repository,
+ if (!lookup_commit_reference_gently(r, &oid, 1)) {
+ enum object_type type = oid_object_info(r,
&oid,
NULL);
return error(_("%s: can't cherry-pick a %s"),
return error(_("empty commit set passed"));
if (get_revision(opts->revs))
BUG("unexpected extra commit from walk");
- return single_pick(cmit, opts);
+ return single_pick(r, cmit, opts);
}
/*
if (save_opts(opts))
return -1;
update_abort_safety_file();
- res = pick_commits(&todo_list, opts);
+ res = pick_commits(r, &todo_list, opts);
todo_list_release(&todo_list);
return res;
}
return 0;
}
-int sequencer_make_script(FILE *out, int argc, const char **argv,
+int sequencer_make_script(struct repository *r, FILE *out,
+ int argc, const char **argv,
unsigned flags)
{
char *format = NULL;
const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(r, &revs, NULL);
revs.verbose_header = 1;
if (!rebase_merges)
revs.max_parents = 1;
* Add commands after pick and (series of) squash/fixup commands
* in the todo list.
*/
-int sequencer_add_exec_commands(const char *commands)
+int sequencer_add_exec_commands(struct repository *r,
+ const char *commands)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT;
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error(_("could not read '%s'."), todo_file);
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list)) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) {
todo_list_release(&todo_list);
return error(_("unusable todo list: '%s'"), todo_file);
}
return i;
}
-int transform_todos(unsigned flags)
+int transform_todos(struct repository *r, unsigned flags)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT;
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error(_("could not read '%s'."), todo_file);
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list)) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) {
todo_list_release(&todo_list);
return error(_("unusable todo list: '%s'"), todo_file);
}
* Check if there is an unrecognized command or a
* bad SHA-1 in a command.
*/
-int check_todo_list(void)
+int check_todo_list(struct repository *r)
{
enum missing_commit_check_level check_level = get_missing_commit_check_level();
struct strbuf todo_file = STRBUF_INIT;
goto leave_check;
}
advise_to_edit_todo = res =
- parse_insn_buffer(todo_list.buf.buf, &todo_list);
+ parse_insn_buffer(r, todo_list.buf.buf, &todo_list);
if (res || check_level == MISSING_COMMIT_CHECK_IGNORE)
goto leave_check;
goto leave_check;
}
strbuf_release(&todo_file);
- res = !!parse_insn_buffer(todo_list.buf.buf, &todo_list);
+ res = !!parse_insn_buffer(r, todo_list.buf.buf, &todo_list);
/* Find commits in git-rebase-todo.backup yet unseen */
for (i = todo_list.nr - 1; i >= 0; i--) {
}
/* skip picking commits whose parents are unchanged */
-static int skip_unnecessary_picks(struct object_id *output_oid)
+static int skip_unnecessary_picks(struct repository *r, struct object_id *output_oid)
{
const char *todo_file = rebase_path_todo();
struct strbuf buf = STRBUF_INIT;
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
return -1;
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) {
todo_list_release(&todo_list);
return -1;
}
return 0;
}
-int complete_action(struct replay_opts *opts, unsigned flags,
+int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
const char *shortrevisions, const char *onto_name,
const char *onto, const char *orig_head, const char *cmd,
unsigned autosquash)
write_message("noop\n", 5, todo_file, 0))
return -1;
- if (autosquash && rearrange_squash())
+ if (autosquash && rearrange_squash(r))
return -1;
if (cmd && *cmd)
- sequencer_add_exec_commands(cmd);
+ sequencer_add_exec_commands(r, cmd);
if (strbuf_read_file(buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
- if (parse_insn_buffer(buf->buf, &todo_list)) {
+ if (parse_insn_buffer(r, buf->buf, &todo_list)) {
todo_list_release(&todo_list);
return error(_("unusable todo list: '%s'"), todo_file);
}
return error(_("could not copy '%s' to '%s'."), todo_file,
rebase_path_todo_backup());
- if (transform_todos(flags | TODO_LIST_SHORTEN_IDS))
+ if (transform_todos(r, flags | TODO_LIST_SHORTEN_IDS))
return error(_("could not transform the todo list"));
strbuf_reset(buf);
todo_list_release(&todo_list);
- if (check_todo_list()) {
+ if (check_todo_list(r)) {
checkout_onto(opts, onto_name, onto, orig_head);
return -1;
}
- if (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS)))
+ if (transform_todos(r, flags & ~(TODO_LIST_SHORTEN_IDS)))
return error(_("could not transform the todo list"));
- if (opts->allow_ff && skip_unnecessary_picks(&oid))
+ if (opts->allow_ff && skip_unnecessary_picks(r, &oid))
return error(_("could not skip unnecessary pick commands"));
if (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head))
return -1;
- if (require_clean_work_tree("rebase", "", 1, 1))
+ if (require_clean_work_tree(r, "rebase", "", 1, 1))
return -1;
- return sequencer_continue(opts);
+ return sequencer_continue(r, opts);
}
struct subject2item_entry {
* message will have to be retrieved from the commit (as the oneline in the
* script cannot be trusted) in order to normalize the autosquash arrangement.
*/
-int rearrange_squash(void)
+int rearrange_squash(struct repository *r)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT;
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
return -1;
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) {
todo_list_release(&todo_list);
return -1;
}
#include "strbuf.h"
struct commit;
+struct repository;
const char *git_path_commit_editmsg(void);
const char *git_path_seq_dir(void);
/* Call this to setup defaults before parsing command line options */
void sequencer_init_config(struct replay_opts *opts);
-int sequencer_pick_revisions(struct replay_opts *opts);
-int sequencer_continue(struct replay_opts *opts);
-int sequencer_rollback(struct replay_opts *opts);
+int sequencer_pick_revisions(struct repository *repo,
+ struct replay_opts *opts);
+int sequencer_continue(struct repository *repo, struct replay_opts *opts);
+int sequencer_rollback(struct repository *repo, struct replay_opts *opts);
int sequencer_remove_state(struct replay_opts *opts);
#define TODO_LIST_KEEP_EMPTY (1U << 0)
* commits should be rebased onto the new base, this flag needs to be passed.
*/
#define TODO_LIST_REBASE_COUSINS (1U << 4)
-int sequencer_make_script(FILE *out, int argc, const char **argv,
+int sequencer_make_script(struct repository *repo, FILE *out,
+ int argc, const char **argv,
unsigned flags);
-int sequencer_add_exec_commands(const char *command);
-int transform_todos(unsigned flags);
+int sequencer_add_exec_commands(struct repository *r, const char *command);
+int transform_todos(struct repository *r, unsigned flags);
enum missing_commit_check_level get_missing_commit_check_level(void);
-int check_todo_list(void);
-int complete_action(struct replay_opts *opts, unsigned flags,
+int check_todo_list(struct repository *r);
+int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
const char *shortrevisions, const char *onto_name,
const char *onto, const char *orig_head, const char *cmd,
unsigned autosquash);
-int rearrange_squash(void);
+int rearrange_squash(struct repository *r);
extern const char sign_off_header[];
*/
void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
-void append_conflicts_hint(struct strbuf *msgbuf);
+void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
int message_is_empty(const struct strbuf *sb,
enum commit_msg_cleanup_mode cleanup_mode);
int template_untouched(const struct strbuf *sb, const char *template_file,
#define SUMMARY_INITIAL_COMMIT (1 << 0)
#define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
-void print_commit_summary(const char *prefix, const struct object_id *oid,
+void print_commit_summary(struct repository *repo,
+ const char *prefix,
+ const struct object_id *oid,
unsigned int flags);
int read_author_script(const char *path, char **name, char **email, char **date,
}
}
-void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1)
+static const char *odb_loose_path(struct object_directory *odb,
+ struct strbuf *buf,
+ const unsigned char *sha1)
{
- strbuf_addstr(buf, r->objects->objectdir);
+ strbuf_reset(buf);
+ strbuf_addstr(buf, odb->path);
strbuf_addch(buf, '/');
fill_sha1_path(buf, sha1);
+ return buf->buf;
}
-struct strbuf *alt_scratch_buf(struct alternate_object_database *alt)
-{
- strbuf_setlen(&alt->scratch, alt->base_len);
- return &alt->scratch;
-}
-
-static const char *alt_sha1_path(struct alternate_object_database *alt,
- const unsigned char *sha1)
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+ const unsigned char *sha1)
{
- struct strbuf *buf = alt_scratch_buf(alt);
- fill_sha1_path(buf, sha1);
- return buf->buf;
+ return odb_loose_path(r->objects->odb, buf, sha1);
}
/*
struct strbuf *path,
const char *normalized_objdir)
{
- struct alternate_object_database *alt;
+ struct object_directory *odb;
/* Detect cases where alternate disappeared */
if (!is_directory(path->buf)) {
* Prevent the common mistake of listing the same
* thing twice, or object directory itself.
*/
- for (alt = o->alt_odb_list; alt; alt = alt->next) {
- if (!fspathcmp(path->buf, alt->path))
+ for (odb = o->odb; odb; odb = odb->next) {
+ if (!fspathcmp(path->buf, odb->path))
return 0;
}
if (!fspathcmp(path->buf, normalized_objdir))
* Prepare alternate object database registry.
*
* The variable alt_odb_list points at the list of struct
- * alternate_object_database. The elements on this list come from
+ * object_directory. The elements on this list come from
* non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
* environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
* whose contents is similar to that environment variable but can be
static int link_alt_odb_entry(struct repository *r, const char *entry,
const char *relative_base, int depth, const char *normalized_objdir)
{
- struct alternate_object_database *ent;
+ struct object_directory *ent;
struct strbuf pathbuf = STRBUF_INIT;
if (!is_absolute_path(entry) && relative_base) {
return -1;
}
- ent = alloc_alt_odb(pathbuf.buf);
+ ent = xcalloc(1, sizeof(*ent));
+ ent->path = xstrdup(pathbuf.buf);
/* add the alternate entry */
- *r->objects->alt_odb_tail = ent;
- r->objects->alt_odb_tail = &(ent->next);
+ *r->objects->odb_tail = ent;
+ r->objects->odb_tail = &(ent->next);
ent->next = NULL;
/* recursively add alternates */
return;
}
- strbuf_add_absolute_path(&objdirbuf, r->objects->objectdir);
+ strbuf_add_absolute_path(&objdirbuf, r->objects->odb->path);
if (strbuf_normalize_path(&objdirbuf) < 0)
die(_("unable to normalize object directory: %s"),
objdirbuf.buf);
free(path);
}
-struct alternate_object_database *alloc_alt_odb(const char *dir)
-{
- struct alternate_object_database *ent;
-
- FLEX_ALLOC_STR(ent, path, dir);
- strbuf_init(&ent->scratch, 0);
- strbuf_addf(&ent->scratch, "%s/", dir);
- ent->base_len = ent->scratch.len;
-
- return ent;
-}
-
void add_to_alternates_file(const char *reference)
{
struct lock_file lock = LOCK_INIT;
fprintf_or_die(out, "%s\n", reference);
if (commit_lock_file(&lock))
die_errno(_("unable to move new alternates file into place"));
- if (the_repository->objects->alt_odb_tail)
+ if (the_repository->objects->loaded_alternates)
link_alt_odb_entries(the_repository, reference,
'\n', NULL, 0);
}
int foreach_alt_odb(alt_odb_fn fn, void *cb)
{
- struct alternate_object_database *ent;
+ struct object_directory *ent;
int r = 0;
prepare_alt_odb(the_repository);
- for (ent = the_repository->objects->alt_odb_list; ent; ent = ent->next) {
+ for (ent = the_repository->objects->odb->next; ent; ent = ent->next) {
r = fn(ent, cb);
if (r)
break;
void prepare_alt_odb(struct repository *r)
{
- if (r->objects->alt_odb_tail)
+ if (r->objects->loaded_alternates)
return;
- r->objects->alt_odb_tail = &r->objects->alt_odb_list;
link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0);
- read_info_alternates(r, r->objects->objectdir, 0);
+ read_info_alternates(r, r->objects->odb->path, 0);
+ r->objects->loaded_alternates = 1;
}
/* Returns 1 if we have successfully freshened the file, 0 otherwise. */
return 1;
}
-static int check_and_freshen_local(const struct object_id *oid, int freshen)
+static int check_and_freshen_odb(struct object_directory *odb,
+ const struct object_id *oid,
+ int freshen)
{
- static struct strbuf buf = STRBUF_INIT;
-
- strbuf_reset(&buf);
- sha1_file_name(the_repository, &buf, oid->hash);
+ static struct strbuf path = STRBUF_INIT;
+ odb_loose_path(odb, &path, oid->hash);
+ return check_and_freshen_file(path.buf, freshen);
+}
- return check_and_freshen_file(buf.buf, freshen);
+static int check_and_freshen_local(const struct object_id *oid, int freshen)
+{
+ return check_and_freshen_odb(the_repository->objects->odb, oid, freshen);
}
static int check_and_freshen_nonlocal(const struct object_id *oid, int freshen)
{
- struct alternate_object_database *alt;
+ struct object_directory *odb;
+
prepare_alt_odb(the_repository);
- for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
- const char *path = alt_sha1_path(alt, oid->hash);
- if (check_and_freshen_file(path, freshen))
+ for (odb = the_repository->objects->odb->next; odb; odb = odb->next) {
+ if (check_and_freshen_odb(odb, oid, freshen))
return 1;
}
return 0;
*
* The "path" out-parameter will give the path of the object we found (if any).
* Note that it may point to static storage and is only valid until another
- * call to sha1_file_name(), etc.
+ * call to stat_sha1_file().
*/
static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
struct stat *st, const char **path)
{
- struct alternate_object_database *alt;
+ struct object_directory *odb;
static struct strbuf buf = STRBUF_INIT;
- strbuf_reset(&buf);
- sha1_file_name(r, &buf, sha1);
- *path = buf.buf;
-
- if (!lstat(*path, st))
- return 0;
-
prepare_alt_odb(r);
- errno = ENOENT;
- for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
- *path = alt_sha1_path(alt, sha1);
+ for (odb = r->objects->odb; odb; odb = odb->next) {
+ *path = odb_loose_path(odb, &buf, sha1);
if (!lstat(*path, st))
return 0;
}
const unsigned char *sha1, const char **path)
{
int fd;
- struct alternate_object_database *alt;
- int most_interesting_errno;
+ struct object_directory *odb;
+ int most_interesting_errno = ENOENT;
static struct strbuf buf = STRBUF_INIT;
- strbuf_reset(&buf);
- sha1_file_name(r, &buf, sha1);
- *path = buf.buf;
-
- fd = git_open(*path);
- if (fd >= 0)
- return fd;
- most_interesting_errno = errno;
-
prepare_alt_odb(r);
- for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
- *path = alt_sha1_path(alt, sha1);
+ for (odb = r->objects->odb; odb; odb = odb->next) {
+ *path = odb_loose_path(odb, &buf, sha1);
fd = git_open(*path);
if (fd >= 0)
return fd;
+
if (most_interesting_errno == ENOENT)
most_interesting_errno = errno;
}
return -1;
}
+static int quick_has_loose(struct repository *r,
+ const unsigned char *sha1)
+{
+ int subdir_nr = sha1[0];
+ struct object_id oid;
+ struct object_directory *odb;
+
+ hashcpy(oid.hash, sha1);
+
+ prepare_alt_odb(r);
+ for (odb = r->objects->odb; odb; odb = odb->next) {
+ odb_load_loose_cache(odb, subdir_nr);
+ if (oid_array_lookup(&odb->loose_objects_cache, &oid) >= 0)
+ return 1;
+ }
+ return 0;
+}
+
/*
* Map the loose object at "path" if it is not NULL, or the path found by
* searching for a loose object named "sha1".
if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
const char *path;
struct stat st;
+ if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
+ return quick_has_loose(r, sha1) ? 0 : -1;
if (stat_sha1_file(r, sha1, &st, &path) < 0)
return -1;
if (oi->disk_sizep)
static struct strbuf tmp_file = STRBUF_INIT;
static struct strbuf filename = STRBUF_INIT;
- strbuf_reset(&filename);
- sha1_file_name(the_repository, &filename, oid->hash);
+ loose_object_path(the_repository, &filename, oid->hash);
fd = create_tmpfile(&tmp_file, filename.buf);
if (fd < 0) {
return r;
}
-struct loose_alt_odb_data {
- each_loose_object_fn *cb;
- void *data;
-};
-
-static int loose_from_alt_odb(struct alternate_object_database *alt,
- void *vdata)
+int for_each_loose_object(each_loose_object_fn cb, void *data,
+ enum for_each_object_flags flags)
{
- struct loose_alt_odb_data *data = vdata;
- struct strbuf buf = STRBUF_INIT;
- int r;
+ struct object_directory *odb;
- strbuf_addstr(&buf, alt->path);
- r = for_each_loose_file_in_objdir_buf(&buf,
- data->cb, NULL, NULL,
- data->data);
- strbuf_release(&buf);
- return r;
+ prepare_alt_odb(the_repository);
+ for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+ int r = for_each_loose_file_in_objdir(odb->path, cb, NULL,
+ NULL, data);
+ if (r)
+ return r;
+
+ if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
+ break;
+ }
+
+ return 0;
}
-int for_each_loose_object(each_loose_object_fn cb, void *data,
- enum for_each_object_flags flags)
+static int append_loose_object(const struct object_id *oid, const char *path,
+ void *data)
{
- struct loose_alt_odb_data alt;
- int r;
+ oid_array_append(data, oid);
+ return 0;
+}
- r = for_each_loose_file_in_objdir(get_object_directory(),
- cb, NULL, NULL, data);
- if (r)
- return r;
+void odb_load_loose_cache(struct object_directory *odb, int subdir_nr)
+{
+ struct strbuf buf = STRBUF_INIT;
- if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
- return 0;
+ if (subdir_nr < 0 ||
+ subdir_nr >= ARRAY_SIZE(odb->loose_objects_subdir_seen))
+ BUG("subdir_nr out of range");
- alt.cb = cb;
- alt.data = data;
- return foreach_alt_odb(loose_from_alt_odb, &alt);
+ if (odb->loose_objects_subdir_seen[subdir_nr])
+ return;
+
+ strbuf_addstr(&buf, odb->path);
+ for_each_file_in_obj_subdir(subdir_nr, &buf,
+ append_loose_object,
+ NULL, NULL,
+ &odb->loose_objects_cache);
+ odb->loose_objects_subdir_seen[subdir_nr] = 1;
+ strbuf_release(&buf);
}
static int check_stream_sha1(git_zstream *stream,
/* otherwise, current can be discarded and candidate is still good */
}
-static int append_loose_object(const struct object_id *oid, const char *path,
- void *data)
-{
- oid_array_append(data, oid);
- return 0;
-}
-
static int match_sha(unsigned, const unsigned char *, const unsigned char *);
static void find_short_object_filename(struct disambiguate_state *ds)
{
int subdir_nr = ds->bin_pfx.hash[0];
- struct alternate_object_database *alt;
- static struct alternate_object_database *fakeent;
+ struct object_directory *odb;
- if (!fakeent) {
- /*
- * Create a "fake" alternate object database that
- * points to our own object database, to make it
- * easier to get a temporary working space in
- * alt->name/alt->base while iterating over the
- * object databases including our own.
- */
- fakeent = alloc_alt_odb(get_object_directory());
- }
- fakeent->next = the_repository->objects->alt_odb_list;
-
- for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
+ for (odb = the_repository->objects->odb;
+ odb && !ds->ambiguous;
+ odb = odb->next) {
int pos;
- if (!alt->loose_objects_subdir_seen[subdir_nr]) {
- struct strbuf *buf = alt_scratch_buf(alt);
- for_each_file_in_obj_subdir(subdir_nr, buf,
- append_loose_object,
- NULL, NULL,
- &alt->loose_objects_cache);
- alt->loose_objects_subdir_seen[subdir_nr] = 1;
- }
-
- pos = oid_array_lookup(&alt->loose_objects_cache, &ds->bin_pfx);
+ odb_load_loose_cache(odb, subdir_nr);
+ pos = oid_array_lookup(&odb->loose_objects_cache, &ds->bin_pfx);
if (pos < 0)
pos = -1 - pos;
- while (!ds->ambiguous && pos < alt->loose_objects_cache.nr) {
+ while (!ds->ambiguous && pos < odb->loose_objects_cache.nr) {
const struct object_id *oid;
- oid = alt->loose_objects_cache.oid + pos;
+ oid = odb->loose_objects_cache.oid + pos;
if (!match_sha(ds->len, ds->bin_pfx.hash, oid->hash))
break;
update_candidates(ds, oid);
struct keyword_entry *p = keywords + i;
int len = strlen(p->keyword);
- if (n <= len)
+ if (n < len)
continue;
/*
* Match case insensitively, so we colorize output from existing
* messages. We only highlight the word precisely, so
* "successful" stays uncolored.
*/
- if (!strncasecmp(p->keyword, src, len) && !isalnum(src[len])) {
+ if (!strncasecmp(p->keyword, src, len) &&
+ (len == n || !isalnum(src[len]))) {
strbuf_addstr(dest, p->color);
strbuf_add(dest, src, len);
strbuf_addstr(dest, GIT_COLOR_RESET);
return *item->string != '\0';
}
-void string_list_remove_empty_items(struct string_list *list, int free_util) {
+void string_list_remove_empty_items(struct string_list *list, int free_util)
+{
filter_string_list(list, free_util, item_is_not_empty, NULL);
}
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();
if (is_empty_dir(path))
rmdir_or_warn(path);
+
+ submodule_unset_core_worktree(sub);
}
}
out:
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
*/
int check_leading_path(const char *name, int len)
{
- return threaded_check_leading_path(&default_cache, name, len);
+ return threaded_check_leading_path(&default_cache, name, len);
}
/*
chomp;
}
+ /\bcp\s+-a/ and err 'cp -a is not portable';
/\bsed\s+-i/ and err 'sed -i is not portable';
/\becho\s+-[neE]/ and err 'echo with option is not portable (use printf)';
/^\s*declare\s+/ and err 'arrays/declare not portable';
X(three)
#undef X
-int cmd__sigchain(int argc, const char **argv) {
+int cmd__sigchain(int argc, const char **argv)
+{
sigchain_push(SIGTERM, one);
sigchain_push(SIGTERM, two);
sigchain_push(SIGTERM, three);
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" &&
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.
do
rm crlf_false_attr__$f.txt &&
if test -z "$ceol"; then
- git checkout crlf_false_attr__$f.txt
+ git checkout -- crlf_false_attr__$f.txt
else
- git -c core.eol=$ceol checkout crlf_false_attr__$f.txt
+ git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt
fi
done
test_expect_success '-c with comment char defined in .git/config' '
test_config core.commentchar = &&
printf "= foo\n" >expect &&
- printf "foo" | (
- mkdir sub && cd sub && git stripspace -c
- ) >actual &&
+ rm -fr sub &&
+ mkdir sub &&
+ printf "foo" | git -C sub stripspace -c >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '-c outside git repository' '
+ printf "# foo\n" >expect &&
+ printf "foo" | nongit git stripspace -c >actual &&
test_cmp expect actual
'
test_expect_success 'detect possible typos' '
test_must_fail test-tool parse-options -boolean >output 2>output.err &&
test_must_be_empty output &&
- test_cmp typo.err output.err
+ test_i18ncmp typo.err output.err
'
cat >typo.err <<\EOF
test_expect_success 'detect possible typos' '
test_must_fail test-tool parse-options -ambiguous >output 2>output.err &&
test_must_be_empty output &&
- test_cmp typo.err output.err
+ test_i18ncmp typo.err output.err
'
test_expect_success 'keep some options as arguments' '
test_must_be_empty err
'
-test_expect_success 'run_command is restricted to PATH' '
+
+test_lazy_prereq RUNS_COMMANDS_FROM_PWD '
+ write_script runs-commands-from-pwd <<-\EOF &&
+ true
+ EOF
+ runs-commands-from-pwd >/dev/null 2>&1
+'
+
+test_expect_success !RUNS_COMMANDS_FROM_PWD 'run_command is restricted to PATH' '
write_script should-not-run <<-\EOF &&
echo yikes
EOF
grep $(git -C repo rev-parse bar) out # sanity check that some walking was done
'
-test_expect_success 'rev-list accepts missing and promised objects on command line' '
+test_expect_success 'rev-list dies for missing objects on cmd line' '
rm -rf repo &&
test_create_repo repo &&
test_commit -C repo foo &&
git -C repo config core.repositoryformatversion 1 &&
git -C repo config extensions.partialclone "arbitrary string" &&
- git -C repo rev-list --exclude-promisor-objects --objects "$COMMIT" "$TREE" "$BLOB"
+
+ for OBJ in "$COMMIT" "$TREE" "$BLOB"; do
+ test_must_fail git -C repo rev-list --objects \
+ --exclude-promisor-objects "$OBJ" &&
+ test_must_fail git -C repo rev-list --objects-edge-aggressive \
+ --exclude-promisor-objects "$OBJ" &&
+
+ # Do not die or crash when --ignore-missing is passed.
+ git -C repo rev-list --ignore-missing --objects \
+ --exclude-promisor-objects "$OBJ" &&
+ git -C repo rev-list --ignore-missing --objects-edge-aggressive \
+ --exclude-promisor-objects "$OBJ"
+ done
'
test_expect_success 'gc repacks promisor objects separately from non-promisor objects' '
}
check_fsck () {
- output=$(git fsck --full)
+ git fsck --full >fsck.output
case "$1" in
'')
- test -z "$output" ;;
+ test_must_be_empty fsck.output ;;
*)
- echo "$output" | grep "$1" ;;
+ test_i18ngrep "$1" fsck.output ;;
esac
}
test_must_fail git fsck 2>out &&
cat out &&
- grep "$sha.*corrupt" out
+ test_i18ngrep "$sha.*corrupt" out
'
test_expect_success 'branch pointing to non-commit' '
test_when_finished "git update-ref -d refs/heads/invalid" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "not a commit" out
+ test_i18ngrep "not a commit" out
'
test_expect_success 'HEAD link pointing at a funny object' '
# avoid corrupt/broken HEAD from interfering with repo discovery
test_must_fail env GIT_DIR=.git git fsck 2>out &&
cat out &&
- grep "detached HEAD points" out
+ test_i18ngrep "detached HEAD points" out
'
test_expect_success 'HEAD link pointing at a funny place' '
# avoid corrupt/broken HEAD from interfering with repo discovery
test_must_fail env GIT_DIR=.git git fsck 2>out &&
cat out &&
- grep "HEAD points to something strange" out
+ test_i18ngrep "HEAD points to something strange" out
'
test_expect_success 'HEAD link pointing at a funny object (from different wt)' '
echo $ZERO_OID >.git/HEAD &&
# avoid corrupt/broken HEAD from interfering with repo discovery
test_must_fail git -C wt fsck 2>out &&
- grep "main-worktree/HEAD: detached HEAD points" out
+ test_i18ngrep "main-worktree/HEAD: detached HEAD points" out
'
test_expect_success 'other worktree HEAD link pointing at a funny object' '
git worktree add other &&
echo $ZERO_OID >.git/worktrees/other/HEAD &&
test_must_fail git fsck 2>out &&
- grep "worktrees/other/HEAD: detached HEAD points" out
+ test_i18ngrep "worktrees/other/HEAD: detached HEAD points" out
'
test_expect_success 'other worktree HEAD link pointing at missing object' '
git worktree add other &&
echo "Contents missing from repo" | git hash-object --stdin >.git/worktrees/other/HEAD &&
test_must_fail git fsck 2>out &&
- grep "worktrees/other/HEAD: invalid sha1 pointer" out
+ test_i18ngrep "worktrees/other/HEAD: invalid sha1 pointer" out
'
test_expect_success 'other worktree HEAD link pointing at a funny place' '
git worktree add other &&
echo "ref: refs/funny/place" >.git/worktrees/other/HEAD &&
test_must_fail git fsck 2>out &&
- grep "worktrees/other/HEAD points to something strange" out
+ test_i18ngrep "worktrees/other/HEAD points to something strange" out
'
test_expect_success 'email without @ is okay' '
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "error in commit $new" out
+ test_i18ngrep "error in commit $new" out
'
test_expect_success 'missing < email delimiter is reported nicely' '
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "error in commit $new.* - bad name" out
+ test_i18ngrep "error in commit $new.* - bad name" out
'
test_expect_success 'missing email is reported nicely' '
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "error in commit $new.* - missing email" out
+ test_i18ngrep "error in commit $new.* - missing email" out
'
test_expect_success '> in name is reported' '
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "error in commit $new" out
+ test_i18ngrep "error in commit $new" out
'
# date is 2^64 + 1
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "error in commit $new.*integer overflow" out
+ test_i18ngrep "error in commit $new.*integer overflow" out
'
test_expect_success 'commit with NUL in header' '
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
cat out &&
- grep "error in commit $new.*unterminated header: NUL at offset" out
+ test_i18ngrep "error in commit $new.*unterminated header: NUL at offset" out
'
test_expect_success 'tree object with duplicate entries' '
git hash-object -w -t tree --stdin
) &&
test_must_fail git fsck 2>out &&
- grep "error in tree .*contains duplicate file entries" out
+ test_i18ngrep "error in tree .*contains duplicate file entries" out
'
test_expect_success 'unparseable tree object' '
test_when_finished "git update-ref -d refs/tags/invalid" &&
test_must_fail git fsck --tags >out &&
cat out &&
- grep "broken link" out
+ test_i18ngrep "broken link" out
'
test_expect_success 'tag pointing to something else than its type' '
warning in tag $tag: badTagName: invalid '\''tag'\'' name: wrong name format
warning in tag $tag: missingTaggerEntry: invalid format - expected '\''tagger'\'' line
EOF
- test_cmp expect out
+ test_i18ncmp expect out
'
test_expect_success 'tag with bad tagger' '
echo $tag >.git/refs/tags/wrong &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
test_must_fail git fsck --tags 2>out &&
- grep "error in tag .*: invalid author/committer" out
+ test_i18ngrep "error in tag .*: invalid author/committer" out
'
test_expect_success 'tag with NUL in header' '
test_when_finished "git update-ref -d refs/tags/wrong" &&
test_must_fail git fsck --tags 2>out &&
cat out &&
- grep "error in tag $tag.*unterminated header: NUL at offset" out
+ test_i18ngrep "error in tag $tag.*unterminated header: NUL at offset" out
'
test_expect_success 'cleaned up' '
git hash-object -w --stdin -t tree) &&
git fsck 2>out &&
cat out &&
- grep "warning.*null sha1" out
+ test_i18ngrep "warning.*null sha1" out
)
'
git hash-object -w --stdin -t tree) &&
git fsck 2>out &&
cat out &&
- grep "warning.*null sha1" out
+ test_i18ngrep "warning.*null sha1" out
)
'
bad_tree=$(git mktree <bad) &&
git fsck 2>out &&
cat out &&
- grep "warning.*tree $bad_tree" out
+ test_i18ngrep "warning.*tree $bad_tree" out
)'
done <<-\EOF
100644 blob
git branch bad $(cat name) &&
test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 &&
- grep nulInCommit warn.1 &&
+ test_i18ngrep nulInCommit warn.1 &&
git fsck 2>warn.2 &&
- grep nulInCommit warn.2
+ test_i18ngrep nulInCommit warn.2
)
'
remove_object $(git rev-parse julius:caesar.t) &&
test_must_fail git fsck --name-objects >out &&
tree=$(git rev-parse --verify julius:) &&
- egrep "$tree \((refs/heads/master|HEAD)@\{[0-9]*\}:" out
+ test_i18ngrep -E "$tree \((refs/heads/master|HEAD)@\{[0-9]*\}:" out
)
'
mkdir alt.git/objects/12 &&
>alt.git/objects/12/34567890123456789012345678901234567890 &&
test_must_fail git fsck >out 2>&1 &&
- grep alt.git out
+ test_i18ngrep alt.git out
'
test_expect_success 'fsck errors in packed objects' '
remove_object $one &&
remove_object $two &&
test_must_fail git fsck 2>out &&
- grep "error in commit $one.* - bad name" out &&
- grep "error in commit $two.* - bad name" out &&
+ test_i18ngrep "error in commit $one.* - bad name" out &&
+ test_i18ngrep "error in commit $two.* - bad name" out &&
! grep corrupt out
'
git fsck >actual &&
# the output order is non-deterministic, as it comes from a hash
sort <actual >actual.sorted &&
- test_cmp expect actual.sorted
+ test_i18ncmp expect actual.sorted
)
'
test_when_finished "mv .git/index.backup .git/index" &&
corrupt_index_checksum &&
test_must_fail git fsck --cache 2>errors &&
- grep "bad index file" errors
+ test_i18ngrep "bad index file" errors
'
test_done
test_cmp expect actual
'
+test_expect_success 'reject when arg could be part of dwim branch' '
+ git remote add foo file://non-existent-place &&
+ git update-ref refs/remotes/foo/dwim-arg HEAD &&
+ echo foo >dwim-arg &&
+ git add dwim-arg &&
+ echo bar >dwim-arg &&
+ test_must_fail git checkout dwim-arg &&
+ test_must_fail git rev-parse refs/heads/dwim-arg -- &&
+ grep bar dwim-arg
+'
+
+test_expect_success 'disambiguate dwim branch and checkout path (1)' '
+ git update-ref refs/remotes/foo/dwim-arg1 HEAD &&
+ echo foo >dwim-arg1 &&
+ git add dwim-arg1 &&
+ echo bar >dwim-arg1 &&
+ git checkout -- dwim-arg1 &&
+ test_must_fail git rev-parse refs/heads/dwim-arg1 -- &&
+ grep foo dwim-arg1
+'
+
+test_expect_success 'disambiguate dwim branch and checkout path (2)' '
+ git update-ref refs/remotes/foo/dwim-arg2 HEAD &&
+ echo foo >dwim-arg2 &&
+ git add dwim-arg2 &&
+ echo bar >dwim-arg2 &&
+ git checkout dwim-arg2 -- &&
+ git rev-parse refs/heads/dwim-arg2 -- &&
+ grep bar dwim-arg2
+'
+
test_done
test_path_is_file subdir/untracked
'
+test_expect_success 'stash works when user.name and user.email are not set' '
+ git reset &&
+ >1 &&
+ git add 1 &&
+ echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" >expect &&
+ git stash &&
+ git show -s --format="%an <%ae>" refs/stash >actual &&
+ test_cmp expect actual &&
+ >2 &&
+ git add 2 &&
+ test_config user.useconfigonly true &&
+ test_config stash.usebuiltin true &&
+ (
+ sane_unset GIT_AUTHOR_NAME &&
+ sane_unset GIT_AUTHOR_EMAIL &&
+ sane_unset GIT_COMMITTER_NAME &&
+ sane_unset GIT_COMMITTER_EMAIL &&
+ test_unconfig user.email &&
+ test_unconfig user.name &&
+ test_must_fail git commit -m "should fail" &&
+ echo "git stash <git@stash>" >expect &&
+ >2 &&
+ git stash &&
+ git show -s --format="%an <%ae>" refs/stash >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
test_cmp expected actual
'
+test_expect_success 'bogus settings in move detection erroring out' '
+ test_must_fail git diff --color-moved=bogus 2>err &&
+ test_i18ngrep "must be one of" err &&
+ test_i18ngrep bogus err &&
+
+ test_must_fail git -c diff.colormoved=bogus diff 2>err &&
+ test_i18ngrep "must be one of" err &&
+ test_i18ngrep "from command-line config" err &&
+
+ test_must_fail git diff --color-moved-ws=bogus 2>err &&
+ test_i18ngrep "possible values" err &&
+ test_i18ngrep bogus err &&
+
+ test_must_fail git -c diff.colormovedws=bogus diff 2>err &&
+ test_i18ngrep "possible values" err &&
+ test_i18ngrep "from command-line config" err
+'
+
test_expect_success 'compare whitespace delta incompatible with other space options' '
test_must_fail git diff \
--color-moved-ws=allow-indentation-change,ignore-all-space \
rm .gitattributes
'
+test_expect_success 'setup log -[GS] binary & --text' '
+ git checkout --orphan GS-binary-and-text &&
+ git read-tree --empty &&
+ printf "a\na\0a\n" >data.bin &&
+ git add data.bin &&
+ git commit -m "create binary file" data.bin &&
+ printf "a\na\0a\n" >>data.bin &&
+ git commit -m "modify binary file" data.bin &&
+ git rm data.bin &&
+ git commit -m "delete binary file" data.bin &&
+ git log >full-log
+'
+
+test_expect_success 'log -G ignores binary files' '
+ git log -Ga >log &&
+ test_must_be_empty log
+'
+
+test_expect_success 'log -G looks into binary files with -a' '
+ git log -a -Ga >log &&
+ test_cmp log full-log
+'
+
+test_expect_success 'log -G looks into binary files with textconv filter' '
+ test_when_finished "rm .gitattributes" &&
+ echo "* diff=bin" >.gitattributes &&
+ git -c diff.bin.textconv=cat log -Ga >log &&
+ test_cmp log full-log
+'
+
+test_expect_success 'log -S looks into binary files' '
+ git log -Sa >log &&
+ test_cmp log full-log
+'
+
test_done
test_bad_opts () {
test_expect_success "invalid args: $1" "
test_must_fail git log $1 2>errors &&
- grep '$2' errors
+ test_i18ngrep '$2' errors
"
}
test_description='test corner cases of git-archive'
. ./test-lib.sh
-test_expect_success 'create commit with empty tree' '
- git commit --allow-empty -m foo
+# the 10knuls.tar file is used to test for an empty git generated tar
+# without having to invoke tar because an otherwise valid empty GNU tar
+# will be considered broken by {Open,Net}BSD tar
+test_expect_success 'create commit with empty tree and fake empty tar' '
+ git commit --allow-empty -m foo &&
+ perl -e "print \"\\0\" x 10240" >10knuls.tar
'
# Make a dir and clean it up afterwards
test_expect_success 'tar archive of empty tree is empty' '
git archive --format=tar HEAD: >empty.tar &&
- perl -e "print \"\\0\" x 10240" >10knuls.tar &&
test_cmp_bin 10knuls.tar empty.tar
'
test_expect_success 'archive empty subtree with no pathspec' '
git archive --format=tar $root_tree >subtree-all.tar &&
- make_dir extract &&
- "$TAR" xf subtree-all.tar -C extract &&
- check_dir extract
+ test_cmp_bin 10knuls.tar subtree-all.tar
'
test_expect_success 'archive empty subtree by direct pathspec' '
git archive --format=tar $root_tree -- sub >subtree-path.tar &&
- make_dir extract &&
- "$TAR" xf subtree-path.tar -C extract &&
- check_dir extract
+ test_cmp_bin 10knuls.tar subtree-path.tar
'
ZIPINFO=zipinfo
echo " " "error: leading space"
echo " "
echo Err
+ echo SUCCESS
exit 0
EOF
echo 1 >file &&
grep "<BOLD;RED>error<RESET>: error" decoded &&
grep "<YELLOW>hint<RESET>:" decoded &&
grep "<BOLD;GREEN>success<RESET>:" decoded &&
+ grep "<BOLD;GREEN>SUCCESS<RESET>" decoded &&
grep "<BOLD;YELLOW>warning<RESET>:" decoded
'
git remote add backup xyz@example.com
'
+test_expect_success 'unqualified <dst> refspec DWIM and advice' '
+ test_when_finished "(cd test && git tag -d some-tag)" &&
+ (
+ cd test &&
+ git tag -a -m "Some tag" some-tag master &&
+ exit_with=true &&
+ for type in commit tag tree blob
+ do
+ if test "$type" = "blob"
+ then
+ oid=$(git rev-parse some-tag:file)
+ else
+ oid=$(git rev-parse some-tag^{$type})
+ fi &&
+ test_must_fail git push origin $oid:dst 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+ test_i18ngrep "hint: Did you mean" err &&
+ test_must_fail git -c advice.pushUnqualifiedRefName=false \
+ push origin $oid:dst 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+ test_i18ngrep ! "hint: Did you mean" err ||
+ exit_with=false
+ done &&
+ $exit_with
+ )
+'
+
+test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and advice' '
+ (
+ cd two &&
+ git tag -a -m "Some tag" my-tag master &&
+ git update-ref refs/trees/my-head-tree HEAD^{tree} &&
+ git update-ref refs/blobs/my-file-blob HEAD:file
+ ) &&
+ (
+ cd test &&
+ git config --add remote.two.fetch "+refs/tags/*:refs/remotes/tags-from-two/*" &&
+ git config --add remote.two.fetch "+refs/trees/*:refs/remotes/trees-from-two/*" &&
+ git config --add remote.two.fetch "+refs/blobs/*:refs/remotes/blobs-from-two/*" &&
+ git fetch --no-tags two &&
+
+ test_must_fail git push origin refs/remotes/two/another:dst 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+
+ test_must_fail git push origin refs/remotes/tags-from-two/my-tag:dst-tag 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+
+ test_must_fail git push origin refs/remotes/trees-from-two/my-head-tree:dst-tree 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+
+ test_must_fail git push origin refs/remotes/blobs-from-two/my-file-blob:dst-blob 2>err &&
+ test_i18ngrep "error: The destination you" err
+ )
+'
+
test_done
git config fetch.recurseSubmodules true &&
(
cd downstream &&
+ GIT_TRACE=$(pwd)/trace.out git fetch &&
+ grep "1 tasks" trace.out &&
GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 &&
grep "7 tasks" trace.out &&
git config submodule.fetchJobs 8 &&
expect_ssh "$@"
}
-test_expect_success !MINGW 'clone c:temp is ssl' '
+test_expect_success !MINGW,!CYGWIN 'clone c:temp is ssl' '
test_clone_url c:temp c temp
'
test_cmp expect child/file
'
+test_expect_success 'clone -c remote.origin.fetch=<refspec> works' '
+ rm -rf child &&
+ git update-ref refs/grab/it refs/heads/master &&
+ git update-ref refs/leave/out refs/heads/master &&
+ git clone -c "remote.origin.fetch=+refs/grab/*:refs/grab/*" . child &&
+ git -C child for-each-ref --format="%(refname)" >actual &&
+
+ cat >expect <<-\EOF &&
+ refs/grab/it
+ refs/heads/master
+ refs/remotes/origin/HEAD
+ refs/remotes/origin/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'git -c remote.origin.fetch=<refspec> clone works' '
+ rm -rf child &&
+ git -c "remote.origin.fetch=+refs/grab/*:refs/grab/*" clone . child &&
+ git -C child for-each-ref --format="%(refname)" >actual &&
+
+ cat >expect <<-\EOF &&
+ refs/grab/it
+ refs/heads/master
+ refs/remotes/origin/HEAD
+ refs/remotes/origin/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
+ rm -rf child &&
+ git clone --origin=upstream \
+ -c "remote.upstream.fetch=+refs/grab/*:refs/grab/*" \
+ -c "remote.origin.fetch=+refs/leave/*:refs/leave/*" \
+ . child &&
+ git -C child for-each-ref --format="%(refname)" >actual &&
+
+ cat >expect <<-\EOF &&
+ refs/grab/it
+ refs/heads/master
+ refs/remotes/upstream/HEAD
+ refs/remotes/upstream/master
+ EOF
+ test_cmp expect actual
+'
+
# Tests for the hidden file attribute on windows
is_hidden () {
# Use the output of `attrib`, ignore the absolute path
test_must_fail git -c protocol.version=2 clone \
--filter=blob:none $HTTPD_URL/one_time_sed/server repo 2>err &&
- grep "did not send all necessary objects" err &&
+ test_i18ngrep "did not send all necessary objects" err &&
# Ensure that the one-time-sed script was used.
! test -e "$HTTPD_ROOT_PATH/one-time-sed"
cp -r "$LOCAL_PRISTINE" local &&
inconsistency master 1234567890123456789012345678901234567890 &&
test_must_fail git -C local fetch 2>err &&
- grep "ERR upload-pack: not our ref" err
+ test_i18ngrep "ERR upload-pack: not our ref" err
'
test_expect_success 'server is initially ahead - ref in want' '
echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
test_must_fail git -C local fetch 2>err &&
- grep "ERR unknown ref refs/heads/raster" err
+ test_i18ngrep "ERR unknown ref refs/heads/raster" err
'
stop_httpd
git ls-files -u >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 3 out &&
+ test_line_count = 1 out &&
git rev-parse >expect \
- L2:three R2:three \
L2:three R2:three &&
git rev-parse >actual \
:2:three :3:three &&
- git hash-object >>actual \
- three~HEAD three~R2^0 &&
test_cmp expect actual
)
'
git ls-files -u >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 3 out &&
+ test_line_count = 1 out &&
git rev-parse >expect \
- L2:three R2:three \
L2:three R2:three &&
git rev-parse >actual \
:2:three :3:three &&
- git hash-object >>actual \
- three~HEAD three~R2^0 &&
test_cmp expect actual
)
'
git branch B &&
git checkout -b C &&
echo 10 >>a &&
- echo "other content" >>new_a &&
+ test_write_lines 0 1 2 3 4 5 6 7 foobar >new_a &&
git add a new_a &&
test_tick && git commit -m C &&
git checkout B^0 &&
test_must_fail git merge C &&
- git clean -f &&
+ git show :2:new_a >new_a &&
+ git add new_a &&
test_tick && git commit -m D &&
git tag D &&
git checkout C^0 &&
test_must_fail git merge B &&
- rm new_a~HEAD new_a &&
- printf "Incorrectly merged content" >>new_a &&
+ test_write_lines 0 1 2 3 4 5 6 7 bad_merge >new_a &&
git add -u &&
test_tick && git commit -m E &&
git tag E
test_line_count = 1 out &&
git rev-parse >expect \
- D:new_a E:new_a &&
+ C:new_a D:new_a E:new_a &&
git rev-parse >actual \
- :2:new_a :3:new_a &&
+ :1:new_a :2:new_a :3:new_a &&
test_cmp expect actual &&
- git cat-file -p C:new_a >ours &&
- git cat-file -p B:new_a >theirs &&
+ # Test that the two-way merge in new_a is as expected
+ git cat-file -p D:new_a >ours &&
+ git cat-file -p E:new_a >theirs &&
>empty &&
test_must_fail git merge-file \
- -L "Temporary merge branch 1" \
+ -L "HEAD" \
-L "" \
- -L "Temporary merge branch 2" \
+ -L "E^0" \
ours empty theirs &&
sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect &&
- git cat-file -p :1:new_a >actual &&
+ git hash-object new_a >actual &&
+ git hash-object ours >expect &&
+ test_cmp expect actual
+ )
+'
+
+# Repeat the above testcase with precisely the same setup, other than with
+# the two merge bases having different orderings of commit timestamps so
+# that they are reversed in the order they are provided to merge-recursive,
+# so that we can improve code coverage.
+test_expect_success 'git detects differently handled merges conflict, swapped' '
+ (
+ cd rename-add &&
+
+ # Difference #1: Do cleanup from previous testrun
+ git reset --hard &&
+ git clean -fdqx &&
+
+ # Difference #2: Change commit timestamps
+ btime=$(git log --no-walk --date=raw --format=%cd B | awk "{print \$1}") &&
+ ctime=$(git log --no-walk --date=raw --format=%cd C | awk "{print \$1}") &&
+ newctime=$(($btime+1)) &&
+ git fast-export --no-data --all | sed -e s/$ctime/$newctime/ | git fast-import --force --quiet &&
+ # End of differences; rest is copy-paste of last test
+
+ git checkout D^0 &&
+ test_must_fail git merge -s recursive E^0 &&
+
+ git ls-files -s >out &&
+ test_line_count = 3 out &&
+ git ls-files -u >out &&
+ test_line_count = 3 out &&
+ git ls-files -o >out &&
+ test_line_count = 1 out &&
+
+ git rev-parse >expect \
+ C:new_a D:new_a E:new_a &&
+ git rev-parse >actual \
+ :1:new_a :2:new_a :3:new_a &&
+ test_cmp expect actual &&
+
+ # Test that the two-way merge in new_a is as expected
+ git cat-file -p D:new_a >ours &&
+ git cat-file -p E:new_a >theirs &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "E^0" \
+ ours empty theirs &&
+ sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect &&
+ git hash-object new_a >actual &&
+ git hash-object ours >expect &&
test_cmp expect actual
)
'
)
'
+# Setup:
+# L1---L2
+# / \ / \
+# master X ?
+# \ / \ /
+# R1---R2
+#
+# Where:
+# master has two files, named 'b' and 'a'
+# branches L1 and R1 both modify each of the two files in conflicting ways
+#
+# L2 is a merge of R1 into L1; more on it later.
+# R2 is a merge of L1 into R1; more on it later.
+#
+# X is an auto-generated merge-base used when merging L2 and R2.
+# since X is a merge of L1 and R1, it has conflicting versions of each file
+#
+# More about L2 and R2:
+# - both resolve the conflicts in 'b' and 'a' differently
+# - L2 renames 'b' to 'm'
+# - R2 renames 'a' to 'm'
+#
+# In the end, in file 'm' we have four different conflicting files (from
+# two versions of 'b' and two of 'a'). In addition, if
+# merge.conflictstyle is diff3, then the base version also has
+# conflict markers of its own, leading to a total of three levels of
+# conflict markers. This is a pretty weird corner case, but we just want
+# to ensure that we handle it as well as practical.
+
+test_expect_success 'setup nested conflicts' '
+ test_create_repo nested_conflicts &&
+ (
+ cd nested_conflicts &&
+
+ # Create some related files now
+ for i in $(test_seq 1 10)
+ do
+ echo Random base content line $i
+ done >initial &&
+
+ cp initial b_L1 &&
+ cp initial b_R1 &&
+ cp initial b_L2 &&
+ cp initial b_R2 &&
+ cp initial a_L1 &&
+ cp initial a_R1 &&
+ cp initial a_L2 &&
+ cp initial a_R2 &&
+
+ test_write_lines b b_L1 >>b_L1 &&
+ test_write_lines b b_R1 >>b_R1 &&
+ test_write_lines b b_L2 >>b_L2 &&
+ test_write_lines b b_R2 >>b_R2 &&
+ test_write_lines a a_L1 >>a_L1 &&
+ test_write_lines a a_R1 >>a_R1 &&
+ test_write_lines a a_L2 >>a_L2 &&
+ test_write_lines a a_R2 >>a_R2 &&
+
+ # Setup original commit (or merge-base), consisting of
+ # files named "b" and "a"
+ cp initial b &&
+ cp initial a &&
+ echo b >>b &&
+ echo a >>a &&
+ git add b a &&
+ test_tick && git commit -m initial &&
+
+ git branch L &&
+ git branch R &&
+
+ # Handle the left side
+ git checkout L &&
+ mv -f b_L1 b &&
+ mv -f a_L1 a &&
+ git add b a &&
+ test_tick && git commit -m "version L1 of files" &&
+ git tag L1 &&
+
+ # Handle the right side
+ git checkout R &&
+ mv -f b_R1 b &&
+ mv -f a_R1 a &&
+ git add b a &&
+ test_tick && git commit -m "verson R1 of files" &&
+ git tag R1 &&
+
+ # Create first merge on left side
+ git checkout L &&
+ test_must_fail git merge R1 &&
+ mv -f b_L2 b &&
+ mv -f a_L2 a &&
+ git add b a &&
+ git mv b m &&
+ test_tick && git commit -m "left merge, rename b->m" &&
+ git tag L2 &&
+
+ # Create first merge on right side
+ git checkout R &&
+ test_must_fail git merge L1 &&
+ mv -f b_R2 b &&
+ mv -f a_R2 a &&
+ git add b a &&
+ git mv a m &&
+ test_tick && git commit -m "right merge, rename a->m" &&
+ git tag R2
+ )
+'
+
+test_expect_success 'check nested conflicts' '
+ (
+ cd nested_conflicts &&
+
+ git clean -f &&
+ git checkout L2^0 &&
+
+ # Merge must fail; there is a conflict
+ test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R2^0 &&
+
+ # Make sure the index has the right number of entries
+ git ls-files -s >out &&
+ test_line_count = 2 out &&
+ git ls-files -u >out &&
+ test_line_count = 2 out &&
+ # Ensure we have the correct number of untracked files
+ git ls-files -o >out &&
+ test_line_count = 1 out &&
+
+ # Create a and b from virtual merge base X
+ git cat-file -p master:a >base &&
+ git cat-file -p L1:a >ours &&
+ git cat-file -p R1:a >theirs &&
+ test_must_fail git merge-file --diff3 \
+ -L "Temporary merge branch 1" \
+ -L "merged common ancestors" \
+ -L "Temporary merge branch 2" \
+ ours \
+ base \
+ theirs &&
+ sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_a &&
+
+ git cat-file -p master:b >base &&
+ git cat-file -p L1:b >ours &&
+ git cat-file -p R1:b >theirs &&
+ test_must_fail git merge-file --diff3 \
+ -L "Temporary merge branch 1" \
+ -L "merged common ancestors" \
+ -L "Temporary merge branch 2" \
+ ours \
+ base \
+ theirs &&
+ sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_b &&
+
+ # Compare :2:m to expected values
+ git cat-file -p L2:m >ours &&
+ git cat-file -p R2:b >theirs &&
+ test_must_fail git merge-file --diff3 \
+ -L "HEAD:m" \
+ -L "merged common ancestors:b" \
+ -L "R2^0:b" \
+ ours \
+ vmb_b \
+ theirs &&
+ sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_2 &&
+ git cat-file -p :2:m >actual &&
+ test_cmp m_stage_2 actual &&
+
+ # Compare :3:m to expected values
+ git cat-file -p L2:a >ours &&
+ git cat-file -p R2:m >theirs &&
+ test_must_fail git merge-file --diff3 \
+ -L "HEAD:a" \
+ -L "merged common ancestors:a" \
+ -L "R2^0:m" \
+ ours \
+ vmb_a \
+ theirs &&
+ sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_3 &&
+ git cat-file -p :3:m >actual &&
+ test_cmp m_stage_3 actual &&
+
+ # Compare m to expected contents
+ >empty &&
+ cp m_stage_2 expected_final_m &&
+ test_must_fail git merge-file --diff3 \
+ -L "HEAD" \
+ -L "merged common ancestors" \
+ -L "R2^0" \
+ expected_final_m \
+ empty \
+ m_stage_3 &&
+ test_cmp expected_final_m m
+ )
+'
+
+# Setup:
+# L1---L2---L3
+# / \ / \ / \
+# master X1 X2 ?
+# \ / \ / \ /
+# R1---R2---R3
+#
+# Where:
+# master has one file named 'content'
+# branches L1 and R1 both modify each of the two files in conflicting ways
+#
+# L<n> (n>1) is a merge of R<n-1> into L<n-1>
+# R<n> (n>1) is a merge of L<n-1> into R<n-1>
+# L<n> and R<n> resolve the conflicts differently.
+#
+# X<n> is an auto-generated merge-base used when merging L<n+1> and R<n+1>.
+# By construction, X1 has conflict markers due to conflicting versions.
+# X2, due to using merge.conflictstyle=3, has nested conflict markers.
+#
+# So, merging R3 into L3 using merge.conflictstyle=3 should show the
+# nested conflict markers from X2 in the base version -- that means we
+# have three levels of conflict markers. Can we distinguish all three?
+
+test_expect_success 'setup virtual merge base with nested conflicts' '
+ test_create_repo virtual_merge_base_has_nested_conflicts &&
+ (
+ cd virtual_merge_base_has_nested_conflicts &&
+
+ # Create some related files now
+ for i in $(test_seq 1 10)
+ do
+ echo Random base content line $i
+ done >content &&
+
+ # Setup original commit
+ git add content &&
+ test_tick && git commit -m initial &&
+
+ git branch L &&
+ git branch R &&
+
+ # Create L1
+ git checkout L &&
+ echo left >>content &&
+ git add content &&
+ test_tick && git commit -m "version L1 of content" &&
+ git tag L1 &&
+
+ # Create R1
+ git checkout R &&
+ echo right >>content &&
+ git add content &&
+ test_tick && git commit -m "verson R1 of content" &&
+ git tag R1 &&
+
+ # Create L2
+ git checkout L &&
+ test_must_fail git -c merge.conflictstyle=diff3 merge R1 &&
+ git checkout L1 content &&
+ test_tick && git commit -m "version L2 of content" &&
+ git tag L2 &&
+
+ # Create R2
+ git checkout R &&
+ test_must_fail git -c merge.conflictstyle=diff3 merge L1 &&
+ git checkout R1 content &&
+ test_tick && git commit -m "version R2 of content" &&
+ git tag R2 &&
+
+ # Create L3
+ git checkout L &&
+ test_must_fail git -c merge.conflictstyle=diff3 merge R2 &&
+ git checkout L1 content &&
+ test_tick && git commit -m "version L3 of content" &&
+ git tag L3 &&
+
+ # Create R3
+ git checkout R &&
+ test_must_fail git -c merge.conflictstyle=diff3 merge L2 &&
+ git checkout R1 content &&
+ test_tick && git commit -m "version R3 of content" &&
+ git tag R3
+ )
+'
+
+test_expect_success 'check virtual merge base with nested conflicts' '
+ (
+ cd virtual_merge_base_has_nested_conflicts &&
+
+ git checkout L3^0 &&
+
+ # Merge must fail; there is a conflict
+ test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R3^0 &&
+
+ # Make sure the index has the right number of entries
+ git ls-files -s >out &&
+ test_line_count = 3 out &&
+ git ls-files -u >out &&
+ test_line_count = 3 out &&
+ # Ensure we have the correct number of untracked files
+ git ls-files -o >out &&
+ test_line_count = 1 out &&
+
+ # Compare :[23]:content to expected values
+ git rev-parse L1:content R1:content >expect &&
+ git rev-parse :2:content :3:content >actual &&
+ test_cmp expect actual &&
+
+ # Imitate X1 merge base, except without long enough conflict
+ # markers because a subsequent sed will modify them. Put
+ # result into vmb.
+ git cat-file -p master:content >base &&
+ git cat-file -p L:content >left &&
+ git cat-file -p R:content >right &&
+ cp left merged-once &&
+ test_must_fail git merge-file --diff3 \
+ -L "Temporary merge branch 1" \
+ -L "merged common ancestors" \
+ -L "Temporary merge branch 2" \
+ merged-once \
+ base \
+ right &&
+ sed -e "s/^\([<|=>]\)/\1\1\1/" merged-once >vmb &&
+
+ # Imitate X2 merge base, overwriting vmb. Note that we
+ # extend both sets of conflict markers to make them longer
+ # with the sed command.
+ cp left merged-twice &&
+ test_must_fail git merge-file --diff3 \
+ -L "Temporary merge branch 1" \
+ -L "merged common ancestors" \
+ -L "Temporary merge branch 2" \
+ merged-twice \
+ vmb \
+ right &&
+ sed -e "s/^\([<|=>]\)/\1\1\1/" merged-twice >vmb &&
+
+ # Compare :1:content to expected value
+ git cat-file -p :1:content >actual &&
+ test_cmp vmb actual &&
+
+ # Determine expected content in final outer merge, compare to
+ # what the merge generated.
+ cp -f left expect &&
+ test_must_fail git merge-file --diff3 \
+ -L "HEAD" -L "merged common ancestors" -L "R3^0" \
+ expect vmb right &&
+ test_cmp expect content
+ )
+'
+
test_done
git ls-files -u c >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 3 out &&
+ test_line_count = 1 out &&
test_path_is_missing a &&
test_path_is_missing b &&
- test_path_is_file c~HEAD &&
- test_path_is_file c~C^0 &&
- git rev-parse >expect \
- C:a B:b &&
- git hash-object >actual \
- c~HEAD c~C^0 &&
+ git rev-parse >expect \
+ C:a B:b &&
+ git rev-parse >actual \
+ :2:c :3:c &&
+ test_cmp expect actual &&
+
+ # Test that the two-way merge in new_a is as expected
+ git cat-file -p :2:c >>ours &&
+ git cat-file -p :3:c >>theirs &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "C^0" \
+ ours empty theirs &&
+ git hash-object c >actual &&
+ git hash-object ours >expect &&
test_cmp expect actual
)
'
git ls-files -u c >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 5 out &&
+ test_line_count = 1 out &&
git rev-parse >expect \
A:a C:b B:b C:c B:c &&
:1:a :2:b :3:b :2:c :3:c &&
test_cmp expect actual &&
- git rev-parse >expect \
- C:c B:c C:b B:b &&
- git hash-object >actual \
- c~HEAD c~B\^0 b~HEAD b~B\^0 &&
- test_cmp expect actual &&
+ # Record some contents for re-doing merges
+ git cat-file -p A:a >stuff &&
+ git cat-file -p C:b >important_info &&
+ git cat-file -p B:c >precious_data &&
+ >empty &&
- test_path_is_missing b &&
- test_path_is_missing c
+ # Test the merge in b
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ important_info empty stuff &&
+ test_cmp important_info b &&
+
+ # Test the merge in c
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ stuff empty precious_data &&
+ test_cmp stuff c
)
'
)
'
+test_conflicts_with_adds_and_renames() {
+ sideL=$1
+ sideR=$2
+
+ # Setup:
+ # L
+ # / \
+ # master ?
+ # \ /
+ # R
+ #
+ # Where:
+ # Both L and R have files named 'three' which collide. Each of
+ # the colliding files could have been involved in a rename, in
+ # which case there was a file named 'one' or 'two' that was
+ # modified on the opposite side of history and renamed into the
+ # collision on this side of history.
+ #
+ # Questions:
+ # 1) The index should contain both a stage 2 and stage 3 entry
+ # for the colliding file. Does it?
+ # 2) When renames are involved, the content merges are clean, so
+ # the index should reflect the content merges, not merely the
+ # version of the colliding file from the prior commit. Does
+ # it?
+ # 3) There should be a file in the worktree named 'three'
+ # containing the two-way merged contents of the content-merged
+ # versions of 'three' from each of the two colliding
+ # files. Is it present?
+ # 4) There should not be any three~* files in the working
+ # tree
+ test_expect_success "setup simple $sideL/$sideR conflict" '
+ test_create_repo simple_${sideL}_${sideR} &&
+ (
+ cd simple_${sideL}_${sideR} &&
+
+ # Create some related files now
+ for i in $(test_seq 1 10)
+ do
+ echo Random base content line $i
+ done >file_v1 &&
+ cp file_v1 file_v2 &&
+ echo modification >>file_v2 &&
+
+ cp file_v1 file_v3 &&
+ echo more stuff >>file_v3 &&
+ cp file_v3 file_v4 &&
+ echo yet more stuff >>file_v4 &&
+
+ # Use a tag to record both these files for simple
+ # access, and clean out these untracked files
+ git tag file_v1 $(git hash-object -w file_v1) &&
+ git tag file_v2 $(git hash-object -w file_v2) &&
+ git tag file_v3 $(git hash-object -w file_v3) &&
+ git tag file_v4 $(git hash-object -w file_v4) &&
+ git clean -f &&
+
+ # Setup original commit (or merge-base), consisting of
+ # files named "one" and "two" if renames were involved.
+ touch irrelevant_file &&
+ git add irrelevant_file &&
+ if [ $sideL = "rename" ]
+ then
+ git show file_v1 >one &&
+ git add one
+ fi &&
+ if [ $sideR = "rename" ]
+ then
+ git show file_v3 >two &&
+ git add two
+ fi &&
+ test_tick && git commit -m initial &&
+
+ git branch L &&
+ git branch R &&
+
+ # Handle the left side
+ git checkout L &&
+ if [ $sideL = "rename" ]
+ then
+ git mv one three
+ else
+ git show file_v2 >three &&
+ git add three
+ fi &&
+ if [ $sideR = "rename" ]
+ then
+ git show file_v4 >two &&
+ git add two
+ fi &&
+ test_tick && git commit -m L &&
+
+ # Handle the right side
+ git checkout R &&
+ if [ $sideL = "rename" ]
+ then
+ git show file_v2 >one &&
+ git add one
+ fi &&
+ if [ $sideR = "rename" ]
+ then
+ git mv two three
+ else
+ git show file_v4 >three &&
+ git add three
+ fi &&
+ test_tick && git commit -m R
+ )
+ '
+
+ test_expect_success "check simple $sideL/$sideR conflict" '
+ (
+ cd simple_${sideL}_${sideR} &&
+
+ git checkout L^0 &&
+
+ # Merge must fail; there is a conflict
+ test_must_fail git merge -s recursive R^0 &&
+
+ # Make sure the index has the right number of entries
+ git ls-files -s >out &&
+ test_line_count = 3 out &&
+ git ls-files -u >out &&
+ test_line_count = 2 out &&
+ # Ensure we have the correct number of untracked files
+ git ls-files -o >out &&
+ test_line_count = 1 out &&
+
+ # Nothing should have touched irrelevant_file
+ git rev-parse >actual \
+ :0:irrelevant_file \
+ :2:three \
+ :3:three &&
+ git rev-parse >expected \
+ master:irrelevant_file \
+ file_v2 \
+ file_v4 &&
+ test_cmp expected actual &&
+
+ # Make sure we have the correct merged contents for
+ # three
+ git show file_v1 >expected &&
+ cat <<-\EOF >>expected &&
+ <<<<<<< HEAD
+ modification
+ =======
+ more stuff
+ yet more stuff
+ >>>>>>> R^0
+ EOF
+
+ test_cmp expected three
+ )
+ '
+}
+
+test_conflicts_with_adds_and_renames rename rename
+test_conflicts_with_adds_and_renames rename add
+test_conflicts_with_adds_and_renames add rename
+test_conflicts_with_adds_and_renames add add
+
+# Setup:
+# L
+# / \
+# master ?
+# \ /
+# R
+#
+# Where:
+# master has two files, named 'one' and 'two'.
+# branches L and R both modify 'one', in conflicting ways.
+# branches L and R both modify 'two', in conflicting ways.
+# branch L also renames 'one' to 'three'.
+# branch R also renames 'two' to 'three'.
+#
+# So, we have four different conflicting files that all end up at path
+# 'three'.
+test_expect_success 'setup nested conflicts from rename/rename(2to1)' '
+ test_create_repo nested_conflicts_from_rename_rename &&
+ (
+ cd nested_conflicts_from_rename_rename &&
+
+ # Create some related files now
+ for i in $(test_seq 1 10)
+ do
+ echo Random base content line $i
+ done >file_v1 &&
+
+ cp file_v1 file_v2 &&
+ cp file_v1 file_v3 &&
+ cp file_v1 file_v4 &&
+ cp file_v1 file_v5 &&
+ cp file_v1 file_v6 &&
+
+ echo one >>file_v1 &&
+ echo uno >>file_v2 &&
+ echo eins >>file_v3 &&
+
+ echo two >>file_v4 &&
+ echo dos >>file_v5 &&
+ echo zwei >>file_v6 &&
+
+ # Setup original commit (or merge-base), consisting of
+ # files named "one" and "two".
+ mv file_v1 one &&
+ mv file_v4 two &&
+ git add one two &&
+ test_tick && git commit -m english &&
+
+ git branch L &&
+ git branch R &&
+
+ # Handle the left side
+ git checkout L &&
+ git mv one three &&
+ mv -f file_v2 three &&
+ mv -f file_v5 two &&
+ git add two three &&
+ test_tick && git commit -m spanish &&
+
+ # Handle the right side
+ git checkout R &&
+ git mv two three &&
+ mv -f file_v3 one &&
+ mv -f file_v6 three &&
+ git add one three &&
+ test_tick && git commit -m german
+ )
+'
+
+test_expect_success 'check nested conflicts from rename/rename(2to1)' '
+ (
+ cd nested_conflicts_from_rename_rename &&
+
+ git checkout L^0 &&
+
+ # Merge must fail; there is a conflict
+ test_must_fail git merge -s recursive R^0 &&
+
+ # Make sure the index has the right number of entries
+ git ls-files -s >out &&
+ test_line_count = 2 out &&
+ git ls-files -u >out &&
+ test_line_count = 2 out &&
+ # Ensure we have the correct number of untracked files
+ git ls-files -o >out &&
+ test_line_count = 1 out &&
+
+ # Compare :2:three to expected values
+ git cat-file -p master:one >base &&
+ git cat-file -p L:three >ours &&
+ git cat-file -p R:one >theirs &&
+ test_must_fail git merge-file \
+ -L "HEAD:three" -L "" -L "R^0:one" \
+ ours base theirs &&
+ sed -e "s/^\([<=>]\)/\1\1/" ours >L-three &&
+ git cat-file -p :2:three >expect &&
+ test_cmp expect L-three &&
+
+ # Compare :2:three to expected values
+ git cat-file -p master:two >base &&
+ git cat-file -p L:two >ours &&
+ git cat-file -p R:three >theirs &&
+ test_must_fail git merge-file \
+ -L "HEAD:two" -L "" -L "R^0:three" \
+ ours base theirs &&
+ sed -e "s/^\([<=>]\)/\1\1/" ours >R-three &&
+ git cat-file -p :3:three >expect &&
+ test_cmp expect R-three &&
+
+ # Compare three to expected contents
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" -L "" -L "R^0" \
+ L-three empty R-three &&
+ test_cmp three L-three
+ )
+'
+
test_done
git ls-files -u >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 3 out &&
+ test_line_count = 1 out &&
git rev-parse >actual \
:0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n &&
A:y/wham B:z/wham &&
test_cmp expect actual &&
- test_path_is_missing x/wham &&
- test_path_is_file x/wham~HEAD &&
- test_path_is_file x/wham~B^0 &&
-
- git hash-object >actual \
- x/wham~HEAD x/wham~B^0 &&
- git rev-parse >expect \
- A:y/wham B:z/wham &&
- test_cmp expect actual
+ # Test that the two-way merge in x/wham is as expected
+ git cat-file -p :2:x/wham >expect &&
+ git cat-file -p :3:x/wham >other &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ expect empty other &&
+ test_cmp expect x/wham
)
'
git ls-files -u >out &&
test_line_count = 6 out &&
git ls-files -o >out &&
- test_line_count = 3 out &&
+ test_line_count = 1 out &&
git rev-parse >actual \
:0:y/b :0:y/c :0:y/e &&
test_cmp expect actual &&
git hash-object >actual \
- w/d~HEAD w/d~B^0 z/d &&
+ z/d &&
git rev-parse >expect \
- O:x/d B:w/d O:x/d &&
+ O:x/d &&
test_cmp expect actual &&
test_path_is_missing x/d &&
test_path_is_file y/d &&
git ls-files -u >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 3 out &&
+ test_line_count = 1 out &&
git rev-parse >actual \
:0:y/b :0:y/c :2:y/d :3:y/d &&
O:z/b O:z/c O:w/d O:x/d &&
test_cmp expect actual &&
- test_path_is_missing y/d &&
- test_path_is_file y/d~HEAD &&
- test_path_is_file y/d~B^0 &&
-
- git hash-object >actual \
- y/d~HEAD y/d~B^0 &&
- git rev-parse >expect \
- O:w/d O:x/d &&
- test_cmp expect actual
+ # Test that the two-way merge in y/d is as expected
+ git cat-file -p :2:y/d >expect &&
+ git cat-file -p :3:y/d >other &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ expect empty other &&
+ test_cmp expect y/d
)
'
)
'
+test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2), other direction' '
+ (
+ cd 10c &&
+
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout B^0 &&
+ mkdir y &&
+ echo important >y/c &&
+
+ test_must_fail git merge -s recursive A^0 >out 2>err &&
+ test_i18ngrep "CONFLICT (rename/rename)" out &&
+ test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~HEAD instead" out &&
+
+ git ls-files -s >out &&
+ test_line_count = 6 out &&
+ git ls-files -u >out &&
+ test_line_count = 3 out &&
+ git ls-files -o >out &&
+ test_line_count = 3 out &&
+
+ git rev-parse >actual \
+ :0:y/a :0:y/b :0:x/d :1:x/c :3:w/c :2:y/c &&
+ git rev-parse >expect \
+ O:z/a O:z/b O:x/d O:x/c O:x/c O:x/c &&
+ test_cmp expect actual &&
+
+ git hash-object y/c~HEAD >actual &&
+ git rev-parse O:x/c >expect &&
+ test_cmp expect actual &&
+
+ echo important >expect &&
+ test_cmp expect y/c
+ )
+'
+
# Testcase 10d, Delete untracked w/ dir rename/rename(2to1)
# Commit O: z/{a,b,c_1}, x/{d,e,f_2}
# Commit A: y/{a,b}, x/{d,e,f_2,wham_1} + untracked y/wham
# Commit B: z/{a,b,c_1,wham_2}, y/{d,e}
-# Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~B^0,wham~HEAD}+
+# Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~merged}+
# CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham
# ERROR_MSG(Refusing to lose untracked file at y/wham)
git ls-files -u >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 4 out &&
+ test_line_count = 3 out &&
git rev-parse >actual \
:0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&
echo important >expect &&
test_cmp expect y/wham &&
- git hash-object >actual \
- y/wham~B^0 y/wham~HEAD &&
- git rev-parse >expect \
- O:x/f O:z/c &&
- test_cmp expect actual
+ # Test that the two-way merge in y/wham~merged is as expected
+ git cat-file -p :2:y/wham >expect &&
+ git cat-file -p :3:y/wham >other &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ expect empty other &&
+ test_cmp expect y/wham~merged
)
'
git ls-files -u >out &&
test_line_count = 4 out &&
git ls-files -o >out &&
- test_line_count = 4 out &&
+ test_line_count = 3 out &&
echo different >expected &&
echo mods >>expected &&
O:z/a O:z/b O:x/d O:x/c O:x/c A:y/c O:x/c &&
test_cmp expect actual &&
- git hash-object >actual \
- y/c~B^0 y/c~HEAD &&
- git rev-parse >expect \
- O:x/c A:y/c &&
- test_cmp expect actual
+ # See if y/c~merged has expected contents; requires manually
+ # doing the expected file merge
+ git cat-file -p A:y/c >c1 &&
+ git cat-file -p B:z/c >c2 &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ c1 empty c2 &&
+ test_cmp c1 y/c~merged
)
'
# Commit O: z/{a,b}, x/{c_1,d_2}
# Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods
# Commit B: z/{a,b,wham_2}, x/c_1
-# Expected: Failed Merge; y/{a,b} + untracked y/{wham~B^0,wham~B^HEAD} +
+# Expected: Failed Merge; y/{a,b} + untracked y/{wham~merged} +
# y/wham with dirty changes from before merge +
# CONFLICT(rename/rename) x/c vs x/d -> y/wham
# ERROR_MSG(Refusing to lose dirty file at y/wham)
git ls-files -u >out &&
test_line_count = 2 out &&
git ls-files -o >out &&
- test_line_count = 4 out &&
+ test_line_count = 3 out &&
test_seq 1 10 >expected &&
echo important >>expected &&
test_cmp expected y/wham &&
test_must_fail git rev-parse :1:y/wham &&
- git hash-object >actual \
- y/wham~B^0 y/wham~HEAD &&
- git rev-parse >expect \
- O:x/d O:x/c &&
- test_cmp expect actual &&
git rev-parse >actual \
:0:y/a :0:y/b :2:y/wham :3:y/wham &&
git rev-parse >expect \
O:z/a O:z/b O:x/c O:x/d &&
- test_cmp expect actual
+ test_cmp expect actual &&
+
+ # Test that the two-way merge in y/wham~merged is as expected
+ git cat-file -p :2:y/wham >expect &&
+ git cat-file -p :3:y/wham >other &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ expect empty other &&
+ test_cmp expect y/wham~merged
)
'
test_expect_success '"git fsck" works' '
git fsck master >fsck_master.out &&
- grep "dangling commit $R" fsck_master.out &&
- grep "dangling tag $(cat .git/refs/tags/mytag)" fsck_master.out &&
+ test_i18ngrep "dangling commit $R" fsck_master.out &&
+ test_i18ngrep "dangling tag $(cat .git/refs/tags/mytag)" fsck_master.out &&
test -z "$(git fsck)"
'
mkdir sub &&
while read path
do
- : >$path &&
+ echo content >$path &&
git add $path || return 1
done <expect &&
git commit -m "initial commit" &&
test_must_be_empty actual
'
+test_expect_success 'pathspec with labels and non existent .gitattributes (2)' '
+ test_must_fail git grep content HEAD -- ":(attr:label)"
+'
+
test_expect_success 'setup .gitattributes' '
cat <<-\EOF >.gitattributes &&
fileA labelA
test_cmp expect actual
'
+test_expect_success 'check specific set attr (2)' '
+ cat <<-\EOF >expect &&
+ HEAD:fileSetLabel
+ HEAD:sub/fileSetLabel
+ EOF
+ git grep -l content HEAD ":(attr:label)" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'check specific unset attr' '
cat <<-\EOF >expect &&
fileUnsetLabel
test_cmp expect actual
'
+test_expect_success 'check specific unset attr (2)' '
+ cat <<-\EOF >expect &&
+ HEAD:fileUnsetLabel
+ HEAD:sub/fileUnsetLabel
+ EOF
+ git grep -l content HEAD ":(attr:-label)" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'check specific value attr' '
cat <<-\EOF >expect &&
fileValue
test_must_be_empty actual
'
+test_expect_success 'check specific value attr (2)' '
+ cat <<-\EOF >expect &&
+ HEAD:fileValue
+ HEAD:sub/fileValue
+ EOF
+ git grep -l content HEAD ":(attr:label=foo)" >actual &&
+ test_cmp expect actual &&
+ test_must_fail git grep -l content HEAD ":(attr:label=bar)"
+'
+
test_expect_success 'check unspecified attr' '
cat <<-\EOF >expect &&
.gitattributes
test_cmp expect actual
'
+test_expect_success 'check unspecified attr (2)' '
+ cat <<-\EOF >expect &&
+ HEAD:.gitattributes
+ HEAD:fileA
+ HEAD:fileAB
+ HEAD:fileAC
+ HEAD:fileB
+ HEAD:fileBC
+ HEAD:fileC
+ HEAD:fileNoLabel
+ HEAD:fileWrongLabel
+ HEAD:sub/fileA
+ HEAD:sub/fileAB
+ HEAD:sub/fileAC
+ HEAD:sub/fileB
+ HEAD:sub/fileBC
+ HEAD:sub/fileC
+ HEAD:sub/fileNoLabel
+ HEAD:sub/fileWrongLabel
+ EOF
+ git grep -l ^ HEAD ":(attr:!label)" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'check multiple unspecified attr' '
cat <<-\EOF >expect &&
.gitattributes
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 &&
GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \
core.worktree "../../../nested" &&
# make sure this re-setup is correct
- git status --ignore-submodules=none
+ git status --ignore-submodules=none &&
+
+ # also make sure this old setup does not regress
+ git submodule update --init --recursive >out 2>err &&
+ test_must_be_empty out &&
+ test_must_be_empty err
'
test_expect_success 'absorb the git dir in a nested submodule' '
# symlink detector; this grep string comes from the config
# variable name and will not be translated.
test_must_fail git fsck 2>output &&
- grep gitmodulesSymlink output
+ test_i18ngrep gitmodulesSymlink output
)
'
git ls-tree HEAD | sed s/subdir/.gitmodules/ | git mktree &&
test_must_fail git fsck 2>output &&
- grep gitmodulesBlob output
+ test_i18ngrep gitmodulesBlob output
)
'
git commit -m "broken gitmodules" &&
git fsck 2>output &&
- grep gitmodulesParse output &&
+ test_i18ngrep gitmodulesParse output &&
test_i18ngrep ! "bad config" output
)
'
'
+test_expect_success 'fast-export --reference-excluded-parents master~2..master' '
+
+ git fast-export --reference-excluded-parents master~2..master >actual &&
+ grep commit.refs/heads/master actual >commit-count &&
+ test_line_count = 2 commit-count &&
+ sed "s/master/rewrite/" actual |
+ (cd new &&
+ git fast-import &&
+ test $MASTER = $(git rev-parse --verify refs/heads/rewrite))
+'
+
+test_expect_success 'fast-export --show-original-ids' '
+
+ git fast-export --show-original-ids master >output &&
+ grep ^original-oid output| sed -e s/^original-oid.// | sort >actual &&
+ git rev-list --objects master muss >objects-and-names &&
+ awk "{print \$1}" objects-and-names | sort >commits-trees-blobs &&
+ comm -23 actual commits-trees-blobs >unfound &&
+ test_must_be_empty unfound
+'
+
+test_expect_success 'fast-export --show-original-ids | git fast-import' '
+
+ git fast-export --show-original-ids master muss | git fast-import --quiet &&
+ test $MASTER = $(git rev-parse --verify refs/heads/master) &&
+ test $MUSS = $(git rev-parse --verify refs/tags/muss)
+'
+
test_expect_success 'iso-8859-1' '
git config i18n.commitencoding ISO8859-1 &&
)
'
+test_expect_success 'rewrite tag predating pathspecs to nothing' '
+ test_create_repo rewrite_tag_predating_pathspecs &&
+ (
+ cd rewrite_tag_predating_pathspecs &&
+
+ test_commit initial &&
+
+ git tag -a -m "Some old tag" v0.0.0.0.0.0.1 &&
+
+ test_commit bar &&
+
+ git fast-export --tag-of-filtered-object=rewrite --all -- bar.t >output &&
+ grep from.$ZERO_OID output
+ )
+'
+
cat > limit-by-paths/expected << EOF
blob
mark :1
grep file0 actual
'
+test_expect_success 'avoid corrupt stream with non-existent mark' '
+ test_create_repo avoid_non_existent_mark &&
+ (
+ cd avoid_non_existent_mark &&
+
+ test_commit important-path &&
+
+ test_commit ignored &&
+
+ git branch A &&
+ git branch B &&
+
+ echo foo >>important-path.t &&
+ git add important-path.t &&
+ test_commit more changes &&
+
+ git fast-export --all -- important-path.t | git fast-import --force
+ )
+'
+
test_expect_success 'full-tree re-shows unmodified files' '
git checkout -f simple &&
git fast-export --full-tree simple >actual &&
test_cmp expected actual
'
-test_expect_success 'delete refspec' '
+test_expect_success 'delete ref because entire history excluded' '
git branch to-delete &&
- git fast-export --refspec :refs/heads/to-delete to-delete ^to-delete > actual &&
- cat > expected <<-EOF &&
+ git fast-export to-delete ^to-delete >actual &&
+ cat >expected <<-EOF &&
+ reset refs/heads/to-delete
+ from 0000000000000000000000000000000000000000
+
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'delete refspec' '
+ git fast-export --refspec :refs/heads/to-delete >actual &&
+ cat >expected <<-EOF &&
reset refs/heads/to-delete
from 0000000000000000000000000000000000000000
--ignore-other-worktrees Z
--recurse-submodules Z
--progress Z
- --no-quiet Z
+ --guess Z
+ --no-guess Z
--no-... Z
EOF
'
}
-static int has_attribute(const char *attrs, const char *attr) {
+static int has_attribute(const char *attrs, const char *attr)
+{
int len;
if (!attrs)
return 0;
int nr_heads, struct ref **to_fetch)
{
struct bundle_transport_data *data = transport->data;
- return unbundle(&data->header, data->fd,
+ return unbundle(the_repository, &data->header, data->fd,
transport->progress ? BUNDLE_VERBOSE : 0);
}
return ret;
}
-int transport_push(struct transport *transport,
+int transport_push(struct repository *r,
+ struct transport *transport,
struct refspec *rs, int flags,
unsigned int *reject_reasons)
{
oid_array_append(&commits,
&ref->new_oid);
- if (!push_unpushed_submodules(the_repository,
+ if (!push_unpushed_submodules(r,
&commits,
transport->remote,
rs,
oid_array_append(&commits,
&ref->new_oid);
- if (find_unpushed_submodules(the_repository,
+ if (find_unpushed_submodules(r,
&commits,
transport->remote->name,
&needs_pushing)) {
void *data;
};
-static int refs_from_alternate_cb(struct alternate_object_database *e,
+static int refs_from_alternate_cb(struct object_directory *e,
void *data)
{
struct strbuf path = STRBUF_INIT;
#define REJECT_FETCH_FIRST 0x08
#define REJECT_NEEDS_FORCE 0x10
-int transport_push(struct transport *connection,
+int transport_push(struct repository *repo,
+ struct transport *connection,
struct refspec *rs, int flags,
unsigned int * reject_reasons);
enum interesting match;
while (t->size) {
- match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
+ match = tree_entry_interesting(opt->repo->index, &t->entry,
+ base, 0, &opt->pathspec);
if (match) {
if (match == all_entries_not_interesting)
t->size = 0;
}
}
-static inline int prune_traversal(struct name_entry *e,
+static inline int prune_traversal(struct index_state *istate,
+ struct name_entry *e,
struct traverse_info *info,
struct strbuf *base,
int still_interesting)
return 2;
if (still_interesting < 0)
return still_interesting;
- return tree_entry_interesting(e, base, 0, info->pathspec);
+ return tree_entry_interesting(istate, e, base,
+ 0, info->pathspec);
}
-int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
+int traverse_trees(struct index_state *istate,
+ int n, struct tree_desc *t,
+ struct traverse_info *info)
{
int error = 0;
struct name_entry *entry = xmalloc(n*sizeof(*entry));
}
if (!mask)
break;
- interesting = prune_traversal(e, info, &base, interesting);
+ interesting = prune_traversal(istate, e, info, &base, interesting);
if (interesting < 0)
break;
if (interesting) {
* Pre-condition: either baselen == base_offset (i.e. empty path)
* or base[baselen-1] == '/' (i.e. with trailing slash).
*/
-static enum interesting do_match(const struct name_entry *entry,
+static enum interesting do_match(struct index_state *istate,
+ const struct name_entry *entry,
struct strbuf *base, int base_offset,
const struct pathspec *ps,
int exclude)
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
if (!ps->nr) {
if (!ps->recursive ||
if (!ps->recursive ||
!(ps->magic & PATHSPEC_MAXDEPTH) ||
- ps->max_depth == -1)
- return all_entries_interesting;
-
- return within_depth(base_str + matchlen + 1,
- baselen - matchlen - 1,
- !!S_ISDIR(entry->mode),
- ps->max_depth) ?
- entry_interesting : entry_not_interesting;
+ ps->max_depth == -1) {
+ if (!item->attr_match_nr)
+ return all_entries_interesting;
+ else
+ goto interesting;
+ }
+
+ if (within_depth(base_str + matchlen + 1,
+ baselen - matchlen - 1,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth))
+ goto interesting;
+ else
+ return entry_not_interesting;
}
/* Either there must be no base, or the base must match. */
if (match_entry(item, entry, pathlen,
match + baselen, matchlen - baselen,
&never_interesting))
- return entry_interesting;
+ goto interesting;
if (item->nowildcard_len < item->len) {
if (!git_fnmatch(item, match + baselen, entry->path,
item->nowildcard_len - baselen))
- return entry_interesting;
+ goto interesting;
/*
* Match all directories. We'll try to
!ps_strncmp(item, match + baselen,
entry->path,
item->nowildcard_len - baselen))
- return entry_interesting;
+ goto interesting;
}
continue;
if (!git_fnmatch(item, match, base->buf + base_offset,
item->nowildcard_len)) {
strbuf_setlen(base, base_offset + baselen);
- return entry_interesting;
+ goto interesting;
}
/*
!ps_strncmp(item, match, base->buf + base_offset,
item->nowildcard_len)) {
strbuf_setlen(base, base_offset + baselen);
- return entry_interesting;
+ goto interesting;
}
strbuf_setlen(base, base_offset + baselen);
*/
if (ps->recursive && S_ISDIR(entry->mode))
return entry_interesting;
+ continue;
+interesting:
+ if (item->attr_match_nr) {
+ int ret;
+
+ /*
+ * Must not return all_entries_not_interesting
+ * prematurely. We do not know if all entries do not
+ * match some attributes with current attr API.
+ */
+ never_interesting = entry_not_interesting;
+
+ /*
+ * Consider all directories interesting (because some
+ * of those files inside may match some attributes
+ * even though the parent dir does not)
+ *
+ * FIXME: attributes _can_ match directories and we
+ * can probably return all_entries_interesting or
+ * all_entries_not_interesting here if matched.
+ */
+ if (S_ISDIR(entry->mode))
+ return entry_interesting;
+
+ strbuf_add(base, entry->path, pathlen);
+ ret = match_pathspec_attrs(istate, base->buf + base_offset,
+ base->len - base_offset, item);
+ strbuf_setlen(base, base_offset + baselen);
+ if (!ret)
+ continue;
+ }
+ return entry_interesting;
}
return never_interesting; /* No matches */
}
* Pre-condition: either baselen == base_offset (i.e. empty path)
* or base[baselen-1] == '/' (i.e. with trailing slash).
*/
-enum interesting tree_entry_interesting(const struct name_entry *entry,
+enum interesting tree_entry_interesting(struct index_state *istate,
+ const struct name_entry *entry,
struct strbuf *base, int base_offset,
const struct pathspec *ps)
{
enum interesting positive, negative;
- positive = do_match(entry, base, base_offset, ps, 0);
+ positive = do_match(istate, entry, base, base_offset, ps, 0);
/*
* case | entry | positive | negative | result
positive <= entry_not_interesting) /* #1, #2, #11, #12 */
return positive;
- negative = do_match(entry, base, base_offset, ps, 1);
+ negative = do_match(istate, entry, base, base_offset, ps, 1);
/* #8, #18 */
if (positive == all_entries_interesting &&
#ifndef TREE_WALK_H
#define TREE_WALK_H
+struct index_state;
struct strbuf;
struct name_entry {
struct traverse_info;
typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *);
-int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info);
+int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info);
enum follow_symlinks_result {
FOUND = 0, /* This includes out-of-tree links */
all_entries_interesting = 2 /* yes, and all subsequent entries will be */
};
-extern enum interesting tree_entry_interesting(const struct name_entry *,
- struct strbuf *, int,
- const struct pathspec *ps);
+enum interesting tree_entry_interesting(struct index_state *istate,
+ const struct name_entry *,
+ struct strbuf *, int,
+ const struct pathspec *ps);
#endif
ADD_CACHE_JUST_APPEND);
}
-static int read_tree_1(struct tree *tree, struct strbuf *base,
+static int read_tree_1(struct repository *r,
+ struct tree *tree, struct strbuf *base,
int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
while (tree_entry(&desc, &entry)) {
if (retval != all_entries_interesting) {
- retval = tree_entry_interesting(&entry, base, 0, pathspec);
+ retval = tree_entry_interesting(r->index, &entry,
+ base, 0, pathspec);
if (retval == all_entries_not_interesting)
break;
if (retval == entry_not_interesting)
else if (S_ISGITLINK(entry.mode)) {
struct commit *commit;
- commit = lookup_commit(the_repository, entry.oid);
+ commit = lookup_commit(r, entry.oid);
if (!commit)
die("Commit %s in submodule path %s%s not found",
oid_to_hex(entry.oid),
len = tree_entry_len(&entry);
strbuf_add(base, entry.path, len);
strbuf_addch(base, '/');
- retval = read_tree_1(lookup_tree(the_repository, &oid),
+ retval = read_tree_1(r, lookup_tree(r, &oid),
base, stage, pathspec,
fn, context);
strbuf_setlen(base, oldlen);
return 0;
}
-int read_tree_recursive(struct tree *tree,
+int read_tree_recursive(struct repository *r,
+ struct tree *tree,
const char *base, int baselen,
int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
int ret;
strbuf_add(&sb, base, baselen);
- ret = read_tree_1(tree, &sb, stage, pathspec, fn, context);
+ ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
strbuf_release(&sb);
return ret;
}
ce2->name, ce2->ce_namelen, ce_stage(ce2));
}
-int read_tree(struct tree *tree, int stage, struct pathspec *match,
- struct index_state *istate)
+int read_tree(struct repository *r, struct tree *tree, int stage,
+ struct pathspec *match, struct index_state *istate)
{
read_tree_fn_t fn = NULL;
int i, err;
if (!fn)
fn = read_one_entry_quick;
- err = read_tree_recursive(tree, "", 0, stage, match, fn, istate);
+ err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
if (fn == read_one_entry || err)
return err;
#include "object.h"
-extern const char *tree_type;
+struct repository;
struct strbuf;
struct tree {
unsigned long size;
};
+extern const char *tree_type;
+
struct tree *lookup_tree(struct repository *r, const struct object_id *oid);
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
#define READ_TREE_RECURSIVE 1
typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
-extern int read_tree_recursive(struct tree *tree,
- const char *base, int baselen,
- int stage, const struct pathspec *pathspec,
- read_tree_fn_t fn, void *context);
+int read_tree_recursive(struct repository *r,
+ struct tree *tree,
+ const char *base, int baselen,
+ int stage, const struct pathspec *pathspec,
+ read_tree_fn_t fn, void *context);
-extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec,
- struct index_state *istate);
+int read_tree(struct repository *r, struct tree *tree,
+ int stage, struct pathspec *pathspec,
+ struct index_state *istate);
#endif /* TREE_H */
repo_read_gitmodules(the_repository);
} else if (state && (ce->ce_flags & CE_UPDATE)) {
submodule_free(the_repository);
- checkout_entry(ce, state, NULL);
+ checkout_entry(ce, state, NULL, NULL);
repo_read_gitmodules(the_repository);
}
}
display_progress(progress, ++cnt);
ce->ce_flags &= ~CE_UPDATE;
if (o->update && !o->dry_run) {
- errs |= checkout_entry(ce, &state, NULL);
+ errs |= checkout_entry(ce, &state, NULL, NULL);
}
}
}
stop_progress(&progress);
- errs |= finish_delayed_checkout(&state);
+ errs |= finish_delayed_checkout(&state, NULL);
if (o->update)
git_attr_set_direction(GIT_ATTR_CHECKIN);
struct name_entry *names,
struct traverse_info *info)
{
+ struct unpack_trees_options *o = info->data;
int i, ret, bottom;
int nr_buf = 0;
struct tree_desc t[MAX_UNPACK_TREES];
nr_entries = all_trees_same_as_cache_tree(n, dirmask, names, info);
if (nr_entries > 0) {
- struct unpack_trees_options *o = info->data;
int pos = index_pos_by_traverse_info(names, info);
if (!o->merge || df_conflicts)
}
bottom = switch_cache_bottom(&newinfo);
- ret = traverse_trees(n, t, &newinfo);
+ ret = traverse_trees(o->src_index, n, t, &newinfo);
restore_cache_bottom(&newinfo, bottom);
for (i = 0; i < nr_buf; i++)
}
trace_performance_enter();
- ret = traverse_trees(len, t, &info);
+ ret = traverse_trees(o->src_index, len, t, &info);
trace_performance_leave("traverse_trees");
if (ret < 0)
goto return_failed;
move_index_extensions(&o->result, o->src_index);
if (!ret) {
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
- cache_tree_verify(&o->result);
+ cache_tree_verify(the_repository, &o->result);
if (!o->result.cache_tree)
o->result.cache_tree = cache_tree();
if (!cache_tree_fully_valid(o->result.cache_tree))
strbuf_complete(buf, '/');
}
-void str_end_url_with_slash(const char *url, char **dest) {
+void str_end_url_with_slash(const char *url, char **dest)
+{
struct strbuf buf = STRBUF_INIT;
end_url_with_slash(&buf, url);
free(*dest);
return 0;
}
-struct userdiff_driver *userdiff_find_by_name(const char *name) {
+struct userdiff_driver *userdiff_find_by_name(const char *name)
+{
int len = strlen(name);
return userdiff_find_by_namelen(name, len);
}
return userdiff_find_by_name(check->items[0].value);
}
-struct userdiff_driver *userdiff_get_textconv(struct userdiff_driver *driver)
+struct userdiff_driver *userdiff_get_textconv(struct repository *r,
+ struct userdiff_driver *driver)
{
if (!driver->textconv)
return NULL;
struct strbuf name = STRBUF_INIT;
strbuf_addf(&name, "textconv/%s", driver->name);
- notes_cache_init(c, name.buf, driver->textconv);
+ notes_cache_init(r, c, name.buf, driver->textconv);
driver->textconv_cache = c;
strbuf_release(&name);
}
#include "notes-cache.h"
struct index_state;
+struct repository;
struct userdiff_funcname {
const char *pattern;
* Initialize any textconv-related fields in the driver and return it, or NULL
* if it does not have textconv enabled at all.
*/
-struct userdiff_driver *userdiff_get_textconv(struct userdiff_driver *driver);
+struct userdiff_driver *userdiff_get_textconv(struct repository *r,
+ struct userdiff_driver *driver);
#endif /* USERDIFF */
va_end(ap);
}
-void wt_status_prepare(struct wt_status *s)
+void wt_status_prepare(struct repository *r, struct wt_status *s)
{
memset(s, 0, sizeof(*s));
+ s->repo = r;
memcpy(s->color_palette, default_wt_status_colors,
sizeof(default_wt_status_colors));
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
}
}
-static int unmerged_mask(const char *path)
+static int unmerged_mask(struct index_state *istate, const char *path)
{
int pos, mask;
const struct cache_entry *ce;
- pos = cache_name_pos(path, strlen(path));
+ pos = index_name_pos(istate, path, strlen(path));
if (0 <= pos)
return 0;
mask = 0;
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
if (strcmp(ce->name, path) || !ce_stage(ce))
break;
mask |= (1 << (ce_stage(ce) - 1));
s->committable = 1;
break;
case DIFF_STATUS_UNMERGED:
- d->stagemask = unmerged_mask(p->two->path);
+ d->stagemask = unmerged_mask(s->repo->index,
+ p->two->path);
/*
* Don't bother setting {mode,oid}_{head,index} since the print
* code will output the stage values directly and not use the
{
struct rev_info rev;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.flags.dirty_submodules = 1;
struct rev_info rev;
struct setup_revision_opt opt;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
memset(&opt, 0, sizeof(opt));
opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
setup_revisions(0, NULL, &rev, &opt);
static void wt_status_collect_changes_initial(struct wt_status *s)
{
+ struct index_state *istate = s->repo->index;
int i;
- for (i = 0; i < active_nr; i++) {
+ for (i = 0; i < istate->cache_nr; i++) {
struct string_list_item *it;
struct wt_status_change_data *d;
- const struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = istate->cache[i];
- if (!ce_path_match(&the_index, ce, &s->pathspec, NULL))
+ if (!ce_path_match(istate, ce, &s->pathspec, NULL))
continue;
if (ce_intent_to_add(ce))
continue;
int i;
struct dir_struct dir;
uint64_t t_begin = getnanotime();
+ struct index_state *istate = s->repo->index;
if (!s->show_untracked_files)
return;
if (s->show_ignored_mode == SHOW_MATCHING_IGNORED)
dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
} else {
- dir.untracked = the_index.untracked;
+ dir.untracked = istate->untracked;
}
setup_standard_excludes(&dir);
- fill_directory(&dir, &the_index, &s->pathspec);
+ fill_directory(&dir, istate, &s->pathspec);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))
+ if (index_name_is_other(istate, ent->name, ent->len) &&
+ dir_path_match(istate, ent, &s->pathspec, 0, NULL))
string_list_insert(&s->untracked, ent->name);
free(ent);
}
for (i = 0; i < dir.ignored_nr; i++) {
struct dir_entry *ent = dir.ignored[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))
+ if (index_name_is_other(istate, ent->name, ent->len) &&
+ dir_path_match(istate, ent, &s->pathspec, 0, NULL))
string_list_insert(&s->ignored, ent->name);
free(ent);
}
wt_status_collect_changes_index(s);
wt_status_collect_untracked(s);
- wt_status_get_state(&s->state, s->branch && !strcmp(s->branch, "HEAD"));
+ wt_status_get_state(s->repo, &s->state, s->branch && !strcmp(s->branch, "HEAD"));
if (s->state.merge_in_progress && !has_unmerged(s))
s->committable = 1;
}
int dirty_submodules;
const char *c = color(WT_STATUS_HEADER, s);
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
rev.diffopt.flags.allow_textconv = 1;
rev.diffopt.ita_invisible_in_index = 1;
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
} else if (s->state.rebase_in_progress ||
- !stat(git_path_merge_msg(the_repository), &st)) {
+ !stat(git_path_merge_msg(s->repo), &st)) {
print_rebase_state(s, color);
if (s->hints)
status_printf_ln(s, color,
return 1;
}
-static void wt_status_get_detached_from(struct wt_status_state *state)
+static void wt_status_get_detached_from(struct repository *r,
+ struct wt_status_state *state)
{
struct grab_1st_switch_cbdata cb;
struct commit *commit;
/* sha1 is a commit? match without further lookup */
(oideq(&cb.noid, &oid) ||
/* perhaps sha1 is a tag, try to dereference to a commit */
- ((commit = lookup_commit_reference_gently(the_repository, &oid, 1)) != NULL &&
+ ((commit = lookup_commit_reference_gently(r, &oid, 1)) != NULL &&
oideq(&cb.noid, &commit->object.oid)))) {
const char *from = ref;
if (!skip_prefix(from, "refs/tags/", &from))
return 0;
}
-void wt_status_get_state(struct wt_status_state *state,
+void wt_status_get_state(struct repository *r,
+ struct wt_status_state *state,
int get_detached_from)
{
struct stat st;
struct object_id oid;
- if (!stat(git_path_merge_head(the_repository), &st)) {
+ if (!stat(git_path_merge_head(r), &st)) {
wt_status_check_rebase(NULL, state);
state->merge_in_progress = 1;
} else if (wt_status_check_rebase(NULL, state)) {
; /* all set */
- } else if (!stat(git_path_cherry_pick_head(the_repository), &st) &&
+ } else if (!stat(git_path_cherry_pick_head(r), &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(the_repository), &st) &&
+ if (!stat(git_path_revert_head(r), &st) &&
!get_oid("REVERT_HEAD", &oid)) {
state->revert_in_progress = 1;
oidcpy(&state->revert_head_oid, &oid);
}
if (get_detached_from)
- wt_status_get_detached_from(state);
+ wt_status_get_detached_from(r, state);
}
static void wt_longstatus_print_state(struct wt_status *s)
struct wt_status *s)
{
struct wt_status_change_data *d = it->util;
+ struct index_state *istate = s->repo->index;
const struct cache_entry *ce;
struct strbuf buf_index = STRBUF_INIT;
const char *path_index = NULL;
*/
memset(stages, 0, sizeof(stages));
sum = 0;
- pos = cache_name_pos(it->string, strlen(it->string));
+ pos = index_name_pos(istate, it->string, strlen(it->string));
assert(pos < 0);
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
stage = ce_stage(ce);
if (strcmp(ce->name, it->string) || !stage)
break;
/**
* Returns 1 if there are unstaged changes, 0 otherwise.
*/
-int has_unstaged_changes(int ignore_submodules)
+int has_unstaged_changes(struct repository *r, int ignore_submodules)
{
struct rev_info rev_info;
int result;
- repo_init_revisions(the_repository, &rev_info, NULL);
+ repo_init_revisions(r, &rev_info, NULL);
if (ignore_submodules) {
rev_info.diffopt.flags.ignore_submodules = 1;
rev_info.diffopt.flags.override_submodule_config = 1;
/**
* Returns 1 if there are uncommitted changes, 0 otherwise.
*/
-int has_uncommitted_changes(int ignore_submodules)
+int has_uncommitted_changes(struct repository *r,
+ int ignore_submodules)
{
struct rev_info rev_info;
int result;
- if (is_cache_unborn())
+ if (is_index_unborn(r->index))
return 0;
- repo_init_revisions(the_repository, &rev_info, NULL);
+ repo_init_revisions(r, &rev_info, NULL);
if (ignore_submodules)
rev_info.diffopt.flags.ignore_submodules = 1;
rev_info.diffopt.flags.quick = 1;
* We have no head (or it's corrupt); use the empty tree,
* which will complain if the index is non-empty.
*/
- struct tree *tree = lookup_tree(the_repository, the_hash_algo->empty_tree);
+ struct tree *tree = lookup_tree(r, the_hash_algo->empty_tree);
add_pending_object(&rev_info, &tree->object, "");
}
* If the work tree has unstaged or uncommitted changes, dies with the
* appropriate message.
*/
-int require_clean_work_tree(const char *action, const char *hint, int ignore_submodules, int gently)
+int require_clean_work_tree(struct repository *r,
+ const char *action,
+ const char *hint,
+ int ignore_submodules,
+ int gently)
{
struct lock_file lock_file = LOCK_INIT;
int err = 0, fd;
fd = hold_locked_index(&lock_file, 0);
- refresh_cache(REFRESH_QUIET);
+ refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
- update_index_if_able(&the_index, &lock_file);
+ update_index_if_able(r->index, &lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(ignore_submodules)) {
+ if (has_unstaged_changes(r, ignore_submodules)) {
/* TRANSLATORS: the action is e.g. "pull with rebase" */
error(_("cannot %s: You have unstaged changes."), _(action));
err = 1;
}
- if (has_uncommitted_changes(ignore_submodules)) {
+ if (has_uncommitted_changes(r, ignore_submodules)) {
if (err)
error(_("additionally, your index contains uncommitted changes."));
else
#include "pathspec.h"
#include "remote.h"
+struct repository;
struct worktree;
enum color_wt_status {
};
struct wt_status {
+ struct repository *repo;
int is_initial;
char *branch;
const char *reference;
size_t wt_status_locate_end(const char *s, size_t len);
void wt_status_add_cut_line(FILE *fp);
-void wt_status_prepare(struct wt_status *s);
+void wt_status_prepare(struct repository *r, struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
void wt_status_collect_free_buffers(struct wt_status *s);
-void wt_status_get_state(struct wt_status_state *state, int get_detached_from);
+void wt_status_get_state(struct repository *repo,
+ struct wt_status_state *state,
+ int get_detached_from);
int wt_status_check_rebase(const struct worktree *wt,
struct wt_status_state *state);
int wt_status_check_bisect(const struct worktree *wt,
void status_printf(struct wt_status *s, const char *color, const char *fmt, ...);
/* The following functions expect that the caller took care of reading the index. */
-int has_unstaged_changes(int ignore_submodules);
-int has_uncommitted_changes(int ignore_submodules);
-int require_clean_work_tree(const char *action, const char *hint,
- int ignore_submodules, int gently);
+int has_unstaged_changes(struct repository *repo,
+ int ignore_submodules);
+int has_uncommitted_changes(struct repository *repo,
+ int ignore_submodules);
+int require_clean_work_tree(struct repository *repo,
+ const char *action,
+ const char *hint,
+ int ignore_submodules,
+ int gently);
#endif /* STATUS_H */